aboutsummaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/Makefile25
-rw-r--r--lib/appmon/doc/src/make.dep26
-rw-r--r--lib/appmon/src/appmon_web.erl6
-rw-r--r--lib/asn1/c_src/Makefile41
-rw-r--r--lib/asn1/c_src/asn1_erl_driver.c1677
-rw-r--r--lib/asn1/c_src/asn1_erl_nif.c1305
-rw-r--r--lib/asn1/doc/src/Makefile90
-rw-r--r--lib/asn1/doc/src/asn1_spec.xmlsrc8
-rw-r--r--lib/asn1/doc/src/asn1_ug.xml50
-rw-r--r--lib/asn1/doc/src/asn1ct.xml33
-rw-r--r--lib/asn1/doc/src/asn1rt.xml65
-rw-r--r--lib/asn1/doc/src/make.dep31
-rw-r--r--lib/asn1/src/Makefile4
-rw-r--r--lib/asn1/src/asn1.app.src5
-rw-r--r--lib/asn1/src/asn1_app.erl2
-rw-r--r--lib/asn1/src/asn1_server.erl107
-rw-r--r--lib/asn1/src/asn1ct.erl12
-rw-r--r--lib/asn1/src/asn1ct_constructed_ber.erl2
-rw-r--r--lib/asn1/src/asn1ct_constructed_ber_bin_v2.erl12
-rw-r--r--lib/asn1/src/asn1ct_constructed_per.erl116
-rw-r--r--lib/asn1/src/asn1ct_gen.erl35
-rw-r--r--lib/asn1/src/asn1ct_gen_ber_bin_v2.erl25
-rw-r--r--lib/asn1/src/asn1ct_gen_per.erl5
-rw-r--r--lib/asn1/src/asn1ct_gen_per_rt2ct.erl5
-rw-r--r--lib/asn1/src/asn1rt.erl40
-rw-r--r--lib/asn1/src/asn1rt_ber_bin_v2.erl160
-rw-r--r--lib/asn1/src/asn1rt_check.erl2
-rw-r--r--lib/asn1/src/asn1rt_driver_handler.erl144
-rw-r--r--lib/asn1/src/asn1rt_nif.erl87
-rw-r--r--lib/asn1/src/asn1rt_per_bin.erl4
-rw-r--r--lib/asn1/src/asn1rt_per_bin_rt2ct.erl131
-rw-r--r--lib/asn1/test/asn1.cover1
-rw-r--r--lib/asn1/test/asn1_SUITE.erl.src6
-rw-r--r--[-rwxr-xr-x]lib/asn1/test/asn1_SUITE_data/DirectoryAbstractService.asn0
-rw-r--r--[-rwxr-xr-x]lib/asn1/test/asn1_SUITE_data/InformationFramework.asn0
-rw-r--r--[-rwxr-xr-x]lib/asn1/test/asn1_SUITE_data/LDAP.asn10
-rw-r--r--[-rwxr-xr-x]lib/asn1/test/asn1_SUITE_data/Nortel.asn0
-rw-r--r--[-rwxr-xr-x]lib/asn1/test/asn1_SUITE_data/UpperBounds.asn0
-rw-r--r--[-rwxr-xr-x]lib/asn1/test/asn1_SUITE_data/UsefulDefinitions.asn0
-rw-r--r--[-rwxr-xr-x]lib/asn1/test/asn1_SUITE_data/nbapsystem/NBAP-CommonDataTypes.asn0
-rw-r--r--[-rwxr-xr-x]lib/asn1/test/asn1_SUITE_data/nbapsystem/NBAP-Constants.asn0
-rw-r--r--[-rwxr-xr-x]lib/asn1/test/asn1_SUITE_data/nbapsystem/NBAP-Containers.asn0
-rw-r--r--[-rwxr-xr-x]lib/asn1/test/asn1_SUITE_data/nbapsystem/NBAP-IEs.asn0
-rw-r--r--[-rwxr-xr-x]lib/asn1/test/asn1_SUITE_data/nbapsystem/NBAP-PDU-Contents.asn0
-rw-r--r--[-rwxr-xr-x]lib/asn1/test/asn1_SUITE_data/nbapsystem/NBAP-PDU-Discriptions.asn0
-rw-r--r--lib/asn1/test/asn1_bin_v2_particular_SUITE.erl.src270
-rw-r--r--lib/asn1/test/ber_decode_error.erl6
-rw-r--r--lib/asn1/test/testPrim.erl21
-rw-r--r--lib/common_test/doc/src/Makefile15
-rw-r--r--lib/common_test/doc/src/ct_hooks.xml6
-rw-r--r--lib/common_test/doc/src/ct_hooks_chapter.xml37
-rw-r--r--[-rwxr-xr-x]lib/common_test/doc/src/filestruct.gifbin2960 -> 2960 bytes
-rw-r--r--lib/common_test/doc/src/make.dep27
-rw-r--r--lib/common_test/doc/src/run_test_chapter.xml10
-rw-r--r--lib/common_test/include/ct.hrl3
-rw-r--r--lib/common_test/priv/Makefile.in8
-rw-r--r--lib/common_test/priv/ct_default.css186
-rw-r--r--lib/common_test/src/Makefile7
-rw-r--r--lib/common_test/src/common_test.app.src1
-rw-r--r--lib/common_test/src/ct.erl4
-rw-r--r--lib/common_test/src/ct_framework.erl32
-rw-r--r--lib/common_test/src/ct_hooks.erl29
-rw-r--r--lib/common_test/src/ct_line.erl266
-rw-r--r--lib/common_test/src/ct_logs.erl634
-rw-r--r--lib/common_test/src/ct_run.erl112
-rw-r--r--lib/common_test/src/ct_testspec.erl5
-rw-r--r--lib/common_test/src/ct_util.hrl1
-rw-r--r--lib/common_test/src/cth_log_redirect.erl111
-rw-r--r--lib/common_test/test/ct_error_SUITE.erl79
-rw-r--r--lib/common_test/test/ct_repeat_1_SUITE.erl7
-rw-r--r--lib/common_test/test/ct_skip_SUITE.erl9
-rw-r--r--lib/compiler/doc/src/compile.xml8
-rw-r--r--lib/compiler/doc/src/make.dep19
-rw-r--r--lib/compiler/src/beam_asm.erl113
-rw-r--r--lib/compiler/src/beam_block.erl35
-rw-r--r--lib/compiler/src/beam_bsm.erl9
-rw-r--r--lib/compiler/src/beam_clean.erl26
-rw-r--r--lib/compiler/src/beam_dead.erl10
-rw-r--r--lib/compiler/src/beam_dict.erl66
-rw-r--r--lib/compiler/src/beam_disasm.erl31
-rw-r--r--lib/compiler/src/beam_jump.erl49
-rw-r--r--lib/compiler/src/beam_listing.erl2
-rw-r--r--lib/compiler/src/beam_receive.erl2
-rw-r--r--lib/compiler/src/beam_trim.erl13
-rw-r--r--lib/compiler/src/beam_type.erl3
-rw-r--r--lib/compiler/src/beam_utils.erl16
-rw-r--r--lib/compiler/src/beam_validator.erl15
-rw-r--r--lib/compiler/src/compile.erl49
-rw-r--r--lib/compiler/src/erl_bifs.erl2
-rw-r--r--lib/compiler/src/genop.tab4
-rw-r--r--lib/compiler/src/sys_expand_pmod.erl2
-rw-r--r--lib/compiler/src/sys_pre_expand.erl71
-rw-r--r--lib/compiler/src/v3_codegen.erl108
-rw-r--r--lib/compiler/src/v3_core.erl45
-rw-r--r--lib/compiler/src/v3_kernel.erl35
-rw-r--r--lib/compiler/src/v3_life.erl4
-rw-r--r--lib/compiler/test/bs_match_SUITE.erl4
-rw-r--r--lib/compiler/test/bs_utf_SUITE.erl21
-rw-r--r--lib/compiler/test/compile_SUITE.erl36
-rw-r--r--lib/compiler/test/fun_SUITE.erl52
-rw-r--r--lib/compiler/test/guard_SUITE.erl29
-rw-r--r--lib/compiler/test/inline_SUITE.erl3
-rw-r--r--lib/compiler/test/lc_SUITE.erl4
-rw-r--r--lib/compiler/test/misc_SUITE.erl4
-rw-r--r--lib/compiler/test/pmod_SUITE.erl5
-rw-r--r--lib/compiler/test/pmod_SUITE_data/pmod_basic.erl4
-rw-r--r--lib/compiler/test/trycatch_SUITE.erl16
-rw-r--r--lib/cosEvent/doc/src/Makefile84
-rw-r--r--lib/cosEvent/doc/src/make.dep34
-rw-r--r--lib/cosEvent/src/Makefile14
-rw-r--r--lib/cosEvent/test/Makefile14
-rw-r--r--lib/cosEventDomain/doc/src/Makefile87
-rw-r--r--lib/cosEventDomain/doc/src/make.dep23
-rw-r--r--lib/cosEventDomain/src/Makefile9
-rw-r--r--lib/cosFileTransfer/doc/src/Makefile87
-rw-r--r--lib/cosFileTransfer/doc/src/make.dep30
-rw-r--r--lib/cosFileTransfer/src/Makefile9
-rw-r--r--lib/cosNotification/doc/src/Makefile86
-rw-r--r--lib/cosNotification/doc/src/make.dep48
-rw-r--r--lib/cosNotification/src/Makefile31
-rw-r--r--lib/cosNotification/test/Makefile11
-rw-r--r--lib/cosProperty/doc/src/Makefile98
-rw-r--r--lib/cosProperty/doc/src/make.dep26
-rw-r--r--lib/cosProperty/src/Makefile8
-rw-r--r--lib/cosTime/doc/src/Makefile86
-rw-r--r--lib/cosTime/doc/src/make.dep22
-rw-r--r--lib/cosTime/src/Makefile13
-rw-r--r--lib/cosTransactions/doc/src/Makefile86
-rw-r--r--lib/cosTransactions/doc/src/make.dep27
-rw-r--r--lib/cosTransactions/src/Makefile9
-rw-r--r--lib/cosTransactions/test/Makefile11
-rw-r--r--lib/crypto/c_src/Makefile.in8
-rw-r--r--lib/crypto/c_src/crypto.c75
-rw-r--r--lib/crypto/doc/src/crypto.xml109
-rw-r--r--lib/crypto/doc/src/make.dep20
-rw-r--r--lib/crypto/src/crypto.erl85
-rw-r--r--lib/crypto/test/crypto_SUITE.erl132
-rw-r--r--lib/debugger/doc/src/debugger_chapter.xml42
-rw-r--r--lib/debugger/doc/src/int.xml4
-rw-r--r--lib/debugger/doc/src/make.dep29
-rw-r--r--lib/debugger/src/Makefile1
-rw-r--r--lib/debugger/src/dbg_debugged.erl15
-rw-r--r--lib/debugger/src/dbg_icmd.erl16
-rw-r--r--lib/debugger/src/dbg_ieval.erl570
-rw-r--r--lib/debugger/src/dbg_ieval.hrl8
-rw-r--r--lib/debugger/src/dbg_iload.erl356
-rw-r--r--lib/debugger/src/dbg_iserver.erl5
-rw-r--r--lib/debugger/src/dbg_istk.erl245
-rw-r--r--lib/debugger/src/dbg_ui_break_win.erl26
-rw-r--r--lib/debugger/src/dbg_ui_edit_win.erl8
-rw-r--r--lib/debugger/src/dbg_ui_filedialog_win.erl2
-rw-r--r--lib/debugger/src/dbg_ui_interpret.erl2
-rw-r--r--lib/debugger/src/dbg_ui_settings.erl4
-rw-r--r--lib/debugger/src/dbg_wx_break_win.erl30
-rw-r--r--lib/debugger/src/dbg_wx_filedialog_win.erl2
-rw-r--r--lib/debugger/src/dbg_wx_settings.erl6
-rw-r--r--[-rwxr-xr-x]lib/debugger/src/dbg_wx_trace_win.erl0
-rw-r--r--[-rwxr-xr-x]lib/debugger/src/dbg_wx_winman.erl0
-rw-r--r--lib/debugger/src/debugger.app.src1
-rw-r--r--lib/debugger/test/Makefile1
-rw-r--r--lib/debugger/test/bs_construct_SUITE.erl395
-rw-r--r--lib/debugger/test/bs_match_bin_SUITE.erl141
-rw-r--r--lib/debugger/test/bs_match_int_SUITE.erl206
-rw-r--r--lib/debugger/test/bs_match_misc_SUITE.erl453
-rw-r--r--lib/debugger/test/bs_match_tail_SUITE.erl12
-rw-r--r--lib/debugger/test/bug_SUITE.erl4
-rw-r--r--lib/debugger/test/exception_SUITE.erl264
-rw-r--r--lib/debugger/test/fun_SUITE.erl52
-rw-r--r--lib/debugger/test/guard_SUITE.erl217
-rw-r--r--lib/debugger/test/int_eval_SUITE.erl47
-rw-r--r--lib/debugger/test/int_eval_SUITE_data/my_int_eval_module.erl4
-rw-r--r--lib/debugger/test/int_eval_SUITE_data/stacktrace.erl130
-rw-r--r--lib/debugger/test/lc_SUITE.erl119
-rw-r--r--lib/debugger/test/line_number_SUITE.erl220
-rw-r--r--lib/debugger/test/test_lib.erl2
-rw-r--r--lib/debugger/test/trycatch_SUITE.erl17
-rw-r--r--[-rwxr-xr-x]lib/dialyzer/doc/src/Makefile0
-rw-r--r--[-rwxr-xr-x]lib/dialyzer/doc/src/book.xml0
-rw-r--r--[-rwxr-xr-x]lib/dialyzer/doc/src/fascicules.xml0
-rwxr-xr-xlib/dialyzer/doc/src/make.dep20
-rw-r--r--[-rwxr-xr-x]lib/dialyzer/doc/src/notes.xml0
-rw-r--r--[-rwxr-xr-x]lib/dialyzer/doc/src/part.xml0
-rw-r--r--[-rwxr-xr-x]lib/dialyzer/doc/src/part_notes.xml0
-rw-r--r--[-rwxr-xr-x]lib/dialyzer/doc/src/ref_man.xml0
-rw-r--r--[-rwxr-xr-x]lib/dialyzer/info0
-rw-r--r--lib/dialyzer/src/dialyzer.erl34
-rw-r--r--lib/dialyzer/src/dialyzer.hrl4
-rw-r--r--lib/dialyzer/src/dialyzer_analysis_callgraph.erl127
-rw-r--r--lib/dialyzer/src/dialyzer_behaviours.erl341
-rw-r--r--lib/dialyzer/src/dialyzer_cl.erl23
-rw-r--r--lib/dialyzer/src/dialyzer_cl_parse.erl9
-rw-r--r--lib/dialyzer/src/dialyzer_codeserver.erl50
-rw-r--r--lib/dialyzer/src/dialyzer_contracts.erl146
-rw-r--r--lib/dialyzer/src/dialyzer_options.erl10
-rw-r--r--lib/dialyzer/src/dialyzer_plt.erl74
-rw-r--r--lib/dialyzer/src/dialyzer_succ_typings.erl24
-rw-r--r--lib/dialyzer/src/dialyzer_typesig.erl22
-rw-r--r--lib/dialyzer/src/dialyzer_utils.erl49
-rw-r--r--lib/dialyzer/test/behaviour_SUITE_data/dialyzer_options1
-rw-r--r--lib/dialyzer/test/behaviour_SUITE_data/results/callbacks_and_specs5
-rw-r--r--lib/dialyzer/test/behaviour_SUITE_data/results/gen_event_incorrect_return2
-rw-r--r--lib/dialyzer/test/behaviour_SUITE_data/results/gen_server_incorrect_args8
-rw-r--r--lib/dialyzer/test/behaviour_SUITE_data/results/gen_server_missing_callbacks3
-rw-r--r--lib/dialyzer/test/behaviour_SUITE_data/results/sample_behaviour9
-rw-r--r--lib/dialyzer/test/behaviour_SUITE_data/results/sample_behaviour_old4
-rw-r--r--lib/dialyzer/test/behaviour_SUITE_data/results/supervisor_incorrect_return2
-rw-r--r--lib/dialyzer/test/behaviour_SUITE_data/results/undefined_callbacks2
-rw-r--r--lib/dialyzer/test/behaviour_SUITE_data/src/callbacks_and_specs/my_behaviour.erl11
-rw-r--r--lib/dialyzer/test/behaviour_SUITE_data/src/callbacks_and_specs/my_callbacks_correct.erl59
-rw-r--r--lib/dialyzer/test/behaviour_SUITE_data/src/callbacks_and_specs/my_callbacks_wrong.erl61
-rw-r--r--lib/dialyzer/test/behaviour_SUITE_data/src/gen_event_incorrect_return.erl33
-rw-r--r--lib/dialyzer/test/behaviour_SUITE_data/src/gen_server_incorrect_args.erl11
-rw-r--r--lib/dialyzer/test/behaviour_SUITE_data/src/gen_server_missing_callbacks.erl23
-rw-r--r--lib/dialyzer/test/behaviour_SUITE_data/src/sample_behaviour/sample_behaviour.erl13
-rw-r--r--lib/dialyzer/test/behaviour_SUITE_data/src/sample_behaviour/sample_callback_correct.erl32
-rw-r--r--lib/dialyzer/test/behaviour_SUITE_data/src/sample_behaviour/sample_callback_correct_2.erl38
-rw-r--r--lib/dialyzer/test/behaviour_SUITE_data/src/sample_behaviour/sample_callback_wrong.erl25
-rw-r--r--lib/dialyzer/test/behaviour_SUITE_data/src/sample_behaviour_old/correct_behaviour.erl6
-rw-r--r--lib/dialyzer/test/behaviour_SUITE_data/src/sample_behaviour_old/correct_callback.erl15
-rw-r--r--lib/dialyzer/test/behaviour_SUITE_data/src/sample_behaviour_old/incorrect_args_callback.erl13
-rw-r--r--lib/dialyzer/test/behaviour_SUITE_data/src/sample_behaviour_old/incorrect_return_callback.erl15
-rw-r--r--lib/dialyzer/test/behaviour_SUITE_data/src/sample_behaviour_old/missing_callback.erl10
-rw-r--r--lib/dialyzer/test/behaviour_SUITE_data/src/supervisor_incorrect_return.erl17
-rw-r--r--lib/dialyzer/test/behaviour_SUITE_data/src/undefined_callbacks/undefined_beh_callback.erl13
-rw-r--r--lib/dialyzer/test/behaviour_SUITE_data/src/undefined_callbacks/undefined_behaviour.erl10
-rw-r--r--lib/dialyzer/test/opaque_SUITE_data/results/crash1
-rw-r--r--lib/dialyzer/test/r9c_SUITE_data/results/inets32
-rw-r--r--lib/dialyzer/test/r9c_SUITE_data/results/mnesia4
-rw-r--r--lib/dialyzer/test/small_SUITE_data/results/higher_order_discrepancy4
-rw-r--r--lib/dialyzer/test/small_SUITE_data/results/higher_order_discrepancy_28
-rw-r--r--lib/dialyzer/test/small_SUITE_data/results/tuple_set_crash1
-rw-r--r--lib/dialyzer/test/small_SUITE_data/src/higher_order_discrepancy.erl14
-rw-r--r--lib/dialyzer/test/small_SUITE_data/src/higher_order_discrepancy_2.erl14
-rw-r--r--lib/dialyzer/test/underspecs_SUITE_data/dialyzer_options1
-rw-r--r--lib/dialyzer/test/underspecs_SUITE_data/results/remote9
-rw-r--r--lib/dialyzer/test/underspecs_SUITE_data/src/remote/remotes1.erl61
-rw-r--r--lib/dialyzer/test/underspecs_SUITE_data/src/remote/some_known_remote.erl5
-rwxr-xr-xlib/diameter/bin/diameterc35
-rw-r--r--lib/diameter/configure.in1
-rw-r--r--lib/diameter/doc/src/Makefile6
-rw-r--r--lib/diameter/doc/src/depend.sed12
-rw-r--r--lib/diameter/doc/src/diameter.xml144
-rw-r--r--lib/diameter/doc/src/diameter_compile.xml32
-rw-r--r--lib/diameter/doc/src/diameter_soc.xml10
-rw-r--r--lib/diameter/doc/src/diameter_tcp.xml50
-rw-r--r--lib/diameter/doc/src/diameter_transport.xml38
-rw-r--r--lib/diameter/include/diameter_gen.hrl8
-rw-r--r--lib/diameter/make/rules.mk.in2
-rw-r--r--lib/diameter/src/.gitignore (renamed from lib/diameter/src/compiler/.gitignore)1
-rw-r--r--lib/diameter/src/Makefile221
-rw-r--r--lib/diameter/src/app/.gitignore6
-rw-r--r--lib/diameter/src/app/Makefile212
-rw-r--r--lib/diameter/src/app/diameter.appup.src47
-rw-r--r--lib/diameter/src/app/diameter.mk.in47
-rw-r--r--lib/diameter/src/app/diameter_gen_base_accounting.dia68
-rw-r--r--lib/diameter/src/app/diameter_gen_base_rfc3588.dia413
-rw-r--r--lib/diameter/src/app/modules.mk70
-rw-r--r--lib/diameter/src/base/diameter.app.src (renamed from lib/diameter/src/app/diameter.app.src)2
-rw-r--r--lib/diameter/src/base/diameter.appup.src (renamed from lib/ssl/test/ssl_test_MACHINE.hrl)33
-rw-r--r--lib/diameter/src/base/diameter.erl (renamed from lib/diameter/src/app/diameter.erl)0
-rw-r--r--lib/diameter/src/base/diameter_app.erl (renamed from lib/diameter/src/app/diameter_app.erl)0
-rw-r--r--lib/diameter/src/base/diameter_callback.erl (renamed from lib/diameter/src/app/diameter_callback.erl)0
-rw-r--r--lib/diameter/src/base/diameter_capx.erl (renamed from lib/diameter/src/app/diameter_capx.erl)154
-rw-r--r--lib/diameter/src/base/diameter_codec.erl (renamed from lib/diameter/src/app/diameter_codec.erl)22
-rw-r--r--lib/diameter/src/base/diameter_config.erl (renamed from lib/diameter/src/app/diameter_config.erl)0
-rw-r--r--lib/diameter/src/base/diameter_dbg.erl (renamed from lib/diameter/src/app/diameter_dbg.erl)0
-rw-r--r--lib/diameter/src/base/diameter_dict.erl (renamed from lib/diameter/src/app/diameter_dict.erl)0
-rw-r--r--lib/diameter/src/base/diameter_info.erl (renamed from lib/diameter/src/app/diameter_info.erl)0
-rw-r--r--lib/diameter/src/base/diameter_internal.hrl (renamed from lib/diameter/src/app/diameter_internal.hrl)0
-rw-r--r--lib/diameter/src/base/diameter_lib.erl (renamed from lib/diameter/src/app/diameter_lib.erl)0
-rw-r--r--lib/diameter/src/base/diameter_misc_sup.erl (renamed from lib/diameter/src/app/diameter_misc_sup.erl)0
-rw-r--r--lib/diameter/src/base/diameter_peer.erl (renamed from lib/diameter/src/app/diameter_peer.erl)0
-rw-r--r--lib/diameter/src/base/diameter_peer_fsm.erl (renamed from lib/diameter/src/app/diameter_peer_fsm.erl)319
-rw-r--r--lib/diameter/src/base/diameter_peer_fsm_sup.erl (renamed from lib/diameter/src/app/diameter_peer_fsm_sup.erl)0
-rw-r--r--lib/diameter/src/base/diameter_reg.erl (renamed from lib/diameter/src/app/diameter_reg.erl)0
-rw-r--r--lib/diameter/src/base/diameter_service.erl (renamed from lib/diameter/src/app/diameter_service.erl)116
-rw-r--r--lib/diameter/src/base/diameter_service_sup.erl (renamed from lib/diameter/src/app/diameter_service_sup.erl)0
-rw-r--r--lib/diameter/src/base/diameter_session.erl (renamed from lib/diameter/src/app/diameter_session.erl)0
-rw-r--r--lib/diameter/src/base/diameter_stats.erl (renamed from lib/diameter/src/app/diameter_stats.erl)0
-rw-r--r--lib/diameter/src/base/diameter_sup.erl (renamed from lib/diameter/src/app/diameter_sup.erl)0
-rw-r--r--lib/diameter/src/base/diameter_sync.erl (renamed from lib/diameter/src/app/diameter_sync.erl)0
-rw-r--r--lib/diameter/src/base/diameter_types.erl (renamed from lib/diameter/src/app/diameter_types.erl)0
-rw-r--r--lib/diameter/src/base/diameter_types.hrl (renamed from lib/diameter/src/app/diameter_types.hrl)0
-rw-r--r--lib/diameter/src/base/diameter_watchdog.erl (renamed from lib/diameter/src/app/diameter_watchdog.erl)10
-rw-r--r--lib/diameter/src/base/diameter_watchdog_sup.erl (renamed from lib/diameter/src/app/diameter_watchdog_sup.erl)0
-rw-r--r--lib/diameter/src/compiler/Makefile131
-rw-r--r--lib/diameter/src/compiler/diameter_codegen.erl4
-rw-r--r--lib/diameter/src/compiler/diameter_exprecs.erl (renamed from lib/diameter/src/app/diameter_exprecs.erl)0
-rw-r--r--lib/diameter/src/compiler/diameter_make.erl122
-rw-r--r--lib/diameter/src/compiler/diameter_spec_util.erl37
-rw-r--r--lib/diameter/src/compiler/modules.mk27
-rw-r--r--lib/diameter/src/depend.sed51
-rw-r--r--lib/diameter/src/dict/base_accounting.dia69
-rw-r--r--lib/diameter/src/dict/base_rfc3588.dia414
-rw-r--r--lib/diameter/src/dict/relay.dia (renamed from lib/diameter/src/app/diameter_gen_relay.dia)1
-rw-r--r--lib/diameter/src/gen/.gitignore2
-rw-r--r--lib/diameter/src/modules.mk93
-rw-r--r--lib/diameter/src/subdirs.mk21
-rw-r--r--lib/diameter/src/transport/.gitignore3
-rw-r--r--lib/diameter/src/transport/Makefile141
-rw-r--r--lib/diameter/src/transport/diameter_sctp.erl89
-rw-r--r--lib/diameter/src/transport/diameter_tcp.erl284
-rw-r--r--lib/diameter/src/transport/modules.mk29
-rw-r--r--lib/diameter/test/Makefile123
-rw-r--r--lib/diameter/test/depend.sed18
-rw-r--r--lib/diameter/test/diameter_app_SUITE.erl31
-rw-r--r--lib/diameter/test/diameter_capx_SUITE.erl432
-rw-r--r--lib/diameter/test/diameter_codec_test.erl2
-rw-r--r--lib/diameter/test/diameter_failover_SUITE.erl257
-rw-r--r--lib/diameter/test/diameter_relay_SUITE.erl200
-rw-r--r--lib/diameter/test/diameter_tls_SUITE.erl406
-rw-r--r--lib/diameter/test/diameter_tls_SUITE_data/Makefile.ca (renamed from lib/ssl/c_src/Makefile)39
-rw-r--r--lib/diameter/test/diameter_traffic_SUITE.erl118
-rw-r--r--lib/diameter/test/diameter_transport_SUITE.erl76
-rw-r--r--lib/diameter/test/diameter_util.erl159
-rw-r--r--lib/diameter/test/diameter_watchdog_SUITE.erl2
-rw-r--r--lib/diameter/test/modules.mk7
-rw-r--r--lib/diameter/test/release.sed (renamed from lib/diameter/src/app/depend.sed)20
-rw-r--r--lib/diameter/vsn.mk2
-rw-r--r--lib/docbuilder/AUTHORS10
-rw-r--r--lib/docbuilder/Makefile37
-rw-r--r--lib/docbuilder/doc/pdf/.gitignore0
-rw-r--r--lib/docbuilder/doc/src/book.xml50
-rw-r--r--lib/docbuilder/doc/src/docb_gen.xml213
-rw-r--r--lib/docbuilder/doc/src/docb_transform.xml224
-rw-r--r--lib/docbuilder/doc/src/docbuilder_app.xml57
-rw-r--r--lib/docbuilder/doc/src/make.dep33
-rw-r--r--lib/docbuilder/doc/src/man.ps750
-rw-r--r--lib/docbuilder/doc/src/notes.xml256
-rw-r--r--lib/docbuilder/doc/src/part_notes.xml37
-rw-r--r--lib/docbuilder/dtd/Makefile91
-rw-r--r--lib/docbuilder/dtd/common.dtd87
-rw-r--r--lib/docbuilder/dtd/common.refs.dtd40
-rw-r--r--lib/docbuilder/dtd/erlref.dtd31
-rw-r--r--lib/docbuilder/dtd/xhtml-lat1.ent196
-rw-r--r--lib/docbuilder/ebin/.gitignore0
-rw-r--r--lib/docbuilder/etc/Makefile67
-rw-r--r--lib/docbuilder/etc/note.gifbin1539 -> 0 bytes
-rw-r--r--lib/docbuilder/etc/warning.gifbin1498 -> 0 bytes
-rw-r--r--lib/docbuilder/info2
-rw-r--r--lib/docbuilder/src/Makefile121
-rw-r--r--lib/docbuilder/src/docb_gen.erl142
-rw-r--r--lib/docbuilder/src/docb_html.erl393
-rw-r--r--lib/docbuilder/src/docb_html_layout.erl380
-rw-r--r--lib/docbuilder/src/docb_html_ref.erl79
-rw-r--r--lib/docbuilder/src/docb_html_util.erl542
-rw-r--r--lib/docbuilder/src/docb_html_util_iso.erl204
-rw-r--r--lib/docbuilder/src/docb_main.erl657
-rw-r--r--lib/docbuilder/src/docb_pretty_format.erl177
-rw-r--r--lib/docbuilder/src/docb_tr_application2html.erl286
-rw-r--r--lib/docbuilder/src/docb_tr_appref2html.erl48
-rw-r--r--lib/docbuilder/src/docb_tr_chapter2html.erl59
-rw-r--r--lib/docbuilder/src/docb_tr_cite2html.erl134
-rw-r--r--lib/docbuilder/src/docb_tr_comref2html.erl46
-rw-r--r--lib/docbuilder/src/docb_tr_cref2html.erl61
-rw-r--r--lib/docbuilder/src/docb_tr_erlref2html.erl46
-rw-r--r--lib/docbuilder/src/docb_tr_fileref2html.erl46
-rw-r--r--lib/docbuilder/src/docb_tr_first2html.erl46
-rw-r--r--lib/docbuilder/src/docb_tr_index2html.erl195
-rw-r--r--lib/docbuilder/src/docb_tr_part2html.erl237
-rw-r--r--lib/docbuilder/src/docb_tr_refs2kwic.erl156
-rw-r--r--lib/docbuilder/src/docb_tr_report2html.erl70
-rw-r--r--lib/docbuilder/src/docb_tr_term2html.erl124
-rw-r--r--lib/docbuilder/src/docb_transform.erl163
-rw-r--r--lib/docbuilder/src/docb_util.erl237
-rw-r--r--lib/docbuilder/src/docb_util.hrl34
-rw-r--r--lib/docbuilder/src/docb_xmerl_tree_cb.erl343
-rw-r--r--lib/docbuilder/src/docbuilder.app.src37
-rw-r--r--lib/docbuilder/src/docbuilder.appup.src1
-rw-r--r--lib/docbuilder/test/Makefile80
-rw-r--r--lib/docbuilder/test/docb.cover2
-rwxr-xr-xlib/docbuilder/test/docb_SUITE_data/cdata_problem.xml22
-rw-r--r--lib/docbuilder/vsn.mk1
-rwxr-xr-xlib/docbuilder/xsd/application.xsd31
-rwxr-xr-xlib/docbuilder/xsd/appref.xsd27
-rwxr-xr-xlib/docbuilder/xsd/book.xsd292
-rwxr-xr-xlib/docbuilder/xsd/chapter.xsd45
-rwxr-xr-xlib/docbuilder/xsd/common.entities.xsd2
-rwxr-xr-xlib/docbuilder/xsd/common.header.xsd29
-rwxr-xr-xlib/docbuilder/xsd/common.image.xsd18
-rwxr-xr-xlib/docbuilder/xsd/common.refs.xsd102
-rwxr-xr-xlib/docbuilder/xsd/common.table.xsd42
-rwxr-xr-xlib/docbuilder/xsd/common.xsd212
-rwxr-xr-xlib/docbuilder/xsd/comref.xsd26
-rwxr-xr-xlib/docbuilder/xsd/cref.xsd35
-rwxr-xr-xlib/docbuilder/xsd/erlref.xsd26
-rwxr-xr-xlib/docbuilder/xsd/fascicules.xsd25
-rwxr-xr-xlib/docbuilder/xsd/fileref.xsd26
-rwxr-xr-xlib/docbuilder/xsd/part.xsd31
-rw-r--r--lib/edoc/doc/Makefile9
-rw-r--r--lib/edoc/doc/src/make.dep21
-rw-r--r--lib/erl_docgen/Makefile3
-rw-r--r--lib/erl_docgen/doc/html/.gitignore (renamed from lib/docbuilder/doc/html/.gitignore)0
-rw-r--r--lib/erl_docgen/doc/man6/.gitignore (renamed from lib/docbuilder/doc/man3/.gitignore)0
-rw-r--r--lib/erl_docgen/doc/pdf/.gitignore (renamed from lib/docbuilder/doc/man6/.gitignore)0
-rw-r--r--lib/erl_docgen/doc/src/Makefile (renamed from lib/docbuilder/doc/src/Makefile)81
-rw-r--r--lib/erl_docgen/doc/src/block_tags.xml (renamed from lib/docbuilder/doc/src/block_tags.xml)16
-rw-r--r--lib/erl_docgen/doc/src/book.xml15
-rw-r--r--lib/erl_docgen/doc/src/character_entities.xml (renamed from lib/docbuilder/doc/src/character_entities.xml)2
-rw-r--r--lib/erl_docgen/doc/src/convert.howto13
-rw-r--r--lib/erl_docgen/doc/src/docgen_xml_check.xml (renamed from lib/docbuilder/doc/src/docb_xml_check.xml)6
-rw-r--r--lib/erl_docgen/doc/src/erl_docgen.txt6
-rw-r--r--lib/erl_docgen/doc/src/erl_docgen_app.xml64
-rw-r--r--lib/erl_docgen/doc/src/example.txt (renamed from lib/docbuilder/doc/src/gazonk)2
-rw-r--r--lib/erl_docgen/doc/src/fasc_dtds.xml (renamed from lib/docbuilder/doc/src/fasc_dtds.xml)0
-rw-r--r--lib/erl_docgen/doc/src/fascicules.xml (renamed from lib/docbuilder/doc/src/fascicules.xml)0
-rw-r--r--lib/erl_docgen/doc/src/header_tags.xml (renamed from lib/docbuilder/doc/src/header_tags.xml)16
-rw-r--r--lib/erl_docgen/doc/src/inline_tags.xml (renamed from lib/docbuilder/doc/src/inline_tags.xml)49
-rw-r--r--lib/erl_docgen/doc/src/man.gif (renamed from lib/docbuilder/doc/src/man.gif)bin6048 -> 6048 bytes
-rw-r--r--lib/erl_docgen/doc/src/notes.xml6
-rw-r--r--lib/erl_docgen/doc/src/overview.xml (renamed from lib/docbuilder/doc/src/overview.xml)50
-rw-r--r--lib/erl_docgen/doc/src/part.xml (renamed from lib/docbuilder/doc/src/part.xml)9
-rw-r--r--lib/erl_docgen/doc/src/ref_man.xml (renamed from lib/docbuilder/doc/src/ref_man.xml)20
-rw-r--r--lib/erl_docgen/doc/src/refman_dtds.xml (renamed from lib/docbuilder/doc/src/refman_dtds.xml)6
-rw-r--r--lib/erl_docgen/doc/src/user_guide_dtds.xml (renamed from lib/docbuilder/doc/src/user_guide_dtds.xml)0
-rw-r--r--lib/erl_docgen/info3
-rw-r--r--lib/erl_docgen/priv/Makefile2
-rw-r--r--lib/erl_docgen/priv/bin/specs_gen.escript4
-rwxr-xr-xlib/erl_docgen/priv/bin/xml_from_edoc.escript4
-rw-r--r--lib/erl_docgen/priv/docbuilder_dtd/application.dtd29
-rw-r--r--lib/erl_docgen/priv/docbuilder_dtd/appref.dtd33
-rw-r--r--lib/erl_docgen/priv/docbuilder_dtd/book.dtd73
-rw-r--r--lib/erl_docgen/priv/docbuilder_dtd/bookinsidecover.dtd36
-rw-r--r--lib/erl_docgen/priv/docbuilder_dtd/chapter.dtd36
-rw-r--r--lib/erl_docgen/priv/docbuilder_dtd/cites.dtd35
-rw-r--r--lib/erl_docgen/priv/docbuilder_dtd/common.entities.dtd24
-rw-r--r--lib/erl_docgen/priv/docbuilder_dtd/common.header.dtd42
-rw-r--r--lib/erl_docgen/priv/docbuilder_dtd/common.image.dtd21
-rw-r--r--lib/erl_docgen/priv/docbuilder_dtd/common.table.dtd25
-rw-r--r--lib/erl_docgen/priv/docbuilder_dtd/comref.dtd31
-rw-r--r--lib/erl_docgen/priv/docbuilder_dtd/cref.dtd34
-rw-r--r--lib/erl_docgen/priv/docbuilder_dtd/fascicules.dtd35
-rw-r--r--lib/erl_docgen/priv/docbuilder_dtd/fileref.dtd31
-rw-r--r--lib/erl_docgen/priv/docbuilder_dtd/part.dtd29
-rw-r--r--lib/erl_docgen/priv/docbuilder_dtd/report.dtd138
-rw-r--r--lib/erl_docgen/priv/docbuilder_dtd/terms.dtd36
-rw-r--r--lib/erl_docgen/priv/docbuilder_dtd/xhtml1-frameset.dtd1235
-rw-r--r--lib/erl_docgen/priv/docbuilder_dtd/xhtml1-strict.dtd978
-rw-r--r--lib/erl_docgen/priv/docbuilder_dtd/xhtml1-transitional.dtd1201
-rw-r--r--lib/erl_docgen/priv/dtd/Makefile (renamed from lib/erl_docgen/priv/docbuilder_dtd/Makefile)8
-rw-r--r--lib/erl_docgen/priv/dtd/application.dtd (renamed from lib/docbuilder/dtd/application.dtd)0
-rw-r--r--lib/erl_docgen/priv/dtd/appref.dtd (renamed from lib/docbuilder/dtd/appref.dtd)0
-rw-r--r--lib/erl_docgen/priv/dtd/book.dtd (renamed from lib/docbuilder/dtd/book.dtd)0
-rw-r--r--lib/erl_docgen/priv/dtd/bookinsidecover.dtd (renamed from lib/docbuilder/dtd/bookinsidecover.dtd)0
-rw-r--r--lib/erl_docgen/priv/dtd/chapter.dtd (renamed from lib/docbuilder/dtd/chapter.dtd)0
-rw-r--r--lib/erl_docgen/priv/dtd/cites.dtd (renamed from lib/docbuilder/dtd/cites.dtd)0
-rw-r--r--lib/erl_docgen/priv/dtd/common.dtd (renamed from lib/erl_docgen/priv/docbuilder_dtd/common.dtd)0
-rw-r--r--lib/erl_docgen/priv/dtd/common.entities.dtd (renamed from lib/docbuilder/dtd/common.entities.dtd)0
-rw-r--r--lib/erl_docgen/priv/dtd/common.header.dtd (renamed from lib/docbuilder/dtd/common.header.dtd)0
-rw-r--r--lib/erl_docgen/priv/dtd/common.image.dtd (renamed from lib/docbuilder/dtd/common.image.dtd)0
-rw-r--r--lib/erl_docgen/priv/dtd/common.refs.dtd (renamed from lib/erl_docgen/priv/docbuilder_dtd/common.refs.dtd)0
-rw-r--r--lib/erl_docgen/priv/dtd/common.table.dtd (renamed from lib/docbuilder/dtd/common.table.dtd)0
-rw-r--r--lib/erl_docgen/priv/dtd/comref.dtd (renamed from lib/docbuilder/dtd/comref.dtd)0
-rw-r--r--lib/erl_docgen/priv/dtd/cref.dtd (renamed from lib/docbuilder/dtd/cref.dtd)0
-rw-r--r--lib/erl_docgen/priv/dtd/erlref.dtd (renamed from lib/erl_docgen/priv/docbuilder_dtd/erlref.dtd)0
-rw-r--r--lib/erl_docgen/priv/dtd/fascicules.dtd (renamed from lib/docbuilder/dtd/fascicules.dtd)0
-rw-r--r--lib/erl_docgen/priv/dtd/fileref.dtd (renamed from lib/docbuilder/dtd/fileref.dtd)0
-rw-r--r--lib/erl_docgen/priv/dtd/part.dtd (renamed from lib/docbuilder/dtd/part.dtd)0
-rw-r--r--lib/erl_docgen/priv/dtd/report.dtd (renamed from lib/docbuilder/dtd/report.dtd)0
-rw-r--r--lib/erl_docgen/priv/dtd/terms.dtd (renamed from lib/docbuilder/dtd/terms.dtd)0
-rw-r--r--lib/erl_docgen/priv/dtd/xhtml-special.ent (renamed from lib/docbuilder/dtd/xhtml-special.ent)0
-rw-r--r--lib/erl_docgen/priv/dtd/xhtml-symbol.ent (renamed from lib/docbuilder/dtd/xhtml-symbol.ent)0
-rw-r--r--lib/erl_docgen/priv/dtd/xhtml1-frameset.dtd (renamed from lib/docbuilder/dtd/xhtml1-frameset.dtd)0
-rw-r--r--lib/erl_docgen/priv/dtd/xhtml1-strict.dtd (renamed from lib/docbuilder/dtd/xhtml1-strict.dtd)0
-rw-r--r--lib/erl_docgen/priv/dtd/xhtml1-transitional.dtd (renamed from lib/docbuilder/dtd/xhtml1-transitional.dtd)0
-rw-r--r--lib/erl_docgen/priv/xsl/db_eix.xsl8
-rw-r--r--lib/erl_docgen/priv/xsl/db_man.xsl19
-rw-r--r--lib/erl_docgen/src/Makefile4
-rw-r--r--lib/erl_docgen/src/docgen_edoc_xml_cb.erl (renamed from lib/docbuilder/src/docb_edoc_xml_cb.erl)30
-rw-r--r--lib/erl_docgen/src/docgen_otp_specs.erl (renamed from lib/erl_docgen/src/otp_specs.erl)2
-rw-r--r--lib/erl_docgen/src/docgen_xmerl_xml_cb.erl (renamed from lib/docbuilder/src/docb_xmerl_xml_cb.erl)10
-rw-r--r--lib/erl_docgen/src/docgen_xml_check.erl (renamed from lib/docbuilder/src/docb_xml_check.erl)4
-rw-r--r--lib/erl_docgen/src/erl_docgen.app.src4
-rw-r--r--lib/erl_docgen/vsn.mk2
-rw-r--r--lib/erl_interface/configure.in6
-rw-r--r--lib/erl_interface/doc/src/make.dep24
-rw-r--r--lib/erl_interface/src/Makefile.in34
-rw-r--r--lib/erl_interface/test/all_SUITE_data/Makefile.src2
-rw-r--r--lib/erl_interface/test/all_SUITE_data/init_tc.erl18
-rw-r--r--lib/eunit/doc/src/make.dep19
-rw-r--r--lib/eunit/src/Makefile13
-rw-r--r--lib/gs/doc/src/make.dep58
-rw-r--r--lib/gs/src/Makefile4
-rw-r--r--lib/gs/src/gstk_editor.erl4
-rw-r--r--lib/gs/src/gstk_generic.erl2
-rw-r--r--lib/gs/src/gstk_image.erl4
-rw-r--r--lib/gs/src/tool_utils.erl3
-rw-r--r--lib/hipe/cerl/erl_bif_types.erl12
-rw-r--r--lib/hipe/doc/src/make.dep13
-rw-r--r--lib/hipe/icode/hipe_beam_to_icode.erl72
-rw-r--r--lib/hipe/icode/hipe_icode_coordinator.erl9
-rw-r--r--lib/hipe/icode/hipe_icode_mulret.erl4
-rw-r--r--[-rwxr-xr-x]lib/hipe/icode/hipe_icode_pp.erl0
-rw-r--r--[-rwxr-xr-x]lib/hipe/icode/hipe_icode_ssa.erl0
-rw-r--r--lib/hipe/main/hipe.erl137
-rw-r--r--lib/hipe/rtl/Makefile26
-rw-r--r--lib/hipe/rtl/hipe_rtl.erl5
-rw-r--r--lib/hipe/rtl/hipe_rtl_arch.erl27
-rw-r--r--lib/hipe/rtl/hipe_rtl_lcm.erl21
-rw-r--r--lib/hipe/tools/Makefile2
-rw-r--r--lib/hipe/tools/hipe_ceach.erl74
-rw-r--r--[-rwxr-xr-x]lib/hipe/util/hipe_dot.erl0
-rw-r--r--lib/ic/c_src/Makefile.in8
-rw-r--r--lib/ic/doc/src/Makefile108
-rw-r--r--lib/ic/doc/src/make.dep24
-rw-r--r--lib/ic/doc/src/notes.xml16
-rw-r--r--lib/ic/examples/pre_post_condition/Makefile9
-rw-r--r--lib/ic/java_src/com/ericsson/otp/ic/ignore_config_record.inf1
-rw-r--r--lib/ic/src/ic_pragma.erl6
-rw-r--r--lib/ic/vsn.mk2
-rw-r--r--lib/inets/doc/archive/rfc3986.txt3419
-rw-r--r--lib/inets/doc/src/Makefile96
-rw-r--r--lib/inets/doc/src/ftp.xml21
-rw-r--r--lib/inets/doc/src/httpc.xml13
-rw-r--r--lib/inets/doc/src/httpd.xml12
-rw-r--r--lib/inets/doc/src/make.dep47
-rw-r--r--lib/inets/doc/src/notes.xml721
-rw-r--r--lib/inets/src/ftp/ftp.erl151
-rw-r--r--lib/inets/src/http_client/Makefile1
-rw-r--r--lib/inets/src/http_client/http.erl132
-rw-r--r--lib/inets/src/http_client/httpc.erl46
-rw-r--r--lib/inets/src/http_client/httpc_internal.hrl41
-rw-r--r--lib/inets/src/http_client/httpc_manager.erl29
-rw-r--r--lib/inets/src/http_client/httpc_response.erl9
-rw-r--r--lib/inets/src/http_lib/http_internal.hrl1
-rw-r--r--lib/inets/src/http_lib/http_transport.erl59
-rw-r--r--lib/inets/src/http_lib/http_uri.erl63
-rw-r--r--lib/inets/src/http_lib/http_util.erl4
-rw-r--r--lib/inets/src/http_server/httpd_conf.erl6
-rw-r--r--lib/inets/src/http_server/httpd_file.erl6
-rw-r--r--lib/inets/src/http_server/httpd_request.erl6
-rw-r--r--lib/inets/src/http_server/httpd_request_handler.erl6
-rw-r--r--lib/inets/src/http_server/httpd_response.erl17
-rw-r--r--lib/inets/src/http_server/httpd_util.erl53
-rw-r--r--lib/inets/src/http_server/mod_log.erl10
-rw-r--r--lib/inets/src/http_server/mod_responsecontrol.erl55
-rw-r--r--lib/inets/src/inets_app/Makefile3
-rw-r--r--lib/inets/src/inets_app/inets.app.src3
-rw-r--r--lib/inets/src/inets_app/inets.appup.src60
-rw-r--r--lib/inets/src/inets_app/inets.mk4
-rw-r--r--lib/inets/src/inets_app/inets_service.erl37
-rw-r--r--lib/inets/src/tftp/tftp.erl57
-rw-r--r--lib/inets/test/ftp_suite_lib.erl82
-rw-r--r--lib/inets/test/ftp_windows_2003_server_test.erl22
-rw-r--r--lib/inets/test/httpc_SUITE.erl201
-rw-r--r--lib/inets/test/httpc_cookie_SUITE.erl70
-rw-r--r--lib/inets/test/httpd_1_1.erl108
-rw-r--r--lib/inets/test/httpd_SUITE.erl330
-rw-r--r--lib/inets/test/httpd_basic_SUITE.erl140
-rw-r--r--lib/inets/test/httpd_mod.erl32
-rw-r--r--lib/inets/test/httpd_test_lib.erl55
-rw-r--r--lib/inets/test/httpd_time_test.erl6
-rw-r--r--lib/inets/test/inets_test_lib.erl10
-rw-r--r--lib/inets/vsn.mk2
-rw-r--r--lib/inviso/doc/src/make.dep27
-rw-r--r--lib/inviso/src/inviso_tool_lib.erl8
-rw-r--r--lib/jinterface/doc/src/make.dep20
-rw-r--r--lib/jinterface/java_src/Makefile16
-rw-r--r--lib/jinterface/java_src/com/ericsson/otp/erlang/Makefile (renamed from lib/jinterface/java_src/com/ericsson/otp/erlang/Makefile.otp)2
-rw-r--r--lib/jinterface/java_src/com/ericsson/otp/erlang/OtpErlangString.java5
-rw-r--r--lib/jinterface/java_src/com/ericsson/otp/erlang/ignore_config_record.inf1
-rw-r--r--lib/kernel/doc/src/gen_sctp.xml54
-rw-r--r--lib/kernel/doc/src/heart.xml2
-rw-r--r--lib/kernel/doc/src/kernel_app.xml11
-rw-r--r--lib/kernel/doc/src/make.dep28
-rw-r--r--lib/kernel/doc/src/net_kernel.xml4
-rw-r--r--lib/kernel/include/dist.hrl (renamed from lib/kernel/src/dist.hrl)0
-rw-r--r--lib/kernel/include/dist_util.hrl (renamed from lib/kernel/src/dist_util.hrl)0
-rw-r--r--lib/kernel/include/net_address.hrl (renamed from lib/kernel/src/net_address.hrl)0
-rw-r--r--lib/kernel/src/Makefile17
-rw-r--r--lib/kernel/src/application.erl12
-rw-r--r--lib/kernel/src/application_controller.erl19
-rw-r--r--lib/kernel/src/code.erl29
-rw-r--r--lib/kernel/src/code_server.erl33
-rw-r--r--lib/kernel/src/disk_log.erl22
-rw-r--r--lib/kernel/src/error_handler.erl9
-rw-r--r--lib/kernel/src/file.erl7
-rw-r--r--lib/kernel/src/gen_sctp.erl32
-rw-r--r--lib/kernel/src/global.erl23
-rw-r--r--lib/kernel/src/hipe_unified_loader.erl11
-rw-r--r--lib/kernel/src/inet.erl43
-rw-r--r--lib/kernel/src/inet6_sctp.erl17
-rw-r--r--lib/kernel/src/inet6_tcp.erl8
-rw-r--r--lib/kernel/src/inet6_udp.erl6
-rw-r--r--lib/kernel/src/inet_int.hrl16
-rw-r--r--lib/kernel/src/inet_sctp.erl21
-rw-r--r--lib/kernel/src/inet_tcp.erl8
-rw-r--r--lib/kernel/src/inet_udp.erl4
-rw-r--r--lib/kernel/src/kernel.appup.src28
-rw-r--r--lib/kernel/src/user_drv.erl8
-rw-r--r--lib/kernel/src/user_sup.erl6
-rw-r--r--lib/kernel/test/application_SUITE.erl30
-rw-r--r--lib/kernel/test/application_SUITE_data/Makefile.src5
-rw-r--r--lib/kernel/test/application_SUITE_data/deadlock/deadlock.app8
-rw-r--r--lib/kernel/test/application_SUITE_data/deadlock/deadlock.erl69
-rw-r--r--lib/kernel/test/code_SUITE.erl16
-rw-r--r--lib/kernel/test/disk_log_SUITE.erl11
-rw-r--r--lib/kernel/test/erl_boot_server_SUITE.erl2
-rw-r--r--lib/kernel/test/file_SUITE.erl4
-rw-r--r--lib/kernel/test/gen_sctp_SUITE.erl954
-rw-r--r--lib/kernel/test/gen_udp_SUITE.erl69
-rw-r--r--lib/kernel/test/global_SUITE.erl17
-rw-r--r--lib/kernel/test/inet_SUITE.erl8
-rw-r--r--lib/kernel/test/inet_res_SUITE.erl7
-rwxr-xr-xlib/kernel/test/inet_res_SUITE_data/run-named33
-rw-r--r--lib/kernel/test/kernel_SUITE.erl64
-rw-r--r--lib/kernel/test/pg2_SUITE.erl1
-rw-r--r--lib/kernel/test/wrap_log_reader_SUITE.erl2
-rw-r--r--lib/kernel/test/zlib_SUITE.erl4
-rw-r--r--lib/kernel/vsn.mk2
-rw-r--r--lib/megaco/.gitignore3
-rw-r--r--lib/megaco/configure.in5
-rw-r--r--lib/megaco/doc/src/Makefile105
-rw-r--r--lib/megaco/doc/src/make.dep59
-rw-r--r--lib/megaco/doc/src/notes.xml55
-rw-r--r--lib/megaco/examples/meas/Makefile.in (renamed from lib/megaco/examples/meas/Makefile)38
-rw-r--r--lib/megaco/examples/meas/meas.sh.skel.src (renamed from lib/megaco/examples/meas/meas.sh.skel)4
-rw-r--r--lib/megaco/examples/meas/modules.mk8
-rw-r--r--lib/megaco/examples/meas/mstone1.sh.skel.src (renamed from lib/megaco/examples/meas/mstone1.sh.skel)4
-rw-r--r--lib/megaco/src/app/megaco.appup.src11
-rw-r--r--lib/megaco/src/binary/depend.mk198
-rw-r--r--lib/megaco/src/flex/Makefile.in11
-rw-r--r--lib/megaco/test/megaco_codec_v1_test.erl4
-rw-r--r--lib/megaco/test/megaco_codec_v2_test.erl4
-rw-r--r--lib/megaco/test/megaco_mess_test.erl92
-rw-r--r--lib/megaco/test/megaco_profile.erl343
-rw-r--r--lib/megaco/test/megaco_test_lib.erl10
-rw-r--r--lib/megaco/vsn.mk2
-rw-r--r--lib/mnesia/doc/src/Makefile86
-rw-r--r--lib/mnesia/doc/src/make.dep46
-rw-r--r--lib/mnesia/doc/src/notes.xml30
-rw-r--r--lib/mnesia/src/mnesia.appup.src4
-rw-r--r--lib/mnesia/src/mnesia_bup.erl4
-rw-r--r--lib/mnesia/src/mnesia_controller.erl35
-rw-r--r--lib/mnesia/src/mnesia_event.erl6
-rw-r--r--lib/mnesia/src/mnesia_frag.erl12
-rw-r--r--lib/mnesia/src/mnesia_frag_hash.erl18
-rw-r--r--lib/mnesia/src/mnesia_lib.erl2
-rw-r--r--lib/mnesia/src/mnesia_loader.erl2
-rw-r--r--lib/mnesia/src/mnesia_monitor.erl6
-rw-r--r--lib/mnesia/src/mnesia_schema.erl108
-rw-r--r--lib/mnesia/test/mnesia_evil_backup.erl8
-rw-r--r--lib/mnesia/test/mnesia_evil_coverage_test.erl8
-rw-r--r--lib/mnesia/test/mnesia_frag_hash_test.erl94
-rw-r--r--lib/mnesia/test/mnesia_install_test.erl23
-rw-r--r--lib/mnesia/vsn.mk2
-rw-r--r--lib/observer/doc/src/make.dep29
-rw-r--r--lib/observer/doc/src/ttb.xml233
-rw-r--r--lib/observer/doc/src/ttb_ug.xml385
-rw-r--r--lib/observer/priv/erlang_observer.pngbin0 -> 4351 bytes
-rw-r--r--lib/observer/src/Makefile23
-rw-r--r--lib/observer/src/observer.erl25
-rw-r--r--lib/observer/src/observer_defs.hrl62
-rw-r--r--lib/observer/src/observer_lib.erl297
-rw-r--r--lib/observer/src/observer_pro_wx.erl608
-rw-r--r--lib/observer/src/observer_procinfo.erl274
-rw-r--r--lib/observer/src/observer_sys_wx.erl223
-rw-r--r--lib/observer/src/observer_trace_wx.erl628
-rw-r--r--lib/observer/src/observer_traceoptions_wx.erl572
-rw-r--r--lib/observer/src/observer_tv.hrl34
-rw-r--r--lib/observer/src/observer_tv_table.erl801
-rw-r--r--lib/observer/src/observer_tv_wx.erl475
-rw-r--r--lib/observer/src/observer_wx.erl537
-rw-r--r--lib/observer/src/ttb.erl754
-rw-r--r--lib/observer/test/Makefile3
-rw-r--r--lib/observer/test/client.erl28
-rw-r--r--lib/observer/test/crashdump_helper.erl2
-rw-r--r--lib/observer/test/crashdump_viewer_SUITE.erl6
-rw-r--r--lib/observer/test/server.erl44
-rw-r--r--lib/observer/test/ttb_SUITE.erl916
-rw-r--r--lib/observer/test/ttb_helper.erl157
-rw-r--r--lib/odbc/c_src/Makefile.in7
-rw-r--r--lib/odbc/doc/src/Makefile87
-rw-r--r--lib/odbc/doc/src/make.dep27
-rw-r--r--lib/odbc/src/odbc.appup.src2
-rw-r--r--lib/odbc/src/odbc.erl3
-rw-r--r--lib/orber/COSS/CosNaming/Makefile8
-rw-r--r--lib/orber/doc/src/Makefile89
-rw-r--r--lib/orber/doc/src/Orber/ignore_config_record.inf1
-rw-r--r--lib/orber/doc/src/make.dep62
-rw-r--r--lib/orber/examples/Stack/Makefile12
-rw-r--r--[-rwxr-xr-x]lib/orber/priv/Makefile0
-rw-r--r--[-rwxr-xr-x]lib/orber/priv/blank.html0
-rw-r--r--[-rwxr-xr-x]lib/orber/priv/info_frames.html0
-rw-r--r--[-rwxr-xr-x]lib/orber/priv/main_frame.html0
-rw-r--r--[-rwxr-xr-x]lib/orber/priv/orber.tool0
-rw-r--r--[-rwxr-xr-x]lib/orber/priv/orber_help.txt0
-rw-r--r--[-rwxr-xr-x]lib/orber/priv/start_info.html0
-rw-r--r--lib/orber/src/Makefile13
-rw-r--r--lib/orber/src/corba.erl4
-rw-r--r--lib/orber/src/orber_diagnostics.erl4
-rw-r--r--lib/orber/src/orber_ifr.erl2
-rw-r--r--lib/orber/test/Makefile26
-rw-r--r--lib/orber/test/csiv2_SUITE.erl4
-rw-r--r--lib/orber/test/multi_ORB_SUITE.erl2
-rw-r--r--lib/orber/test/orber_test_lib.erl3
-rw-r--r--lib/orber/vsn.mk2
-rw-r--r--lib/os_mon/c_src/Makefile.in8
-rw-r--r--lib/os_mon/doc/src/make.dep21
-rw-r--r--lib/os_mon/mibs/Makefile3
-rw-r--r--lib/os_mon/src/os_mon_mib.erl4
-rw-r--r--lib/os_mon/test/os_mon_mib_SUITE.erl2
-rw-r--r--lib/otp_mibs/doc/src/make.dep20
-rw-r--r--lib/otp_mibs/src/otp_mib.erl4
-rw-r--r--lib/parsetools/doc/src/make.dep21
-rw-r--r--lib/parsetools/include/yeccpre.hrl9
-rw-r--r--lib/parsetools/src/yeccparser.erl4
-rw-r--r--lib/parsetools/test/yecc_SUITE.erl7
-rw-r--r--lib/percept/doc/src/make.dep34
-rw-r--r--[-rwxr-xr-x]lib/percept/doc/src/part_notes.xml0
-rw-r--r--[-rwxr-xr-x]lib/percept/test/percept_SUITE_data/ipc-dist.datbin2098105 -> 2098105 bytes
-rw-r--r--lib/pman/doc/src/make.dep26
-rw-r--r--lib/public_key/.gitignore7
-rw-r--r--[-rwxr-xr-x]lib/public_key/asn1/DSS.asn10
-rw-r--r--lib/public_key/asn1/InformationFramework.asn1682
-rw-r--r--lib/public_key/asn1/Makefile24
-rw-r--r--[-rwxr-xr-x]lib/public_key/asn1/PKCS-1.asn10
-rw-r--r--lib/public_key/asn1/PKCS-8.asn183
-rw-r--r--lib/public_key/asn1/PKCS-FRAME.set.asn3
-rw-r--r--lib/public_key/asn1/PKCS5v2-0.asn1142
-rw-r--r--lib/public_key/doc/src/Makefile86
-rw-r--r--lib/public_key/doc/src/introduction.xml8
-rw-r--r--lib/public_key/doc/src/make.dep21
-rw-r--r--lib/public_key/doc/src/public_key.xml23
-rw-r--r--lib/public_key/include/public_key.hrl1
-rw-r--r--lib/public_key/src/Makefile6
-rw-r--r--lib/public_key/src/pubkey_pbe.erl213
-rw-r--r--lib/public_key/src/pubkey_pem.erl81
-rw-r--r--lib/public_key/src/public_key.app.src4
-rw-r--r--lib/public_key/src/public_key.appup.src74
-rw-r--r--lib/public_key/src/public_key.erl102
-rw-r--r--lib/public_key/test/Makefile3
-rw-r--r--lib/public_key/test/pbe_SUITE.erl259
-rw-r--r--lib/public_key/test/pbe_SUITE_data/des_cbc_enc_key.pem11
-rw-r--r--lib/public_key/test/pbe_SUITE_data/des_ede3_cbc_enc_key.pem11
-rw-r--r--lib/public_key/test/pbe_SUITE_data/rc2_cbc_enc_key.pem12
-rw-r--r--lib/public_key/test/public_key_SUITE.erl27
-rw-r--r--lib/public_key/vsn.mk2
-rw-r--r--lib/reltool/doc/src/make.dep20
-rw-r--r--lib/runtime_tools/c_src/Makefile.in15
-rw-r--r--lib/runtime_tools/doc/src/dbg.xml23
-rw-r--r--lib/runtime_tools/doc/src/make.dep20
-rw-r--r--lib/runtime_tools/src/Makefile3
-rw-r--r--lib/runtime_tools/src/dbg.erl65
-rw-r--r--lib/runtime_tools/src/inviso_rt.erl4
-rw-r--r--lib/runtime_tools/src/inviso_rt_lib.erl16
-rw-r--r--lib/runtime_tools/src/observer_backend.erl123
-rw-r--r--lib/runtime_tools/src/runtime_tools.app.src3
-rw-r--r--lib/runtime_tools/src/runtime_tools_sup.erl4
-rw-r--r--lib/runtime_tools/src/ttb_autostart.erl55
-rw-r--r--lib/runtime_tools/test/inviso_SUITE.erl22
-rw-r--r--lib/sasl/doc/src/appup.xml37
-rw-r--r--lib/sasl/doc/src/make.dep22
-rw-r--r--lib/sasl/doc/src/release_handler.xml70
-rw-r--r--lib/sasl/doc/src/systools.xml16
-rw-r--r--lib/sasl/examples/src/target_system.erl8
-rw-r--r--lib/sasl/src/release_handler.erl456
-rw-r--r--lib/sasl/src/release_handler_1.erl133
-rw-r--r--lib/sasl/src/sasl.appup.src26
-rw-r--r--lib/sasl/src/systools_make.erl267
-rw-r--r--lib/sasl/src/systools_rc.erl40
-rw-r--r--lib/sasl/src/systools_relup.erl153
-rw-r--r--lib/sasl/test/Makefile4
-rw-r--r--lib/sasl/test/installer.erl576
-rw-r--r--lib/sasl/test/release_handler_SUITE.erl574
-rw-r--r--lib/sasl/test/release_handler_SUITE_data/Makefile.src39
-rw-r--r--lib/sasl/test/release_handler_SUITE_data/app1_app2/lib3/app1-3.0/ebin/app1.app9
-rw-r--r--lib/sasl/test/release_handler_SUITE_data/app1_app2/lib3/app1-3.0/ebin/app1.appup4
-rw-r--r--lib/sasl/test/release_handler_SUITE_data/app1_app2/lib3/app1-3.0/src/app1.erl22
-rw-r--r--lib/sasl/test/release_handler_SUITE_data/app1_app2/lib3/app1-3.0/src/app1_server.erl35
-rw-r--r--lib/sasl/test/release_handler_SUITE_data/app1_app2/lib3/app1-3.0/src/app1_sup.erl17
-rw-r--r--lib/sasl/test/release_handler_SUITE_data/app1_app2/lib4/app1-4.0/ebin/app1.app9
-rw-r--r--lib/sasl/test/release_handler_SUITE_data/app1_app2/lib4/app1-4.0/ebin/app1.appup4
-rw-r--r--lib/sasl/test/release_handler_SUITE_data/app1_app2/lib4/app1-4.0/src/app1.erl22
-rw-r--r--lib/sasl/test/release_handler_SUITE_data/app1_app2/lib4/app1-4.0/src/app1_server.erl35
-rw-r--r--lib/sasl/test/release_handler_SUITE_data/app1_app2/lib4/app1-4.0/src/app1_sup.erl17
-rw-r--r--[-rwxr-xr-x]lib/sasl/test/release_handler_SUITE_data/heart_restart.bat0
-rw-r--r--lib/sasl/test/release_handler_SUITE_data/lib/README8
-rw-r--r--lib/sasl/test/release_handler_SUITE_data/lib/a-1.1/ebin/a.appup2
-rw-r--r--lib/sasl/test/release_handler_SUITE_data/lib/a-1.1/src/a.erl4
-rw-r--r--lib/sasl/test/release_handler_SUITE_data/lib/a-9.0/ebin/a.app8
-rw-r--r--lib/sasl/test/release_handler_SUITE_data/lib/a-9.0/ebin/a.appup3
-rw-r--r--lib/sasl/test/release_handler_SUITE_data/lib/a-9.0/src/a.erl56
-rw-r--r--lib/sasl/test/release_handler_SUITE_data/lib/a-9.0/src/a_sup.erl (renamed from lib/asn1/src/asn1_sup.erl)30
-rw-r--r--lib/sasl/test/release_handler_SUITE_data/lib/a-9.1/ebin/a.app8
-rw-r--r--lib/sasl/test/release_handler_SUITE_data/lib/a-9.1/ebin/a.appup3
-rw-r--r--lib/sasl/test/release_handler_SUITE_data/lib/a-9.1/src/a.erl56
-rw-r--r--lib/sasl/test/release_handler_SUITE_data/lib/a-9.1/src/a_sup.erl (renamed from lib/docbuilder/test/docb_SUITE.erl)47
-rw-r--r--lib/sasl/test/sasl_SUITE.erl99
-rw-r--r--lib/sasl/test/systools_SUITE.erl693
-rw-r--r--lib/sasl/test/systools_SUITE_data/d_bad_appup/lib/fe-2.1/ebin/fe.app7
-rw-r--r--lib/sasl/test/systools_SUITE_data/d_no_appup/lib/fe-500.18.7/ebin/fe.app7
-rw-r--r--lib/sasl/test/systools_SUITE_data/d_regexp_appup/lib/fe-2.1.1/ebin/fe.app8
-rw-r--r--lib/sasl/test/systools_SUITE_data/d_regexp_appup/lib/fe-2.1/ebin/fe.app8
-rw-r--r--lib/sasl/test/systools_SUITE_data/d_regexp_appup/lib/fe-3.1/ebin/fe.app7
-rw-r--r--lib/sasl/test/systools_SUITE_data/d_regexp_appup/lib/fe-3.1/ebin/fe.appup28
-rw-r--r--lib/sasl/test/systools_SUITE_data/lib/sasl-9.9/ebin/sasl.app6
-rw-r--r--lib/sasl/test/systools_SUITE_data/lib/sasl-9.9/ebin/sasl.appup12
-rw-r--r--lib/sasl/test/systools_SUITE_data/lib/sasl/ebin/sasl.app6
-rw-r--r--lib/sasl/test/systools_SUITE_data/lib/sasl/ebin/sasl.appup12
-rw-r--r--lib/sasl/test/systools_rc_SUITE.erl92
-rw-r--r--lib/sasl/test/test_lib.hrl3
-rw-r--r--lib/sasl/vsn.mk2
-rw-r--r--lib/snmp/doc/src/Makefile136
-rw-r--r--lib/snmp/doc/src/depend.mk83
-rw-r--r--lib/snmp/doc/src/make.dep77
-rw-r--r--lib/snmp/doc/src/notes.xml1035
-rw-r--r--lib/snmp/doc/src/notes_history.xml924
-rw-r--r--lib/snmp/mibs/Makefile.in34
-rw-r--r--lib/snmp/src/agent/snmpa_local_db.erl2
-rw-r--r--lib/snmp/src/agent/snmpa_set_lib.erl8
-rw-r--r--lib/snmp/src/app/snmp.appup.src148
-rw-r--r--lib/snmp/src/compile/depend.mk2
-rw-r--r--lib/snmp/src/compile/snmpc.src23
-rw-r--r--lib/snmp/src/misc/snmp_note_store.erl15
-rw-r--r--lib/snmp/test/Makefile4
-rw-r--r--[-rwxr-xr-x]lib/snmp/test/snmp_manager_user_old.erl0
-rw-r--r--lib/snmp/vsn.mk2
-rw-r--r--lib/ssh/doc/src/Makefile85
-rw-r--r--lib/ssh/doc/src/make.dep19
-rw-r--r--[-rwxr-xr-x]lib/ssh/src/DSS.asn10
-rw-r--r--lib/ssh/src/Makefile9
-rw-r--r--[-rwxr-xr-x]lib/ssh/src/PKCS-1.asn10
-rw-r--r--[-rwxr-xr-x]lib/ssh/src/ssh_bits.erl0
-rw-r--r--[-rwxr-xr-x]lib/ssh/src/ssh_connect.hrl0
-rw-r--r--[-rwxr-xr-x]lib/ssh/src/ssh_dsa.erl0
-rw-r--r--[-rwxr-xr-x]lib/ssh/src/ssh_file.erl0
-rw-r--r--[-rwxr-xr-x]lib/ssh/src/ssh_io.erl0
-rw-r--r--[-rwxr-xr-x]lib/ssh/src/ssh_math.erl0
-rw-r--r--[-rwxr-xr-x]lib/ssh/src/ssh_rsa.erl0
-rw-r--r--[-rwxr-xr-x]lib/ssh/src/ssh_sftp.erl0
-rw-r--r--[-rwxr-xr-x]lib/ssh/src/ssh_userauth.hrl0
-rw-r--r--[-rwxr-xr-x]lib/ssh/src/ssh_xfer.hrl0
-rw-r--r--lib/ssl/Makefile4
-rw-r--r--lib/ssl/c_src/Makefile.dist33
-rw-r--r--lib/ssl/c_src/Makefile.in215
-rw-r--r--lib/ssl/c_src/Makefile.win32147
-rw-r--r--lib/ssl/c_src/Makefile.win32.dist45
-rw-r--r--lib/ssl/c_src/debuglog.c251
-rw-r--r--lib/ssl/c_src/debuglog.h50
-rw-r--r--lib/ssl/c_src/esock.c1904
-rw-r--r--lib/ssl/c_src/esock.h273
-rw-r--r--lib/ssl/c_src/esock_openssl.c1213
-rw-r--r--lib/ssl/c_src/esock_osio.c328
-rw-r--r--lib/ssl/c_src/esock_osio.h34
-rw-r--r--lib/ssl/c_src/esock_poll.c222
-rw-r--r--lib/ssl/c_src/esock_poll.h60
-rw-r--r--lib/ssl/c_src/esock_posix_str.c642
-rw-r--r--lib/ssl/c_src/esock_posix_str.h28
-rw-r--r--lib/ssl/c_src/esock_ssl.h110
-rw-r--r--lib/ssl/c_src/esock_utils.c150
-rw-r--r--lib/ssl/c_src/esock_utils.h32
-rw-r--r--lib/ssl/c_src/esock_winsock.h36
-rw-r--r--lib/ssl/doc/src/Makefile4
-rw-r--r--lib/ssl/doc/src/old_ssl.xml709
-rw-r--r--lib/ssl/doc/src/refman.xml5
-rw-r--r--lib/ssl/doc/src/ssl.xml13
-rw-r--r--lib/ssl/doc/src/ssl_distribution.xml209
-rw-r--r--lib/ssl/doc/src/ssl_protocol.xml14
-rw-r--r--lib/ssl/src/Makefile12
-rw-r--r--lib/ssl/src/inet_ssl_dist.erl456
-rw-r--r--lib/ssl/src/inet_tls_dist.erl275
-rw-r--r--lib/ssl/src/ssl.app.src10
-rw-r--r--lib/ssl/src/ssl.appup.src2
-rw-r--r--lib/ssl/src/ssl.erl385
-rw-r--r--lib/ssl/src/ssl_broker.erl1188
-rw-r--r--lib/ssl/src/ssl_broker_int.hrl38
-rw-r--r--lib/ssl/src/ssl_broker_sup.erl46
-rw-r--r--lib/ssl/src/ssl_certificate.erl33
-rw-r--r--lib/ssl/src/ssl_certificate_db.erl48
-rw-r--r--lib/ssl/src/ssl_cipher.erl80
-rw-r--r--lib/ssl/src/ssl_connection.erl413
-rw-r--r--lib/ssl/src/ssl_connection_sup.erl12
-rw-r--r--lib/ssl/src/ssl_dist_sup.erl84
-rw-r--r--lib/ssl/src/ssl_handshake.erl20
-rw-r--r--lib/ssl/src/ssl_int.hrl99
-rw-r--r--lib/ssl/src/ssl_internal.hrl7
-rw-r--r--lib/ssl/src/ssl_manager.erl75
-rw-r--r--lib/ssl/src/ssl_prim.erl173
-rw-r--r--lib/ssl/src/ssl_record.erl71
-rw-r--r--lib/ssl/src/ssl_record.hrl9
-rw-r--r--lib/ssl/src/ssl_server.erl1378
-rw-r--r--lib/ssl/src/ssl_session.erl15
-rw-r--r--lib/ssl/src/ssl_sup.erl42
-rw-r--r--lib/ssl/src/ssl_tls_dist_proxy.erl325
-rw-r--r--lib/ssl/test/Makefile16
-rw-r--r--lib/ssl/test/old_ssl_active_SUITE.erl395
-rw-r--r--lib/ssl/test/old_ssl_active_once_SUITE.erl417
-rw-r--r--lib/ssl/test/old_ssl_misc_SUITE.erl117
-rw-r--r--lib/ssl/test/old_ssl_passive_SUITE.erl382
-rw-r--r--lib/ssl/test/old_ssl_peer_cert_SUITE.erl191
-rw-r--r--lib/ssl/test/old_ssl_protocol_SUITE.erl185
-rw-r--r--lib/ssl/test/old_ssl_verify_SUITE.erl153
-rw-r--r--lib/ssl/test/old_transport_accept_SUITE.erl258
-rw-r--r--lib/ssl/test/ssl.cover19
-rw-r--r--lib/ssl/test/ssl_basic_SUITE.erl316
-rw-r--r--lib/ssl/test/ssl_cipher_SUITE.erl163
-rw-r--r--lib/ssl/test/ssl_dist_SUITE.erl (renamed from lib/ssl/test/old_ssl_dist_SUITE.erl)363
-rw-r--r--lib/ssl/test/ssl_dist_SUITE_data/dHParam.pem5
-rw-r--r--lib/ssl/test/ssl_packet_SUITE.erl46
-rw-r--r--lib/ssl/test/ssl_session_cache_SUITE.erl11
-rw-r--r--lib/ssl/test/ssl_test_MACHINE.erl940
-rw-r--r--lib/ssl/test/ssl_test_lib.erl35
-rw-r--r--lib/ssl/test/ssl_to_openssl_SUITE.erl132
-rw-r--r--lib/ssl/vsn.mk2
-rw-r--r--lib/stdlib/doc/src/Makefile1
-rw-r--r--lib/stdlib/doc/src/filename.xml6
-rw-r--r--lib/stdlib/doc/src/gen_event.xml17
-rw-r--r--lib/stdlib/doc/src/gen_server.xml10
-rw-r--r--lib/stdlib/doc/src/lists.xml26
-rw-r--r--lib/stdlib/doc/src/make.dep40
-rw-r--r--lib/stdlib/doc/src/random.xml5
-rw-r--r--lib/stdlib/doc/src/re.xml3
-rw-r--r--lib/stdlib/doc/src/ref_man.xml1
-rw-r--r--lib/stdlib/doc/src/regexp.xml381
-rw-r--r--lib/stdlib/doc/src/specs.xml1
-rw-r--r--lib/stdlib/doc/src/supervisor.xml75
-rw-r--r--lib/stdlib/doc/src/unicode.xml3
-rw-r--r--lib/stdlib/doc/src/unicode_usage.xml2
-rw-r--r--lib/stdlib/examples/erl_id_trans.erl9
-rw-r--r--lib/stdlib/src/Makefile1
-rw-r--r--lib/stdlib/src/beam_lib.erl19
-rw-r--r--lib/stdlib/src/c.erl2
-rw-r--r--lib/stdlib/src/dets.erl108
-rw-r--r--lib/stdlib/src/dets.hrl3
-rw-r--r--lib/stdlib/src/dets_v8.erl16
-rw-r--r--lib/stdlib/src/dets_v9.erl118
-rw-r--r--lib/stdlib/src/epp.erl37
-rw-r--r--lib/stdlib/src/erl_eval.erl41
-rw-r--r--lib/stdlib/src/erl_internal.erl2
-rw-r--r--lib/stdlib/src/erl_lint.erl63
-rw-r--r--lib/stdlib/src/erl_parse.yrl22
-rw-r--r--lib/stdlib/src/erl_pp.erl10
-rw-r--r--lib/stdlib/src/error_logger_tty_h.erl69
-rw-r--r--lib/stdlib/src/escript.erl2
-rw-r--r--lib/stdlib/src/eval_bits.erl47
-rw-r--r--lib/stdlib/src/filename.erl46
-rw-r--r--lib/stdlib/src/gen.erl4
-rw-r--r--lib/stdlib/src/gen_event.erl84
-rw-r--r--lib/stdlib/src/gen_fsm.erl63
-rw-r--r--lib/stdlib/src/gen_server.erl47
-rw-r--r--lib/stdlib/src/lib.erl46
-rw-r--r--lib/stdlib/src/lists.erl29
-rw-r--r--lib/stdlib/src/ms_transform.erl17
-rw-r--r--lib/stdlib/src/otp_internal.erl168
-rw-r--r--lib/stdlib/src/qlc.erl12
-rw-r--r--lib/stdlib/src/random.erl42
-rw-r--r--lib/stdlib/src/re.erl18
-rw-r--r--lib/stdlib/src/regexp.erl557
-rw-r--r--lib/stdlib/src/shell.erl9
-rw-r--r--lib/stdlib/src/stdlib.app.src1
-rw-r--r--lib/stdlib/src/stdlib.appup.src28
-rw-r--r--lib/stdlib/src/supervisor.erl142
-rw-r--r--lib/stdlib/src/supervisor_bridge.erl9
-rw-r--r--lib/stdlib/src/unicode.erl12
-rw-r--r--lib/stdlib/test/Makefile1
-rw-r--r--lib/stdlib/test/beam_lib_SUITE.erl30
-rw-r--r--lib/stdlib/test/binary_module_SUITE.erl18
-rw-r--r--lib/stdlib/test/dets_SUITE.erl291
-rw-r--r--lib/stdlib/test/epp_SUITE.erl33
-rw-r--r--lib/stdlib/test/epp_SUITE_data/bar.hrl4
-rw-r--r--lib/stdlib/test/epp_SUITE_data/include/bar.hrl3
-rw-r--r--lib/stdlib/test/epp_SUITE_data/include/foo.hrl4
-rw-r--r--lib/stdlib/test/epp_SUITE_data/include_local.erl6
-rw-r--r--lib/stdlib/test/erl_eval_SUITE.erl6
-rw-r--r--lib/stdlib/test/erl_pp_SUITE.erl5
-rw-r--r--lib/stdlib/test/ets_SUITE.erl23
-rw-r--r--lib/stdlib/test/filelib_SUITE.erl7
-rw-r--r--lib/stdlib/test/filename_SUITE.erl16
-rw-r--r--lib/stdlib/test/gen_server_SUITE.erl2
-rw-r--r--lib/stdlib/test/ms_transform_SUITE.erl45
-rw-r--r--lib/stdlib/test/proc_lib_SUITE.erl2
-rw-r--r--lib/stdlib/test/qlc_SUITE.erl122
-rw-r--r--lib/stdlib/test/qlc_SUITE_data/join_info_compat.erl1771
-rw-r--r--lib/stdlib/test/re_SUITE.erl92
-rw-r--r--lib/stdlib/test/shell_SUITE.erl6
-rw-r--r--lib/stdlib/test/sofs_SUITE.erl6
-rw-r--r--lib/stdlib/test/stdlib_SUITE.erl63
-rw-r--r--lib/stdlib/test/supervisor_1.erl6
-rw-r--r--lib/stdlib/test/supervisor_2.erl42
-rw-r--r--lib/stdlib/test/supervisor_SUITE.erl252
-rw-r--r--lib/stdlib/test/supervisor_bridge_SUITE.erl42
-rw-r--r--lib/stdlib/test/tar_SUITE.erl27
-rw-r--r--lib/stdlib/test/unicode_SUITE.erl4
-rw-r--r--lib/stdlib/vsn.mk2
-rw-r--r--lib/syntax_tools/doc/Makefile9
-rw-r--r--lib/syntax_tools/doc/src/make.dep22
-rw-r--r--lib/syntax_tools/src/erl_syntax.erl7
-rw-r--r--lib/syntax_tools/src/erl_tidy.erl4
-rw-r--r--lib/test_server/doc/src/Makefile6
-rw-r--r--lib/test_server/doc/src/make.dep24
-rw-r--r--lib/test_server/include/test_server.hrl5
-rw-r--r--lib/test_server/include/test_server_line.hrl3
-rw-r--r--lib/test_server/src/Makefile1
-rw-r--r--lib/test_server/src/erl2html2.erl51
-rw-r--r--lib/test_server/src/test_server.app.src1
-rw-r--r--lib/test_server/src/test_server.erl232
-rw-r--r--lib/test_server/src/test_server_ctrl.erl266
-rw-r--r--lib/test_server/src/test_server_line.erl387
-rw-r--r--lib/test_server/src/test_server_sup.erl11
-rw-r--r--lib/toolbar/doc/src/make.dep26
-rw-r--r--lib/tools/c_src/Makefile.in11
-rw-r--r--lib/tools/doc/src/eprof.xml2
-rw-r--r--lib/tools/doc/src/make.dep33
-rw-r--r--lib/tools/src/cover.erl4
-rw-r--r--lib/tools/src/fprof.erl12
-rw-r--r--lib/tools/src/xref_compiler.erl7
-rw-r--r--lib/tools/src/xref_reader.erl25
-rw-r--r--lib/tools/test/cover_SUITE.erl31
-rw-r--r--lib/tools/test/cover_SUITE_data/otp_6115/f1.erl11
-rw-r--r--lib/tools/test/eprof_SUITE_data/ed.script2
-rw-r--r--lib/tools/test/eprof_SUITE_data/eed.erl91
-rw-r--r--lib/tools/test/xref_SUITE.erl87
-rw-r--r--lib/tools/test/xref_SUITE_data/fun_mfa_r14.beambin0 -> 1116 bytes
-rw-r--r--lib/tools/test/xref_SUITE_data/fun_mfa_r14.erl18
-rw-r--r--lib/tv/doc/src/Makefile83
-rw-r--r--lib/tv/doc/src/make.dep32
-rw-r--r--lib/tv/src/tv_db_search.erl32
-rw-r--r--lib/tv/src/tv_main.erl2
-rw-r--r--lib/tv/src/tv_mnesia_rpc.erl2
-rw-r--r--lib/typer/src/typer.erl15
-rw-r--r--lib/webtool/doc/src/make.dep20
-rw-r--r--lib/wx/api_gen/wx_doxygen.conf1
-rw-r--r--lib/wx/api_gen/wx_gen_cpp.erl1
-rw-r--r--lib/wx/api_gen/wx_gen_erl.erl6
-rw-r--r--lib/wx/api_gen/wxapi.conf3
-rw-r--r--lib/wx/c_src/Makefile.in7
-rw-r--r--lib/wx/c_src/egl_impl.cpp14
-rw-r--r--lib/wx/c_src/gen/wxe_events.cpp46
-rw-r--r--lib/wx/c_src/gen/wxe_funcs.cpp54
-rw-r--r--lib/wx/c_src/gen/wxe_macros.h47
-rw-r--r--lib/wx/c_src/wxe_impl.cpp24
-rwxr-xr-xlib/wx/configure.in65
-rw-r--r--lib/wx/doc/src/make.dep13
-rw-r--r--[-rwxr-xr-x]lib/wx/examples/demo/Makefile2
-rw-r--r--lib/wx/examples/simple/Makefile2
-rw-r--r--[-rwxr-xr-x]lib/wx/examples/simple/hello.erl0
-rw-r--r--[-rwxr-xr-x]lib/wx/examples/simple/menu.erl0
-rw-r--r--[-rwxr-xr-x]lib/wx/examples/simple/minimal.erl0
-rw-r--r--[-rwxr-xr-x]lib/wx/examples/simple/sample.xpm0
-rw-r--r--[-rwxr-xr-x]lib/wx/examples/sudoku/Makefile2
-rw-r--r--[-rwxr-xr-x]lib/wx/examples/sudoku/sudoku.erl0
-rw-r--r--[-rwxr-xr-x]lib/wx/examples/sudoku/sudoku.hrl0
-rw-r--r--[-rwxr-xr-x]lib/wx/examples/sudoku/sudoku_board.erl0
-rw-r--r--[-rwxr-xr-x]lib/wx/examples/sudoku/sudoku_game.erl0
-rw-r--r--[-rwxr-xr-x]lib/wx/examples/sudoku/sudoku_gui.erl0
-rw-r--r--[-rwxr-xr-x]lib/wx/examples/xrc/Makefile5
-rw-r--r--lib/wx/include/wx.hrl10
-rw-r--r--lib/wx/src/gen/wxArtProvider.erl6
-rw-r--r--lib/wx/src/gen/wxAuiManager.erl8
-rw-r--r--lib/wx/src/gen/wxAuiNotebook.erl8
-rw-r--r--lib/wx/src/gen/wxAuiPaneInfo.erl12
-rw-r--r--lib/wx/src/gen/wxBitmap.erl4
-rw-r--r--lib/wx/src/gen/wxBitmapButton.erl6
-rw-r--r--lib/wx/src/gen/wxBufferedDC.erl10
-rw-r--r--lib/wx/src/gen/wxButton.erl8
-rw-r--r--lib/wx/src/gen/wxCalendarCtrl.erl8
-rw-r--r--lib/wx/src/gen/wxCaret.erl14
-rw-r--r--lib/wx/src/gen/wxCheckBox.erl6
-rw-r--r--lib/wx/src/gen/wxCheckListBox.erl4
-rw-r--r--lib/wx/src/gen/wxChoice.erl8
-rw-r--r--lib/wx/src/gen/wxChoicebook.erl10
-rw-r--r--lib/wx/src/gen/wxColourPickerCtrl.erl6
-rw-r--r--lib/wx/src/gen/wxComboBox.erl8
-rw-r--r--lib/wx/src/gen/wxContextMenuEvent.erl6
-rw-r--r--lib/wx/src/gen/wxDC.erl92
-rw-r--r--lib/wx/src/gen/wxDatePickerCtrl.erl4
-rw-r--r--lib/wx/src/gen/wxDialog.erl6
-rw-r--r--lib/wx/src/gen/wxDirDialog.erl4
-rw-r--r--lib/wx/src/gen/wxDirPickerCtrl.erl6
-rw-r--r--lib/wx/src/gen/wxFileDialog.erl4
-rw-r--r--lib/wx/src/gen/wxFilePickerCtrl.erl6
-rw-r--r--lib/wx/src/gen/wxFontPickerCtrl.erl6
-rw-r--r--lib/wx/src/gen/wxFrame.erl8
-rw-r--r--lib/wx/src/gen/wxGLCanvas.erl6
-rw-r--r--lib/wx/src/gen/wxGauge.erl6
-rw-r--r--lib/wx/src/gen/wxGenericDirCtrl.erl6
-rw-r--r--lib/wx/src/gen/wxGraphicsContext.erl12
-rw-r--r--lib/wx/src/gen/wxGraphicsMatrix.erl8
-rw-r--r--lib/wx/src/gen/wxGraphicsPath.erl18
-rw-r--r--lib/wx/src/gen/wxGrid.erl42
-rw-r--r--lib/wx/src/gen/wxGridBagSizer.erl52
-rw-r--r--lib/wx/src/gen/wxGridCellAttr.erl4
-rw-r--r--lib/wx/src/gen/wxGridCellEditor.erl6
-rw-r--r--lib/wx/src/gen/wxGridCellRenderer.erl6
-rw-r--r--lib/wx/src/gen/wxGridEvent.erl4
-rw-r--r--lib/wx/src/gen/wxHelpEvent.erl6
-rw-r--r--lib/wx/src/gen/wxHtmlWindow.erl8
-rw-r--r--lib/wx/src/gen/wxIconBundle.erl4
-rw-r--r--lib/wx/src/gen/wxImage.erl26
-rw-r--r--lib/wx/src/gen/wxImageList.erl4
-rw-r--r--lib/wx/src/gen/wxJoystickEvent.erl4
-rw-r--r--lib/wx/src/gen/wxKeyEvent.erl4
-rw-r--r--lib/wx/src/gen/wxLayoutAlgorithm.erl4
-rw-r--r--lib/wx/src/gen/wxListBox.erl12
-rw-r--r--lib/wx/src/gen/wxListCtrl.erl16
-rw-r--r--lib/wx/src/gen/wxListEvent.erl4
-rw-r--r--lib/wx/src/gen/wxListbook.erl10
-rw-r--r--lib/wx/src/gen/wxMDIChildFrame.erl6
-rw-r--r--lib/wx/src/gen/wxMDIParentFrame.erl6
-rw-r--r--lib/wx/src/gen/wxMessageDialog.erl4
-rw-r--r--lib/wx/src/gen/wxMiniFrame.erl6
-rw-r--r--lib/wx/src/gen/wxMouseEvent.erl6
-rw-r--r--lib/wx/src/gen/wxMoveEvent.erl4
-rw-r--r--lib/wx/src/gen/wxMultiChoiceDialog.erl4
-rw-r--r--lib/wx/src/gen/wxNotebook.erl12
-rw-r--r--lib/wx/src/gen/wxPageSetupDialogData.erl22
-rw-r--r--lib/wx/src/gen/wxPalette.erl4
-rw-r--r--lib/wx/src/gen/wxPanel.erl4
-rw-r--r--lib/wx/src/gen/wxPasswordEntryDialog.erl4
-rw-r--r--lib/wx/src/gen/wxPreviewControlBar.erl4
-rw-r--r--lib/wx/src/gen/wxPreviewFrame.erl4
-rw-r--r--lib/wx/src/gen/wxPrintout.erl24
-rw-r--r--lib/wx/src/gen/wxRadioBox.erl12
-rw-r--r--lib/wx/src/gen/wxRadioButton.erl6
-rw-r--r--lib/wx/src/gen/wxRegion.erl18
-rw-r--r--lib/wx/src/gen/wxSashEvent.erl4
-rw-r--r--lib/wx/src/gen/wxSashLayoutWindow.erl8
-rw-r--r--lib/wx/src/gen/wxSashWindow.erl4
-rw-r--r--lib/wx/src/gen/wxScrollBar.erl6
-rw-r--r--lib/wx/src/gen/wxScrolledWindow.erl16
-rw-r--r--lib/wx/src/gen/wxSingleChoiceDialog.erl4
-rw-r--r--lib/wx/src/gen/wxSizeEvent.erl4
-rw-r--r--lib/wx/src/gen/wxSizer.erl18
-rw-r--r--lib/wx/src/gen/wxSizerItem.erl22
-rw-r--r--lib/wx/src/gen/wxSlider.erl6
-rw-r--r--lib/wx/src/gen/wxSpinButton.erl6
-rw-r--r--lib/wx/src/gen/wxSpinCtrl.erl6
-rw-r--r--lib/wx/src/gen/wxSplashScreen.erl4
-rw-r--r--lib/wx/src/gen/wxSplitterWindow.erl6
-rw-r--r--lib/wx/src/gen/wxStaticBitmap.erl6
-rw-r--r--lib/wx/src/gen/wxStaticBox.erl6
-rw-r--r--lib/wx/src/gen/wxStaticLine.erl6
-rw-r--r--lib/wx/src/gen/wxStaticText.erl6
-rw-r--r--lib/wx/src/gen/wxStatusBar.erl4
-rw-r--r--lib/wx/src/gen/wxStyledTextCtrl.erl18
-rw-r--r--lib/wx/src/gen/wxSystemOptions.erl87
-rw-r--r--lib/wx/src/gen/wxTextCtrl.erl10
-rw-r--r--lib/wx/src/gen/wxTextEntryDialog.erl4
-rw-r--r--lib/wx/src/gen/wxToggleButton.erl6
-rw-r--r--lib/wx/src/gen/wxToolBar.erl10
-rw-r--r--lib/wx/src/gen/wxToolbook.erl10
-rw-r--r--lib/wx/src/gen/wxTreeCtrl.erl18
-rw-r--r--lib/wx/src/gen/wxTreeEvent.erl4
-rw-r--r--lib/wx/src/gen/wxTreebook.erl10
-rw-r--r--lib/wx/src/gen/wxWindow.erl82
-rw-r--r--lib/wx/src/gen/wx_misc.erl8
-rw-r--r--lib/wx/src/gen/wxe_debug.hrl46
-rw-r--r--lib/wx/src/gen/wxe_funcs.hrl46
-rw-r--r--lib/wx/src/wx_object.erl6
-rw-r--r--lib/wx/test/wx_event_SUITE.erl34
-rw-r--r--[-rwxr-xr-x]lib/xmerl/doc/examples/test_html.erl0
-rw-r--r--[-rwxr-xr-x]lib/xmerl/doc/examples/xml/test.xml0
-rw-r--r--[-rwxr-xr-x]lib/xmerl/doc/examples/xml/test2.xml0
-rw-r--r--[-rwxr-xr-x]lib/xmerl/doc/examples/xml/test3.xml0
-rw-r--r--[-rwxr-xr-x]lib/xmerl/doc/examples/xml/test4.xml0
-rw-r--r--[-rwxr-xr-x]lib/xmerl/doc/examples/xml/test5.xml0
-rw-r--r--[-rwxr-xr-x]lib/xmerl/doc/examples/xml/testdtd.dtd0
-rw-r--r--[-rwxr-xr-x]lib/xmerl/doc/examples/xml/xmerl.xml0
-rw-r--r--lib/xmerl/doc/src/make.dep24
-rw-r--r--[-rwxr-xr-x]lib/xmerl/doc/src/part_notes.xml0
-rw-r--r--[-rwxr-xr-x]lib/xmerl/include/xmerl.hrl17
-rw-r--r--[-rwxr-xr-x]lib/xmerl/include/xmerl_xlink.hrl0
-rw-r--r--lib/xmerl/src/xmerl.erl2
-rw-r--r--lib/xmerl/src/xmerl_lib.erl3
-rw-r--r--lib/xmerl/src/xmerl_sax_parser_base.erlsrc38
-rw-r--r--lib/xmerl/src/xmerl_scan.erl376
-rw-r--r--lib/xmerl/src/xmerl_validate.erl103
-rw-r--r--lib/xmerl/src/xmerl_xpath.erl114
-rw-r--r--lib/xmerl/src/xmerl_xpath_lib.erl4
-rw-r--r--lib/xmerl/src/xmerl_xpath_parse.yrl1
-rw-r--r--lib/xmerl/src/xmerl_xpath_pred.erl9
-rw-r--r--lib/xmerl/src/xmerl_xpath_scan.erl1
-rw-r--r--lib/xmerl/src/xmerl_xsd.erl63
-rw-r--r--lib/xmerl/test/xmerl_SUITE.erl36
-rw-r--r--lib/xmerl/test/xmerl_SUITE_data/misc.tar.gzbin47340 -> 48157 bytes
-rw-r--r--lib/xmerl/test/xmerl_SUITE_data/xpath/xpath_abbrev.erl2
-rw-r--r--lib/xmerl/test/xmerl_test_lib.erl6
-rw-r--r--[-rwxr-xr-x]lib/xmerl/test/xmerl_xsd_SUITE_data/mim.xsd0
-rw-r--r--lib/xmerl/vsn.mk2
-rw-r--r--[-rwxr-xr-x]lib/xmerl/xmerl.pub0
1181 files changed, 38818 insertions, 45343 deletions
diff --git a/lib/Makefile b/lib/Makefile
index 98d746925f..37e8ce06d7 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -33,20 +33,6 @@ ifeq ($(findstring vxworks,$(TARGET)),vxworks)
cosFileTransfer cosEventDomain
endif
else
- ifeq ($(findstring ose,$(TARGET)),ose)
- ERTS_SUB_DIRECTORIES = stdlib sasl kernel compiler erl_interface
- OTHER_SUB_DIRECTORIES = \
- snmp otp_mibs appmon tools
-# OTHER_SUB_DIRECTORIES = \
-# appmon os_mon tools runtime_tools
- ifdef BUILD_ALL
- OTHER_SUB_DIRECTORIES += mnesia \
- inets pman tv observer
-# OTHER_SUB_DIRECTORIES += mnesia ic asn1 debugger \
-# inets orber pman tv observer cosTransactions cosEvent \
-# cosTime cosNotification cosProperty cosFileTransfer cosEventDomain
- endif
- else
#
# unix and win32
# --------------
@@ -59,10 +45,11 @@ else
snmp otp_mibs appmon erl_interface asn1 jinterface gs wx inets ic \
mnesia crypto orber os_mon parsetools syntax_tools pman \
public_key ssl toolbar tv observer debugger reltool odbc \
- runtime_tools diameter \
+ diameter \
cosTransactions cosEvent cosTime cosNotification cosProperty \
cosFileTransfer cosEventDomain et megaco webtool \
- xmerl edoc eunit ssh inviso typer docbuilder erl_docgen common_test percept
+ xmerl edoc eunit ssh inviso typer erl_docgen \
+ common_test percept dialyzer
# dialyzer
OTHER_SUB_DIRECTORIES += hipe
else # BUILD_ALL on unix
@@ -70,15 +57,15 @@ else
snmp otp_mibs appmon erl_interface asn1 jinterface wx debugger reltool gs inets \
ic mnesia crypto orber os_mon parsetools syntax_tools \
pman public_key ssl toolbar tv observer odbc \
- runtime_tools diameter \
+ diameter \
cosTransactions cosEvent cosTime cosNotification \
cosProperty cosFileTransfer cosEventDomain et megaco webtool \
- xmerl edoc eunit ssh inviso typer docbuilder erl_docgen common_test percept
+ xmerl edoc eunit ssh inviso typer erl_docgen \
+ common_test percept dialyzer
# dialyzer
OTHER_SUB_DIRECTORIES += hipe $(TSP_APP)
endif
endif
- endif
endif
ifdef BOOTSTRAP
diff --git a/lib/appmon/doc/src/make.dep b/lib/appmon/doc/src/make.dep
deleted file mode 100644
index ce0d7571a3..0000000000
--- a/lib/appmon/doc/src/make.dep
+++ /dev/null
@@ -1,26 +0,0 @@
-# ----------------------------------------------------
-# >>>> Do not edit this file <<<<
-# This file was automaticly generated by
-# /home/otp/bin/docdepend
-# ----------------------------------------------------
-
-
-# ----------------------------------------------------
-# TeX files that the DVI file depend on
-# ----------------------------------------------------
-
-book.dvi: appmon.tex appmon_chapter.tex book.tex part.tex \
- ref_man.tex
-
-# ----------------------------------------------------
-# Source inlined when transforming from source to LaTeX
-# ----------------------------------------------------
-
-book.tex: ref_man.xml
-
-# ----------------------------------------------------
-# Pictures that the DVI file depend on
-# ----------------------------------------------------
-
-book.dvi: app_win.ps listbox_win.ps main_win.ps pinfo_win.ps
-
diff --git a/lib/appmon/src/appmon_web.erl b/lib/appmon/src/appmon_web.erl
index fb7144246c..7c0451c3c3 100644
--- a/lib/appmon/src/appmon_web.erl
+++ b/lib/appmon/src/appmon_web.erl
@@ -578,9 +578,9 @@ htmlify_pid([],New)->
%% the HTTP protocol %%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
urlify_pid(Pid) ->
- case regexp:first_match(Pid,"[<].*[>]") of
- {match,Start,Len}->
- "%3C"++string:substr(Pid,Start+1,Len-2)++"%3E";
+ case re:run(Pid,"[<](.*)[>]",[{capture,all_but_first,list}]) of
+ {match,[PidStr]}->
+ "%3C"++PidStr++"%3E";
_->
Pid
end.
diff --git a/lib/asn1/c_src/Makefile b/lib/asn1/c_src/Makefile
index 9e9cb18524..8c06be56f8 100644
--- a/lib/asn1/c_src/Makefile
+++ b/lib/asn1/c_src/Makefile
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2002-2010. All Rights Reserved.
+# Copyright Ericsson AB 2002-2011. All Rights Reserved.
#
# The contents of this file are subject to the Erlang Public License,
# Version 1.1, (the "License"); you may not use this file except in
@@ -51,33 +51,26 @@ EI_LIBDIR = $(ERL_TOP)/lib/erl_interface/obj$(TYPEMARKER)/$(TARGET)
# ----------------------------------------------------
# FLAGS
# ----------------------------------------------------
-EI_INCLUDES = -I$(ERL_TOP)/lib/erl_interface/include
CFLAGS = $(DED_INCLUDES) $(EI_INCLUDES) $(DED_CFLAGS)
LDFLAGS += $(DED_LDFLAGS)
-LD_INCL_EI = -L$(EI_LIBDIR)
-
# ----------------------------------------------------
# Target Specs
# ----------------------------------------------------
-C_FILES = asn1_erl_driver.c
+NIF_OBJ_FILES = $(OBJDIR)/asn1_erl_nif.o
ifeq ($(TARGET),win32)
-LD_EI = -lei_md
-SHARED_OBJ_FILES = $(LIBDIR)/asn1_erl_drv.dll
-OBJ_FILES = $(OBJDIR)/asn1_erl_drv.o
+NIF_SHARED_OBJ_FILE = $(LIBDIR)/asn1_erl_nif.dll
CLIB_FLAGS =
LN=cp
else
-LD_EI = -lei
-OBJ_FILES = $(OBJDIR)/asn1_erl_drv.o
ifeq ($(findstring vxworks,$(TARGET)),vxworks)
-SHARED_OBJ_FILES = $(LIBDIR)/asn1_erl_drv.eld
+NIF_SHARED_OBJ_FILE = $(LIBDIR)/asn1_erl_nif.eld
CLIB_FLAGS =
else
-SHARED_OBJ_FILES = $(LIBDIR)/asn1_erl_drv.so
+NIF_SHARED_OBJ_FILE = $(LIBDIR)/asn1_erl_nif.so
CLIB_FLAGS = -lc
endif
LN= ln -s
@@ -87,7 +80,9 @@ endif
# Targets
# ----------------------------------------------------
-opt: $(OBJDIR) $(LIBDIR) $(SHARED_OBJ_FILES)
+_create_dirs := $(shell mkdir -p $(OBJDIR) $(LIBDIR))
+
+opt: $(NIF_SHARED_OBJ_FILE)
debug: opt
@@ -103,20 +98,12 @@ docs:
# ----------------------------------------------------
-$(OBJ_FILES): $(C_FILES)
- $(CC) -c $(CFLAGS) -o $(OBJ_FILES) $(C_FILES)
-
-$(SHARED_OBJ_FILES): $(OBJ_FILES)
- $(LD) $(LDFLAGS) $(LD_INCL_EI) -o $(SHARED_OBJ_FILES) $(OBJ_FILES) $(LD_EI) $(CLIB_FLAGS) $(LIBS)
-
-$(LIBDIR):
- -mkdir -p $(LIBDIR)
-
-$(OBJDIR):
- -mkdir -p $(OBJDIR)
+$(OBJDIR)/%.o: %.c
+ $(CC) -c $(CFLAGS) -O3 -o $@ $<
+$(NIF_SHARED_OBJ_FILE): $(NIF_OBJ_FILES)
+ $(LD) $(LDFLAGS) -o $(NIF_SHARED_OBJ_FILE) $(NIF_OBJ_FILES) $(CLIB_FLAGS) $(LIBS)
-
# ----------------------------------------------------
# Release Target
# ----------------------------------------------------
@@ -124,9 +111,9 @@ include $(ERL_TOP)/make/otp_release_targets.mk
release_spec: opt
$(INSTALL_DIR) $(RELSYSDIR)/priv/lib
- $(INSTALL_PROGRAM) $(SHARED_OBJ_FILES) $(RELSYSDIR)/priv/lib
+ $(INSTALL_PROGRAM) $(NIF_SHARED_OBJ_FILE) $(RELSYSDIR)/priv/lib
$(INSTALL_DIR) $(RELSYSDIR)/c_src
- $(INSTALL_DATA) $(C_FILES) $(RELSYSDIR)/c_src
+ $(INSTALL_DATA) *.c $(RELSYSDIR)/c_src
release_docs_spec:
diff --git a/lib/asn1/c_src/asn1_erl_driver.c b/lib/asn1/c_src/asn1_erl_driver.c
deleted file mode 100644
index 18d4157941..0000000000
--- a/lib/asn1/c_src/asn1_erl_driver.c
+++ /dev/null
@@ -1,1677 +0,0 @@
-/*
- * %CopyrightBegin%
- *
- * Copyright Ericsson AB 2002-2011. All Rights Reserved.
- *
- * The contents of this file are subject to the Erlang Public License,
- * Version 1.1, (the "License"); you may not use this file except in
- * compliance with the License. You should have received a copy of the
- * Erlang Public License along with this software. If not, it can be
- * retrieved online at http://www.erlang.org/.
- *
- * Software distributed under the License is distributed on an "AS IS"
- * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
- * the License for the specific language governing rights and limitations
- * under the License.
- *
- * %CopyrightEnd%
- *
- */
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include "erl_driver.h"
-#include "ei.h"
-
-
-/* #define ASN1_DEBUG 1 */
-
-#define ASN1_OK 0
-#define ASN1_ERROR -1
-#define ASN1_COMPL_ERROR 1
-#define ASN1_MEMORY_ERROR 0
-#define ASN1_DECODE_ERROR 2
-#define ASN1_TAG_ERROR -3
-#define ASN1_LEN_ERROR -4
-#define ASN1_INDEF_LEN_ERROR -5
-#define ASN1_VALUE_ERROR -6
-
-
-#define ASN1_CLASS 0xc0
-#define ASN1_FORM 0x20
-#define ASN1_CLASSFORM (ASN1_CLASS | ASN1_FORM)
-#define ASN1_TAG 0x1f
-#define ASN1_LONG_TAG 0x7f
-
-#define ASN1_INDEFINITE_LENGTH 0x80
-#define ASN1_SHORT_DEFINITE_LENGTH 0
-
-#define ASN1_PRIMITIVE 0
-#define ASN1_CONSTRUCTED 0x20
-
-#define ASN1_COMPLETE 1
-#define ASN1_BER_TLV_DECODE 2
-#define ASN1_BER_TLV_PARTIAL_DECODE 3
-
-#define ASN1_NOVALUE 0
-
-#define ASN1_SKIPPED 0
-#define ASN1_OPTIONAL 1
-#define ASN1_CHOOSEN 2
-
-
-#define CEIL(X,Y) ((X-1) / Y + 1)
-
-#define INVMASK(X,M) (X & (M ^ 0xff))
-#define MASK(X,M) (X & M)
-
-typedef struct {
- ErlDrvPort port;
- int buffer_size;
-} asn1_data;
-
-/* int min_alloc_bytes; */
-
-
-static ErlDrvData asn1_drv_start(ErlDrvPort, char *);
-
-static void asn1_drv_stop(ErlDrvData);
-
-int asn1_drv_control(ErlDrvData, unsigned int, char *, int, char **, int);
-
-int complete(ErlDrvBinary **,unsigned char *,unsigned char *, int);
-
-int insert_octets(int, unsigned char **, unsigned char **, int *);
-
-int insert_octets_except_unused(int, unsigned char **, unsigned char **,
- int *, int);
-
-int insert_octets_as_bits_exact_len(int, int, unsigned char **,
- unsigned char **, int *);
-
-int insert_octets_as_bits(int, unsigned char **, unsigned char **,int *);
-
-int pad_bits(int, unsigned char **, int *);
-
-int insert_least_sign_bits(int, unsigned char, unsigned char **, int *);
-
-int insert_most_sign_bits(int, unsigned char, unsigned char **, int *);
-
-int insert_bits_as_bits(int, int, unsigned char **, unsigned char **, int *);
-
-int insert_octets_unaligned(int, unsigned char **, unsigned char **, int);
-
-int realloc_decode_buf(ErlDrvBinary **,int);
-
-int realloc_memory(ErlDrvBinary **,int,unsigned char **,unsigned char **);
-
-int decode_begin(ErlDrvBinary **,unsigned char *, int, unsigned int *);
-
-int decode(ErlDrvBinary **,int *,unsigned char *,int *, int);
-
-int decode_tag(char *,int *,unsigned char *,int,int *);
-
-int decode_value(int *,unsigned char *,int *,ErlDrvBinary **,int ,int);
-
-
-/* declaration of functions used for partial decode of a BER encoded
- message */
-
-int decode_partial(ErlDrvBinary **,unsigned char *, int);
-
-int skip_tag(unsigned char *,int *,int);
-
-int skip_length_and_value(unsigned char *,int *,int);
-
-int get_tag(unsigned char *,int *,int);
-
-int get_length(unsigned char *,int *,int *,int);
-
-int get_value(char *,unsigned char *,int *,int);
-
-static ErlDrvEntry asn1_drv_entry = {
- NULL, /* init, always NULL for dynamic drivers */
- asn1_drv_start, /* start, called when port is opened */
- asn1_drv_stop, /* stop, called when port is closed */
- NULL, /* output, called when erlang has sent */
- NULL, /* ready_input, called when input descriptor ready */
- NULL, /* ready_output, called when output descriptor ready */
- "asn1_erl_drv", /* char *driver_name, the argument to open_port */
- NULL, /* finish, called when unloaded */
- NULL, /* void * that is not used (BC) */
- asn1_drv_control, /* control, port_control callback */
- NULL, /* timeout, called on timeouts */
- NULL, /* outputv, vector output interface */
-
- NULL, /* ready_async */
- NULL, /* flush */
- NULL, /* call */
- NULL, /* event */
- ERL_DRV_EXTENDED_MARKER,
- ERL_DRV_EXTENDED_MAJOR_VERSION,
- ERL_DRV_EXTENDED_MINOR_VERSION,
- ERL_DRV_FLAG_USE_PORT_LOCKING,
- NULL, /* handle2 */
- NULL /* process_exit */
-};
-
-
-
-DRIVER_INIT(asn1_erl_drv) /* must match name in driver_entry */
-{
- return &asn1_drv_entry;
-}
-
-static ErlDrvData asn1_drv_start(ErlDrvPort port, char *buff)
-{
- /* extern int min_alloc_bytes; */
- char *ptr;
- asn1_data* d;
-
- d = (asn1_data*)driver_alloc(sizeof(asn1_data));
- set_port_control_flags(port, PORT_CONTROL_FLAG_BINARY);
- d->port = port;
-
- if ((ptr = getenv("ASN1_MIN_BUF_SIZE")) == NULL)
- d->buffer_size = 1024;
- else
- d->buffer_size = atoi(ptr);
- return (ErlDrvData)d;
-}
-
-
-static void asn1_drv_stop(ErlDrvData handle)
-{
- driver_free((char*)handle);
-}
-
-
-
-int asn1_drv_control(ErlDrvData handle,
- unsigned int command,
- char *buf,
- int buf_len,
- char **res_buf,
- int res_buf_len)
-{
- unsigned char *complete_buf;
- int complete_len, decode_len;
- ErlDrvBinary *drv_binary;
- ErlDrvBinary **drv_bin_ptr;
- asn1_data* a_data;
- int min_alloc_bytes;
- unsigned int err_pos = 0; /* in case of error, return last correct position */
- int ret_err; /* return value in case of error in TLV decode, i.e. length of list in res_buf */
-
- /* In case previous call to asn1_drv_control resulted in a change of
- return value from binary to integer list */
- a_data = (asn1_data *)handle;
- min_alloc_bytes = a_data->buffer_size;
- set_port_control_flags(a_data->port, PORT_CONTROL_FLAG_BINARY);
-
- if (command == ASN1_COMPLETE)
- {
- if (buf_len==0) {
- return 0; /* Avoid binary buffer overwrite (OTP-8451) */
- }
- /* Do the PER complete encode step */
- if ((drv_binary = driver_alloc_binary(buf_len))==NULL) {
- /* error handling */
- set_port_control_flags(a_data->port, 0);
- return ASN1_MEMORY_ERROR;
- }
- complete_buf = (unsigned char*) drv_binary->orig_bytes;
- if ((complete_len = complete(&drv_binary,complete_buf,(unsigned char*) buf,buf_len)) == ASN1_ERROR)
- {
- /* error handling due to failure in complete */
- /* printf("error when running complete\n\r"); */
- driver_free_binary(drv_binary);
- set_port_control_flags(a_data->port, 0);
- **res_buf = '1';
- return ASN1_COMPL_ERROR;
- }
- /* printf("complete_len=%dbuf_len=%d,orig_size=%d\n\r",complete_len,buf_len,drv_binary->orig_size); */
- /* now the message is complete packed, return to Erlang */
- /* if (complete_len < buf_len) {*/
- if (complete_len < drv_binary->orig_size) {
- ErlDrvBinary *tmp;
- if ((tmp=driver_realloc_binary(drv_binary,complete_len)) == NULL){
- /*error handling due to memory allocation failure */
- driver_free_binary(drv_binary);
- set_port_control_flags(a_data->port, 0);
- return ASN1_MEMORY_ERROR;
- }else
- drv_binary=tmp;
- }
- *res_buf = (char *)drv_binary;
- return complete_len;
- } else if (command == ASN1_BER_TLV_DECODE) { /* control == 2 */
- /* Do the tlv decode,
- return the resulting term encoded on the Erlang
- external format */
-/* printf("driver: buffer_len = %d, min_alloc_bytes = %d\r\n",buf_len,min_alloc_bytes); */
- if ((drv_binary = driver_alloc_binary((buf_len*5)+min_alloc_bytes))==NULL) {
- /* error handling */
- set_port_control_flags(a_data->port, 0);
- return ASN1_MEMORY_ERROR;
- }
- drv_bin_ptr = &drv_binary;
- if ((decode_len = decode_begin(drv_bin_ptr,(unsigned char*)buf,buf_len,&err_pos)) <= ASN1_ERROR)
- {
- /* error handling due to failure in decode */
- char tmp_res_buf[5];
- driver_free_binary(*drv_bin_ptr);
- set_port_control_flags(a_data->port, 0);
-
- if(decode_len==ASN1_ERROR)
- tmp_res_buf[0]='1';
- else if(decode_len==ASN1_TAG_ERROR)
- tmp_res_buf[0]='2';
- else if(decode_len==ASN1_LEN_ERROR)
- tmp_res_buf[0]='3';
- else if(decode_len==ASN1_INDEF_LEN_ERROR)
- tmp_res_buf[0]='4';
- else if(decode_len==ASN1_VALUE_ERROR)
- tmp_res_buf[0]='5';
-/* printf("err_pos=%d\r\n",err_pos); */
-/* printf("decode_len:%d\r\n",decode_len); */
- ret_err = 1;
- while(err_pos>0){
- tmp_res_buf[ret_err] =(char)err_pos;/* c;*/
- err_pos = err_pos >> 8;
- ret_err++;
- }
- strncpy(*res_buf,tmp_res_buf,ret_err);
- return ret_err;
- }
-/* printf("decode_len=%d\r\n",decode_len); */
- if (decode_len < ((buf_len * 5) + min_alloc_bytes)) {
- /* not all memory was used => we have to reallocate */
- ErlDrvBinary *tmp;
- if ((tmp=driver_realloc_binary(*drv_bin_ptr,decode_len)) == NULL){
- /*error handling due to memory allocation failure */
- driver_free_binary(*drv_bin_ptr);
- set_port_control_flags(a_data->port, 0);
- return ASN1_MEMORY_ERROR;
- }else
- *drv_bin_ptr=tmp;
- }
- *res_buf = (char *)(*drv_bin_ptr);
- return decode_len;
- } else { /*command == ASN1_BER_TLV_PARTIAL_DECODE */
- if ((drv_binary = driver_alloc_binary(buf_len))==NULL) {
- /* error handling */
- set_port_control_flags(a_data->port, 0);
- return ASN1_MEMORY_ERROR;
- }
- drv_bin_ptr = &drv_binary;
- if ((decode_len = decode_partial(drv_bin_ptr,(unsigned char*)buf,buf_len))
- <= ASN1_ERROR) {
- /* error handling due to failure in decode */
- driver_free_binary(*drv_bin_ptr);
- set_port_control_flags(a_data->port, 0);
-
-/* printf("asn1_drv_control 1: decode_len=%d\r\n",decode_len); */
-
- if(decode_len==ASN1_ERROR)
- **res_buf = '1';
- return ASN1_DECODE_ERROR;
- }
- if (decode_len < buf_len) {
- /* not all memory was used => we have to reallocate */
- ErlDrvBinary *tmp;
-/* printf("asn1_drv_control 2: decode_len=%d\r\n",decode_len); */
- if ((tmp=driver_realloc_binary(*drv_bin_ptr,decode_len)) == NULL){
- /*error handling due to memory allocation failure */
- driver_free_binary(*drv_bin_ptr);
- set_port_control_flags(a_data->port, 0);
- return ASN1_MEMORY_ERROR;
- }else
- *drv_bin_ptr=tmp;
- }
- *res_buf = (char *)(*drv_bin_ptr);
- return decode_len;
- }
-}
-
-
-
-/*
- *
- * This section defines functionality for the complete encode of a
- * PER encoded message
- *
- */
-
-int complete(ErlDrvBinary **drv_binary,unsigned char *complete_buf,
- unsigned char *in_buf, int in_buf_len)
-{
- int counter = in_buf_len;
- /* counter keeps track of number of bytes left in the
- input buffer */
-
- int buf_space = in_buf_len;
- /* This is the amount of allocated space left of the complete_buf. It
- is possible when padding is applied that more space is needed than
- was originally allocated. */
-
- int buf_size = in_buf_len;
- /* Size of the buffer. May become reallocated and thus other than
- in_buf_len */
-
- unsigned char *in_ptr, *ptr;
- /* in_ptr points at the next byte in in_buf to be moved to
- complete_buf.
- ptr points into the new completed buffer, complete_buf, at the
- position of the next byte that will be set */
- int unused = 8;
- /* unused = [1,...,8] indicates how many of the rigthmost bits of
- the byte that ptr points at that are unassigned */
-
- int no_bits,no_bytes,in_unused,desired_len,ret, saved_mem, needed, pad_bits;
-
- unsigned char val;
-
- in_ptr = in_buf;
- ptr = complete_buf;
- *ptr = 0x00;
- while(counter > 0) {
- counter--;
-/* printf("*in_ptr = %d\n\r",*in_ptr); */
- switch (*in_ptr) {
- case 0:
- /* just one zero-bit should be added to the buffer */
- if(unused == 1){
- unused = 8;
- *++ptr = 0x00;
- buf_space--;
- } else
- unused--;
- break;
-
- case 1:
- /* one one-bit should be added to the buffer */
- if(unused == 1){
- *ptr = *ptr | 1;
- unused = 8;
- *++ptr = 0x00;
- buf_space--;
- } else {
- *ptr = *ptr | (1 << (unused - 1));
- unused--;
- }
- break;
-
- case 2:
- /* align buffer to end of byte */
- if (unused != 8) {
- *++ptr = 0x00;
- buf_space--;
- unused = 8;
- }
- break;
-
- case 10:
- /* next byte in in_buf tells how many bits in the second next
- byte that will be used */
- /* The leftmost unused bits in the value byte are supposed to be
- zero bits */
- no_bits = (int)*(++in_ptr);
- val = *(++in_ptr);
- counter -= 2;
- if ((ret=insert_least_sign_bits(no_bits,val,&ptr,&unused)) == ASN1_ERROR)
- return ASN1_ERROR;
- buf_space -= ret;
- break;
-
- case 20:
- /* in this case the next value in_ptr points at holds the number
- of following bytes that holds the value that will be inserted
- in the completed buffer */
- no_bytes = (int)*(++in_ptr);
- counter -= (no_bytes + 1);
- if ((counter<0) ||
- (ret=insert_octets(no_bytes,&in_ptr,&ptr,&unused)) == ASN1_ERROR)
- return ASN1_ERROR;
- buf_space -= ret;
- break;
-
- case 21:
- /* in this case the next two bytes in_ptr points at holds the number
- of following bytes that holds the value that will be inserted
- in the completed buffer */
- no_bytes = (int)*(++in_ptr);
- no_bytes = no_bytes << 8;
- no_bytes = no_bytes | (int)*(++in_ptr);
- counter -= (2 + no_bytes);
- if ((counter<0) ||
- (ret=insert_octets(no_bytes,&in_ptr,&ptr,&unused)) == ASN1_ERROR)
- return ASN1_ERROR;
- buf_space -= ret;
- break;
-
- case 30:
- /* If we call the following bytes, in the buffer in_ptr points at,
- By1,By2,Rest then Rest is the value that will be transfered to
- the completed buffer. By1 tells how many of the rightmost bits in
- Rest that should not be used. By2 is the length of Rest in bytes.*/
- in_unused = (int)*(++in_ptr);
- no_bytes = (int)*(++in_ptr);
- counter -= (2 + no_bytes);
-/* printf("%d: case 30: in_unused=%d, no_bytes=%d,counter=%d\n\r",__LINE__,in_unused,no_bytes,counter); */
- ret = -4711;
- if ((counter<0) ||
- (ret=insert_octets_except_unused(no_bytes,&in_ptr,&ptr,&unused,in_unused)) == ASN1_ERROR)
- return ASN1_ERROR;
-/* printf("%d: ret=%d\n\r",__LINE__, ret); */
- buf_space -= ret;
- break;
-
- case 31:
- /* If we call the following bytes, in the buffer in_ptr points at,
- By1,By2,By3,Rest then Rest is the value that will be transfered to
- the completed buffer. By1 tells how many of the rightmost bits in
- Rest that should not be used. By2 and By3 is the length of
- Rest in bytes.*/
- in_unused = (int)*(++in_ptr);
- no_bytes = (int)*(++in_ptr);
- no_bytes = no_bytes << 8;
- no_bytes = no_bytes | (int)*(++in_ptr);
- counter -= (3 + no_bytes);
- if ((counter<0) ||
- (ret=insert_octets_except_unused(no_bytes,&in_ptr,&ptr,&unused,in_unused)) == ASN1_ERROR)
- return ASN1_ERROR;
- buf_space -= ret;
- break;
-
- case 40:
- /* This case implies that next byte,By1,(..,By1,By2,Bin,...)
- is the desired length of the completed value, maybe needs
- padding zero bits or removal of trailing zero bits from Bin.
- By2 is the length of Bin and Bin is the value that will be
- put into the completed buffer. Each byte in Bin has the value
- 1 or 0.*/
- desired_len = (int)*(++in_ptr);
- no_bytes=(int)*(++in_ptr);
-
- /* This is the algorithm for need of memory reallocation:
- Only when padding (cases 40 - 43,45 - 47) more memory may be
- used than allocated. Therefore one has to keep track of how
- much of the allocated memory that has been saved, i.e. the
- difference between the number of parsed bytes of the input buffer
- and the number of used bytes of the output buffer.
- If saved memory is less than needed for the padding then we
- need more memory. */
- saved_mem = buf_space - counter;
- pad_bits = desired_len - no_bytes - unused;
- needed = (pad_bits > 0) ? CEIL(pad_bits,8) : 0;
- if (saved_mem < needed) {
- /* Have to allocate more memory */
- buf_size += needed;
- buf_space += needed;
- if (realloc_memory(drv_binary,buf_size,&ptr,
- &complete_buf) == ASN1_ERROR)
- return ASN1_ERROR;
- }
-
- counter -= (2 + no_bytes);
- if ((counter<0) ||
- (ret=insert_octets_as_bits_exact_len(desired_len,no_bytes,&in_ptr,
- &ptr,&unused)) == ASN1_ERROR)
- return ASN1_ERROR;
- buf_space -= ret;
- break;
-
- case 41:
- /* Same as case 40 apart from By2, the length of Bin, which is in
- two bytes*/
- desired_len = (int)*(++in_ptr);
- no_bytes=(int)*(++in_ptr);
- no_bytes = no_bytes << 8;
- no_bytes = no_bytes | (int)*(++in_ptr);
-
- saved_mem = buf_space - counter;
- needed = CEIL((desired_len-unused),8) - no_bytes;
- if (saved_mem < needed) {
- /* Have to allocate more memory */
- buf_size += needed;
- buf_space += needed;
- if (realloc_memory(drv_binary,buf_size,&ptr,
- &complete_buf) == ASN1_ERROR)
- return ASN1_ERROR;
- }
-
- counter -= (3 + no_bytes);
- if ((counter<0) ||
- (ret=insert_octets_as_bits_exact_len(desired_len,no_bytes,&in_ptr,
- &ptr,&unused)) == ASN1_ERROR)
- return ASN1_ERROR;
- buf_space -= ret;
- break;
-
- case 42:
- /* Same as case 40 apart from By1, the desired length, which is in
- two bytes*/
- desired_len = (int)*(++in_ptr);
- desired_len = desired_len << 8;
- desired_len = desired_len | (int)*(++in_ptr);
- no_bytes=(int)*(++in_ptr);
-
- saved_mem = buf_space - counter;
- needed = CEIL((desired_len-unused),8) - no_bytes;
- if (saved_mem < needed) {
- /* Have to allocate more memory */
- buf_size += needed;
- buf_space += needed;
- if (realloc_memory(drv_binary,buf_size,&ptr,
- &complete_buf) == ASN1_ERROR)
- return ASN1_ERROR;
- }
-
- counter -= (3 + no_bytes);
- if ((counter<0) ||
- (ret=insert_octets_as_bits_exact_len(desired_len,no_bytes,&in_ptr,
- &ptr,&unused)) == ASN1_ERROR)
- return ASN1_ERROR;
- buf_space -= ret;
- break;
-
- case 43:
- /* Same as case 40 apart from By1 and By2, the desired length and
- the length of Bin, which are in two bytes each. */
- desired_len = (int)*(++in_ptr);
- desired_len = desired_len << 8;
- desired_len = desired_len | (int)*(++in_ptr);
- no_bytes=(int)*(++in_ptr);
- no_bytes = no_bytes << 8;
- no_bytes = no_bytes | (int)*(++in_ptr);
-
- saved_mem = buf_space - counter;
- needed = CEIL((desired_len-unused),8) - no_bytes;
- if (saved_mem < needed) {
- /* Have to allocate more memory */
- buf_size += needed;
- buf_space += needed;
- if (realloc_memory(drv_binary,buf_size,&ptr,
- &complete_buf) == ASN1_ERROR)
- return ASN1_ERROR;
- }
-
- counter -= (4 + no_bytes);
- if ((counter<0) ||
- (ret=insert_octets_as_bits_exact_len(desired_len,no_bytes,&in_ptr,
- &ptr,&unused)) == ASN1_ERROR)
- return ASN1_ERROR;
- buf_space -= ret;
- break;
-
- case 45:
- /* This case assumes that the following bytes in the incoming buffer
- (called By1,By2,Bin) is By1, which is the number of bits (n) that
- will be inserted in the completed buffer. By2 is the number of
- bytes in Bin. Each bit in the buffer Bin should be inserted from
- the leftmost until the nth.*/
- desired_len = (int)*(++in_ptr);
- no_bytes=(int)*(++in_ptr);
-
- saved_mem = buf_space - counter;
- needed = CEIL((desired_len-unused),8) - no_bytes;
-/* printf("buf_space=%d, counter=%d, needed=%d",buf_space,counter,needed); */
- if (saved_mem < needed) {
- /* Have to allocate more memory */
- buf_size += needed;
- buf_space += needed;
- if (realloc_memory(drv_binary,buf_size,&ptr,
- &complete_buf) == ASN1_ERROR)
- return ASN1_ERROR;
- }
-
- counter -= (2 + no_bytes);
-/* printf("calling insert_bits_as_bits: desired_len=%d, no_bytes=%d\n\r",desired_len,no_bytes); */
-/* printf("1in_ptr=%d\n\r",in_ptr); */
-
- if((counter<0) ||
- (ret=insert_bits_as_bits(desired_len,no_bytes,&in_ptr,
- &ptr,&unused)) == ASN1_ERROR)
- return ASN1_ERROR;
-/* printf("2in_ptr=%d, ptr=%d, complete_buf=%d\n\r",in_ptr,ptr,complete_buf); */
-/* printf("buf_space=%d, ret=%d, counter=%d\n\r",buf_space,ret,counter); */
- buf_space -= ret;
- break;
-
- case 46:
- /* Same as case 45 apart from By1, the desired length, which is
- in two bytes. */
- desired_len = (int)*(++in_ptr);
- desired_len = desired_len << 8;
- desired_len = desired_len | (int)*(++in_ptr);
- no_bytes=(int)*(++in_ptr);
-
- saved_mem = buf_space - counter;
- needed = CEIL((desired_len-unused),8) - no_bytes;
- if (saved_mem < needed) {
- /* Have to allocate more memory */
- buf_size += needed;
- buf_space += needed;
- if (realloc_memory(drv_binary,buf_size,&ptr,
- &complete_buf) == ASN1_ERROR)
- return ASN1_ERROR;
- }
-
- counter -= (3 + no_bytes);
- if((counter<0) ||
- (ret=insert_bits_as_bits(desired_len,no_bytes,&in_ptr,
- &ptr,&unused)) == ASN1_ERROR)
- return ASN1_ERROR;
- buf_space -= ret;
- break;
-
- case 47:
- /* Same as case 45 apart from By1 and By2, the desired length
- and the length of Bin, which are in two bytes each. */
- desired_len = (int)*(++in_ptr);
- desired_len = desired_len << 8;
- desired_len = desired_len | (int)*(++in_ptr);
- no_bytes=(int)*(++in_ptr);
- no_bytes = no_bytes << 8;
- no_bytes = no_bytes | (int)*(++in_ptr);
-
- saved_mem = buf_space - counter;
- needed = CEIL((desired_len-unused),8) - no_bytes;
- if (saved_mem < needed) {
- /* Have to allocate more memory */
- buf_size += needed;
- buf_space += needed;
- if (realloc_memory(drv_binary,buf_size,&ptr,
- &complete_buf) == ASN1_ERROR)
- return ASN1_ERROR;
- }
-
- counter -= (4 + no_bytes);
- if((counter<0) ||
- (ret=insert_bits_as_bits(desired_len,no_bytes,&in_ptr,
- &ptr,&unused)) == ASN1_ERROR)
- return ASN1_ERROR;
- buf_space -= ret;
- break;
-
- default:
- return ASN1_ERROR;
- }
- in_ptr++;
- }
- /* The returned buffer must be at least one byte and
- it must be octet aligned */
- if ((unused == 8) && (ptr != complete_buf))
- return (ptr - complete_buf);
- else {
- ptr++; /* octet align buffer */
- return (ptr - complete_buf);
- }
-}
-
-
-int realloc_memory(ErlDrvBinary **drv_binary,
- int amount,
- unsigned char **ptr,
- unsigned char **complete_buf) {
-
- ErlDrvBinary *tmp_bin;
- int i;
-
-/* printf("realloc_momory: amount = %d\n",amount); */
- if ((tmp_bin=driver_realloc_binary(*drv_binary,amount)) == NULL) {
- /*error handling due to memory allocation failure */
-/* printf("error when allocating memory\n"); */
- return ASN1_ERROR;
- }else {
- i = *ptr - *complete_buf;
- *drv_binary=tmp_bin;
- *complete_buf = (unsigned char*)(*drv_binary)->orig_bytes;
- *ptr = *complete_buf + i;
- }
- return ASN1_OK;
-}
-
-
-int insert_most_sign_bits(int no_bits,
- unsigned char val,
- unsigned char **output_ptr,
- int *unused) {
- unsigned char *ptr = *output_ptr;
-
- if (no_bits < *unused){
- *ptr = *ptr | (val >> (8 - *unused));
- *unused -= no_bits;
- } else if (no_bits == *unused) {
- *ptr = *ptr | (val >> (8 - *unused));
- *unused = 8;
- *++ptr = 0x00;
- } else {
- *ptr = *ptr | (val >> (8 - *unused));
- *++ptr = 0x00;
- *ptr = *ptr | (val << *unused);
- *unused = 8 - (no_bits - *unused);
- }
- *output_ptr = ptr;
- return ASN1_OK;
-}
-
-
-int insert_least_sign_bits(int no_bits,
- unsigned char val,
- unsigned char **output_ptr,
- int *unused) {
- unsigned char *ptr = *output_ptr;
- int ret = 0;
-
- if (no_bits < *unused){
- *ptr = *ptr | (val << (*unused - no_bits));
- *unused -= no_bits;
- } else if (no_bits == *unused){
- *ptr = *ptr | val;
- *unused = 8;
- *++ptr = 0x00;
- ret++;
- } else {
- /* first in the begun byte in the completed buffer insert
- so many bits that fit, then insert the rest in next byte.*/
- *ptr = *ptr | (val >> (no_bits - *unused));
- *++ptr = 0x00;
- ret++;
- *ptr = *ptr | (val << (8 - (no_bits - *unused)));
- *unused = 8 - (no_bits - *unused);
- }
- *output_ptr = ptr;
- return ret;
-}
-
-/* pad_bits adds no_bits bits in the buffer that output_ptr
- points at.
- */
-int pad_bits(int no_bits, unsigned char **output_ptr, int *unused)
- {
- unsigned char *ptr = *output_ptr;
- int ret = 0;
-
- while (no_bits > 0) {
- if(*unused == 1){
- *unused = 8;
- *++ptr = 0x00;
- ret++;
- } else
- (*unused)--;
- no_bits--;
- }
- *output_ptr = ptr;
- return ret;
- }
-
-
-/* insert_bits_as_bits removes no_bytes bytes from the buffer that in_ptr
- points at and takes the desired_no leftmost bits from those removed
- bytes and inserts them in the buffer(output buffer) that ptr points at.
- The unused parameter tells how many bits that are not set in the
- actual byte in the output buffer. If desired_no is more bits than the
- input buffer has in no_bytes bytes, then zero bits is padded.*/
-int insert_bits_as_bits(int desired_no,
- int no_bytes,
- unsigned char **input_ptr,
- unsigned char **output_ptr,
- int *unused)
-{
- unsigned char *in_ptr = *input_ptr;
- unsigned char val;
- int no_bits, ret, ret2;
-
- if (desired_no == (no_bytes * 8)) {
- if(insert_octets_unaligned(no_bytes,&in_ptr,output_ptr,*unused)
- == ASN1_ERROR)
- return ASN1_ERROR;
- ret = no_bytes;
- }
- else if (desired_no < (no_bytes * 8)) {
-/* printf("insert_bits_as_bits 1\n\r"); */
- if(insert_octets_unaligned(desired_no/8,&in_ptr,output_ptr,*unused)
- == ASN1_ERROR)
- return ASN1_ERROR;
-/* printf("insert_bits_as_bits 2\n\r"); */
- val = *++in_ptr;
-/* printf("val = %d\n\r",(int)val); */
- no_bits = desired_no % 8;
-/* printf("no_bits = %d\n\r",no_bits); */
- insert_most_sign_bits(no_bits,val,output_ptr,unused);
- ret = CEIL(desired_no,8);
- }
- else {
- if(insert_octets_unaligned(no_bytes,&in_ptr,output_ptr,*unused)
- == ASN1_ERROR)
- return ASN1_ERROR;
- ret2 = pad_bits(desired_no - (no_bytes * 8),output_ptr,unused);
-/* printf("ret2 = %d\n\r",ret2); */
- ret = CEIL(desired_no,8);
-/* printf("ret = %d\n\r",ret); */
- }
-/* printf("*unused = %d\n\r",*unused); */
- *input_ptr = in_ptr;
- return ret;
-}
-
-
-/* insert_octets_as_bits_exact_len */
-int
-insert_octets_as_bits_exact_len(int desired_len,
- int in_buff_len,
- unsigned char **in_ptr,
- unsigned char **ptr,
- int *unused)
-{
- int ret = 0;
- int ret2 = 0;
-
- if (desired_len == in_buff_len) {
- if ((ret = insert_octets_as_bits(in_buff_len,in_ptr,ptr,unused)) == ASN1_ERROR)
- return ASN1_ERROR;
- }
- else if(desired_len > in_buff_len) {
- if((ret = insert_octets_as_bits(in_buff_len,in_ptr,ptr,unused)) == ASN1_ERROR)
- return ASN1_ERROR;
- /* now pad with zero bits */
-/* printf("~npad_bits: called with %d bits padding~n~n~r",desired_len - in_buff_len); */
- if ((ret2=pad_bits(desired_len - in_buff_len,ptr,unused)) == ASN1_ERROR)
- return ASN1_ERROR;
- }
- else {/* desired_len < no_bits */
- if ((ret=insert_octets_as_bits(desired_len,in_ptr,ptr,unused)) == ASN1_ERROR)
- return ASN1_ERROR;
- /* now remove no_bits - desired_len bytes from in buffer */
- *in_ptr += (in_buff_len - desired_len);
- }
- return (ret+ret2);
-}
-
-
-
-/* insert_octets_as_bits takes no_bytes bytes from the buffer that input_ptr
- points at and inserts the least significant bit of it in the buffer that
- output_ptr points at. Each byte in the input buffer must be 1 or 0
- otherwise the function returns ASN1_ERROR. The output buffer is concatenated
- without alignment.
- */
-int insert_octets_as_bits(int no_bytes,
- unsigned char **input_ptr,
- unsigned char **output_ptr,
- int *unused)
-{
- unsigned char *in_ptr = *input_ptr;
- unsigned char *ptr = *output_ptr;
- int used_bits = 8 - *unused;
-
- while (no_bytes > 0) {
- switch (*++in_ptr) {
- case 0:
- if(*unused == 1){
- *unused = 8;
- *++ptr = 0x00;
- } else
- (*unused)--;
- break;
- case 1:
- if(*unused == 1){
- *ptr = *ptr | 1;
- *unused = 8;
- *++ptr = 0x00;
- } else {
- *ptr = *ptr | (1 << (*unused - 1));
- (*unused)--;
- }
- break;
- default:
- return ASN1_ERROR;
- }
- no_bytes--;
- }
- *input_ptr = in_ptr;
- *output_ptr = ptr;
- return ((used_bits+no_bytes) / 8); /*return number of new bytes
- in completed buffer */
-}
-
-/* insert_octets inserts bytes from the input buffer, *input_ptr,
- into the output buffer, *output_ptr. Before the first byte is
- inserted the input buffer is aligned.
- */
-int insert_octets(int no_bytes,
- unsigned char **input_ptr,
- unsigned char **output_ptr,
- int *unused)
-{
- unsigned char *in_ptr = *input_ptr;
- unsigned char *ptr = *output_ptr;
- int ret = 0;
-
- if (*unused != 8) {/* must align before octets are added */
- *++ptr = 0x00;
- ret++;
- *unused = 8;
- }
- while(no_bytes > 0) {
- *ptr = *(++in_ptr);
- *++ptr = 0x00;
- /* *unused = *unused - 1; */
- no_bytes--;
- }
- *input_ptr = in_ptr;
- *output_ptr = ptr;
- return (ret + no_bytes);
-}
-
-/* insert_octets_unaligned inserts bytes from the input buffer, *input_ptr,
- into the output buffer, *output_ptr.No alignment is done.
- */
-int insert_octets_unaligned(int no_bytes,
- unsigned char **input_ptr,
- unsigned char **output_ptr,
- int unused)
-{
- unsigned char *in_ptr = *input_ptr;
- unsigned char *ptr = *output_ptr;
- int n = no_bytes;
- unsigned char val;
-
- while (n > 0) {
- if (unused == 8) {
- *ptr = *++in_ptr;
- *++ptr = 0x00;
- }else {
- val = *++in_ptr;
- *ptr = *ptr | val >> (8 - unused);
- *++ptr = 0x00;
- *ptr = val << unused;
- }
- n--;
- }
- *input_ptr = in_ptr;
- *output_ptr = ptr;
- return no_bytes;
-}
-
-
-int insert_octets_except_unused(int no_bytes,
- unsigned char **input_ptr,
- unsigned char **output_ptr,
- int *unused,
- int in_unused)
-{
- unsigned char *in_ptr = *input_ptr;
- unsigned char *ptr = *output_ptr;
- int val, no_bits;
- int ret = 0;
-
- if (in_unused == 0){
-/* printf("%d: insert_octets_except_unused: if\n\r",__LINE__); */
- if ((ret = insert_octets_unaligned(no_bytes,&in_ptr,&ptr,
- *unused)) == ASN1_ERROR)
- return ASN1_ERROR;
- }
- else {
-/* printf("%d: insert_octets_except_unused: else\n\r",__LINE__); */
- if ((ret=insert_octets_unaligned(no_bytes - 1,&in_ptr,&ptr,*unused)) != ASN1_ERROR) {
- val = (int) *(++in_ptr);
- no_bits = 8 - in_unused;
- /* no_bits is always less than *unused since the buffer is
- octet aligned after insert:octets call, so the following
- if clasuse is obsolete I think */
- if(no_bits < *unused){
- *ptr = *ptr | (val >> (8 - *unused));
- *unused = *unused - no_bits;
- } else if (no_bits == *unused) {
- *ptr = *ptr | (val >> (8 - *unused));
- *++ptr = 0x00;
- ret++;
- *unused = 8;
- } else {
- *ptr = *ptr | (val >> (8 - *unused));
- *++ptr = 0x00;
- ret++;
- *ptr = *ptr | (val << *unused);
- *unused = 8 - (no_bits - *unused);
- }
- } else
- return ASN1_ERROR;
- }
- *input_ptr = in_ptr;
- *output_ptr = ptr;
-/* printf("%d: insert_octets_except_unused: ret=%d\n\r",__LINE__,ret); */
- return ret;
-}
-
-
-
-/*
- *
- * This section defines functionality for the partial decode of a
- * BER encoded message
- *
- */
-
-/*
- * int decode(ErlDrvBinary **drv_binary,unsigned char *decode_buf,
- * unsigned char *in_buf, int in_buf_len)
- * drv_binary is a pointer to a pointer to an allocated driver binary.
- * in_buf is a pointer into the buffer of incoming bytes.
- * in_buf_len is the length of the incoming buffer.
- * The function reads the bytes in the incoming buffer and structures
- * it in a nested way as Erlang terms. The buffer contains data in the
- * order tag - length - value. Tag, length and value has the following
- * format:
- * A tag is normally one byte but may be of any length, if the tag number
- * is greater than 30. +----------+
- * |CL|C|NNNNN|
- * +----------+
- * If NNNNN is 31 then will the 7 l.s.b of each of the following tag number
- * bytes contain the tag number. Each tag number byte that is not the last one
- * has the m.s.b. set to 1.
- * The length can be short definite length (sdl), long definite length (ldl)
- * or indefinite length (il).
- * sdl: +---------+ the L bits is the length
- * |0|LLLLLLL|
- * +---------+
- * ldl: +---------+ +---------+ +---------+ +-----------+
- * |1|lllllll| |first len| | | |the Nth len|
- * +---------+ +---------+ +---------+ ... +-----------+
- * The first byte tells how many len octets will follow, max 127
- * il: +---------+ +----------------------+ +--------+ +--------+
- * |1|0000000| |content octets (Value)| |00000000| |00000000|
- * +---------+ +----------------------+ +--------+ +--------+
- * The value octets are preceded by one octet and followed by two
- * exactly as above. The value must be some tag-length-value encoding.
- *
- * The function returns a value in Erlnag term format:
- * {{TagNo,Value},Rest}
- * TagNo is an integer ((CL bsl 16) + tag number) which limits the tag number
- * to 65535.
- * Value is a binary if the C bit in tag was unset, otherwise (if tag was
- * constructed) Value is a list, List.
- * List is like: [{TagNo,Value},{TagNo,Value},...]
- * Rest is a binary, i.e. the undecoded part of the buffer. Most often Rest
- * is the empty binary.
- * If some error occured during the decoding of the in_buf an error is returned.
- */
-int decode_begin(ErlDrvBinary **drv_binary,unsigned char *in_buf, int in_buf_len, unsigned int *err_pos)
-{
- int maybe_ret;
- char *decode_buf = (*drv_binary)->orig_bytes;
- int ei_index = 0;
- int ib_index = 0;
- /* ei_index is the index used by the ei functions to encode an
- Erlang term into the buffer decode_buf */
- /* ib_index is the index were to read the next byte from in_buf */
-
-
-#ifdef ASN1_DEBUG
- printf("decode_begin1: ei_index=%d, ib_index=%d\n\r",ei_index,ib_index);
-#endif
- /* the first byte must be a "version magic" */
- if(ei_encode_version(decode_buf,&ei_index) == ASN1_ERROR)
- return ASN1_ERROR; /* 1 byte */
-#ifdef ASN1_DEBUG
- printf("decode_begin2: ei_index=%d, ib_index=%d\n\r",ei_index,ib_index);
-#endif
- if (ei_encode_tuple_header(decode_buf,&ei_index,2) == ASN1_ERROR)
- return ASN1_ERROR; /* 2 bytes */
-#ifdef ASN1_DEBUG
- printf("decode_begin3: ei_index=%d, ib_index=%d\n\r",ei_index,ib_index);
-#endif
- if((maybe_ret=decode(drv_binary,&ei_index,in_buf,&ib_index,in_buf_len)) <= ASN1_ERROR)
- {
- *err_pos = ib_index;
-#ifdef ASN1_DEBUG
- printf("err_pos=%d,ib_index=%d\r\n",*err_pos,ib_index);
-#endif
- return maybe_ret;
- };
-
- decode_buf = (*drv_binary)->orig_bytes; /* maybe a realloc during decode_value */
-#ifdef ASN1_DEBUG
- printf("decode_begin4: in_buf_len=%d, ei_index=%d, ib_index=%d\n\r",
- in_buf_len,ei_index,ib_index);
-#endif
- /* "{{TagNo,Value},Rest}" */
- if (ei_encode_binary(decode_buf,&ei_index,&(in_buf[ib_index]),in_buf_len-ib_index)
- == ASN1_ERROR) /* at least 5 bytes */
- return ASN1_ERROR;
-#ifdef ASN1_DEBUG
- printf("decode_begin5: ei_index=%d, ib_index=%d\n\r",ei_index,ib_index);
-#endif
- return ei_index;
-}
-
-int decode(ErlDrvBinary **drv_binary,int *ei_index,unsigned char *in_buf,
- int *ib_index, int in_buf_len)
-{
- int maybe_ret;
- char *decode_buf = (*drv_binary)->orig_bytes;
- int form;
-#ifdef ASN1_DEBUG
- printf("decode 1\n\r");
-#endif
- if (((*drv_binary)->orig_size - *ei_index) < 19) {/* minimum amount of bytes */
- /* allocate more memory */
- if (realloc_decode_buf(drv_binary,(*drv_binary)->orig_size * 2) ==
- ASN1_ERROR)
- return ASN1_ERROR;
- decode_buf = (*drv_binary)->orig_bytes;
- }
-/* printf("decode 2\n\r"); */
- /* "{" */
- if (ei_encode_tuple_header(decode_buf,ei_index,2) == ASN1_ERROR)
- return ASN1_ERROR; /* 2 bytes */
-#ifdef ASN1_DEBUG
- printf("decode 3:orig_size=%ld, ei_index=%d, ib_index=%d\n\r",(*drv_binary)->orig_size,*ei_index,*ib_index);
-#endif
-
- /*buffer must hold at least two bytes*/
- if ((*ib_index +2) > in_buf_len)
- return ASN1_VALUE_ERROR;
- /* "{{TagNo," */
- if ((form = decode_tag(decode_buf,ei_index,in_buf,in_buf_len,ib_index)) <= ASN1_ERROR)
- return form; /* 5 bytes */
-#ifdef ASN1_DEBUG
- printf("i_i=%d,in_buf_len=%d\r\n",*ei_index,in_buf_len);
-#endif
- if (*ib_index >= in_buf_len){
- return ASN1_TAG_ERROR;
- }
-#ifdef ASN1_DEBUG
- printf("decode 5 ib_index=%d\n\r",*ib_index);
-#endif
- /* buffer must hold at least one byte (0 as length and nothing as
- value) */
- /* "{{TagNo,Value}," */
- if ((maybe_ret=decode_value(ei_index,in_buf,ib_index,drv_binary,form,
- in_buf_len)) <= ASN1_ERROR)
- return maybe_ret; /* at least 5 bytes */
-#ifdef ASN1_DEBUG
- printf("decode 7\n\r");
-#endif
- return *ei_index;
-}
-
-/*
- * decode_tag decodes the BER encoded tag in in_buf and puts it in the
- * decode_buf encoded by the Erlang extern format as an Erlang term.
- */
-int decode_tag(char *decode_buf,int *db_index,unsigned char *in_buf,
- int in_buf_len, int *ib_index)
-{
- int tag_no, tmp_tag, form;
-
-
- /* first get the class of tag and bit shift left 16*/
- tag_no = ((MASK(in_buf[*ib_index],ASN1_CLASS)) << 10);
-
- form = (MASK(in_buf[*ib_index],ASN1_FORM));
-#ifdef ASN1_DEBUG
- printf("decode_tag0:ii=%d, tag_no=%d, form=%d.\r\n",
- *ib_index,tag_no,form);
-#endif
-
- /* then get the tag number */
- if((tmp_tag = (int) INVMASK(in_buf[*ib_index],ASN1_CLASSFORM)) < 31) {
- ei_encode_ulong(decode_buf,db_index,tag_no+tmp_tag); /* usual case */
- (*ib_index)++;
-#ifdef ASN1_DEBUG
- printf("decode_tag1:ii=%d.\r\n",*ib_index);
-#endif
- }
- else
- {
- int n = 0; /* n is used to check that the 64K limit is not
- exceeded*/
-#ifdef ASN1_DEBUG
- printf("decode_tag1:ii=%d, in_buf_len=%d.\r\n",*ib_index,in_buf_len);
-#endif
-
- /* should check that at least three bytes are left in
- in-buffer,at least two tag byte and at least one length byte */
- if ((*ib_index +3) > in_buf_len)
- return ASN1_VALUE_ERROR;
- (*ib_index)++;
-#ifdef ASN1_DEBUG
- printf("decode_tag2:ii=%d.\r\n",*ib_index);
-#endif
- /* The tag is in the following bytes in in_buf as
- 1ttttttt 1ttttttt ... 0ttttttt, where the t-bits
- is the tag number*/
- /* In practice is the tag size limited to 64K, i.e. 16 bits. If
- the tag is greater then 64K return an error */
- while (((tmp_tag = (int)in_buf[*ib_index]) >= 128) && n < 2){
- /* m.s.b. = 1 */
- tag_no = tag_no + (MASK(tmp_tag,ASN1_LONG_TAG) << 7);
- (*ib_index)++;
-#ifdef ASN1_DEBUG
- printf("decode_tag3:ii=%d.\r\n",*ib_index);
-#endif
- n++;
- };
- if ((n==2) && in_buf[*ib_index] > 3)
- return ASN1_TAG_ERROR; /* tag number > 64K */
- tag_no = tag_no + in_buf[*ib_index];
- (*ib_index)++;
-#ifdef ASN1_DEBUG
- printf("decode_tag4:ii=%d.\r\n",*ib_index);
-#endif
- ei_encode_ulong(decode_buf,db_index,tag_no);
- }
- return form;
-}
-
-
-/*
- * decode_value decodes the BER encoded length and value fields in the
- * in_buf and puts the value part in the decode_buf as an Erlang term
- * encoded by the Erlang extern format
- */
-int decode_value(int *ei_index,unsigned char *in_buf,
- int *ib_index,ErlDrvBinary **drv_binary,int form,
- int in_buf_len)
-{
- int maybe_ret;
- char *decode_buf = (*drv_binary)->orig_bytes;
- unsigned int len = 0;
- unsigned int lenoflen = 0;
- int indef = 0;
-
-#ifdef ASN1_DEBUG
- printf("decode_value1:ib_index=%d\n\r",*ib_index);
-#endif
- if (((in_buf[*ib_index]) & 0x80) == ASN1_SHORT_DEFINITE_LENGTH) {
- len = in_buf[*ib_index];
- }
- else if (in_buf[*ib_index] == ASN1_INDEFINITE_LENGTH)
- indef = 1;
- else /* long definite length */ {
- lenoflen = (in_buf[*ib_index] & 0x7f); /*length of length */
-#ifdef ASN1_DEBUG
- printf("decode_value,lenoflen:%d\r\n",lenoflen);
-#endif
- if (lenoflen > (in_buf_len - (*ib_index+1)))
- return ASN1_LEN_ERROR;
- len = 0;
- while (lenoflen-- ) {
- (*ib_index)++;
-#ifdef ASN1_DEBUG
- printf("decode_value1:*ib_index=%d, byte = %d.\r\n",*ib_index,in_buf[*ib_index]);
-#endif
- if (!(len < (1 << (sizeof(len)-1)*8)))
- return ASN1_LEN_ERROR; /* length does not fit in 32 bits */
- len = (len << 8) + in_buf[*ib_index];
- }
- }
- if (len > (in_buf_len - (*ib_index + 1)))
- return ASN1_VALUE_ERROR;
- (*ib_index)++;
-#ifdef ASN1_DEBUG
- printf("decode_value2:ii=%d.\r\n",*ib_index);
-#endif
- if (indef == 1)
- { /* in this case it is desireably to check that indefinite length
- end bytes exist in inbuffer */
- while (!(in_buf[*ib_index]==0 && in_buf[*ib_index + 1]==0)) {
-#ifdef ASN1_DEBUG
- printf("decode_value while:ib_index=%d in_buf_len=%d\n\r",
- *ib_index,in_buf_len);
-#endif
- if(*ib_index >= in_buf_len)
- return ASN1_INDEF_LEN_ERROR;
- ei_encode_list_header(decode_buf,ei_index,1); /* 5 bytes */
- if((maybe_ret=decode(drv_binary,ei_index,in_buf,
- ib_index,in_buf_len)) <= ASN1_ERROR)
- return maybe_ret;
- decode_buf = (*drv_binary)->orig_bytes;
- }
- (*ib_index) += 2; /* skip the indefinite length end bytes */
-#ifdef ASN1_DEBUG
- printf("decode_value3:ii=%d.\r\n",*ib_index);
-#endif
- ei_encode_empty_list(decode_buf,ei_index); /* 1 byte */
- }
- else if (form == ASN1_CONSTRUCTED)
- {
- int end_index = *ib_index + len;
- if(end_index > in_buf_len)
- return ASN1_LEN_ERROR;
- while (*ib_index < end_index) {
-
-#ifdef ASN1_DEBUG
- printf("decode_value3:*ib_index=%d, end_index=%d\n\r",*ib_index,end_index);
-#endif
- ei_encode_list_header(decode_buf,ei_index,1); /* 5 bytes */
- if((maybe_ret=decode(drv_binary,ei_index,in_buf,
- ib_index,in_buf_len))<=ASN1_ERROR)
- return maybe_ret;
- decode_buf = (*drv_binary)->orig_bytes;
- }
- ei_encode_empty_list(decode_buf,ei_index); /* 1 byte */
- }
- else
- {
- if (((*drv_binary)->orig_size - *ei_index) < 10+len) { /* 5+len for the binary*/
- if (realloc_decode_buf(drv_binary,(*drv_binary)->orig_size * 2) ==
- ASN1_ERROR)
- return ASN1_ERROR;
- decode_buf = (*drv_binary)->orig_bytes;
- }
- if((*ib_index + len) > in_buf_len)
- return ASN1_LEN_ERROR;
- ei_encode_binary(decode_buf,ei_index,&in_buf[*ib_index],len);
- *ib_index = *ib_index + len;
-#ifdef ASN1_DEBUG
- printf("decode_value4:ii=%d.\r\n",*ib_index);
-#endif
- }
- return ASN1_OK;
-}
-
-int realloc_decode_buf(ErlDrvBinary **drv_binary,int amount) {
- ErlDrvBinary *tmp_bin;
-
- if ((tmp_bin=driver_realloc_binary(*drv_binary,amount)) == NULL)
- return ASN1_ERROR;
- *drv_binary = tmp_bin;
- return ASN1_OK;
-}
-
-
-
-/*
- * int decode_partial(drv_binary,in_buf,in_buf_len)
- */
-/*
- * The in_buf contains two parts: first information about which value
- * will be decoded, as a sequence of tags and tag codes, then the
- * encoded BER value. First of all comes a length field that tells how
- * many following bytes contains the sequence of tags. Then starts the
- * BER encoded message. The tag sequence length field is a single
- * byte. The sequence of tags/tag codes may be one of the codes
- * ASN1_SKIPPED, ASN1_CHOOSEN and a tag or ASN1_OPTIONAL and a
- * tag. ASN1_SKIPPED means that the following tag is mandatory and is
- * skipped. ASN1_CHOOSEN means that the value of this tag shall, if
- * this was the last tag in tag sequence, be returned or be searched
- * in for the next tag. ASN1_OPTIONAL means that this tag shall be
- * skipped but it may be missing. Each tag in the tag sequence
- * correspond to a tag in the BER encoded message. If the decode
- * arives to a position where there is no matching tag, an error is
- * returned (if it wasn't the last tag and it was OPTIONAL). After the
- * right value has been detected it is returned in the out_buf.
- *
- */
-int decode_partial(ErlDrvBinary **drv_binary,unsigned char *in_buf, int in_buf_len)
-{
- char *out_buf = (*drv_binary)->orig_bytes;
- int tag_index_val = 1;
- int msg_index_val;
- int *msg_index, *tag_index, tmp_index;
- int tag_seq_length;
- int wanted_tag, next_tag;
- int buf_end_index = in_buf_len;
- int ret = 0, length, old_index;
-
- tag_index = &tag_index_val;
- tag_seq_length = in_buf[0];
- msg_index = &msg_index_val;
- *msg_index = tag_seq_length + 1;
-
-
-/* printf("decode_partial 1: in_buf_len=%d, tag_index=%d, msg_index=%d\r\n,tag_seq_length=%d\r\n",in_buf_len,*tag_index,*msg_index,tag_seq_length); */
- while(*tag_index < tag_seq_length) {
- switch(in_buf[*tag_index]) {
- case ASN1_SKIPPED:
-/* printf("decode_partial ASN1_SKIPPED: in_buf[*msg_index]=%d\r\n",in_buf[*msg_index]); */
- (*tag_index)++;
-/* printf("decode_partial ASN1_SKIPPED 2: *msg_index=%d\r\n",*msg_index); */
- skip_tag(in_buf,msg_index,buf_end_index);
-/* printf("decode_partial ASN1_SKIPPED 3: *msg_index=%d\r\n",*msg_index); */
- skip_length_and_value(in_buf,msg_index,buf_end_index);
-/* printf("decode_partial ASN1_SKIPPED 4: *msg_index=%d\r\n",*msg_index); */
- break;
- case ASN1_OPTIONAL:
- (*tag_index)++;
-/* printf("decode_partial ASN1_OPTIONAL: in_buf[*tag_index]=%d\r\n",in_buf[*tag_index]); */
- wanted_tag = in_buf[*tag_index];
- (*tag_index)++;
- tmp_index = *msg_index;
- next_tag = get_tag(in_buf,msg_index,buf_end_index);
- if (wanted_tag != next_tag) {
- *msg_index = tmp_index;
- } else
- skip_length_and_value(in_buf,msg_index,buf_end_index);
- break;
- case ASN1_CHOOSEN:
-/* printf("decode_partial ASN1_CHOOSEN: in_buf[*msg_index]=%d, *msg_index=%d\r\n",in_buf[*msg_index],*msg_index); */
- (*tag_index)++;
- wanted_tag = in_buf[*tag_index];
- (*tag_index)++;
- old_index = *msg_index;
-/* printf("decode_partial ASN1_CHOOSEN 2: *msg_index=%d\r\n",*msg_index); */
- next_tag = get_tag(in_buf,msg_index,buf_end_index);
-/* printf("decode_partial ASN1_CHOOSEN 3: *msg_index=%d\r\n,wanted_tag=%d, next_tag=%d\r\n",*msg_index,wanted_tag,next_tag); */
- if (wanted_tag != next_tag)
- return ASN1_NOVALUE; /* an empty binary will be returned to Erlang */
- if (*tag_index == (tag_seq_length + 1)) {
- /* get the value and return*/
- if((ret = get_value(out_buf,in_buf,msg_index,buf_end_index)) <= ASN1_ERROR)
- return ASN1_ERROR;
- return ret;
- }
- else {
- /* calculate the length of the sub buffer and let *msg_index
- be at the value part of this BER encoded type*/
- int indef;
- indef = 0;
- length = get_length(in_buf,msg_index,&indef,buf_end_index);
-/* printf("decode_partial ASN1_CHOOSEN 4: length=%d, *msg_index=%d\r\n",length,*msg_index); */
- if ((length == 0) && (indef == 1)) {
- /* indefinite length of value */
- old_index = *msg_index;
- length = skip_length_and_value(in_buf,msg_index,buf_end_index);
- *msg_index = old_index;
- buf_end_index = *msg_index + length - 2;
- /* remove two bytes due to indefinete length end zeros */
- } else
- buf_end_index = (*msg_index + length);
- }
- break;
- default:
- return ASN1_ERROR;
- }
- }
- return ASN1_ERROR;
-}
-
-
-/*
- * int skip_tag(unsigned char *in_buf,int *index,int buf_len)
- * steps past the BER encoded tag in in_buf and updates *index.
- * Returns the number of skipped bytes.
- */
-int skip_tag(unsigned char *in_buf,int *index,int buf_len)
-{
- int start_index = *index;
- if ((MASK(in_buf[*index],ASN1_TAG)) == 31){
- do {
- (*index)++;
- if (*index >= buf_len)
- return ASN1_ERROR;
- }
- while(in_buf[*index] >=128);
- }
- (*index)++;
- return (*index - start_index);
-}
-
-
-/*
- * int skip_length_and_value(unsigned char *in_buf,int *index,int buf_len)
- * steps past the BER encoded length and value in in_buf and updates *index.
- * returns the length if the skipped "length value".
- * Returns the number of skipped bytes.
- */
-int skip_length_and_value(unsigned char *in_buf,int *index,int buf_len)
-{
- long len;
- int indef = 0, lenoflen;
- int start_index = *index;
-
- if ((MASK(in_buf[*index],0x80)) == ASN1_SHORT_DEFINITE_LENGTH){
- len = in_buf[*index];
- if (len > (buf_len - (*index + 1)))
- return ASN1_LEN_ERROR;
- } else if (in_buf[*index] == ASN1_INDEFINITE_LENGTH)
- indef = 1;
- else /* long definite length */ {
- lenoflen = (in_buf[*index] & 0x7f); /*length of length */
- len = 0;
- while (lenoflen--) {
- (*index)++;
- len = (len << 8) + in_buf[*index];
- }
- if (len > (buf_len - (*index + 1)))
- return ASN1_LEN_ERROR;
- }
- (*index)++;
- if (indef == 1)
- {
- while(!(in_buf[*index]==0 && in_buf[*index + 1]==0)) {
- skip_tag(in_buf,index,buf_len);
- skip_length_and_value(in_buf,index,buf_len);
- }
- (*index) += 2;
- }
- else
- (*index) += len;
- return (*index - start_index);
-}
-
-/* int get_tag(unsigned char *in_buf,int *index)
- *
- * assumes next byte/bytes in in_buf is an encoded BER tag. A tag
- * number has theoretically no upper limit in size. Here the tag
- * number is assumed to be less than 64K. Returns an integer value
- * on the format:
- * xxxxxxxx xxxxxxcc tttttttt tttttttt
- * the x-bits are 0 (insignificant)
- * the c-bits are the class of the tag
- * the t-bits are the tag number. This implies that the tag number
- * is limited to 64K-1
- *
- */
-int get_tag(unsigned char *in_buf,int *index,int buf_len)
-{
- int tag_no = 0,tmp_tag = 0;
-
- tag_no = (MASK(in_buf[*index],ASN1_CLASSFORM));
- if ((MASK(in_buf[*index],ASN1_TAG)) == ASN1_TAG) {
- /* long form of tag */
- do {
- (*index)++;
- if (*index >= buf_len)
- return ASN1_TAG_ERROR;
- tmp_tag = tmp_tag << 7;
- tmp_tag += (MASK(in_buf[*index],ASN1_LONG_TAG));
- } while (in_buf[*index] >= 128);
- (*index)++;
- tag_no = tag_no + tmp_tag;
- } else {
- tag_no += (MASK(in_buf[*index],ASN1_TAG));
- (*index)++;
- }
- if (*index >= buf_len)
- return ASN1_TAG_ERROR;
- return tag_no;
-}
-
-
-/*
- * int get_value(char *out_buf,unsigned char *in_buf,
- * int *msg_index,int in_buf_len)
- */
-/* assumes next byte/bytes in in_buf is an encoded BER value preceeded by a BER encoded length. Puts value in out_buf.
- */
-int get_value(char *out_buf,
- unsigned char *in_buf,
- int *msg_index,
- int in_buf_len)
-{
- int len, lenoflen, indef=0, skip_len;
- int ret=0;
- int start_index;
-
-/* printf("get_value 1\n\r"); */
- if (in_buf[*msg_index] < 0x80){ /* short definite length */
- len = in_buf[*msg_index];
-/* printf("short definite length\r\n"); */
- } else if (in_buf[*msg_index] > 0x80) { /* long definite length */
- lenoflen = (in_buf[*msg_index] & 0x7f); /*length of length */
- len = 0;
- while (lenoflen--) {
- (*msg_index)++;
- len = (len << 8) + in_buf[*msg_index];
- }
- if (len > (in_buf_len - (*msg_index + 1)))
- return ASN1_LEN_ERROR;
- } else
- indef = 1;
- (*msg_index)++;
-/* printf("get_value 2: len = %d, *msg_index = %d\r\n",len,*msg_index); */
- if (indef == 1) {
- while(!(in_buf[*msg_index]==0 && in_buf[*msg_index + 1]==0)) {
- start_index = *msg_index;
- skip_len = skip_tag(in_buf,msg_index,in_buf_len);
-/* printf("get_value 3: skip_len=%d,start_index=%d,*msg_index=%d\n\r", */
-/* skip_len,start_index,*msg_index); */
- memcpy(&out_buf[ret],&in_buf[start_index],skip_len);
- ret += skip_len;
- start_index = *msg_index;
- skip_len = skip_length_and_value(in_buf,msg_index,in_buf_len);
-/* printf("get_value 4: skip_len=%d,start_index=%d,*msg_index=%d\n\r", */
-/* skip_len,start_index,*msg_index); */
- memcpy(&out_buf[ret],&in_buf[start_index],skip_len);
- ret += skip_len;
- }
- return ret;
- }
- else
- memcpy(&out_buf[ret],&in_buf[*msg_index],len);
- return len;
-}
-
-
-/*
- * int get_length(unsigned char *in_buf,int *msg_index)
- * assumes next byte/bytes contain a BER encoded length field,
- * which is decoded. The value of the length is returned. If it
- * is an indefinite length the *indef is set to one.
- */
-int get_length(unsigned char *in_buf,int *msg_index,
- int *indef,int in_buf_len)
-{
- int len=0, lenoflen;
-
- if (in_buf[*msg_index] < 0x80) /* short definite length */
- len = in_buf[*msg_index];
- else if (in_buf[*msg_index] > 0x80) { /* long definite length */
- lenoflen = (in_buf[*msg_index] & 0x7f); /*length of length */
- len = 0;
- while (lenoflen--) {
- (*msg_index)++;
- len = (len << 8) + in_buf[*msg_index];
- }
- if (len > (in_buf_len - (*msg_index + 1)))
- return ASN1_LEN_ERROR;
- } else
- *indef = 1;
- (*msg_index)++;
- return len;
-}
diff --git a/lib/asn1/c_src/asn1_erl_nif.c b/lib/asn1/c_src/asn1_erl_nif.c
new file mode 100644
index 0000000000..9c9f83bc2a
--- /dev/null
+++ b/lib/asn1/c_src/asn1_erl_nif.c
@@ -0,0 +1,1305 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 2002-2011. All Rights Reserved.
+ *
+ * The contents of this file are subject to the Erlang Public License,
+ * Version 1.1, (the "License"); you may not use this file except in
+ * compliance with the License. You should have received a copy of the
+ * Erlang Public License along with this software. If not, it can be
+ * retrieved online at http://www.erlang.org/.
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * %CopyrightEnd%
+ *
+ */
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include "erl_nif.h"
+
+/* #define ASN1_DEBUG 1 */
+
+#define ASN1_OK 0
+#define ASN1_ERROR -1
+#define ASN1_COMPL_ERROR 1
+#define ASN1_MEMORY_ERROR 0
+#define ASN1_DECODE_ERROR 2
+#define ASN1_TAG_ERROR -3
+#define ASN1_LEN_ERROR -4
+#define ASN1_INDEF_LEN_ERROR -5
+#define ASN1_VALUE_ERROR -6
+
+#define ASN1_CLASS 0xc0
+#define ASN1_FORM 0x20
+#define ASN1_CLASSFORM (ASN1_CLASS | ASN1_FORM)
+#define ASN1_TAG 0x1f
+#define ASN1_LONG_TAG 0x7f
+
+#define ASN1_INDEFINITE_LENGTH 0x80
+#define ASN1_SHORT_DEFINITE_LENGTH 0
+
+#define ASN1_PRIMITIVE 0
+#define ASN1_CONSTRUCTED 0x20
+
+#define ASN1_NOVALUE 0
+
+#define ASN1_SKIPPED 0
+#define ASN1_OPTIONAL 1
+#define ASN1_CHOOSEN 2
+
+#define CEIL(X,Y) ((X-1) / Y + 1)
+
+#define INVMASK(X,M) (X & (M ^ 0xff))
+#define MASK(X,M) (X & M)
+
+/* PER COMPLETE */
+int per_complete(ErlNifBinary *, unsigned char *, int);
+
+int per_insert_octets(int, unsigned char **, unsigned char **, int *);
+
+int per_insert_octets_except_unused(int, unsigned char **, unsigned char **,
+ int *, int);
+
+int per_insert_octets_as_bits_exact_len(int, int, unsigned char **,
+ unsigned char **, int *);
+
+int per_insert_octets_as_bits(int, unsigned char **, unsigned char **, int *);
+
+int per_pad_bits(int, unsigned char **, int *);
+
+int per_insert_least_sign_bits(int, unsigned char, unsigned char **, int *);
+
+int per_insert_most_sign_bits(int, unsigned char, unsigned char **, int *);
+
+int per_insert_bits_as_bits(int, int, unsigned char **, unsigned char **, int *);
+
+int per_insert_octets_unaligned(int, unsigned char **, unsigned char **, int);
+
+int per_realloc_memory(ErlNifBinary *, int, unsigned char **);
+
+/* BER DECODE */
+int ber_decode_begin(ErlNifEnv *, ERL_NIF_TERM *, unsigned char *, int,
+ unsigned int *);
+
+int ber_decode(ErlNifEnv *, ERL_NIF_TERM *, unsigned char *, int *, int);
+
+int ber_decode_tag(ErlNifEnv *, ERL_NIF_TERM *, unsigned char *, int, int *);
+
+int ber_decode_value(ErlNifEnv*, ERL_NIF_TERM *, unsigned char *, int *, int,
+ int);
+
+/* BER ENCODE */
+typedef struct ber_encode_mem_chunk mem_chunk_t;
+
+int ber_encode(ErlNifEnv *, ERL_NIF_TERM , mem_chunk_t **, unsigned int *);
+
+void ber_free_chunks(mem_chunk_t *chunk);
+mem_chunk_t *ber_new_chunk(unsigned int length);
+int ber_check_memory(mem_chunk_t **curr, unsigned int needed);
+
+int ber_encode_tag(ErlNifEnv *, ERL_NIF_TERM , unsigned int ,
+ mem_chunk_t **, unsigned int *);
+
+int ber_encode_length(size_t , mem_chunk_t **, unsigned int *);
+
+/*
+ *
+ * This section defines functionality for the complete encode of a
+ * PER encoded message
+ *
+ */
+
+int per_complete(ErlNifBinary *out_binary, unsigned char *in_buf,
+ int in_buf_len) {
+ int counter = in_buf_len;
+ /* counter keeps track of number of bytes left in the
+ input buffer */
+
+ int buf_space = in_buf_len;
+ /* This is the amount of allocated space left of the out_binary. It
+ is possible when padding is applied that more space is needed than
+ was originally allocated. */
+
+ int buf_size = in_buf_len;
+ /* Size of the buffer. May become reallocated and thus other than
+ in_buf_len */
+
+ unsigned char *in_ptr, *ptr;
+ /* in_ptr points at the next byte in in_buf to be moved to
+ complete_buf.
+ ptr points into the new completed buffer, complete_buf, at the
+ position of the next byte that will be set */
+ int unused = 8;
+ /* unused = [1,...,8] indicates how many of the rigthmost bits of
+ the byte that ptr points at that are unassigned */
+
+ int no_bits, no_bytes, in_unused, desired_len, ret, saved_mem, needed,
+ pad_bits;
+
+ unsigned char val;
+
+ in_ptr = in_buf;
+ ptr = out_binary->data;
+ *ptr = 0x00;
+ while (counter > 0) {
+ counter--;
+ switch (*in_ptr) {
+ case 0:
+ /* just one zero-bit should be added to the buffer */
+ if (unused == 1) {
+ unused = 8;
+ *++ptr = 0x00;
+ buf_space--;
+ } else
+ unused--;
+ break;
+
+ case 1:
+ /* one one-bit should be added to the buffer */
+ if (unused == 1) {
+ *ptr = *ptr | 1;
+ unused = 8;
+ *++ptr = 0x00;
+ buf_space--;
+ } else {
+ *ptr = *ptr | (1 << (unused - 1));
+ unused--;
+ }
+ break;
+
+ case 2:
+ /* align buffer to end of byte */
+ if (unused != 8) {
+ *++ptr = 0x00;
+ buf_space--;
+ unused = 8;
+ }
+ break;
+
+ case 10:
+ /* next byte in in_buf tells how many bits in the second next
+ byte that will be used */
+ /* The leftmost unused bits in the value byte are supposed to be
+ zero bits */
+ no_bits = (int) *(++in_ptr);
+ val = *(++in_ptr);
+ counter -= 2;
+ if ((ret = per_insert_least_sign_bits(no_bits, val, &ptr, &unused))
+ == ASN1_ERROR
+ )
+ return ASN1_ERROR;
+ buf_space -= ret;
+ break;
+
+ case 20:
+ /* in this case the next value in_ptr points at holds the number
+ of following bytes that holds the value that will be inserted
+ in the completed buffer */
+ no_bytes = (int) *(++in_ptr);
+ counter -= (no_bytes + 1);
+ if ((counter < 0)
+ || (ret = per_insert_octets(no_bytes, &in_ptr, &ptr,
+ &unused)) == ASN1_ERROR
+ )
+ return ASN1_ERROR;
+ buf_space -= ret;
+ break;
+
+ case 21:
+ /* in this case the next two bytes in_ptr points at holds the number
+ of following bytes that holds the value that will be inserted
+ in the completed buffer */
+ no_bytes = (int) *(++in_ptr);
+ no_bytes = no_bytes << 8;
+ no_bytes = no_bytes | (int) *(++in_ptr);
+ counter -= (2 + no_bytes);
+ if ((counter < 0)
+ || (ret = per_insert_octets(no_bytes, &in_ptr, &ptr,
+ &unused)) == ASN1_ERROR
+ )
+ return ASN1_ERROR;
+ buf_space -= ret;
+ break;
+
+ case 30:
+ /* If we call the following bytes, in the buffer in_ptr points at,
+ By1,By2,Rest then Rest is the value that will be transfered to
+ the completed buffer. By1 tells how many of the rightmost bits in
+ Rest that should not be used. By2 is the length of Rest in bytes.*/
+ in_unused = (int) *(++in_ptr);
+ no_bytes = (int) *(++in_ptr);
+ counter -= (2 + no_bytes);
+ ret = -4711;
+ if ((counter < 0)
+ || (ret = per_insert_octets_except_unused(no_bytes, &in_ptr,
+ &ptr, &unused, in_unused)) == ASN1_ERROR
+ )
+ return ASN1_ERROR;
+ buf_space -= ret;
+ break;
+
+ case 31:
+ /* If we call the following bytes, in the buffer in_ptr points at,
+ By1,By2,By3,Rest then Rest is the value that will be transfered to
+ the completed buffer. By1 tells how many of the rightmost bits in
+ Rest that should not be used. By2 and By3 is the length of
+ Rest in bytes.*/
+ in_unused = (int) *(++in_ptr);
+ no_bytes = (int) *(++in_ptr);
+ no_bytes = no_bytes << 8;
+ no_bytes = no_bytes | (int) *(++in_ptr);
+ counter -= (3 + no_bytes);
+ if ((counter < 0)
+ || (ret = per_insert_octets_except_unused(no_bytes, &in_ptr,
+ &ptr, &unused, in_unused)) == ASN1_ERROR
+ )
+ return ASN1_ERROR;
+ buf_space -= ret;
+ break;
+
+ case 40:
+ /* This case implies that next byte,By1,(..,By1,By2,Bin,...)
+ is the desired length of the completed value, maybe needs
+ padding zero bits or removal of trailing zero bits from Bin.
+ By2 is the length of Bin and Bin is the value that will be
+ put into the completed buffer. Each byte in Bin has the value
+ 1 or 0.*/
+ desired_len = (int) *(++in_ptr);
+ no_bytes = (int) *(++in_ptr);
+
+ /* This is the algorithm for need of memory reallocation:
+ Only when padding (cases 40 - 43,45 - 47) more memory may be
+ used than allocated. Therefore one has to keep track of how
+ much of the allocated memory that has been saved, i.e. the
+ difference between the number of parsed bytes of the input buffer
+ and the number of used bytes of the output buffer.
+ If saved memory is less than needed for the padding then we
+ need more memory. */
+ saved_mem = buf_space - counter;
+ pad_bits = desired_len - no_bytes - unused;
+ needed = (pad_bits > 0) ? CEIL(pad_bits,8) : 0;
+ if (saved_mem < needed) {
+ /* Have to allocate more memory */
+ buf_size += needed;
+ buf_space += needed;
+ if (per_realloc_memory(out_binary, buf_size, &ptr) == ASN1_ERROR
+ )
+ return ASN1_ERROR;
+ }
+
+ counter -= (2 + no_bytes);
+ if ((counter < 0)
+ || (ret = per_insert_octets_as_bits_exact_len(desired_len,
+ no_bytes, &in_ptr, &ptr, &unused)) == ASN1_ERROR
+ )
+ return ASN1_ERROR;
+ buf_space -= ret;
+ break;
+
+ case 41:
+ /* Same as case 40 apart from By2, the length of Bin, which is in
+ two bytes*/
+ desired_len = (int) *(++in_ptr);
+ no_bytes = (int) *(++in_ptr);
+ no_bytes = no_bytes << 8;
+ no_bytes = no_bytes | (int) *(++in_ptr);
+
+ saved_mem = buf_space - counter;
+ needed = CEIL((desired_len-unused),8) - no_bytes;
+ if (saved_mem < needed) {
+ /* Have to allocate more memory */
+ buf_size += needed;
+ buf_space += needed;
+ if (per_realloc_memory(out_binary, buf_size, &ptr) == ASN1_ERROR
+ )
+ return ASN1_ERROR;
+ }
+
+ counter -= (3 + no_bytes);
+ if ((counter < 0)
+ || (ret = per_insert_octets_as_bits_exact_len(desired_len,
+ no_bytes, &in_ptr, &ptr, &unused)) == ASN1_ERROR
+ )
+ return ASN1_ERROR;
+ buf_space -= ret;
+ break;
+
+ case 42:
+ /* Same as case 40 apart from By1, the desired length, which is in
+ two bytes*/
+ desired_len = (int) *(++in_ptr);
+ desired_len = desired_len << 8;
+ desired_len = desired_len | (int) *(++in_ptr);
+ no_bytes = (int) *(++in_ptr);
+
+ saved_mem = buf_space - counter;
+ needed = CEIL((desired_len-unused),8) - no_bytes;
+ if (saved_mem < needed) {
+ /* Have to allocate more memory */
+ buf_size += needed;
+ buf_space += needed;
+ if (per_realloc_memory(out_binary, buf_size, &ptr) == ASN1_ERROR
+ )
+ return ASN1_ERROR;
+ }
+
+ counter -= (3 + no_bytes);
+ if ((counter < 0)
+ || (ret = per_insert_octets_as_bits_exact_len(desired_len,
+ no_bytes, &in_ptr, &ptr, &unused)) == ASN1_ERROR
+ )
+ return ASN1_ERROR;
+ buf_space -= ret;
+ break;
+
+ case 43:
+ /* Same as case 40 apart from By1 and By2, the desired length and
+ the length of Bin, which are in two bytes each. */
+ desired_len = (int) *(++in_ptr);
+ desired_len = desired_len << 8;
+ desired_len = desired_len | (int) *(++in_ptr);
+ no_bytes = (int) *(++in_ptr);
+ no_bytes = no_bytes << 8;
+ no_bytes = no_bytes | (int) *(++in_ptr);
+
+ saved_mem = buf_space - counter;
+ needed = CEIL((desired_len-unused),8) - no_bytes;
+ if (saved_mem < needed) {
+ /* Have to allocate more memory */
+ buf_size += needed;
+ buf_space += needed;
+ if (per_realloc_memory(out_binary, buf_size, &ptr) == ASN1_ERROR
+ )
+ return ASN1_ERROR;
+ }
+
+ counter -= (4 + no_bytes);
+ if ((counter < 0)
+ || (ret = per_insert_octets_as_bits_exact_len(desired_len,
+ no_bytes, &in_ptr, &ptr, &unused)) == ASN1_ERROR
+ )
+ return ASN1_ERROR;
+ buf_space -= ret;
+ break;
+
+ case 45:
+ /* This case assumes that the following bytes in the incoming buffer
+ (called By1,By2,Bin) is By1, which is the number of bits (n) that
+ will be inserted in the completed buffer. By2 is the number of
+ bytes in Bin. Each bit in the buffer Bin should be inserted from
+ the leftmost until the nth.*/
+ desired_len = (int) *(++in_ptr);
+ no_bytes = (int) *(++in_ptr);
+
+ saved_mem = buf_space - counter;
+ needed = CEIL((desired_len-unused),8) - no_bytes;
+ if (saved_mem < needed) {
+ /* Have to allocate more memory */
+ buf_size += needed;
+ buf_space += needed;
+ if (per_realloc_memory(out_binary, buf_size, &ptr) == ASN1_ERROR
+ )
+ return ASN1_ERROR;
+ }
+
+ counter -= (2 + no_bytes);
+
+ if ((counter < 0)
+ || (ret = per_insert_bits_as_bits(desired_len, no_bytes,
+ &in_ptr, &ptr, &unused)) == ASN1_ERROR
+ )
+ return ASN1_ERROR;
+ buf_space -= ret;
+ break;
+
+ case 46:
+ /* Same as case 45 apart from By1, the desired length, which is
+ in two bytes. */
+ desired_len = (int) *(++in_ptr);
+ desired_len = desired_len << 8;
+ desired_len = desired_len | (int) *(++in_ptr);
+ no_bytes = (int) *(++in_ptr);
+
+ saved_mem = buf_space - counter;
+ needed = CEIL((desired_len-unused),8) - no_bytes;
+ if (saved_mem < needed) {
+ /* Have to allocate more memory */
+ buf_size += needed;
+ buf_space += needed;
+ if (per_realloc_memory(out_binary, buf_size, &ptr) == ASN1_ERROR
+ )
+ return ASN1_ERROR;
+ }
+
+ counter -= (3 + no_bytes);
+ if ((counter < 0)
+ || (ret = per_insert_bits_as_bits(desired_len, no_bytes,
+ &in_ptr, &ptr, &unused)) == ASN1_ERROR
+ )
+ return ASN1_ERROR;
+ buf_space -= ret;
+ break;
+
+ case 47:
+ /* Same as case 45 apart from By1 and By2, the desired length
+ and the length of Bin, which are in two bytes each. */
+ desired_len = (int) *(++in_ptr);
+ desired_len = desired_len << 8;
+ desired_len = desired_len | (int) *(++in_ptr);
+ no_bytes = (int) *(++in_ptr);
+ no_bytes = no_bytes << 8;
+ no_bytes = no_bytes | (int) *(++in_ptr);
+
+ saved_mem = buf_space - counter;
+ needed = CEIL((desired_len-unused),8) - no_bytes;
+ if (saved_mem < needed) {
+ /* Have to allocate more memory */
+ buf_size += needed;
+ buf_space += needed;
+ if (per_realloc_memory(out_binary, buf_size, &ptr) == ASN1_ERROR
+ )
+ return ASN1_ERROR;
+ }
+
+ counter -= (4 + no_bytes);
+ if ((counter < 0)
+ || (ret = per_insert_bits_as_bits(desired_len, no_bytes,
+ &in_ptr, &ptr, &unused)) == ASN1_ERROR
+ )
+ return ASN1_ERROR;
+ buf_space -= ret;
+ break;
+
+ default:
+ return ASN1_ERROR;
+ }
+ in_ptr++;
+ }
+ /* The returned buffer must be at least one byte and
+ it must be octet aligned */
+ if ((unused == 8) && (ptr != out_binary->data))
+ return (ptr - out_binary->data);
+ else {
+ ptr++; /* octet align buffer */
+ return (ptr - out_binary->data);
+ }
+}
+
+int per_realloc_memory(ErlNifBinary *binary, int amount, unsigned char **ptr) {
+
+ int i = *ptr - binary->data;
+
+ if (!enif_realloc_binary(binary, amount)) {
+ /*error handling due to memory allocation failure */
+ return ASN1_ERROR;
+ } else {
+ *ptr = binary->data + i;
+ }
+ return ASN1_OK;
+}
+
+int per_insert_most_sign_bits(int no_bits, unsigned char val,
+ unsigned char **output_ptr, int *unused) {
+ unsigned char *ptr = *output_ptr;
+
+ if (no_bits < *unused) {
+ *ptr = *ptr | (val >> (8 - *unused));
+ *unused -= no_bits;
+ } else if (no_bits == *unused) {
+ *ptr = *ptr | (val >> (8 - *unused));
+ *unused = 8;
+ *++ptr = 0x00;
+ } else {
+ *ptr = *ptr | (val >> (8 - *unused));
+ *++ptr = 0x00;
+ *ptr = *ptr | (val << *unused);
+ *unused = 8 - (no_bits - *unused);
+ }
+ *output_ptr = ptr;
+ return ASN1_OK;
+}
+
+int per_insert_least_sign_bits(int no_bits, unsigned char val,
+ unsigned char **output_ptr, int *unused) {
+ unsigned char *ptr = *output_ptr;
+ int ret = 0;
+
+ if (no_bits < *unused) {
+ *ptr = *ptr | (val << (*unused - no_bits));
+ *unused -= no_bits;
+ } else if (no_bits == *unused) {
+ *ptr = *ptr | val;
+ *unused = 8;
+ *++ptr = 0x00;
+ ret++;
+ } else {
+ /* first in the begun byte in the completed buffer insert
+ so many bits that fit, then insert the rest in next byte.*/
+ *ptr = *ptr | (val >> (no_bits - *unused));
+ *++ptr = 0x00;
+ ret++;
+ *ptr = *ptr | (val << (8 - (no_bits - *unused)));
+ *unused = 8 - (no_bits - *unused);
+ }
+ *output_ptr = ptr;
+ return ret;
+}
+
+/* per_pad_bits adds no_bits bits in the buffer that output_ptr
+ points at.
+ */
+int per_pad_bits(int no_bits, unsigned char **output_ptr, int *unused) {
+ unsigned char *ptr = *output_ptr;
+ int ret = 0;
+
+ while (no_bits > 0) {
+ if (*unused == 1) {
+ *unused = 8;
+ *++ptr = 0x00;
+ ret++;
+ } else
+ (*unused)--;
+ no_bits--;
+ }
+ *output_ptr = ptr;
+ return ret;
+}
+
+/* insert_bits_as_bits removes no_bytes bytes from the buffer that in_ptr
+ points at and takes the desired_no leftmost bits from those removed
+ bytes and inserts them in the buffer(output buffer) that ptr points at.
+ The unused parameter tells how many bits that are not set in the
+ actual byte in the output buffer. If desired_no is more bits than the
+ input buffer has in no_bytes bytes, then zero bits is padded.*/
+int per_insert_bits_as_bits(int desired_no, int no_bytes,
+ unsigned char **input_ptr, unsigned char **output_ptr, int *unused) {
+ unsigned char *in_ptr = *input_ptr;
+ unsigned char val;
+ int no_bits, ret, ret2;
+
+ if (desired_no == (no_bytes * 8)) {
+ if (per_insert_octets_unaligned(no_bytes, &in_ptr, output_ptr, *unused)
+ == ASN1_ERROR
+ )
+ return ASN1_ERROR;
+ ret = no_bytes;
+ } else if (desired_no < (no_bytes * 8)) {
+ /* printf("per_insert_bits_as_bits 1\n\r"); */
+ if (per_insert_octets_unaligned(desired_no / 8, &in_ptr, output_ptr,
+ *unused) == ASN1_ERROR
+ )
+ return ASN1_ERROR;
+ /* printf("per_insert_bits_as_bits 2\n\r"); */
+ val = *++in_ptr;
+ /* printf("val = %d\n\r",(int)val); */
+ no_bits = desired_no % 8;
+ /* printf("no_bits = %d\n\r",no_bits); */
+ per_insert_most_sign_bits(no_bits, val, output_ptr, unused);
+ ret = CEIL(desired_no,8);
+ } else {
+ if (per_insert_octets_unaligned(no_bytes, &in_ptr, output_ptr, *unused)
+ == ASN1_ERROR
+ )
+ return ASN1_ERROR;
+ ret2 = per_pad_bits(desired_no - (no_bytes * 8), output_ptr, unused);
+ /* printf("ret2 = %d\n\r",ret2); */
+ ret = CEIL(desired_no,8);
+ /* printf("ret = %d\n\r",ret); */
+ }
+ /* printf("*unused = %d\n\r",*unused); */
+ *input_ptr = in_ptr;
+ return ret;
+}
+
+/* per_insert_octets_as_bits_exact_len */
+int per_insert_octets_as_bits_exact_len(int desired_len, int in_buff_len,
+ unsigned char **in_ptr, unsigned char **ptr, int *unused) {
+ int ret = 0;
+ int ret2 = 0;
+
+ if (desired_len == in_buff_len) {
+ if ((ret = per_insert_octets_as_bits(in_buff_len, in_ptr, ptr, unused))
+ == ASN1_ERROR
+ )
+ return ASN1_ERROR;
+ } else if (desired_len > in_buff_len) {
+ if ((ret = per_insert_octets_as_bits(in_buff_len, in_ptr, ptr, unused))
+ == ASN1_ERROR
+ )
+ return ASN1_ERROR;
+ /* now pad with zero bits */
+ /* printf("~npad_bits: called with %d bits padding~n~n~r",desired_len - in_buff_len); */
+ if ((ret2 = per_pad_bits(desired_len - in_buff_len, ptr, unused))
+ == ASN1_ERROR
+ )
+ return ASN1_ERROR;
+ } else {/* desired_len < no_bits */
+ if ((ret = per_insert_octets_as_bits(desired_len, in_ptr, ptr, unused))
+ == ASN1_ERROR
+ )
+ return ASN1_ERROR;
+ /* now remove no_bits - desired_len bytes from in buffer */
+ *in_ptr += (in_buff_len - desired_len);
+ }
+ return (ret + ret2);
+}
+
+/* insert_octets_as_bits takes no_bytes bytes from the buffer that input_ptr
+ points at and inserts the least significant bit of it in the buffer that
+ output_ptr points at. Each byte in the input buffer must be 1 or 0
+ otherwise the function returns ASN1_ERROR. The output buffer is concatenated
+ without alignment.
+ */
+int per_insert_octets_as_bits(int no_bytes, unsigned char **input_ptr,
+ unsigned char **output_ptr, int *unused) {
+ unsigned char *in_ptr = *input_ptr;
+ unsigned char *ptr = *output_ptr;
+ int used_bits = 8 - *unused;
+
+ while (no_bytes > 0) {
+ switch (*++in_ptr) {
+ case 0:
+ if (*unused == 1) {
+ *unused = 8;
+ *++ptr = 0x00;
+ } else
+ (*unused)--;
+ break;
+ case 1:
+ if (*unused == 1) {
+ *ptr = *ptr | 1;
+ *unused = 8;
+ *++ptr = 0x00;
+ } else {
+ *ptr = *ptr | (1 << (*unused - 1));
+ (*unused)--;
+ }
+ break;
+ default:
+ return ASN1_ERROR;
+ }
+ no_bytes--;
+ }
+ *input_ptr = in_ptr;
+ *output_ptr = ptr;
+ return ((used_bits + no_bytes) / 8); /*return number of new bytes
+ in completed buffer */
+}
+
+/* insert_octets inserts bytes from the input buffer, *input_ptr,
+ into the output buffer, *output_ptr. Before the first byte is
+ inserted the input buffer is aligned.
+ */
+int per_insert_octets(int no_bytes, unsigned char **input_ptr,
+ unsigned char **output_ptr, int *unused) {
+ unsigned char *in_ptr = *input_ptr;
+ unsigned char *ptr = *output_ptr;
+ int ret = 0;
+
+ if (*unused != 8) {/* must align before octets are added */
+ *++ptr = 0x00;
+ ret++;
+ *unused = 8;
+ }
+ while (no_bytes > 0) {
+ *ptr = *(++in_ptr);
+ *++ptr = 0x00;
+ /* *unused = *unused - 1; */
+ no_bytes--;
+ }
+ *input_ptr = in_ptr;
+ *output_ptr = ptr;
+ return (ret + no_bytes);
+}
+
+/* per_insert_octets_unaligned inserts bytes from the input buffer, *input_ptr,
+ into the output buffer, *output_ptr.No alignment is done.
+ */
+int per_insert_octets_unaligned(int no_bytes, unsigned char **input_ptr,
+ unsigned char **output_ptr, int unused) {
+ unsigned char *in_ptr = *input_ptr;
+ unsigned char *ptr = *output_ptr;
+ int n = no_bytes;
+ unsigned char val;
+
+ while (n > 0) {
+ if (unused == 8) {
+ *ptr = *++in_ptr;
+ *++ptr = 0x00;
+ } else {
+ val = *++in_ptr;
+ *ptr = *ptr | val >> (8 - unused);
+ *++ptr = 0x00;
+ *ptr = val << unused;
+ }
+ n--;
+ }
+ *input_ptr = in_ptr;
+ *output_ptr = ptr;
+ return no_bytes;
+}
+
+int per_insert_octets_except_unused(int no_bytes, unsigned char **input_ptr,
+ unsigned char **output_ptr, int *unused, int in_unused) {
+ unsigned char *in_ptr = *input_ptr;
+ unsigned char *ptr = *output_ptr;
+ int val, no_bits;
+ int ret = 0;
+
+ if (in_unused == 0) {
+ if ((ret = per_insert_octets_unaligned(no_bytes, &in_ptr, &ptr, *unused))
+ == ASN1_ERROR
+ )
+ return ASN1_ERROR;
+ } else {
+ if ((ret = per_insert_octets_unaligned(no_bytes - 1, &in_ptr, &ptr, *unused))
+ != ASN1_ERROR) {
+ val = (int) *(++in_ptr);
+ no_bits = 8 - in_unused;
+ /* no_bits is always less than *unused since the buffer is
+ octet aligned after insert:octets call, so the following
+ if clasuse is obsolete I think */
+ if (no_bits < *unused) {
+ *ptr = *ptr | (val >> (8 - *unused));
+ *unused = *unused - no_bits;
+ } else if (no_bits == *unused) {
+ *ptr = *ptr | (val >> (8 - *unused));
+ *++ptr = 0x00;
+ ret++;
+ *unused = 8;
+ } else {
+ *ptr = *ptr | (val >> (8 - *unused));
+ *++ptr = 0x00;
+ ret++;
+ *ptr = *ptr | (val << *unused);
+ *unused = 8 - (no_bits - *unused);
+ }
+ } else
+ return ASN1_ERROR;
+ }
+ *input_ptr = in_ptr;
+ *output_ptr = ptr;
+ return ret;
+}
+
+/*
+ *
+ * This section defines functionality for the partial decode of a
+ * BER encoded message
+ *
+ */
+
+/*
+ * int decode(ErlNifEnv* env, ERL_NIF_TERM *term, unsigned char *in_buf,
+ int in_buf_len, unsigned int *err_pos)
+ * term is a pointer to the term which is to be returned to erlang
+ * in_buf is a pointer into the buffer of incoming bytes.
+ * in_buf_len is the length of the incoming buffer.
+ * The function reads the bytes in the incoming buffer and structures
+ * it in a nested way as Erlang terms. The buffer contains data in the
+ * order tag - length - value. Tag, length and value has the following
+ * format:
+ * A tag is normally one byte but may be of any length, if the tag number
+ * is greater than 30. +----------+
+ * |CL|C|NNNNN|
+ * +----------+
+ * If NNNNN is 31 then will the 7 l.s.b of each of the following tag number
+ * bytes contain the tag number. Each tag number byte that is not the last one
+ * has the m.s.b. set to 1.
+ * The length can be short definite length (sdl), long definite length (ldl)
+ * or indefinite length (il).
+ * sdl: +---------+ the L bits is the length
+ * |0|LLLLLLL|
+ * +---------+
+ * ldl: +---------+ +---------+ +---------+ +-----------+
+ * |1|lllllll| |first len| | | |the Nth len|
+ * +---------+ +---------+ +---------+ ... +-----------+
+ * The first byte tells how many len octets will follow, max 127
+ * il: +---------+ +----------------------+ +--------+ +--------+
+ * |1|0000000| |content octets (Value)| |00000000| |00000000|
+ * +---------+ +----------------------+ +--------+ +--------+
+ * The value octets are preceded by one octet and followed by two
+ * exactly as above. The value must be some tag-length-value encoding.
+ *
+ * The function returns a value in Erlang nif term format:
+ * {{TagNo,Value},Rest}
+ * TagNo is an integer ((CL bsl 16) + tag number) which limits the tag number
+ * to 65535.
+ * Value is a binary if the C bit in tag was unset, otherwise (if tag was
+ * constructed) Value is a list, List.
+ * List is like: [{TagNo,Value},{TagNo,Value},...]
+ * Rest is a binary, i.e. the undecoded part of the buffer. Most often Rest
+ * is the empty binary.
+ * If some error occured during the decoding of the in_buf an error is returned.
+ */
+int ber_decode_begin(ErlNifEnv* env, ERL_NIF_TERM *term, unsigned char *in_buf,
+ int in_buf_len, unsigned int *err_pos) {
+ int maybe_ret;
+ int ib_index = 0;
+ unsigned char *rest_data;
+ ERL_NIF_TERM decoded_term, rest;
+
+ if ((maybe_ret = ber_decode(env, &decoded_term, in_buf, &ib_index,
+ in_buf_len)) <= ASN1_ERROR)
+ {
+ *err_pos = ib_index;
+ return maybe_ret;
+ };
+
+ // The remaining binary after one ASN1 segment has been decoded
+ if ((rest_data = enif_make_new_binary(env, in_buf_len - ib_index, &rest))
+ == NULL) {
+ *term = enif_make_atom(env, "could_not_alloc_binary");
+ return ASN1_ERROR;
+ }
+
+ *term = enif_make_tuple2(env, decoded_term, rest);
+ return ASN1_OK;
+}
+
+int ber_decode(ErlNifEnv* env, ERL_NIF_TERM *term, unsigned char *in_buf,
+ int *ib_index, int in_buf_len) {
+ int maybe_ret;
+ int form;
+ ERL_NIF_TERM tag, value;
+
+ /*buffer must hold at least two bytes*/
+ if ((*ib_index + 2) > in_buf_len)
+ return ASN1_VALUE_ERROR;
+ /* "{{TagNo," */
+ if ((form = ber_decode_tag(env, &tag, in_buf, in_buf_len, ib_index))
+ <= ASN1_ERROR
+ )
+ return form; /* 5 bytes */
+ if (*ib_index >= in_buf_len) {
+ return ASN1_TAG_ERROR;
+ }
+ /* buffer must hold at least one byte (0 as length and nothing as
+ value) */
+ /* "{{TagNo,Value}," */
+ if ((maybe_ret = ber_decode_value(env, &value, in_buf, ib_index, form,
+ in_buf_len)) <= ASN1_ERROR
+ )
+ return maybe_ret; /* at least 5 bytes */
+ *term = enif_make_tuple2(env, tag, value);
+ return ASN1_OK;
+}
+
+/*
+ * decode_tag decodes the BER encoded tag in in_buf and creates an
+ * nif term tag
+ */
+int ber_decode_tag(ErlNifEnv* env, ERL_NIF_TERM *tag, unsigned char *in_buf,
+ int in_buf_len, int *ib_index) {
+ int tag_no, tmp_tag, form;
+
+ /* first get the class of tag and bit shift left 16*/
+ tag_no = ((MASK(in_buf[*ib_index],ASN1_CLASS)) << 10);
+
+ form = (MASK(in_buf[*ib_index],ASN1_FORM));
+
+ /* then get the tag number */
+ if ((tmp_tag = (int) INVMASK(in_buf[*ib_index],ASN1_CLASSFORM)) < 31) {
+ *tag = enif_make_uint(env, tag_no + tmp_tag);
+ (*ib_index)++;
+ } else {
+ int n = 0; /* n is used to check that the 64K limit is not
+ exceeded*/
+
+ /* should check that at least three bytes are left in
+ in-buffer,at least two tag byte and at least one length byte */
+ if ((*ib_index + 3) > in_buf_len)
+ return ASN1_VALUE_ERROR;
+ (*ib_index)++;
+ /* The tag is in the following bytes in in_buf as
+ 1ttttttt 1ttttttt ... 0ttttttt, where the t-bits
+ is the tag number*/
+ /* In practice is the tag size limited to 64K, i.e. 16 bits. If
+ the tag is greater then 64K return an error */
+ while (((tmp_tag = (int) in_buf[*ib_index]) >= 128) && n < 2) {
+ /* m.s.b. = 1 */
+ tag_no = tag_no + (MASK(tmp_tag,ASN1_LONG_TAG) << 7);
+ (*ib_index)++;
+ n++;
+ };
+ if ((n == 2) && in_buf[*ib_index] > 3)
+ return ASN1_TAG_ERROR; /* tag number > 64K */
+ tag_no = tag_no + in_buf[*ib_index];
+ (*ib_index)++;
+ *tag = enif_make_uint(env, tag_no);
+ }
+ return form;
+}
+
+/*
+ * ber_decode_value decodes the BER encoded length and value fields in the
+ * in_buf and puts the value part in the decode_buf as an Erlang
+ * nif term into value
+ */
+int ber_decode_value(ErlNifEnv* env, ERL_NIF_TERM *value, unsigned char *in_buf,
+ int *ib_index, int form, int in_buf_len) {
+ int maybe_ret;
+ unsigned int len = 0;
+ unsigned int lenoflen = 0;
+ int indef = 0;
+ unsigned char *tmp_out_buff;
+ ERL_NIF_TERM term = 0, curr_head = 0;
+
+ if (((in_buf[*ib_index]) & 0x80) == ASN1_SHORT_DEFINITE_LENGTH) {
+ len = in_buf[*ib_index];
+ } else if (in_buf[*ib_index] == ASN1_INDEFINITE_LENGTH
+ )
+ indef = 1;
+ else /* long definite length */{
+ lenoflen = (in_buf[*ib_index] & 0x7f); /*length of length */
+ if (lenoflen > (in_buf_len - (*ib_index + 1)))
+ return ASN1_LEN_ERROR;
+ len = 0;
+ while (lenoflen--) {
+ (*ib_index)++;
+ if (!(len < (1 << (sizeof(len) - 1) * 8)))
+ return ASN1_LEN_ERROR; /* length does not fit in 32 bits */
+ len = (len << 8) + in_buf[*ib_index];
+ }
+ }
+ if (len > (in_buf_len - (*ib_index + 1)))
+ return ASN1_VALUE_ERROR;
+ (*ib_index)++;
+ if (indef == 1) { /* in this case it is desireably to check that indefinite length
+ end bytes exist in inbuffer */
+ curr_head = enif_make_list(env, 0);
+ while (!(in_buf[*ib_index] == 0 && in_buf[*ib_index + 1] == 0)) {
+ if (*ib_index >= in_buf_len)
+ return ASN1_INDEF_LEN_ERROR;
+
+ if ((maybe_ret = ber_decode(env, &term, in_buf, ib_index, in_buf_len))
+ <= ASN1_ERROR
+ )
+ return maybe_ret;
+ curr_head = enif_make_list_cell(env, term, curr_head);
+ }
+ enif_make_reverse_list(env, curr_head, value);
+ (*ib_index) += 2; /* skip the indefinite length end bytes */
+ } else if (form == ASN1_CONSTRUCTED)
+ {
+ int end_index = *ib_index + len;
+ if (end_index > in_buf_len)
+ return ASN1_LEN_ERROR;
+ curr_head = enif_make_list(env, 0);
+ while (*ib_index < end_index) {
+
+ if ((maybe_ret = ber_decode(env, &term, in_buf, ib_index,
+ in_buf_len)) <= ASN1_ERROR
+ )
+ return maybe_ret;
+ curr_head = enif_make_list_cell(env, term, curr_head);
+ }
+ enif_make_reverse_list(env, curr_head, value);
+ } else {
+ if ((*ib_index + len) > in_buf_len)
+ return ASN1_LEN_ERROR;
+ tmp_out_buff = enif_make_new_binary(env, len, value);
+ memcpy(tmp_out_buff, in_buf + *ib_index, len);
+ *ib_index = *ib_index + len;
+ }
+ return ASN1_OK;
+}
+
+struct ber_encode_mem_chunk {
+ mem_chunk_t *next;
+ int length;
+ char *top;
+ char *curr;
+};
+
+int ber_encode(ErlNifEnv *env, ERL_NIF_TERM term, mem_chunk_t **curr, unsigned int *count) {
+
+ const ERL_NIF_TERM *tv;
+ unsigned int form;
+ int arity;
+
+ if (!enif_get_tuple(env, term, &arity, &tv))
+ return ASN1_ERROR;
+
+ form = enif_is_list(env, tv[1]) ? ASN1_CONSTRUCTED : ASN1_PRIMITIVE;
+
+ switch (form) {
+ case ASN1_PRIMITIVE: {
+ ErlNifBinary value;
+ if (!enif_inspect_binary(env, tv[1], &value))
+ return ASN1_ERROR;
+
+ if (ber_check_memory(curr, value.size))
+ return ASN1_ERROR;
+ memcpy((*curr)->curr - value.size + 1, value.data, value.size);
+ (*curr)->curr -= value.size;
+ *count += value.size;
+
+ if (ber_encode_length(value.size, curr, count))
+ return ASN1_ERROR;
+
+ break;
+ }
+ case ASN1_CONSTRUCTED: {
+ ERL_NIF_TERM head, tail;
+ unsigned int tmp_cnt;
+
+ if(!enif_make_reverse_list(env, tv[1], &head))
+ return ASN1_ERROR;
+
+ if (!enif_get_list_cell(env, head, &head, &tail)) {
+ if (enif_is_empty_list(env, tv[1])) {
+ *((*curr)->curr) = 0;
+ (*curr)->curr -= 1;
+ (*count)++;
+ break;
+ } else
+ return ASN1_ERROR;
+ }
+
+ do {
+ tmp_cnt = 0;
+ if (ber_encode(env, head, curr, &tmp_cnt)) {
+ return ASN1_ERROR;
+ }
+ *count += tmp_cnt;
+ } while (enif_get_list_cell(env, tail, &head, &tail));
+
+ if (ber_check_memory(curr, *count)) {
+ return ASN1_ERROR;
+ }
+
+ if (ber_encode_length(*count, curr, count)) {
+ return ASN1_ERROR;
+ }
+
+ break;
+ }
+ }
+
+ // We need atleast 5 bytes to encode the next tlv
+ if (ber_check_memory(curr, 3))
+ return ASN1_ERROR;
+
+ if (ber_encode_tag(env, tv[0], form, curr, count))
+ return ASN1_ERROR;
+
+ return ASN1_OK;
+}
+
+int ber_encode_tag(ErlNifEnv *env, ERL_NIF_TERM tag, unsigned int form,
+ mem_chunk_t **curr, unsigned int *count) {
+ unsigned int class_tag_no, head_tag;
+ if (!enif_get_uint(env, tag, &class_tag_no))
+ return ASN1_ERROR;
+
+ head_tag = form | ((class_tag_no & 0x30000) >> 10);
+ class_tag_no = class_tag_no & 0xFFFF;
+
+ if (class_tag_no <= 30) {
+ *(*curr)->curr = head_tag | class_tag_no;
+ (*curr)->curr -= 1;
+ (*count)++;
+ return ASN1_OK;
+ } else {
+ *(*curr)->curr = class_tag_no & 127;
+ class_tag_no = class_tag_no >> 7;
+ (*curr)->curr -= 1;
+ (*count)++;
+
+ while (class_tag_no > 0) {
+ *(*curr)->curr = (class_tag_no & 127) | 0x80;
+ class_tag_no >>= 7;
+ (*curr)->curr -= 1;
+ (*count)++;
+ }
+
+ *(*curr)->curr = head_tag | 0x1F;
+ (*curr)->curr -= 1;
+ (*count)++;
+
+ return ASN1_OK;
+ }
+}
+
+int ber_encode_length(size_t size, mem_chunk_t **curr, unsigned int *count) {
+ if (size < 128) {
+ if (ber_check_memory(curr, 1u))
+ return ASN1_ERROR;
+ *(*curr)->curr = size;
+ (*curr)->curr -= 1;
+ (*count)++;
+ } else {
+ int chunks = size / 256 + 1;
+ if (ber_check_memory(curr, chunks + 1))
+ return ASN1_ERROR;
+
+ while (size > 0)
+ {
+ *(*curr)->curr = size & 0xFF;
+ size >>= 8;
+ (*curr)->curr -= 1;
+ (*count)++;
+ }
+
+ *(*curr)->curr = chunks | 0x80;
+ (*curr)->curr -= 1;
+ (*count)++;
+ }
+ return ASN1_OK;
+}
+
+mem_chunk_t *ber_new_chunk(unsigned int length) {
+ mem_chunk_t *new = enif_alloc(sizeof(mem_chunk_t));
+ if (new == NULL)
+ return NULL;
+ new->next = NULL;
+ new->top = enif_alloc(sizeof(char) * length);
+ if (new->top == NULL) {
+ free(new);
+ return NULL;
+ }
+ new->curr = new->top + length - 1;
+ new->length = length;
+ return new;
+}
+
+void ber_free_chunks(mem_chunk_t *chunk) {
+ mem_chunk_t *curr, *next = chunk;
+ while (next != NULL) {
+ curr = next;
+ next = curr->next;
+ enif_free(curr->top);
+ enif_free(curr);
+ }
+}
+
+int ber_check_memory(mem_chunk_t **curr, unsigned int needed) {
+ mem_chunk_t *new;
+ if ((*curr)->curr-needed >= (*curr)->top)
+ return ASN1_OK;
+
+ if ((new = ber_new_chunk((*curr)->length > needed ? (*curr)->length * 2 : (*curr)->length + needed)) == NULL)
+ return ASN1_ERROR;
+ new->next = *curr;
+ *curr = new;
+ return ASN1_OK;
+}
+
+static ERL_NIF_TERM encode_per_complete(ErlNifEnv* env, int argc,
+ const ERL_NIF_TERM argv[]) {
+ ERL_NIF_TERM err_code;
+ ErlNifBinary in_binary;
+ ErlNifBinary out_binary;
+ int complete_len;
+ if (!enif_inspect_iolist_as_binary(env, argv[0], &in_binary))
+ return enif_make_atom(env, "badarg");
+
+ if (!enif_alloc_binary(in_binary.size, &out_binary))
+ return enif_make_atom(env, "alloc_binary_failed");
+
+ if (in_binary.size == 0)
+ return enif_make_binary(env, &out_binary);
+
+ if ((complete_len = per_complete(&out_binary, in_binary.data,
+ in_binary.size)) <= ASN1_ERROR) {
+ enif_release_binary(&out_binary);
+ if (complete_len == ASN1_ERROR
+ )
+ err_code = enif_make_uint(env, '1');
+ else
+ err_code = enif_make_uint(env, 0);
+ return enif_make_tuple2(env, enif_make_atom(env, "error"), err_code);
+ }
+ if (complete_len < out_binary.size)
+ enif_realloc_binary(&out_binary, complete_len);
+
+ return enif_make_binary(env, &out_binary);
+}
+
+static ERL_NIF_TERM decode_ber_tlv(ErlNifEnv* env, int argc,
+ const ERL_NIF_TERM argv[]) {
+ ErlNifBinary in_binary;
+ ERL_NIF_TERM return_term;
+ unsigned int err_pos = 0, return_code;
+
+ if (!enif_inspect_iolist_as_binary(env, argv[0], &in_binary))
+ return enif_make_badarg(env);
+
+ if ((return_code = ber_decode_begin(env, &return_term, in_binary.data,
+ in_binary.size, &err_pos)) != ASN1_OK
+ )
+ return enif_make_tuple2(env, enif_make_atom(env,"error"), enif_make_tuple2(env,
+ enif_make_int(env, return_code),enif_make_int(env, err_pos)));
+ return return_term;
+}
+
+static ERL_NIF_TERM encode_ber_tlv(ErlNifEnv* env, int argc,
+ const ERL_NIF_TERM argv[]) {
+ ErlNifBinary out_binary;
+ unsigned int length = 0, pos = 0;
+ int encode_err;
+ mem_chunk_t *curr, *top;
+ ERL_NIF_TERM err_code;
+
+ curr = ber_new_chunk(40);
+
+ if ((encode_err = ber_encode(env, argv[0], &curr, &length))
+ <= ASN1_ERROR) {
+ ber_free_chunks(curr);
+ err_code = enif_make_int(env, encode_err);
+ return enif_make_tuple2(env, enif_make_atom(env, "error"), err_code);
+ }
+
+ if (!enif_alloc_binary(length, &out_binary)) {
+ ber_free_chunks(curr);
+ return enif_make_tuple2(env, enif_make_atom(env, "error"), enif_make_atom(env,"oom"));
+ }
+
+ top = curr;
+
+ while (curr != NULL) {
+ length = curr->length - (curr->curr-curr->top) -1;
+ if (length > 0)
+ memcpy(out_binary.data + pos, curr->curr+1, length);
+ pos += length;
+ curr = curr->next;
+ }
+
+ ber_free_chunks(top);
+
+ return enif_make_binary(env, &out_binary);
+}
+
+static int is_ok_load_info(ErlNifEnv* env, ERL_NIF_TERM load_info) {
+ int i;
+ return enif_get_int(env, load_info, &i) && i == 1;
+}
+
+static int load(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_info) {
+ if (!is_ok_load_info(env, load_info))
+ return -1;
+ return 0;
+}
+
+static int upgrade(ErlNifEnv* env, void** priv_data, void** old_priv_data,
+ ERL_NIF_TERM load_info) {
+ if (!is_ok_load_info(env, load_info))
+ return -1;
+ return 0;
+}
+
+static void unload(ErlNifEnv* env, void* priv_data) {
+
+}
+
+static ErlNifFunc nif_funcs[] = { { "encode_per_complete", 1,
+ encode_per_complete }, { "decode_ber_tlv", 1, decode_ber_tlv }, {
+ "encode_ber_tlv", 1, encode_ber_tlv } };
+
+ERL_NIF_INIT(asn1rt_nif, nif_funcs, load, NULL, upgrade, unload)
diff --git a/lib/asn1/doc/src/Makefile b/lib/asn1/doc/src/Makefile
index d29225f6c9..566173837c 100644
--- a/lib/asn1/doc/src/Makefile
+++ b/lib/asn1/doc/src/Makefile
@@ -27,15 +27,6 @@ include ../../vsn.mk
VSN=$(ASN1_VSN)
APPLICATION=asn1
-
-# ----------------------------------------------------
-# Include dependency
-# ----------------------------------------------------
-
-ifndef DOCSUPPORT
-include make.dep
-endif
-
# ----------------------------------------------------
# Release directory specification
# ----------------------------------------------------
@@ -86,34 +77,10 @@ EXTRA_FILES = \
MAN3_FILES = $(XML_REF3_FILES:%.xml=$(MAN3DIR)/%.3)
-ifdef DOCSUPPORT
-
HTML_REF_MAN_FILE = $(HTMLDIR)/index.html
TOP_PDF_FILE = $(PDFDIR)/$(APPLICATION)-$(VSN).pdf
-else
-
-TEX_FILES_BOOK = \
- $(BOOK_FILES:%.xml=%.tex) \
- $(BOOK_FILES:%.xml=%.sgml) part.tex
-TEX_FILES_REF_MAN = $(XML_REF3_FILES:%.xml=%.tex) \
- $(XML_APPLICATION_FILES:%.xml=%.tex)
-TEX_FILES_USERS_GUIDE = \
- $(XML_CHAPTER_FILES:%.xml=%.tex)
-
-TOP_PDF_FILE = $(APPLICATION)-$(VSN).pdf
-TOP_PS_FILE = $(APPLICATION)-$(VSN).ps
-
-$(TOP_PDF_FILE): book.dvi ../../vsn.mk
- $(DVI2PS) $(DVIPS_FLAGS) -f $< | $(DISTILL) $(DISTILL_FLAGS) > $@
-
-$(TOP_PS_FILE): book.dvi ../../vsn.mk
- $(DVI2PS) $(DVIPS_FLAGS) -f $< > $@
-
-endif
-
-
# ----------------------------------------------------
# FLAGS
# ----------------------------------------------------
@@ -126,8 +93,6 @@ DVIPS_FLAGS +=
$(HTMLDIR)/%.gif: %.gif
$(INSTALL_DATA) $< $@
-ifdef DOCSUPPORT
-
docs: pdf html man
$(TOP_PDF_FILE): $(XML_FILES)
@@ -142,32 +107,6 @@ clean clean_docs:
rm -f $(TOP_PDF_FILE) $(TOP_PDF_FILE:%.pdf=%.fo)
rm -f $(GEN_XML) errs core *~
-else
-
-ifeq ($(DOCTYPE),pdf)
-docs: pdf
-else
-ifeq ($(DOCTYPE),ps)
-docs: ps
-else
-docs: html gifs man
-endif
-endif
-
-pdf: $(TOP_PDF_FILE)
-
-ps: $(TOP_PS_FILE)
-
-html: $(HTML_FILES)
-
-clean clean_docs clean_tex:
- rm -f $(TEX_FILES_USERS_GUIDE) $(TEX_FILES_REF_MAN) $(TEX_FILES_BOOK)
- rm -f $(HTML_FILES) $(MAN3_FILES)
- rm -f $(TOP_PDF_FILE) $(TOP_PS_FILE)
- rm -f errs core *~ $(LATEX_CLEAN)
-
-endif
-
man: $(MAN3_FILES)
gifs: $(GIF_FILES:%=$(HTMLDIR)/%)
@@ -179,8 +118,6 @@ debug opt:
# ----------------------------------------------------
include $(ERL_TOP)/make/otp_release_targets.mk
-ifdef DOCSUPPORT
-
release_docs_spec: docs
$(INSTALL_DIR) $(RELSYSDIR)/doc/pdf
$(INSTALL_DATA) $(TOP_PDF_FILE) $(RELSYSDIR)/doc/pdf
@@ -191,31 +128,4 @@ release_docs_spec: docs
$(INSTALL_DIR) $(RELEASE_PATH)/man/man3
$(INSTALL_DATA) $(MAN3DIR)/* $(RELEASE_PATH)/man/man3
-else
-
-ifeq ($(DOCTYPE),pdf)
-release_docs_spec: pdf
- $(INSTALL_DIR) $(RELEASE_PATH)/pdf
- $(INSTALL_DATA) $(TOP_PDF_FILE) $(RELEASE_PATH)/pdf
-else
-ifeq ($(DOCTYPE),ps)
-release_docs_spec: ps
- $(INSTALL_DIR) $(RELEASE_PATH)/ps
- $(INSTALL_DATA) $(TOP_PS_FILE) $(RELEASE_PATH)/ps
-else
-release_docs_spec: docs
- $(INSTALL_DIR) $(RELSYSDIR)/doc/html
- $(INSTALL_DATA) $(GIF_FILES) $(EXTRA_FILES) $(HTML_FILES) \
- $(HTML_APPHISTORY) $(RELSYSDIR)/doc/html
- $(INSTALL_DATA) $(INFO_FILE) $(RELSYSDIR)
- $(INSTALL_DIR) $(RELEASE_PATH)/man/man3
- $(INSTALL_DATA) $(MAN3_FILES) $(RELEASE_PATH)/man/man3
-endif
-endif
-
-endif
-
release_spec:
-
-
-
diff --git a/lib/asn1/doc/src/asn1_spec.xmlsrc b/lib/asn1/doc/src/asn1_spec.xmlsrc
index 8d61834da8..07cba17816 100644
--- a/lib/asn1/doc/src/asn1_spec.xmlsrc
+++ b/lib/asn1/doc/src/asn1_spec.xmlsrc
@@ -4,7 +4,7 @@
<chapter>
<header>
<copyright>
- <year>2003</year><year>2009</year>
+ <year>2003</year><year>2011</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -43,7 +43,7 @@
<p>So far this functionality is only provided when using the
optimized BER_BIN version, that is when compiling with the
options <c>ber_bin</c> and <c>optimize</c>. It does also work
- using the <c>driver</c> option. We have no intent to make this
+ using the <c>nif</c> option. We have no intent to make this
available on the default BER version, but maybe in the PER_BIN
version (<c>per_bin</c>).
</p>
@@ -661,7 +661,9 @@ ValAction = {'Action',17,{'Button',4711,false}}.
<p>The ASN.1 specs in the test are compiled with the options
<c>ber_bin, optimize, driver</c> and <c>asn1config</c>. If the
<c>driver</c> option had been omitted there should have been
- higher values for <c>decode</c> and <c>decode_part</c>.
+ higher values for <c>decode</c> and <c>decode_part</c>. These tests have
+ not been re-run using nifs, but are expected to perform about 5% better
+ than the linked-in driver.
</p>
<p>The test program runs 10000 decodes on the value, resulting
in a printout with the elapsed time in microseconds for the
diff --git a/lib/asn1/doc/src/asn1_ug.xml b/lib/asn1/doc/src/asn1_ug.xml
index 12d986308f..1b399fb641 100644
--- a/lib/asn1/doc/src/asn1_ug.xml
+++ b/lib/asn1/doc/src/asn1_ug.xml
@@ -4,7 +4,7 @@
<chapter>
<header>
<copyright>
- <year>1997</year><year>2010</year>
+ <year>1997</year><year>2011</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -347,7 +347,7 @@ erlc -o ../asnfiles -I ../asnfiles -I /usr/local/standards/asn1 Person.asn
<p>This flag has effect only when used together with one of
<c>per_bin</c> or <c>ber_bin</c> flags. It gives time optimized
code in the generated modules and it uses another runtime module.
- In the <c>per_bin</c> case a linked-in driver is used. The
+ In the <c>per_bin</c> case a nif is used. The
result from an encode is a binary.</p>
<p><em>When this flag is used you cannot use the old format</em><c>{TypeName,Value}</c> when you encode values. Since it is
an unnecessary construct it has been removed in favor of
@@ -362,9 +362,14 @@ erlc -o ../asnfiles -I ../asnfiles -I /usr/local/standards/asn1 Person.asn
</item>
<tag><c>+driver</c></tag>
<item>
- <p>Together with the flags <c>ber_bin</c> and <c>optimize</c>
- you choose to use a linked in driver for considerable faster
- decode.</p>
+ <p>As of R15B this means the same as the <c>nif</c> option. Kept for
+ backwards compatability reasons.</p>
+ </item>
+ <tag><c>+nif</c></tag>
+ <item>
+ <p>Together with the flags <c>ber_bin</c>
+ and <c>optimize</c> you choose to use a nif for considerable
+ faster encode and decode. </p>
</item>
<tag><c>+asn1config</c></tag>
<item>
@@ -492,7 +497,7 @@ asn1ct:decode('H323-MESSAGES','SomeChoiceType',Bytes). </pre>
</row>
<row>
<cell align="left" valign="middle">BER</cell>
- <cell align="left" valign="middle"><em>[ber_bin, optimize, driver]</em></cell>
+ <cell align="left" valign="middle"><em>[ber_bin, optimize, nif]</em></cell>
<cell align="left" valign="middle">EAVF</cell>
<cell align="left" valign="middle">iolist</cell>
<cell align="left" valign="middle">iolist / binary</cell>
@@ -557,7 +562,7 @@ asn1ct:decode('H323-MESSAGES','SomeChoiceType',Bytes). </pre>
</row>
<row>
<cell align="left" valign="middle">DER</cell>
- <cell align="left" valign="middle"><em>[ber_bin, optimize, driver, der]</em></cell>
+ <cell align="left" valign="middle"><em>[ber_bin, optimize, nif, der]</em></cell>
<cell align="left" valign="middle">EAVF</cell>
<cell align="left" valign="middle">iolist</cell>
<cell align="left" valign="middle">binary</cell>
@@ -626,23 +631,24 @@ asn1ct:decode('H323-MESSAGES','SomeChoiceType',Bytes). </pre>
</table>
<p>
- The sole compile options <c>ber</c>, <c>ber_bin</c> and <c>per</c>
- are kept for backwards compatibility and should not be used in
- new code.
+ The compile options <c>ber</c>, <c>per</c> and
+ <c>driver</c> are kept for backwards compatibility and should not be
+ used in new code. The nif implementation which replaces the linked-in
+ driver has been shown to be about 5-15% faster.
</p>
<p>
You are strongly recommended to use the appropriate alternative
of the bold typed options. The <c>optimize</c> and
- <c>driver</c> options does not affect the encode or decode
+ <c>nif</c> options does not affect the encode or decode
result, just the time spent in run-time. When <c>ber_bin</c> and
- <c>driver</c> or <c>per_bin, optimize</c> and <c>driver</c> is
- combined the C-code driver is used in chosen parts of encode /
+ <c>nif</c> or <c>per_bin</c> and <c>optimize</c> is
+ combined the C-code nif is used in chosen parts of encode /
decode procedure.
</p>
<table>
<row>
<cell align="left" valign="middle"><em>Compile options, allowed combinations</em></cell>
- <cell align="left" valign="middle"><em>use of linked-in driver</em></cell>
+ <cell align="left" valign="middle"><em>use of nif</em></cell>
</row>
<row>
<cell align="left" valign="middle">[ber]</cell>
@@ -657,7 +663,7 @@ asn1ct:decode('H323-MESSAGES','SomeChoiceType',Bytes). </pre>
<cell align="left" valign="middle">no</cell>
</row>
<row>
- <cell align="left" valign="middle"><em>[ber_bin, optimize, driver]</em></cell>
+ <cell align="left" valign="middle"><em>[ber_bin, optimize, nif]</em></cell>
<cell align="left" valign="middle">yes</cell>
</row>
<row>
@@ -690,12 +696,12 @@ asn1ct:decode('H323-MESSAGES','SomeChoiceType',Bytes). </pre>
<cell align="left" valign="middle">no</cell>
</row>
<row>
- <cell align="left" valign="middle"><em>[ber_bin, optimize, driver, der]</em></cell>
+ <cell align="left" valign="middle"><em>[ber_bin, optimize, nif, der]</em></cell>
<cell align="left" valign="middle">yes</cell>
</row>
- <tcaption>When the ASN1 linked-in driver is used.</tcaption>
+ <tcaption>When the ASN1 nif is used.</tcaption>
</table>
</section>
@@ -712,14 +718,14 @@ asn1rt:decode('H323-MESSAGES','SomeChoiceType',Bytes). </pre>
<pre>
'H323-MESSAGES':encode('SomeChoiceType',{call,"octetstring"}).
'H323-MESSAGES':decode('SomeChoiceType',Bytes). </pre>
- <p>The asn1 linked-in driver is enabled in two occasions: encoding of
+ <p>The asn1 nif is enabled in two occasions: encoding of
asn1 values when the asn1 spec is compiled with <c>per_bin</c> and
<c>optimize</c> or decode of encoded asn1 values when the asn1 spec is
- compiled with <c>ber_bin</c>, <c>optimize</c> and <c>driver</c>. In
- those cases the driver will be loaded automatically at the first call
+ compiled with <c>ber_bin</c>, <c>optimize</c> and <c>nif</c>. In
+ those cases the nif will be loaded automatically at the first call
to <c>encode</c>/<c>decode</c>. If one doesn't want the performance
- overhead of the driver being loaded at the first call it is possible
- to load the driver separately by <c>asn1rt:load_driver()</c>. </p>
+ overhead of the nif being loaded at the first call it is possible
+ to load the nif separately by loading the <c>asn1rt_nif</c> module.</p>
<p>By invoking the function <c>info/0</c> in a generated module, one
gets information about which compiler options were used.</p>
</section>
diff --git a/lib/asn1/doc/src/asn1ct.xml b/lib/asn1/doc/src/asn1ct.xml
index 29b5d4be75..0b9ec3df7f 100644
--- a/lib/asn1/doc/src/asn1ct.xml
+++ b/lib/asn1/doc/src/asn1ct.xml
@@ -52,7 +52,7 @@
<v>Options = [Option| OldOption]</v>
<v>Option = ber_bin | per_bin | uper_bin | der | compact_bit_string |
noobj | {n2n,EnumTypeName} |{outdir,Dir} | {i,IncludeDir} | optimize |
- driver | asn1config | undec_rest | {inline,OutputName} | inline |
+ nif | asn1config | undec_rest | {inline,OutputName} | inline |
{macro_name_prefix, Prefix} | {record_name_prefix, Prefix} | verbose | warnings_as_errors</v>
<v>OldOption = ber | per</v>
<v>Reason = term()</v>
@@ -212,16 +212,21 @@ Binary = binary()
<c>per_bin</c>
or <c>ber_bin</c> option. It gives time optimized code
generated and it uses another runtime module and
- in the <c>per_bin</c> case a linked-in driver. The result
+ in the <c>per_bin</c> case a nif. The result
in the <c>per_bin</c> case from an encode when compiled
with this option will be a binary.</p>
</item>
<tag><c>driver</c></tag>
<item>
+ <p>As of R15B this means the same as the <c>nif</c> option. Kept for
+ backwards compatability reasons.</p>
+ </item>
+ <tag><c>nif</c></tag>
+ <item>
<p>Option valid together with <c>ber_bin</c> and <c>optimize</c>
- options. It enables the use of a linked-in driver that gives
- considerable faster decode. In <c>ber_bin</c> the driver is
- enabled only by explicit use of the option <c>driver</c>.</p>
+ options. It enables the use of several nifs that gives faster
+ encode and decode. Nifs are only enabled by the explicit use of
+ the option <c>nif</c></p>
</item>
<tag><c>asn1config</c></tag>
<item>
@@ -264,7 +269,11 @@ Binary = binary()
<c>.set.asn</c> are exported, unless a
<c>{export,[atom()]}</c> or <c>{export_all,true}</c> option
are provided. The list of atoms are names of chosen asn1
- specs from the <c>.set.asn</c> file.</p>
+ specs from the <c>.set.asn</c> file. </p>
+ <p>When used together with <c>nif</c> for <c>ber_bin</c>, the
+ asn1 nifs will be used if the <c>asn1rt_nif</c> module is
+ available. If it is not available, a slower erlang fallback
+ will be used.</p>
</item>
<tag><c>inline</c></tag>
<item>
@@ -347,18 +356,6 @@ Binary = binary()
</desc>
</func>
<func>
- <name>validate(Module,Type,Value) -> ok | {error,Reason}</name>
- <fsummary>Validate an ASN.1 value.</fsummary>
- <type>
- <v>Module = Type = atom()</v>
- <v>Value = term()</v>
- </type>
- <desc>
- <p>Validates that <c>Value</c> conforms to <c>Type</c>
- from <c>Module</c>. <em>Not implemented in this version of the ASN.1 application.</em></p>
- </desc>
- </func>
- <func>
<name>value(Module ,Type) -> {ok,Value} | {error,Reason}</name>
<fsummary>Create an ASN.1 value for test purposes.</fsummary>
<type>
diff --git a/lib/asn1/doc/src/asn1rt.xml b/lib/asn1/doc/src/asn1rt.xml
index 1217a07e9b..0c3c257189 100644
--- a/lib/asn1/doc/src/asn1rt.xml
+++ b/lib/asn1/doc/src/asn1rt.xml
@@ -4,7 +4,7 @@
<erlref>
<header>
<copyright>
- <year>1997</year><year>2009</year>
+ <year>1997</year><year>2011</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -42,36 +42,6 @@
<funcs>
<func>
- <name>start() -> ok |{error,Reason}</name>
- <fsummary>Starts the asn1 server.</fsummary>
- <type>
- <v>Reason = term()</v>
- </type>
- <desc>
- <p>Starts the asn1 server that loads the drivers.</p>
- <p>The server schedules a driver that is not blocked by
- another caller. The driver is used by the asn1 application if
- specs are compiled with options <c>[per_bin, optimize]</c> or
- <c>[ber_bin, optimize, driver]</c>. The server will be started
- automatically at encode/decode if it isn't done explicitly. If
- encode/decode with driver is used in test or industrial code
- it is a performance gain to start it explicitly to avoid the
- one time load in run-time.</p>
- </desc>
- </func>
-
- <func>
- <name>stop() -> ok |{error,Reason}</name>
- <fsummary>Stops the asn1 server.</fsummary>
- <type>
- <v>Reason = term()</v>
- </type>
- <desc>
- <p>Stops the asn1 server and unloads the drivers.</p>
- </desc>
- </func>
-
- <func>
<name>decode(Module,Type,Bytes) -> {ok,Value}|{error,Reason}</name>
<fsummary>Decode from bytes into an ASN.1 value.</fsummary>
<type>
@@ -126,35 +96,23 @@
<func>
<name>load_driver() -> ok | {error,Reason}</name>
- <fsummary>Loads the linked-in driver.</fsummary>
+ <fsummary>Loads the linked-in driver. (deprecated)</fsummary>
<type>
<v>Reason = term()</v>
</type>
<desc>
- <p>This function loads the linked-in driver before the first call
- to encode. If this function is not called the driver will be loaded
- automatically at the first call to encode. If one doesn't want the
- performance cost of a driver load when the application is running,
- this function makes it possible to load the driver in an
- initialization.</p>
- <p>The driver is only used when encoding/decoding ASN.1 files that
- were compiled with the options <c>per_bin</c> and <c>optimize</c>.</p>
+ <p>This function is obsolete and will be removed in R16A</p>
</desc>
</func>
<func>
<name>unload_driver() -> ok | {error,Reason}</name>
- <fsummary>Unloads the linked-in driver.</fsummary>
+ <fsummary>Unloads the linked-in driver. (deprecated)</fsummary>
<type>
<v>Reason = term()</v>
</type>
<desc>
- <p>This function unloads the linked-in driver.
- When the driver has been loaded it remains in the environment until
- it is unloaded. Normally the driver should remain loaded, it is
- crucial for the performance of ASN.1 encoding. </p>
- <p>The driver is only used when ASN.1 modules have been compiled
- with the flags <c>per_bin</c> and <c>optimize</c>.</p>
+ <p>This function is obsolete and will be removed in R16A</p>
</desc>
</func>
@@ -188,19 +146,6 @@
value, to a UTF8 encoded binary.</p>
</desc>
</func>
-
- <func>
- <name>validate(Module,Type,Value) -> ok | {error,Reason}</name>
- <fsummary>Validate an ASN.1 value.</fsummary>
- <type>
- <v>Module = Type = atom()</v>
- <v>Value = term()</v>
- </type>
- <desc>
- <p>Validates that <c>Value</c> conforms to <c>Type</c>
- from <c>Module</c>. <em>Not implemented in this version of the ASN.1 application.</em></p>
- </desc>
- </func>
</funcs>
diff --git a/lib/asn1/doc/src/make.dep b/lib/asn1/doc/src/make.dep
deleted file mode 100644
index eb2c0e9a98..0000000000
--- a/lib/asn1/doc/src/make.dep
+++ /dev/null
@@ -1,31 +0,0 @@
-# ----------------------------------------------------
-# >>>> Do not edit this file <<<<
-# This file was automaticly generated by
-# /home/gandalf/otp/bin/docdepend
-# ----------------------------------------------------
-
-
-# ----------------------------------------------------
-# TeX files that the DVI file depend on
-# ----------------------------------------------------
-
-book.dvi: asn1_spec.tex asn1_ug.tex asn1ct.tex asn1rt.tex \
- book.tex part.tex ref_man.tex
-
-# ----------------------------------------------------
-# Source inlined when transforming from source to LaTeX
-# ----------------------------------------------------
-
-asn1_spec.tex: Seq.asn Seq.asn1config
-
-book.tex: part.xml ref_man.xml
-
-asn1_ug.tex: ../../../../system/doc/definitions/cite.defs
-
-# ----------------------------------------------------
-# Pictures that the DVI file depend on
-# ----------------------------------------------------
-
-book.dvi: exclusive_Win_But.ps selective_TypeList.ps \
- selective_Window2.ps
-
diff --git a/lib/asn1/src/Makefile b/lib/asn1/src/Makefile
index 2733cde3f8..3a59773d93 100644
--- a/lib/asn1/src/Makefile
+++ b/lib/asn1/src/Makefile
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 1997-2009. All Rights Reserved.
+# Copyright Ericsson AB 1997-2011. All Rights Reserved.
#
# The contents of this file are subject to the Erlang Public License,
# Version 1.1, (the "License"); you may not use this file except in
@@ -68,7 +68,7 @@ RT_MODULES= \
asn1rt_per_bin_rt2ct \
asn1rt_uper_bin \
asn1rt_check \
- asn1rt_driver_handler
+ asn1rt_nif
# asn1_sup \
# asn1_app \
# asn1_server
diff --git a/lib/asn1/src/asn1.app.src b/lib/asn1/src/asn1.app.src
index abacb0a1e9..09144ba2f7 100644
--- a/lib/asn1/src/asn1.app.src
+++ b/lib/asn1/src/asn1.app.src
@@ -9,12 +9,11 @@
asn1rt_ber_bin,
asn1rt_ber_bin_v2,
asn1rt_check,
- asn1rt_driver_handler
+ asn1rt_nif
]},
{registered, [
asn1_ns,
- asn1db,
- asn1_driver_owner
+ asn1db
]},
{env, []},
{applications, [kernel, stdlib]}
diff --git a/lib/asn1/src/asn1_app.erl b/lib/asn1/src/asn1_app.erl
index 2d3eed1743..9fff96e0bf 100644
--- a/lib/asn1/src/asn1_app.erl
+++ b/lib/asn1/src/asn1_app.erl
@@ -28,7 +28,7 @@
%% {error, Reason}
%%
start(_Type, _StartArgs) ->
- asn1_sup:start_link().
+ {ok, self()}.
%% stop(State)
%%
diff --git a/lib/asn1/src/asn1_server.erl b/lib/asn1/src/asn1_server.erl
deleted file mode 100644
index aeb59d8b0c..0000000000
--- a/lib/asn1/src/asn1_server.erl
+++ /dev/null
@@ -1,107 +0,0 @@
-%% ``The contents of this file are subject to the Erlang Public License,
-%% Version 1.1, (the "License"); you may not use this file except in
-%% compliance with the License. You should have received a copy of the
-%% Erlang Public License along with this software. If not, it can be
-%% retrieved via the world wide web at http://www.erlang.org/.
-%%
-%% Software distributed under the License is distributed on an "AS IS"
-%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
-%% the License for the specific language governing rights and limitations
-%% under the License.
-%%
-%% The Initial Developer of the Original Code is Ericsson Utvecklings AB.
-%% Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings
-%% AB. All Rights Reserved.''
-%%
-%% $Id$
-%%
-
-%% Purpose: Provide complete encode/and pre-decode of asn1.
--module(asn1_server).
-
-
-
--behaviour(gen_server).
-
--export([start_link/0,client_port/0]).
-
-%% Internal exports, call-back functions.
--export([init/1,handle_call/3,handle_cast/2,handle_info/2,code_change/3,
- terminate/2]).
-
-
-%% Macros
--define(port_names,
- { asn1_drv01, asn1_drv02, asn1_drv03, asn1_drv04,
- asn1_drv05, asn1_drv06, asn1_drv07, asn1_drv08,
- asn1_drv09, asn1_drv10, asn1_drv11, asn1_drv12,
- asn1_drv13, asn1_drv14, asn1_drv15, asn1_drv16 }).
-%%% --------------------------------------------------------
-%%% Interface Functions.
-%%% --------------------------------------------------------
-
-start_link() ->
- gen_server:start_link({local, asn1_server}, asn1_server, [], []).
-
-init([]) ->
- process_flag(trap_exit, true),
- erl_ddll:start(),
- PrivDir = code:priv_dir(asn1),
- LibDir1 = filename:join([PrivDir, "lib"]),
- case erl_ddll:load_driver(LibDir1, asn1_erl_drv) of
- ok -> ok;
- {error,_} ->
- LibDir2 =
- filename:join(LibDir1,
- erlang:system_info(system_architecture)),
- erl_ddll:load_driver(LibDir2, asn1_erl_drv)
- end,
- open_ports("asn1_erl_drv",size(?port_names)).
-
-open_ports(_,0) ->
- {ok, []};
-open_ports(Cmd,N) ->
- Port = open_port({spawn, Cmd}, []),
- %% check that driver is loaded, linked and working
- case catch port_control(Port, 0, []) of
- {'EXIT', _} ->
- {stop, nodriver};
- _ ->
- register(element(N,?port_names), Port),
- open_ports(Cmd,N-1)
- end.
-
-client_port() ->
- element(erlang:system_info(scheduler_id) rem size(?port_names) + 1,
- ?port_names).
-
-
-%%% --------------------------------------------------------
-%%% The call-back functions.
-%%% --------------------------------------------------------
-
-handle_call(_, _, State) ->
- {noreply, State}.
-
-handle_cast(_, State) ->
- {noreply, State}.
-
-handle_info({'EXIT', Pid, _Reason}, State) when is_pid(Pid) ->
- {noreply, State};
-
-handle_info({'EXIT', Port, Reason}, State) when is_port(Port) ->
- {stop, {port_died, Reason}, State};
-handle_info(_, State) ->
- {noreply, State}.
-
-code_change(_OldVsn, State, _Extra) ->
- {ok, State}.
-
-terminate(_Reason, _State) ->
- close_ports(size(?port_names)).
-
-close_ports(0) ->
- ok;
-close_ports(N) ->
- element(N,?port_names) ! {self(), close}, %% almost same as port_close(Name)
- close_ports(N-1).
diff --git a/lib/asn1/src/asn1ct.erl b/lib/asn1/src/asn1ct.erl
index e26fadd160..85bb5b2f28 100644
--- a/lib/asn1/src/asn1ct.erl
+++ b/lib/asn1/src/asn1ct.erl
@@ -47,6 +47,10 @@
-import(asn1ct_gen_ber_bin_v2,[encode_tag_val/3,decode_class/1]).
+-ifndef(vsn).
+-define(vsn,"0.0.1").
+-endif.
+
-define(unique_names,0).
-define(dupl_uniquedefs,1).
-define(dupl_equaldefs,2).
@@ -81,6 +85,12 @@ compile(File) ->
compile(File,[]).
compile(File,Options) when is_list(Options) ->
+ case lists:member(driver, Options) of %% remove me in R16A!
+ true ->
+ io:format("Warning: driver option is obsolete and will be removed in R16A, use nif instead!");
+ false ->
+ ok
+ end,
Options1 = optimize_ber_bin(Options),
Options2 = includes(File,Options1),
Includes=[I||{i,I}<-Options2],
@@ -1085,7 +1095,7 @@ get_runtime_mod(Options) ->
ber_bin_v2 -> ["asn1rt_ber_bin_v2.erl"];
uper_bin -> ["asn1rt_uper_bin.erl"]
end,
- RtMod1++["asn1rt_check.erl","asn1rt_driver_handler.erl","asn1rt.erl"].
+ RtMod1++["asn1rt_check.erl","asn1rt.erl"].
erl_compile(OutFile,Options) ->
diff --git a/lib/asn1/src/asn1ct_constructed_ber.erl b/lib/asn1/src/asn1ct_constructed_ber.erl
index 77b78dcac7..edeefe1f43 100644
--- a/lib/asn1/src/asn1ct_constructed_ber.erl
+++ b/lib/asn1/src/asn1ct_constructed_ber.erl
@@ -1542,7 +1542,7 @@ mkfunname(Erule,TopType,Cname,WhatKind,DecOrEnc,Arity) ->
F = lists:concat(["fun '",DecOrEnc,"_",EType,"'/",Arity]),
{F, "?MODULE", F};
#'Externaltypereference'{module=Mod,type=EType} ->
- {lists:concat(["{'",Mod,"','",DecOrEnc,"_",EType,"'}"]),Mod,
+ {lists:concat(["fun '",Mod,"':'",DecOrEnc,"_",EType,"'/",Arity]),Mod,
lists:concat(["'",DecOrEnc,"_",EType,"'"])};
{constructed,bif} ->
F =
diff --git a/lib/asn1/src/asn1ct_constructed_ber_bin_v2.erl b/lib/asn1/src/asn1ct_constructed_ber_bin_v2.erl
index e3be914af4..243ff234a7 100644
--- a/lib/asn1/src/asn1ct_constructed_ber_bin_v2.erl
+++ b/lib/asn1/src/asn1ct_constructed_ber_bin_v2.erl
@@ -877,13 +877,13 @@ gen_dec_choice(Erules,TopType, _ChTag, CompList, Ext) ->
emit([indent(9),"exit({error,{asn1,{invalid_choice_tag,",
{curr,else},"}}})",nl]);
_ ->
- emit([indent(9),"{asn1_ExtAlt, ?RT_BER:encode(",{curr,else},")}",nl])
+ emit([indent(9),"{asn1_ExtAlt, ?RT_BER:encode(",{curr,else},
+ asn1ct_gen:nif_parameter(),")}",nl])
end,
emit([indent(3),"end",nl]),
asn1ct_name:new(tag),
asn1ct_name:new(else).
-
gen_dec_choice_cases(_Erules,_TopType, []) ->
ok;
gen_dec_choice_cases(Erules,TopType, [H|T]) ->
@@ -1227,7 +1227,7 @@ gen_dec_call({typefield,_},_,_,_Cname,Type,BytesVar,Tag,_,_,false,_) ->
emit([nl,indent(6),"begin",nl]),
% emit([indent(9),{curr,opendec}," = ?RT_BER:decode_open_type(",
emit([indent(9),{curr,tmptlv}," = ?RT_BER:decode_open_type(",
- BytesVar,",",{asis,Tag},"),",nl]),
+ BytesVar,",",{asis,Tag},asn1ct_gen:nif_parameter(),"),",nl]),
% emit([indent(9),"{",{curr,tmptlv},",_} = ?RT_BER:decode(",
% {curr,opendec},"),",nl]),
@@ -1242,7 +1242,8 @@ gen_dec_call({typefield,_},_,_,_Cname,Type,BytesVar,Tag,_,_,false,_) ->
emit([indent(9),"end",nl,indent(6),"end",nl]),
[];
gen_dec_call({typefield,_},_,_,Cname,Type,BytesVar,Tag,_,_,_DecObjInf,OptOrMandComp) ->
- emit(["?RT_BER:decode_open_type(",BytesVar,",",{asis,Tag},")"]),
+ emit(["?RT_BER:decode_open_type(",BytesVar,",",{asis,Tag},
+ asn1ct_gen:nif_parameter(),")"]),
RefedFieldName =
% asn1ct_gen:get_constraint(Type#type.constraint,
% tableconstraint_info),
@@ -1250,7 +1251,8 @@ gen_dec_call({typefield,_},_,_,Cname,Type,BytesVar,Tag,_,_,_DecObjInf,OptOrMandC
[{Cname,RefedFieldName,asn1ct_gen:mk_var(asn1ct_name:curr(term)),
asn1ct_gen:mk_var(asn1ct_name:curr(tmpterm)),Tag,OptOrMandComp}];
gen_dec_call({objectfield,PrimFieldName,PFNList},_,_,Cname,_,BytesVar,Tag,_,_,_,OptOrMandComp) ->
- emit(["?RT_BER:decode_open_type(",BytesVar,",",{asis,Tag},")"]),
+ emit(["?RT_BER:decode_open_type(",BytesVar,",",{asis,Tag},
+ asn1ct_gen:nif_parameter(),")"]),
[{Cname,{PrimFieldName,PFNList},asn1ct_gen:mk_var(asn1ct_name:curr(term)),
asn1ct_gen:mk_var(asn1ct_name:curr(tmpterm)),Tag,OptOrMandComp}];
gen_dec_call(InnerType,Erules,TopType,Cname,Type,BytesVar,Tag,PrimOptOrMand,
diff --git a/lib/asn1/src/asn1ct_constructed_per.erl b/lib/asn1/src/asn1ct_constructed_per.erl
index c1b6aa5713..e07680f10b 100644
--- a/lib/asn1/src/asn1ct_constructed_per.erl
+++ b/lib/asn1/src/asn1ct_constructed_per.erl
@@ -73,16 +73,23 @@ gen_encode_constructed(Erule,Typename,D) when is_record(D,type) ->
_ ->
ok
end,
- case {Optionals = optionals(to_textual_order(CompList)),CompList} of
- {[],EmptyCL} when EmptyCL == {[],[],[]};EmptyCL == {[],[]};EmptyCL == [] ->
+ case {Optionals = optionals(to_textual_order(CompList)),CompList,
+ is_optimized(Erule)} of
+ {[],EmptyCL,_} when EmptyCL == {[],[],[]};EmptyCL == {[],[]};EmptyCL == [] ->
emit(["%%Variable setting just to eliminate ",
"compiler warning for unused vars!",nl,
"_Val = ",{curr,val},",",nl]);
- {[],_} ->
+ {[],_,_} ->
emit([{next,val}," = ?RT_PER:list_to_record("]),
emit(["'",asn1ct_gen:list2rname(Typename),"'"]),
emit([", ",{curr,val},"),",nl]);
- _ ->
+ {_,_,true} ->
+ gen_fixoptionals(Optionals),
+ FixOpts = param_map(fun(Var) ->
+ {var,Var}
+ end,asn1ct_name:all(fixopt)),
+ emit({"{",{next,val},",Opt} = {",{curr,val},",[",FixOpts,"]},",nl});
+ {_,_,false} ->
Fixoptcall = ",Opt} = ?RT_PER:fixoptionals(",
emit({"{",{next,val},Fixoptcall,
{asis,Optionals},",",length(Optionals),
@@ -439,9 +446,7 @@ gen_encode_sof(Erule,Typename,SeqOrSetOf,D) when is_record(D,type) ->
_->
""
end,
- emit({nl,indent(3),"?RT_PER:encode_length(",
- {asis,SizeConstraint},
- ",length(Val)),",nl}),
+ gen_encode_length(SizeConstraint, is_optimized(Erule)),
emit({indent(3),"'enc_",asn1ct_gen:list2name(Typename),
"_components'(Val",ObjFun,", [])"}),
emit({nl,"].",nl}),
@@ -453,6 +458,42 @@ gen_encode_sof(Erule,Typename,SeqOrSetOf,D) when is_record(D,type) ->
end,
gen_encode_sof_components(Erule,Typename,SeqOrSetOf,NewComponentType).
+
+%% Logic copied from asn1_per_bin_rt2ct:encode_constrained_number
+gen_encode_length({Lb,Ub},true) when Ub =< 65535, Lb >= 0 ->
+ Range = Ub - Lb + 1,
+ V2 = ["(length(Val) - ",Lb,")"],
+ Encode = if
+ Range == 1 ->
+ "[]";
+ Range == 2 ->
+ {"[",V2,"]"};
+ Range =< 4 ->
+ {"[10,2,",V2,"]"};
+ Range =< 8 ->
+ {"[10,3,",V2,"]"};
+ Range =< 16 ->
+ {"[10,4,",V2,"]"};
+ Range =< 32 ->
+ {"[10,5,",V2,"]"};
+ Range =< 64 ->
+ {"[10,6,",V2,"]"};
+ Range =< 128 ->
+ {"[10,7,",V2,"]"};
+ Range =< 255 ->
+ {"[10,8,",V2,"]"};
+ Range =< 256 ->
+ {"[20,1,",V2,"]"};
+ Range =< 65536 ->
+ {"[20,2,<<",V2,":16>>]"};
+ true ->
+ {"?RT_PER:encode_length(",{asis,{Lb,Ub}},",length(Val))"}
+ end,
+ emit({nl,Encode,",",nl});
+gen_encode_length(SizeConstraint,_) ->
+ emit({nl,indent(3),"?RT_PER:encode_length(",
+ {asis,SizeConstraint},",length(Val)),",nl}).
+
gen_decode_sof(Erules,Typename,SeqOrSetOf,D) when is_record(D,type) ->
asn1ct_name:start(),
{_SeqOrSetOf,ComponentType} = D#type.def,
@@ -469,7 +510,8 @@ gen_decode_sof(Erules,Typename,SeqOrSetOf,D) when is_record(D,type) ->
_ ->
""
end,
- emit({nl,"{Num,Bytes1} = ?RT_PER:decode_length(Bytes,",{asis,SizeConstraint},"),",nl}),
+ gen_decode_length(SizeConstraint,
+ is_optimized(Erules)),
emit({"'dec_",asn1ct_gen:list2name(Typename),
"_components'(Num, Bytes1, telltype",ObjFun,", []).",nl}),
NewComponentType =
@@ -480,6 +522,41 @@ gen_decode_sof(Erules,Typename,SeqOrSetOf,D) when is_record(D,type) ->
end,
gen_decode_sof_components(Erules,Typename,SeqOrSetOf,NewComponentType).
+%% Logic copied from asn1_per_bin_rt2ct:decode_constrained_number
+gen_decode_length({Lb,Ub},true) when Ub =< 65535, Lb >= 0 ->
+ Range = Ub - Lb + 1,
+ Call = if
+ Range == 1 ->
+ "{0,Bytes}";
+ Range == 2 ->
+ "?RT_PER:getbits(Bytes,1)";
+ Range =< 4 ->
+ "?RT_PER:getbits(Bytes,2)";
+ Range =< 8 ->
+ "?RT_PER:getbits(Bytes,3)";
+ Range =< 16 ->
+ "?RT_PER:getbits(Bytes,4)";
+ Range =< 32 ->
+ "?RT_PER:getbits(Bytes,5)";
+ Range =< 64 ->
+ "?RT_PER:getbits(Bytes,6)";
+ Range =< 128 ->
+ "?RT_PER:getbits(Bytes,7)";
+ Range =< 255 ->
+ "?RT_PER:getbits(Bytes,8)";
+ Range =< 256 ->
+ "?RT_PER:getoctets(Bytes,1)";
+ Range =< 65536 ->
+ "?RT_PER:getoctets(Bytes,2)";
+ true ->
+ ["exit({not_supported,{integer_range,",Range,"}}"]
+ end,
+ emit({nl,"{Val,Remain} = ",Call,",",nl}),
+ emit({nl,"{Num,Bytes1} = {Val+",Lb,",Remain},",nl});
+gen_decode_length(SizeConstraint,_) ->
+ emit({nl,"{Num,Bytes1} = ?RT_PER:decode_length(Bytes,",
+ {asis,SizeConstraint},"),",nl}).
+
gen_encode_sof_components(Erule,Typename,SeqOrSetOf,Cont) ->
{ObjFun,ObjFun_Var} =
case Cont#type.tablecinf of
@@ -636,6 +713,27 @@ gen_dec_extension_value(_) ->
emit({"{Ext,",{next,bytes},"} = ?RT_PER:getext(",{curr,bytes},")"}),
asn1ct_name:new(bytes).
+gen_fixoptionals([{Pos,Def}|R]) ->
+ asn1ct_name:new(fixopt),
+ emit({{curr,fixopt}," = case element(",{asis,Pos},",",{curr,val},") of",nl,
+ "asn1_DEFAULT -> 0;",nl,
+ {asis,Def}," -> 0;",nl,
+ "_ -> 1",nl,
+ "end,",nl}),
+ gen_fixoptionals(R);
+gen_fixoptionals([Pos|R]) ->
+ gen_fixoptionals([{Pos,asn1_NOVALUE}|R]);
+gen_fixoptionals([]) ->
+ ok.
+
+
+param_map(Fun, [H]) ->
+ [Fun(H)];
+param_map(Fun, [H|T]) ->
+ [Fun(H),","|param_map(Fun,T)].
+
+
+
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Produce a list with positions (in the Value record) where
%% there are optional components, start with 2 because first element
@@ -922,7 +1020,7 @@ gen_enc_line(Erule,TopType,Cname,Type,Element, _Pos,DynamicEnc,Ext) ->
end,
case Ext of
{ext,_Ep2,_} ->
- emit(["))"]);
+ emit("))");
_ -> true
end.
gen_dec_components_call(Erule,TopType,{Root1,ExtList,Root2},MaybeComma,DecInfObj,Ext,NumberOfOptionals) ->
diff --git a/lib/asn1/src/asn1ct_gen.erl b/lib/asn1/src/asn1ct_gen.erl
index e49829d82f..0f8833f716 100644
--- a/lib/asn1/src/asn1ct_gen.erl
+++ b/lib/asn1/src/asn1ct_gen.erl
@@ -47,6 +47,7 @@
un_hyphen_var/1]).
-export([gen_encode_constructed/4,
gen_decode_constructed/4]).
+-export([nif_parameter/0]).
%% pgen(Outfile, Erules, Module, TypeOrVal, Options)
%% Generate Erlang module (.erl) and (.hrl) file corresponding to an ASN.1 module
@@ -938,13 +939,13 @@ pgen_dispatcher(Erules,_Module,{Types,_Values,_,_,_Objects,_ObjectSets}) ->
NoFinalPadding = lists:member(no_final_padding,get(encoding_options)),
Call = case Erules of
per -> "?RT_PER:complete(encode_disp(Type,Data))";
- per_bin -> "?RT_PER:complete(encode_disp(Type,Data))";
+ per_bin -> ["?RT_PER:complete(encode_disp(Type,Data))"];
ber -> "encode_disp(Type,Data)";
ber_bin -> "encode_disp(Type,Data)";
ber_bin_v2 -> "encode_disp(Type,Data)";
uper_bin when NoFinalPadding == true ->
"?RT_PER:complete_NFP(encode_disp(Type,Data))";
- uper_bin -> "?RT_PER:complete(encode_disp(Type,Data))"
+ uper_bin -> ["?RT_PER:complete(encode_disp(Type,Data))"]
end,
EncWrap = case Erules of
ber -> "wrap_encode(Bytes)";
@@ -974,7 +975,7 @@ pgen_dispatcher(Erules,_Module,{Types,_Values,_,_,_Objects,_ObjectSets}) ->
% case Erules of
% ber_bin_v2 ->
% emit(["decode(Type,Data0) ->",nl]),
-% emit(["{Data,_RestBin} = ?RT_BER:decode(Data0",driver_parameter(),"),",nl]);
+% emit(["{Data,_RestBin} = ?RT_BER:decode(Data0",nif_parameter(),"),",nl]);
% _ ->
% emit(["decode(Type,Data) ->",nl])
% end,
@@ -991,10 +992,10 @@ pgen_dispatcher(Erules,_Module,{Types,_Values,_,_,_Objects,_ObjectSets}) ->
{ber_bin_v2,false} ->
io_lib:format("~s~s~s~n",
["element(1,?RT_BER:decode(Data",
- driver_parameter(),"))"]);
+ nif_parameter(),"))"]);
{ber_bin_v2,true} ->
emit(["{Data,Rest} = ?RT_BER:decode(Data0",
- driver_parameter(),"),",nl]),
+ nif_parameter(),"),",nl]),
"Data";
_ ->
"Data"
@@ -1130,13 +1131,8 @@ gen_decode_partial_incomplete(Erule) when Erule == ber;Erule==ber_bin;
"Data) of",nl]),
EmitCaseClauses(),
emit(["decode_part(Type,Data0) ->",nl]),
- Driver =
- case lists:member(driver,get(encoding_options)) of
- true ->
- ",driver";
- _ -> ""
- end,
- emit([" case catch decode_inc_disp(Type,element(1,?RT_BER:decode(Data0",Driver,"))) of",nl]),
+ emit([" case catch decode_inc_disp(Type,element(1,"
+ "?RT_BER:decode(Data0",nif_parameter(),"))) of",nl]),
% " {Data,_RestBin} = ?RT_BER:decode(Data0),",nl,
% " case catch decode_inc_disp(Type,Data) of",nl]),
EmitCaseClauses();
@@ -1179,12 +1175,12 @@ gen_partial_inc_dispatcher([],_) ->
emit(["decode_partial_inc_disp(Type,_Data) ->",nl,
" exit({error,{asn1,{undefined_type,Type}}}).",nl]).
-driver_parameter() ->
+nif_parameter() ->
Options = get(encoding_options),
- case lists:member(driver,Options) of
- true ->
- ",driver";
- _ -> ""
+ case {lists:member(driver,Options),lists:member(nif,Options)} of
+ {true,_} -> ",nif";
+ {_,true} -> ",nif";
+ _ -> ""
end.
gen_wrapper() ->
@@ -1525,8 +1521,9 @@ gen_head(Erules,Mod,Hrl) ->
emit({"-module('",Mod,"').",nl}),
put(currmod,Mod),
%emit({"-compile(export_all).",nl}),
- case Hrl of
- 0 -> true;
+ case {Hrl,lists:member(inline,get(encoding_options))} of
+ {0,_} -> true;
+ {_,true} -> true;
_ ->
emit({"-include(\"",Mod,".hrl\").",nl})
end,
diff --git a/lib/asn1/src/asn1ct_gen_ber_bin_v2.erl b/lib/asn1/src/asn1ct_gen_ber_bin_v2.erl
index 9ec458e351..781271bae7 100644
--- a/lib/asn1/src/asn1ct_gen_ber_bin_v2.erl
+++ b/lib/asn1/src/asn1ct_gen_ber_bin_v2.erl
@@ -416,7 +416,7 @@ gen_decode_selected(Erules,Type,FuncName) ->
end,
emit([" case ?RT_BER:decode_selective(",{asis,Pattern},",Bin) of",nl,
" {ok,Bin2} when is_binary(Bin2) ->",nl,
- " {Tlv,_} = ?RT_BER:decode(Bin2),",nl]),
+ " {Tlv,_} = ?RT_BER:decode(Bin2",asn1ct_gen:nif_parameter(),"),",nl]),
emit("{ok,"),
gen_decode_selected_type(Erules,Type),
emit(["};",nl," Err -> exit({error,{selctive_decode,Err}})",nl,
@@ -708,7 +708,7 @@ gen_dec_prim(Erules,Att,BytesVar,DoTag,TagIn,Form,OptOrMand) ->
'ASN1_OPEN_TYPE' ->
emit(["?RT_BER:decode_open_type_as_binary(",
BytesVar,","]),
- add_func({decode_open_type_as_binary,2});
+ add_func({decode_open_type_as_binary,3});
#'ObjectClassFieldType'{} ->
case asn1ct_gen:get_inner(Att#type.def) of
{fixedtypevaluefield,_,InnerType} ->
@@ -716,7 +716,7 @@ gen_dec_prim(Erules,Att,BytesVar,DoTag,TagIn,Form,OptOrMand) ->
'ASN1_OPEN_TYPE' ->
emit(["?RT_BER:decode_open_type_as_binary(",
BytesVar,","]),
- add_func({decode_open_type_as_binary,2});
+ add_func({decode_open_type_as_binary,3});
Other ->
exit({'can not decode' ,Other})
end;
@@ -728,13 +728,13 @@ gen_dec_prim(Erules,Att,BytesVar,DoTag,TagIn,Form,OptOrMand) ->
{_,#'ObjectClassFieldType'{}} ->
case asn1ct_gen:get_inner(Att#type.def) of
'ASN1_OPEN_TYPE' ->
- emit([{asis,DoTag},")"]);
+ emit([{asis,DoTag},asn1ct_gen:nif_parameter(),")"]);
_ -> ok
end;
{{string,TagStr},'ASN1_OPEN_TYPE'} ->
- emit([TagStr,")"]);
+ emit([TagStr,asn1ct_gen:nif_parameter(),")"]);
{_,'ASN1_OPEN_TYPE'} ->
- emit([{asis,DoTag},")"]);
+ emit([{asis,DoTag},asn1ct_gen:nif_parameter(),")"]);
{{string,TagStr},_} ->
emit([TagStr,")"]);
_ when is_list(DoTag) ->
@@ -1064,7 +1064,7 @@ emit_tlv_format_function() ->
end.
emit_tlv_format_function1() ->
emit(["tlv_format(Bytes) when is_binary(Bytes) ->",nl,
- " {Tlv,_}=?RT_BER:decode(Bytes),",nl,
+ " {Tlv,_}=?RT_BER:decode(Bytes",asn1ct_gen:nif_parameter(),"),",nl,
" Tlv;",nl,
"tlv_format(Bytes) ->",nl,
" Bytes.",nl]).
@@ -1502,13 +1502,14 @@ gen_objset_dec(Erules,ObjSetName,_UniqueName,['EXTENSIONMARK'],_ClName,
_ClFields,_NthObj) ->
emit(["'getdec_",ObjSetName,"'(_, _) ->",nl]),
emit([indent(2),"fun(_,Bytes, _RestPrimFieldName) ->",nl]),
+
case Erules of
ber_bin_v2 ->
emit([indent(4),"case Bytes of",nl,
indent(6),"Bin when is_binary(Bin) -> ",nl,
indent(8),"Bin;",nl,
indent(6),"_ ->",nl,
- indent(8),"?RT_BER:encode(Bytes)",nl,
+ indent(8),"?RT_BER:encode(Bytes",driver_parameter(),")",nl,
indent(4),"end",nl]);
_ ->
emit([indent(6),"Len = case Bytes of",nl,indent(9),
@@ -1521,6 +1522,14 @@ gen_objset_dec(Erules,ObjSetName,_UniqueName,['EXTENSIONMARK'],_ClName,
gen_objset_dec(_,_,_,[],_,_,_) ->
ok.
+driver_parameter() ->
+ Options = get(encoding_options),
+ case {lists:member(driver,Options),lists:member(nif,Options)} of
+ {true,_} -> ",nif";
+ {_,true} -> ",nif";
+ _ -> ",erlang"
+ end.
+
emit_default_getdec(ObjSetName,UniqueName) ->
emit(["'getdec_",ObjSetName,"'(",{asis,UniqueName},", ErrV) ->",nl]),
emit([indent(2), "fun(C,V,_) -> exit({{component,C},{value,V},{unique_name_and_value,",{asis,UniqueName},", ErrV}}) end"]).
diff --git a/lib/asn1/src/asn1ct_gen_per.erl b/lib/asn1/src/asn1ct_gen_per.erl
index 8313cf1b60..b90a0adf81 100644
--- a/lib/asn1/src/asn1ct_gen_per.erl
+++ b/lib/asn1/src/asn1ct_gen_per.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2010. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2011. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -238,7 +238,8 @@ gen_encode_prim(Erules,D,DoTag,Value) when is_record(D,type) ->
"?RT_PER:complete(enc_~s(~s))",[Tname,Value]);
[#type{def=#'Externaltypereference'{type=Tname}}] ->
io_lib:format(
- "?RT_PER:complete(enc_~s(~s))",[Tname,Value]);
+ "?RT_PER:complete(enc_~s(~s))",
+ [Tname,Value]);
_ -> Value
end,
emit(["?RT_PER:encode_open_type(", {asis,Constraint}, ",",
diff --git a/lib/asn1/src/asn1ct_gen_per_rt2ct.erl b/lib/asn1/src/asn1ct_gen_per_rt2ct.erl
index 4f4fcfafc3..1a0a0e211d 100644
--- a/lib/asn1/src/asn1ct_gen_per_rt2ct.erl
+++ b/lib/asn1/src/asn1ct_gen_per_rt2ct.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2002-2010. All Rights Reserved.
+%% Copyright Ericsson AB 2002-2011. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -230,7 +230,8 @@ gen_encode_prim(Erules,D,DoTag,Value) when is_record(D,type) ->
"?RT_PER:complete(enc_~s(~s))",[Tname,Value]);
[#type{def=#'Externaltypereference'{type=Tname}}] ->
io_lib:format(
- "?RT_PER:complete(enc_~s(~s))",[Tname,Value]);
+ "?RT_PER:complete(enc_~s(~s))",
+ [Tname,Value]);
_ -> Value
end,
emit(["?RT_PER:encode_open_type(", {asis,Constraint}, ",",
diff --git a/lib/asn1/src/asn1rt.erl b/lib/asn1/src/asn1rt.erl
index 9ef68efab5..d18f81346a 100644
--- a/lib/asn1/src/asn1rt.erl
+++ b/lib/asn1/src/asn1rt.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2009. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2011. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -21,12 +21,12 @@
%% Runtime functions for ASN.1 (i.e encode, decode)
--include("asn1_records.hrl").
-
-export([encode/2,encode/3,decode/3,load_driver/0,unload_driver/0,info/1]).
-export([utf8_binary_to_list/1,utf8_list_to_binary/1]).
+-deprecated([load_driver/0,unload_driver/0]).
+
encode(Module,{Type,Term}) ->
encode(Module,Type,Term).
@@ -46,38 +46,12 @@ decode(Module,Type,Bytes) ->
Result
end.
-%% asn1-1.6.8.1
-%% load_driver() ->
-%% asn1rt_driver_handler:load_driver(),
-%% receive
-%% driver_ready ->
-%% ok;
-%% Err={error,_Reason} ->
-%% Err;
-%% Error ->
-%% {error,Error}
-%% end.
-
-%% asn1-1.6.9
- load_driver() ->
- case catch asn1rt_driver_handler:load_driver() of
- ok ->
- ok;
- {error,{already_started,asn1}} ->
- ok;
- Err ->
- {error,Err}
- end.
-
+%% Remove in R16A
+load_driver() ->
+ ok.
unload_driver() ->
- case catch asn1rt_driver_handler:unload_driver() of
- ok ->
- ok;
- Error ->
- {error,Error}
- end.
-
+ ok.
info(Module) ->
case catch apply(Module,info,[]) of
diff --git a/lib/asn1/src/asn1rt_ber_bin_v2.erl b/lib/asn1/src/asn1rt_ber_bin_v2.erl
index a3bb570282..17e66f77c9 100644
--- a/lib/asn1/src/asn1rt_ber_bin_v2.erl
+++ b/lib/asn1/src/asn1rt_ber_bin_v2.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2002-2009. All Rights Reserved.
+%% Copyright Ericsson AB 2002-2011. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -21,7 +21,7 @@
%% encoding / decoding of BER
--export([decode/1, decode/2, match_tags/2, encode/1]).
+-export([decode/1, decode/2, match_tags/2, encode/1, encode/2]).
-export([fixoptionals/2, cindex/3,
list_to_record/2,
encode_tag_val/1,
@@ -49,11 +49,13 @@
decode_tag_and_length/1]).
-export([encode_open_type/1,encode_open_type/2,
- decode_open_type/2,decode_open_type_as_binary/2]).
+ decode_open_type/2,decode_open_type/3,
+ decode_open_type_as_binary/2,
+ decode_open_type_as_binary/3]).
-export([decode_primitive_incomplete/2,decode_selective/2]).
-
--include("asn1_records.hrl").
+
+-export([is_nif_loadable/0]).
% the encoding of class of tag bits 8 and 7
-define(UNIVERSAL, 0).
@@ -125,15 +127,28 @@
% encode(Tlv) ->
% encode_constructed(Tlv).
-encode([Tlv]) ->
- encode(Tlv);
-encode({TlvTag,TlvVal}) when is_list(TlvVal) ->
+encode(Tlv) ->
+ encode(Tlv,erlang).
+
+encode(Tlv,_) when is_binary(Tlv) ->
+ Tlv;
+encode([Tlv],Method) ->
+ encode(Tlv,Method);
+encode(Tlv, nif) ->
+ case is_nif_loadable() of
+ true ->
+ asn1rt_nif:encode_ber_tlv(Tlv);
+ false ->
+ encode_erl(Tlv)
+ end;
+encode(Tlv, _) ->
+ encode_erl(Tlv).
+
+encode_erl({TlvTag,TlvVal}) when is_list(TlvVal) ->
%% constructed form of value
encode_tlv(TlvTag,TlvVal,?CONSTRUCTED);
-encode({TlvTag,TlvVal}) ->
- encode_tlv(TlvTag,TlvVal,?PRIMITIVE);
-encode(Bin) when is_binary(Bin) ->
- Bin.
+encode_erl({TlvTag,TlvVal}) ->
+ encode_tlv(TlvTag,TlvVal,?PRIMITIVE).
encode_tlv(TlvTag,TlvVal,Form) ->
Tag = encode_tlv_tag(TlvTag,Form),
@@ -152,70 +167,61 @@ encode_tlv_val(Bin) ->
{Bin,size(Bin)}.
encode_tlv_list([Tlv|Tlvs],Acc) ->
- EncTlv = encode(Tlv),
+ EncTlv = encode_erl(Tlv),
encode_tlv_list(Tlvs,[EncTlv|Acc]);
encode_tlv_list([],Acc) ->
Bin=list_to_binary(lists:reverse(Acc)),
{Bin,size(Bin)}.
-%% asn1-1.6.8.1
-%% decode(B,driver) ->
-%% case catch port_control(asn1_driver_port,2,B) of
-%% Bin when is_binary(Bin) ->
-%% binary_to_term(Bin);
-%% List when is_list(List) -> handle_error(List,B);
-%% {'EXIT',{badarg,Reason}} ->
-%% asn1rt_driver_handler:load_driver(),
-%% receive
-%% driver_ready ->
-%% case catch port_control(asn1_driver_port,2,B) of
-%% Bin2 when is_binary(Bin2) -> binary_to_term(Bin2);
-%% List when is_list(List) -> handle_error(List,B);
-%% Error -> exit(Error)
-%% end;
-%% {error,Error} -> % error when loading driver
-%% %% the driver could not be loaded
-%% exit(Error);
-%% Error={port_error,Reason} ->
-%% exit(Error)
-%% end;
-%% {'EXIT',Reason} ->
-%% exit(Reason)
-%% end.
-
-%% asn1-1.6.9
-decode(B,driver) ->
- case catch control(?TLV_DECODE,B) of
- Bin when is_binary(Bin) ->
- binary_to_term(Bin);
- List when is_list(List) -> handle_error(List,B);
- {'EXIT',{badarg,_Reason}} ->
- case asn1rt:load_driver() of
- ok ->
- case control(?TLV_DECODE,B) of
- Bin when is_binary(Bin) -> binary_to_term(Bin);
- List when is_list(List) -> handle_error(List,B)
- end;
- Err ->
- Err
- end
- end.
+decode(B) ->
+ decode(B, erlang).
+%% asn1-1.7
+decode(B, nif) ->
+ case is_nif_loadable() of
+ true ->
+ case asn1rt_nif:decode_ber_tlv(B) of
+ {error, Reason} -> handle_error(Reason, B);
+ Else -> Else
+ end;
+ false ->
+ decode(B)
+ end;
+decode(B,erlang) when is_binary(B) ->
+ decode_primitive(B);
+decode(Tlv,erlang) ->
+ {Tlv,<<>>}.
+
+%% Have to check this since asn1 is not guaranteed to be available
+is_nif_loadable() ->
+ case application:get_env(asn1, nif_loadable) of
+ {ok,R} ->
+ R;
+ undefined ->
+ case catch code:load_file(asn1rt_nif) of
+ {module, asn1rt_nif} ->
+ application:set_env(asn1, nif_loadable, true),
+ true;
+ _Else ->
+ application:set_env(asn1, nif_loadable, false),
+ false
+ end
+ end.
handle_error([],_)->
exit({error,{asn1,{"memory allocation problem"}}});
-handle_error([$1|_],L) -> % error in driver
+handle_error({$1,_},L) -> % error in nif
exit({error,{asn1,L}});
-handle_error([$2|T],L) -> % error in driver due to wrong tag
+handle_error({$2,T},L) -> % error in nif due to wrong tag
exit({error,{asn1,{"bad tag after byte:",error_pos(T),L}}});
-handle_error([$3|T],L) -> % error in driver due to length error
+handle_error({$3,T},L) -> % error in driver due to length error
exit({error,{asn1,{"bad length field after byte:",
error_pos(T),L}}});
-handle_error([$4|T],L) -> % error in driver due to indefinite length error
+handle_error({$4,T},L) -> % error in driver due to indefinite length error
exit({error,{asn1,
{"indefinite length without end bytes after byte:",
error_pos(T),L}}});
-handle_error([$5|T],L) -> % error in driver due to indefinite length error
+handle_error({$5,T},L) -> % error in driver due to indefinite length error
exit({error,{asn1,{"bad encoded value after byte:",
error_pos(T),L}}});
handle_error(ErrL,L) ->
@@ -228,16 +234,6 @@ error_pos([B])->
error_pos([B|Bs]) ->
BS = 8 * length(Bs),
B bsl BS + error_pos(Bs).
-%% asn1-1.6.9
-control(Cmd, Data) ->
- Port = asn1rt_driver_handler:client_port(),
- erlang:port_control(Port, Cmd, Data).
-
-decode(Bin) when is_binary(Bin) ->
- decode_primitive(Bin);
-decode(Tlv) -> % assume it is a tlv
- {Tlv,<<>>}.
-
decode_primitive(Bin) ->
{Form,TagNo,V,Rest} = decode_tag_and_length(Bin),
@@ -796,20 +792,24 @@ encode_open_type(Val,Tag) ->
%% Value = binary with decoded data (which must be decoded again as some type)
%%
decode_open_type(Tlv, TagIn) ->
+ decode_open_type(Tlv, TagIn, erlang).
+decode_open_type(Tlv, TagIn, Method) ->
case match_tags(Tlv,TagIn) of
Bin when is_binary(Bin) ->
- {InnerTlv,_} = decode(Bin),
+ {InnerTlv,_} = decode(Bin,Method),
InnerTlv;
TlvBytes -> TlvBytes
end.
-decode_open_type_as_binary(Tlv,TagIn)->
+decode_open_type_as_binary(Tlv, TagIn) ->
+ decode_open_type_as_binary(Tlv, TagIn, erlang).
+decode_open_type_as_binary(Tlv,TagIn, Method)->
case match_tags(Tlv,TagIn) of
V when is_binary(V) ->
V;
- [Tlv2] -> encode(Tlv2);
- Tlv2 -> encode(Tlv2)
+ [Tlv2] -> encode(Tlv2, Method);
+ Tlv2 -> encode(Tlv2, Method)
end.
%%===============================================================================
@@ -1056,7 +1056,7 @@ encode_real(C,Val, TagIn) when is_tuple(Val); is_list(Val) ->
encode_real(C,Val) ->
- ?RT_COMMON:encode_real(C,Val).
+ asn1rt_ber_bin:encode_real(C,Val).
%%============================================================================
@@ -1081,7 +1081,7 @@ decode_real_notag(Buffer) ->
{_T,_V} ->
exit({error,{asn1,{real_not_in_primitive_form,Buffer}}})
end,
- {Val,_Rest,Len} = ?RT_COMMON:decode_real(Buffer,Len),
+ {Val,_Rest,Len} = asn1rt_ber_bin:decode_real(Buffer,Len),
Val.
%% exit({error,{asn1, {unimplemented,real}}}).
%% decode_real2(Buffer, Form, size(Buffer)).
@@ -1577,14 +1577,12 @@ e_object_identifier(V) when is_tuple(V) ->
e_object_identifier([E1, E2 | Tail]) ->
Head = 40*E1 + E2, % wow!
{H,Lh} = mk_object_val(Head),
- {R,Lr} = enc_obj_id_tail(Tail, [], 0),
+ {R,Lr} = lists:mapfoldl(fun enc_obj_id_tail/2,0,Tail),
{[H|R], Lh+Lr}.
-enc_obj_id_tail([], Ack, Len) ->
- {lists:reverse(Ack), Len};
-enc_obj_id_tail([H|T], Ack, Len) ->
+enc_obj_id_tail(H, Len) ->
{B, L} = mk_object_val(H),
- enc_obj_id_tail(T, [B|Ack], Len+L).
+ {B,Len+L}.
%%%%%%%%%%%
diff --git a/lib/asn1/src/asn1rt_check.erl b/lib/asn1/src/asn1rt_check.erl
index 24a2a3802d..d9856901b8 100644
--- a/lib/asn1/src/asn1rt_check.erl
+++ b/lib/asn1/src/asn1rt_check.erl
@@ -19,8 +19,6 @@
%%
-module(asn1rt_check).
--include("asn1_records.hrl").
-
-export([check_bool/2,
check_int/3,
check_bitstring/3,
diff --git a/lib/asn1/src/asn1rt_driver_handler.erl b/lib/asn1/src/asn1rt_driver_handler.erl
deleted file mode 100644
index 146d0043f9..0000000000
--- a/lib/asn1/src/asn1rt_driver_handler.erl
+++ /dev/null
@@ -1,144 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2002-2011. All Rights Reserved.
-%%
-%% The contents of this file are subject to the Erlang Public License,
-%% Version 1.1, (the "License"); you may not use this file except in
-%% compliance with the License. You should have received a copy of the
-%% Erlang Public License along with this software. If not, it can be
-%% retrieved online at http://www.erlang.org/.
-%%
-%% Software distributed under the License is distributed on an "AS IS"
-%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
-%% the License for the specific language governing rights and limitations
-%% under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-
--module(asn1rt_driver_handler).
-
--include("asn1_records.hrl").
-
--export([load_driver/0,unload_driver/0,client_port/0]).
-
-%% Internal exports
--export([init/2]).
-
-%% Macros
--define(port_names,
- { asn1_drv01, asn1_drv02, asn1_drv03, asn1_drv04,
- asn1_drv05, asn1_drv06, asn1_drv07, asn1_drv08,
- asn1_drv09, asn1_drv10, asn1_drv11, asn1_drv12,
- asn1_drv13, asn1_drv14, asn1_drv15, asn1_drv16 }).
-
-%%% --------------------------------------------------------
-%%% Interface Functions.
-%%% --------------------------------------------------------
-load_driver() ->
- load_driver(noreason).
-
-load_driver(Reason) ->
- Ref = make_ref(),
- case whereis(asn1_driver_owner) of % to prevent unnecessary spawn
- Pid when is_pid(Pid) ->
- asn1_driver_owner ! {self(),Ref,are_you_ready},
- receive
- {Ref,driver_ready} ->
- ok
- after 10000 ->
- {error,{timeout,waiting_for_drivers}}
- end;
- _ ->
- {_,Mref} = spawn_monitor(asn1rt_driver_handler, init, [self(),Ref]),
- receive
- {'DOWN', Mref, _, _, NewReason} ->
- case NewReason of
- Reason -> {error,Reason};
- _ -> load_driver(NewReason)
- end;
- {Ref,driver_ready} ->
- erlang:demonitor(Mref),
- ok;
- {Ref,Error = {error,_Reason}} ->
- erlang:demonitor(Mref),
- Error
- after 10000 -> %% 10 seconds
- {error,{timeout,waiting_for_drivers}}
- end
- end.
-
-init(FromPid,FromRef) ->
- case catch register(asn1_driver_owner,self()) of
- true -> true;
- _Other -> exit(normal)
- end,
- Dir = filename:join([code:priv_dir(asn1),"lib"]),
- case catch erl_ddll:load_driver(Dir,asn1_erl_drv) of
- ok ->
- Result = open_named_ports(),
- catch (FromPid ! {FromRef,Result}),
- loop(Result);
- {error,Err} -> % if erl_ddll:load_driver fails
- ForErr = erl_ddll:format_error(Err),
- OSDir = filename:join(Dir,erlang:system_info(system_architecture)),
- case catch erl_ddll:load_driver(OSDir,asn1_erl_drv) of
- ok ->
- Result = open_named_ports(),
- catch (FromPid ! {FromRef,Result}),
- loop(Result);
- {error,Err2} ->
-% catch (FromPid ! {FromRef,Error})
- ForErr2 = erl_ddll:format_error(Err2),
- catch (FromPid ! {FromRef,{error,{{Dir,ForErr},{OSDir,ForErr2}}}})
- end
- end.
-
-
-open_named_ports() ->
- open_named_ports(size(?port_names)).
-
-open_named_ports(0) ->
- driver_ready;
-open_named_ports(N) ->
- case catch open_port({spawn,"asn1_erl_drv"},[]) of
- {'EXIT',Reason} ->
- {error,{port_error,Reason}};
- Port ->
- register(element(N,?port_names),Port),
- open_named_ports(N-1)
- end.
-
-loop(Result) ->
- receive
- {_FromPid,_FromRef,unload} ->
- close_ports(size(?port_names)),
- erl_ddll:unload_driver(asn1_erl_drv),
- ok;
- {FromPid,FromRef,are_you_ready} ->
- catch (FromPid ! {FromRef,driver_ready}),
- loop(Result);
- _ ->
- loop(Result)
- end.
-
-unload_driver() ->
- case whereis(asn1_driver_owner) of
- Pid when is_pid(Pid) ->
- Pid ! {self(),make_ref(),unload},
- ok;
- _ ->
- ok
- end.
-
-close_ports(0) ->
- ok;
-close_ports(N) ->
- element(N,?port_names) ! {self(), close}, %% almost same as port_close(Name)
- close_ports(N-1).
-
-client_port() ->
- element(erlang:system_info(scheduler_id) rem size(?port_names) + 1,
- ?port_names).
diff --git a/lib/asn1/src/asn1rt_nif.erl b/lib/asn1/src/asn1rt_nif.erl
new file mode 100644
index 0000000000..de1fb94816
--- /dev/null
+++ b/lib/asn1/src/asn1rt_nif.erl
@@ -0,0 +1,87 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2002-2011. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+%%
+-module(asn1rt_nif).
+
+%% Nif interface for asn1
+
+-export([encode_per_complete/1,
+ decode_ber_tlv/1,
+ encode_ber_tlv/1]).
+
+-on_load(load_nif/0).
+
+-define(ASN1_NIF_VSN,1).
+
+load_nif() ->
+ LibBaseName = "asn1_erl_nif",
+ PrivDir = code:priv_dir(asn1),
+ LibName = case erlang:system_info(build_type) of
+ opt ->
+ LibBaseName;
+ Type ->
+ LibTypeName = LibBaseName ++ "." ++ atom_to_list(Type),
+ case (filelib:wildcard(
+ filename:join(
+ [PrivDir,
+ "lib",
+ LibTypeName ++ "*"])) /= []) orelse
+ (filelib:wildcard(
+ filename:join(
+ [PrivDir,
+ "lib",
+ erlang:system_info(system_architecture),
+ LibTypeName ++ "*"])) /= []) of
+ true -> LibTypeName;
+ false -> LibBaseName
+ end
+ end,
+ Lib = filename:join([PrivDir, "lib", LibName]),
+ Status = case erlang:load_nif(Lib, ?ASN1_NIF_VSN) of
+ ok -> ok;
+ {error, {load_failed, _}}=Error1 ->
+ ArchLibDir =
+ filename:join([PrivDir, "lib",
+ erlang:system_info(system_architecture)]),
+ Candidate =
+ filelib:wildcard(filename:join([ArchLibDir,LibName ++ "*" ])),
+ case Candidate of
+ [] -> Error1;
+ _ ->
+ ArchLib = filename:join([ArchLibDir, LibName]),
+ erlang:load_nif(ArchLib, ?ASN1_NIF_VSN)
+ end;
+ Error1 -> Error1
+ end,
+ case Status of
+ ok -> ok;
+ {error, {E, Str}} ->
+ error_logger:error_msg("Unable to load asn1 nif library. "
+ "Failed with error:~n\"~p, ~s\"~n",[E,Str]),
+ Status
+ end.
+
+encode_per_complete(_TagValueList) ->
+ erlang:nif_error({nif_not_loaded,module,?MODULE,line,?LINE}).
+
+decode_ber_tlv(_Binary) ->
+ erlang:nif_error({nif_not_loaded,module,?MODULE,line,?LINE}).
+
+encode_ber_tlv(_TagValueList) ->
+ erlang:nif_error({nif_not_loaded,module,?MODULE,line,?LINE}).
diff --git a/lib/asn1/src/asn1rt_per_bin.erl b/lib/asn1/src/asn1rt_per_bin.erl
index 6bbca26209..a124c7553d 100644
--- a/lib/asn1/src/asn1rt_per_bin.erl
+++ b/lib/asn1/src/asn1rt_per_bin.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2001-2009. All Rights Reserved.
+%% Copyright Ericsson AB 2001-2011. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -57,7 +57,7 @@
encode_NumericString/2, decode_NumericString/2,
encode_ObjectDescriptor/2, decode_ObjectDescriptor/1
]).
--export([complete_bytes/1]).
+-export([complete_bytes/1, getbits/2, getoctets/2]).
-define('16K',16384).
-define('32K',32768).
diff --git a/lib/asn1/src/asn1rt_per_bin_rt2ct.erl b/lib/asn1/src/asn1rt_per_bin_rt2ct.erl
index f4aecf9322..c7ead680ce 100644
--- a/lib/asn1/src/asn1rt_per_bin_rt2ct.erl
+++ b/lib/asn1/src/asn1rt_per_bin_rt2ct.erl
@@ -1734,143 +1734,24 @@ get_constraint(C,Key) ->
-ifdef(nodriver).
complete(L) ->
- case complete1(L) of
- {[],[]} ->
- <<0>>;
- {Acc,[]} ->
- Acc;
- {Acc,Bacc} ->
- [Acc|complete_bytes(Bacc)]
- end.
-
-
-% this function builds the ugly form of lists [E1|E2] to avoid having to reverse it at the end.
-% this is done because it is efficient and that the result always will be sent on a port or
-% converted by means of list_to_binary/1
- complete1(InList) when is_list(InList) ->
- complete1(InList,[],[]);
- complete1(InList) ->
- complete1([InList],[],[]).
-
- complete1([],Acc,Bacc) ->
- {Acc,Bacc};
- complete1([H|T],Acc,Bacc) when is_list(H) ->
- {NewH,NewBacc} = complete1(H,Acc,Bacc),
- complete1(T,NewH,NewBacc);
-
- complete1([{octets,Bin}|T],Acc,[]) ->
- complete1(T,[Acc|Bin],[]);
-
- complete1([{octets,Bin}|T],Acc,Bacc) ->
- complete1(T,[Acc|[complete_bytes(Bacc),Bin]],[]);
-
- complete1([{debug,_}|T], Acc,Bacc) ->
- complete1(T,Acc,Bacc);
-
- complete1([{bits,N,Val}|T],Acc,Bacc) ->
- complete1(T,Acc,complete_update_byte(Bacc,Val,N));
-
- complete1([{bit,Val}|T],Acc,Bacc) ->
- complete1(T,Acc,complete_update_byte(Bacc,Val,1));
-
- complete1([align|T],Acc,[]) ->
- complete1(T,Acc,[]);
- complete1([align|T],Acc,Bacc) ->
- complete1(T,[Acc|complete_bytes(Bacc)],[]);
- complete1([{0,Bin}|T],Acc,[]) when is_binary(Bin) ->
- complete1(T,[Acc|Bin],[]);
- complete1([{Unused,Bin}|T],Acc,[]) when is_integer(Unused),is_binary(Bin) ->
- Size = size(Bin)-1,
- <<Bs:Size/binary,B>> = Bin,
- NumBits = 8-Unused,
- complete1(T,[Acc|Bs],[[B bsr Unused]|NumBits]);
- complete1([{Unused,Bin}|T],Acc,Bacc) when is_integer(Unused),is_binary(Bin) ->
- Size = size(Bin)-1,
- <<Bs:Size/binary,B>> = Bin,
- NumBits = 8 - Unused,
- Bf = complete_bytes(Bacc),
- complete1(T,[Acc|[Bf,Bs]],[[B bsr Unused]|NumBits]).
-
-
- complete_update_byte([],Val,Len) ->
- complete_update_byte([[0]|0],Val,Len);
- complete_update_byte([[Byte|Bacc]|NumBits],Val,Len) when NumBits + Len == 8 ->
- [[0,((Byte bsl Len) + Val) band 255|Bacc]|0];
- complete_update_byte([[Byte|Bacc]|NumBits],Val,Len) when NumBits + Len > 8 ->
- Rem = 8 - NumBits,
- Rest = Len - Rem,
- complete_update_byte([[0,((Byte bsl Rem) + (Val bsr Rest)) band 255 |Bacc]|0],Val,Rest);
- complete_update_byte([[Byte|Bacc]|NumBits],Val,Len) ->
- [[((Byte bsl Len) + Val) band 255|Bacc]|NumBits+Len].
-
-
- complete_bytes([[Byte|Bacc]|0]) ->
- lists:reverse(Bacc);
- complete_bytes([[Byte|Bacc]|NumBytes]) ->
- lists:reverse([(Byte bsl (8-NumBytes)) band 255|Bacc]);
- complete_bytes([]) ->
- [].
+ erlang_complete(L).
-else.
-%% asn1-1.6.8.1_dev
-%% complete(L) ->
-%% case catch port_control(asn1_driver_port,1,L) of
-%% Bin when is_binary(Bin) ->
-%% Bin;
-%% List when is_list(List) -> handle_error(List,L);
-%% {'EXIT',{badarg,Reason}} ->
-%% asn1rt_driver_handler:load_driver(),
-%% receive
-%% driver_ready ->
-%% case catch port_control(asn1_driver_port,1,L) of
-%% Bin2 when is_binary(Bin2) -> Bin2;
-%% List when is_list(List) -> handle_error(List,L);
-%% {'EXIT',Reason2={badarg,_R}} ->
-%% exit({"failed to call driver probably due to bad asn1 value",Reason2});
-%% Reason2 -> exit(Reason2)
-%% end;
-%% {error,Error} -> % error when loading driver
-%% %% the driver could not be loaded
-%% exit(Error);
-%% Error={port_error,Reason} ->
-%% exit(Error)
-%% end;
-%% {'EXIT',Reason} ->
-%% exit(Reason)
-%% end.
-
-%% asn1-1.6.9
+%% asn1-1.7
complete(L) ->
- case catch control(?COMPLETE_ENCODE,L) of
- Bin when is_binary(Bin) ->
- Bin;
- List when is_list(List) -> handle_error(List,L);
- {'EXIT',{badarg,_Reason}} ->
- case asn1rt:load_driver() of
- ok ->
- case control(?COMPLETE_ENCODE,L) of
- Bin when is_binary(Bin) ->Bin;
- List when is_list(List) -> handle_error(List,L)
- end;
- Err ->
- Err
- end
+ case asn1rt_nif:encode_per_complete(L) of
+ {error, Reason} -> handle_error(Reason, L);
+ Else when is_binary(Else) -> Else
end.
-
handle_error([],_)->
exit({error,{asn1,{"memory allocation problem in driver"}}});
-handle_error("1",L) -> % error in complete in driver
+handle_error($1,L) -> % error in complete in driver
exit({error,{asn1,L}});
handle_error(ErrL,L) ->
exit({error,{asn1,ErrL,L}}).
-%% asn1-1.6.9
-control(Cmd, Data) ->
- Port = asn1rt_driver_handler:client_port(),
- erlang:port_control(Port, Cmd, Data).
-
-endif.
diff --git a/lib/asn1/test/asn1.cover b/lib/asn1/test/asn1.cover
index 589a8b7e3d..ad3a0f3db9 100644
--- a/lib/asn1/test/asn1.cover
+++ b/lib/asn1/test/asn1.cover
@@ -1,2 +1,3 @@
{incl_app,asn1,details}.
+{excl_mods, asn1, [asn1rt_nif]}. \ No newline at end of file
diff --git a/lib/asn1/test/asn1_SUITE.erl.src b/lib/asn1/test/asn1_SUITE.erl.src
index e7f93a4053..124ee2d2bb 100644
--- a/lib/asn1/test/asn1_SUITE.erl.src
+++ b/lib/asn1/test/asn1_SUITE.erl.src
@@ -2036,11 +2036,7 @@ rtUI(Config) ->
?line {ok,_} = asn1rt:info('Prim'),
?line ok = asn1ct:compile(filename:join(DataDir,"Prim"),[?PER]),
- ?line {ok,_} = asn1rt:info('Prim'),
-
- ?line ok = asn1rt:load_driver(),
- ?line ok = asn1rt:load_driver(),
- ?line ok = asn1rt:unload_driver().
+ ?line {ok,_} = asn1rt:info('Prim').
testROSE(suite) -> [];
testROSE(Config) ->
diff --git a/lib/asn1/test/asn1_SUITE_data/DirectoryAbstractService.asn b/lib/asn1/test/asn1_SUITE_data/DirectoryAbstractService.asn
index 5a5d310729..5a5d310729 100755..100644
--- a/lib/asn1/test/asn1_SUITE_data/DirectoryAbstractService.asn
+++ b/lib/asn1/test/asn1_SUITE_data/DirectoryAbstractService.asn
diff --git a/lib/asn1/test/asn1_SUITE_data/InformationFramework.asn b/lib/asn1/test/asn1_SUITE_data/InformationFramework.asn
index ef236e98a9..ef236e98a9 100755..100644
--- a/lib/asn1/test/asn1_SUITE_data/InformationFramework.asn
+++ b/lib/asn1/test/asn1_SUITE_data/InformationFramework.asn
diff --git a/lib/asn1/test/asn1_SUITE_data/LDAP.asn1 b/lib/asn1/test/asn1_SUITE_data/LDAP.asn1
index 4d845942e1..4d845942e1 100755..100644
--- a/lib/asn1/test/asn1_SUITE_data/LDAP.asn1
+++ b/lib/asn1/test/asn1_SUITE_data/LDAP.asn1
diff --git a/lib/asn1/test/asn1_SUITE_data/Nortel.asn b/lib/asn1/test/asn1_SUITE_data/Nortel.asn
index a27c78a0b5..a27c78a0b5 100755..100644
--- a/lib/asn1/test/asn1_SUITE_data/Nortel.asn
+++ b/lib/asn1/test/asn1_SUITE_data/Nortel.asn
diff --git a/lib/asn1/test/asn1_SUITE_data/UpperBounds.asn b/lib/asn1/test/asn1_SUITE_data/UpperBounds.asn
index 247260495b..247260495b 100755..100644
--- a/lib/asn1/test/asn1_SUITE_data/UpperBounds.asn
+++ b/lib/asn1/test/asn1_SUITE_data/UpperBounds.asn
diff --git a/lib/asn1/test/asn1_SUITE_data/UsefulDefinitions.asn b/lib/asn1/test/asn1_SUITE_data/UsefulDefinitions.asn
index d9601bb7d0..d9601bb7d0 100755..100644
--- a/lib/asn1/test/asn1_SUITE_data/UsefulDefinitions.asn
+++ b/lib/asn1/test/asn1_SUITE_data/UsefulDefinitions.asn
diff --git a/lib/asn1/test/asn1_SUITE_data/nbapsystem/NBAP-CommonDataTypes.asn b/lib/asn1/test/asn1_SUITE_data/nbapsystem/NBAP-CommonDataTypes.asn
index e3f6e83d6b..e3f6e83d6b 100755..100644
--- a/lib/asn1/test/asn1_SUITE_data/nbapsystem/NBAP-CommonDataTypes.asn
+++ b/lib/asn1/test/asn1_SUITE_data/nbapsystem/NBAP-CommonDataTypes.asn
diff --git a/lib/asn1/test/asn1_SUITE_data/nbapsystem/NBAP-Constants.asn b/lib/asn1/test/asn1_SUITE_data/nbapsystem/NBAP-Constants.asn
index 1411d455b7..1411d455b7 100755..100644
--- a/lib/asn1/test/asn1_SUITE_data/nbapsystem/NBAP-Constants.asn
+++ b/lib/asn1/test/asn1_SUITE_data/nbapsystem/NBAP-Constants.asn
diff --git a/lib/asn1/test/asn1_SUITE_data/nbapsystem/NBAP-Containers.asn b/lib/asn1/test/asn1_SUITE_data/nbapsystem/NBAP-Containers.asn
index fb08451103..fb08451103 100755..100644
--- a/lib/asn1/test/asn1_SUITE_data/nbapsystem/NBAP-Containers.asn
+++ b/lib/asn1/test/asn1_SUITE_data/nbapsystem/NBAP-Containers.asn
diff --git a/lib/asn1/test/asn1_SUITE_data/nbapsystem/NBAP-IEs.asn b/lib/asn1/test/asn1_SUITE_data/nbapsystem/NBAP-IEs.asn
index 848d8f6099..848d8f6099 100755..100644
--- a/lib/asn1/test/asn1_SUITE_data/nbapsystem/NBAP-IEs.asn
+++ b/lib/asn1/test/asn1_SUITE_data/nbapsystem/NBAP-IEs.asn
diff --git a/lib/asn1/test/asn1_SUITE_data/nbapsystem/NBAP-PDU-Contents.asn b/lib/asn1/test/asn1_SUITE_data/nbapsystem/NBAP-PDU-Contents.asn
index 9ecfa688a2..9ecfa688a2 100755..100644
--- a/lib/asn1/test/asn1_SUITE_data/nbapsystem/NBAP-PDU-Contents.asn
+++ b/lib/asn1/test/asn1_SUITE_data/nbapsystem/NBAP-PDU-Contents.asn
diff --git a/lib/asn1/test/asn1_SUITE_data/nbapsystem/NBAP-PDU-Discriptions.asn b/lib/asn1/test/asn1_SUITE_data/nbapsystem/NBAP-PDU-Discriptions.asn
index b9be9934e4..b9be9934e4 100755..100644
--- a/lib/asn1/test/asn1_SUITE_data/nbapsystem/NBAP-PDU-Discriptions.asn
+++ b/lib/asn1/test/asn1_SUITE_data/nbapsystem/NBAP-PDU-Discriptions.asn
diff --git a/lib/asn1/test/asn1_bin_v2_particular_SUITE.erl.src b/lib/asn1/test/asn1_bin_v2_particular_SUITE.erl.src
index abd21b0d78..4c3c8c7808 100644
--- a/lib/asn1/test/asn1_bin_v2_particular_SUITE.erl.src
+++ b/lib/asn1/test/asn1_bin_v2_particular_SUITE.erl.src
@@ -11,37 +11,219 @@ smp(Config) ->
?line Msg = {initiatingMessage, testNBAPsystem:cell_setup_req_msg()},
?line ok = testNBAPsystem:compile(Config,per_bin,[optimize]),
-
- Parent = self(),
- ?line ok = asn1rt:load_driver(),
-
- smp2(Parent,NumOfProcs,Msg,2),
+ enc_dec(NumOfProcs,Msg,2),
N = 10000,
- ?line {Time1,ok} = timer:tc(?MODULE,smp2,[Parent,NumOfProcs,Msg, N]),
- ?line {Time1S,ok} = timer:tc(?MODULE,sequential,[NumOfProcs * N,Msg]),
+ ?line {Time1,ok} = timer:tc(?MODULE,enc_dec,[NumOfProcs,Msg, N]),
+ ?line {Time1S,ok} = timer:tc(?MODULE,enc_dec,[1, Msg, NumOfProcs * N]),
- ?line ok = testNBAPsystem:compile(Config,ber_bin,[optimize,driver]),
- ?line {Time2,ok} = timer:tc(?MODULE,smp2,[Parent,NumOfProcs,Msg, N]),
+ ?line ok = testNBAPsystem:compile(Config,ber_bin,[optimize,nif]),
+ ?line {Time3,ok} = timer:tc(?MODULE,enc_dec,[NumOfProcs,Msg, N]),
- ?line {Time2S,ok} = timer:tc(?MODULE,sequential,[NumOfProcs * N,Msg]),
+ ?line {Time3S,ok} = timer:tc(?MODULE,enc_dec,[1, Msg, NumOfProcs * N]),
- {comment,lists:flatten(io_lib:format("Encode/decode time parallell with ~p cores: ~p [microsecs]~nEncode/decode time sequential: ~p [microsecs]",[NumOfProcs,Time1+Time2,Time1S+Time2S]))};
+ {comment,lists:flatten(
+ io_lib:format(
+ "Encode/decode time parallell with ~p cores: ~p [microsecs]~n"
+ "Encode/decode time sequential: ~p [microsecs]",
+ [NumOfProcs,Time1+Time3,Time1S+Time3S]))};
false ->
{skipped,"No smp support"}
end.
-smp2(Parent,NumOfProcs,Msg, N) ->
- Pids = [spawn_link(fun() -> worker(Msg,Parent, N) end)
- || _ <- lists:seq(1,NumOfProcs)],
- ?line ok = wait_pids(Pids).
+per_performance(Config) ->
+ PrivDir = proplists:get_value(priv_dir, Config),
+ NifDir = filename:join(PrivDir,"nif"),
+ ErlDir = filename:join(PrivDir,"erl"),
+ file:make_dir(NifDir),file:make_dir(ErlDir),
+
+ ?line Msg = {initiatingMessage, testNBAPsystem:cell_setup_req_msg()},
+ ?line ok = testNBAPsystem:compile([{priv_dir,NifDir}|Config],per_bin,
+ [optimize]),
+ ?line ok = testNBAPsystem:compile([{priv_dir,ErlDir}|Config],per_bin,
+ []),
+
+ Modules = ['NBAP-CommonDataTypes',
+ 'NBAP-Constants',
+ 'NBAP-Containers',
+ 'NBAP-IEs',
+ 'NBAP-PDU-Contents',
+ 'NBAP-PDU-Discriptions'],
+
+
+ PreNif = fun() ->
+ code:add_patha(NifDir),
+ lists:foreach(fun(M) ->
+ code:purge(M),
+ code:load_file(M)
+ end,Modules)
+ end,
+
+ PreErl = fun() ->
+ code:add_patha(ErlDir),
+ lists:foreach(fun(M) ->
+ code:purge(M),
+ code:load_file(M)
+ end,Modules)
+ end,
+
+ Func = fun() ->
+ element(1,timer:tc(
+ asn1_wrapper,encode,['NBAP-PDU-Discriptions',
+ 'NBAP-PDU',
+ Msg]))
+ end,
+
+ nif_vs_erlang_performance({{{PreNif,Func},{PreErl,Func}},100000,32}).
+
+ber_performance(Config) ->
+
+ ?line Msg = {initiatingMessage, testNBAPsystem:cell_setup_req_msg()},
+ ?line ok = testNBAPsystem:compile(Config,ber_bin,[optimize,nif]),
+
+
+ BerFun = fun() ->
+ {ok,B} = asn1_wrapper:encode('NBAP-PDU-Discriptions',
+ 'NBAP-PDU', Msg),
+ asn1_wrapper:decode(
+ 'NBAP-PDU-Discriptions',
+ 'NBAP-PDU',
+ B)
+ end,
+ nif_vs_erlang_performance({BerFun,100000,32}).
+
+cert_pem_performance(Config) when is_list(Config) ->
+ cert_pem_performance({100000, 32});
+cert_pem_performance({N,S}) ->
+ nif_vs_erlang_performance({fun cert_pem/0,N,S}).
+
+dsa_pem_performance(Config) when is_list(Config) ->
+ cert_pem_performance({100000, 32});
+dsa_pem_performance({N,S}) ->
+ nif_vs_erlang_performance({fun dsa_pem/0,N,S}).
+
+
+nif_vs_erlang_performance({{TC1,TC2},N,Sched}) ->
+ random:seed({123,456,789}),
+ io:format("Running a ~p sample with ~p max procs...~n~n",[N,Sched]),
+
+ {True,False} = exec(TC1,TC2,Sched,N+1),
+
+ io:format("~ndone!~n"),
+
+ io:format("~n"),TStats = print_stats(strip(True,N div 20)),
+ io:format("~n"),FStats = print_stats(strip(False,N div 20)),
+ Str = io_lib:format("~nNifs are ~.3f% faster than erlang!~n",
+ [(element(2,FStats) - element(2,TStats)) /
+ element(2,FStats) * 100]),
+ io:format(Str),
+ {comment, lists:flatten(Str)};
+nif_vs_erlang_performance({T,N,Sched}) ->
+ PTC1 = fun() ->
+ application:set_env(asn1, nif_loadable, true)
+ end,
+ PTC2 = fun() ->
+ application:set_env(asn1, nif_loadable, false)
+ end,
+ TC = fun() ->
+ element(1,timer:tc(T))
+ end,
+ nif_vs_erlang_performance({{{PTC1,TC},{PTC2,TC}},N,Sched}).
+
+
+print_stats(Data) ->
+ Length = length(Data),
+ Mean = lists:sum(Data) / Length,
+ Variance = lists:foldl(fun(N,Acc) -> math:pow(N - Mean, 2)+Acc end, 0, Data),
+ StdDev = math:sqrt(Variance / Length),
+ Median = lists:nth(round(Length/2),Data),
+ Min = lists:min(Data),
+ Max = lists:max(Data),
+ if Length < 20 ->
+ io:format("Data: ~w~n",[Data]);
+ true ->
+ ok
+ end,
+ io:format("Length: ~p~nMean: ~p~nStdDev: ~p~nMedian: ~p~nMin: ~p~nMax: ~p~n",
+ [Length,Mean,StdDev,Median,Min,Max]),
+ {Length,Mean,StdDev,Median,Min,Max}.
+
+collect(Acc) ->
+ receive
+ {Tag,Val} ->
+ Prev = proplists:get_value(Tag,Acc,[]),
+ collect(lists:keystore(Tag,1,Acc,{Tag,[Val|Prev]}))
+ after 100 ->
+ Acc
+ end.
+
+exec(One,Two,Max,N) ->
+ exec(One,Two,Max,N,{[],[]}).
+exec(_,_,_,1,{D1,D2}) ->
+ {lists:flatten(D1),lists:flatten(D2)};
+exec({PreOne,One} = O,{PreTwo,Two} = T,MaxProcs, N, {D1,D2}) ->
+ Num = random:uniform(round(N/2)),
+ if Num rem 3 == 0 ->
+ timer:sleep(Num rem 1000);
+ true ->
+ ok
+ end,
+ Procs = random:uniform(MaxProcs),
+ io:format("\tBatch: ~p items in ~p processes, ~p left~n",[Num,Procs,N-Num]),
+ if Num rem 2 == 1 ->
+ erlang:garbage_collect(),
+ PreOne(),
+ MoreOne = pexec(One, Num, Procs, []),
+ erlang:garbage_collect(),
+ PreTwo(),
+ MoreTwo = pexec(Two, Num, Procs, []);
+ true ->
+ erlang:garbage_collect(),
+ PreTwo(),
+ MoreTwo = pexec(Two, Num, Procs, []),
+ erlang:garbage_collect(),
+ PreOne(),
+ MoreOne = pexec(One, Num, Procs, [])
+ end,
+ exec(O,T,MaxProcs,N-Num,{[MoreOne|D1],
+ [MoreTwo|D2]}).
+
+pexec(_Fun, _, 0, []) ->
+ [];
+pexec(Fun, _, 0, [{Ref,Pid}|Rest]) ->
+ receive
+ {data,D} ->
+ [D|pexec(Fun,0,0,[{Ref,Pid}|Rest])];
+ {'DOWN', Ref, process, Pid, normal} ->
+ pexec(Fun, 0,0,Rest)
+ end;
+pexec(Fun, 0, 1, AccProcs) ->
+ pexec(Fun, 0, 0, AccProcs);
+pexec(Fun, N, 1, AccProcs) ->
+ [Fun()|pexec(Fun, N - 1, 1, AccProcs)];
+pexec(Fun, N, Procs, AccProcs) ->
+ S = self(),
+ Pid = spawn(fun() ->
+ S ! {data,pexec(Fun,N,1,[])}
+ end),
+ Ref = erlang:monitor(process, Pid),
+ pexec(Fun, N, Procs - 1, [{Ref,Pid}|AccProcs]).
-worker(Msg, Parent, N) ->
- %% io:format("smp worker ~p with ~p worker loops.~n",[self(), N]),
- worker_loop(N, Msg),
- Parent ! self().
+strip(Data,Num) ->
+ {_,R} = lists:split(Num,lists:sort(Data)),
+ element(2,lists:split(Num,lists:reverse(R))).
+
+faster(A,B) ->
+ (B - A)/B * 100.
+
+enc_dec(1, Msg, N) ->
+ worker_loop(N, Msg);
+enc_dec(NumOfProcs,Msg, N) ->
+ pforeach(fun(_) ->
+ worker_loop(N, Msg)
+ end, [I || I <- lists:seq(1,NumOfProcs)]).
worker_loop(0, _Msg) ->
ok;
@@ -50,28 +232,24 @@ worker_loop(N, Msg) ->
'NBAP-PDU',
Msg),
?line {ok,_Msg}=asn1_wrapper:decode('NBAP-PDU-Discriptions',
- 'NBAP-PDU',
- B),
+ 'NBAP-PDU',
+ B),
worker_loop(N - 1, Msg).
-wait_pids([]) ->
- ok;
-wait_pids(Pids) ->
+pforeach(Fun, List) ->
+ pforeach(Fun, List, []).
+pforeach(Fun, [], [{Pid,Ref}|Pids]) ->
receive
- Pid when is_pid(Pid) ->
- ?line true = lists:member(Pid,Pids),
- Others = lists:delete(Pid,Pids),
- io:format("wait_pid got ~p, still waiting for ~p\n",[Pid,Others]),
- wait_pids(Others);
- Err ->
- io:format("Err: ~p~n",[Err]),
- ?line exit(Err)
- end.
-
-sequential(N,Msg) ->
- %%io:format("sequential encode/decode with N = ~p~n",[N]),
- worker_loop(N,Msg).
+ {'DOWN', Ref, process, Pid, normal} ->
+ pforeach(Fun, [], Pids)
+ end;
+pforeach(Fun, [H|T], Pids) ->
+ Pid = spawn(fun() -> Fun(H) end),
+ Ref = erlang:monitor(process, Pid),
+ pforeach(Fun, T, [{Pid, Ref}|Pids]);
+pforeach(_Fun,[],[]) ->
+ ok.
-record('InitiatingMessage',{procedureCode,criticality,value}).
-record('Iu-ReleaseCommand',{first,second}).
@@ -93,3 +271,21 @@ ticket7904(Config) ->
?line {ok,_} = 'RANAPextract1':encode('InitiatingMessage', Val1),
asn1rt:unload_driver(),
?line {ok,_} = 'RANAPextract1':encode('InitiatingMessage', Val1).
+
+cert_pem() ->
+ 'OTP-PUB-KEY':decode('Certificate',<<48,130,3,184,48,130,3,33,160,3,2,1,2,2,1,1,48,13,6,9,42,134,72,134,247,13,1,1,5,5,0,48,129,131,49,14,48,12,6,3,85,4,3,19,5,111,116,112,67,65,49,19,48,17,6,3,85,4,11,19,10,69,114,108,97,110,103,32,79,84,80,49,20,48,18,6,3,85,4,10,19,11,69,114,105,99,115,115,111,110,32,65,66,49,11,48,9,6,3,85,4,6,19,2,83,69,49,18,48,16,6,3,85,4,7,19,9,83,116,111,99,107,104,111,108,109,49,37,48,35,6,9,42,134,72,134,247,13,1,9,1,22,22,112,101,116,101,114,64,101,114,105,120,46,101,114,105,99,115,115,111,110,46,115,101,48,30,23,13,48,56,48,49,48,57,48,56,50,57,51,48,90,23,13,49,55,49,49,49,55,48,56,50,57,51,48,90,48,129,132,49,15,48,13,6,3,85,4,3,19,6,99,108,105,101,110,116,49,19,48,17,6,3,85,4,11,19,10,69,114,108,97,110,103,32,79,84,80,49,20,48,18,6,3,85,4,10,19,11,69,114,105,99,115,115,111,110,32,65,66,49,11,48,9,6,3,85,4,6,19,2,83,69,49,18,48,16,6,3,85,4,7,19,9,83,116,111,99,107,104,111,108,109,49,37,48,35,6,9,42,134,72,134,247,13,1,9,1,22,22,112,101,116,101,114,64,101,114,105,120,46,101,114,105,99,115,115,111,110,46,115,101,48,129,159,48,13,6,9,42,134,72,134,247,13,1,1,1,5,0,3,129,141,0,48,129,137,2,129,129,0,245,56,68,254,220,239,193,190,63,221,182,60,67,77,121,163,214,136,137,183,139,8,166,30,100,27,45,17,126,58,15,173,151,218,75,224,148,14,22,164,10,100,186,183,104,175,197,97,96,182,146,150,106,129,140,100,194,106,90,62,133,233,155,46,155,33,101,220,83,193,182,232,240,99,253,249,114,8,159,172,143,77,179,132,229,205,29,110,185,233,224,52,25,149,249,100,80,229,199,125,23,106,146,233,159,26,13,8,161,206,221,43,240,149,42,45,194,190,85,6,235,152,220,219,160,32,144,67,2,3,1,0,1,163,130,1,55,48,130,1,51,48,9,6,3,85,29,19,4,2,48,0,48,11,6,3,85,29,15,4,4,3,2,5,224,48,29,6,3,85,29,14,4,22,4,20,26,59,44,5,72,211,158,214,23,34,30,241,125,27,123,115,93,163,231,120,48,129,179,6,3,85,29,35,4,129,171,48,129,168,128,20,6,171,128,52,58,164,184,118,178,189,157,46,40,229,109,145,222,125,1,155,161,129,140,164,129,137,48,129,134,49,17,48,15,6,3,85,4,3,19,8,101,114,108,97,110,103,67,65,49,19,48,17,6,3,85,4,11,19,10,69,114,108,97,110,103,32,79,84,80,49,20,48,18,6,3,85,4,10,19,11,69,114,105,99,115,115,111,110,32,65,66,49,18,48,16,6,3,85,4,7,19,9,83,116,111,99,107,104,111,108,109,49,11,48,9,6,3,85,4,6,19,2,83,69,49,37,48,35,6,9,42,134,72,134,247,13,1,9,1,22,22,112,101,116,101,114,64,101,114,105,120,46,101,114,105,99,115,115,111,110,46,115,101,130,1,1,48,33,6,3,85,29,17,4,26,48,24,129,22,112,101,116,101,114,64,101,114,105,120,46,101,114,105,99,115,115,111,110,46,115,101,48,33,6,3,85,29,18,4,26,48,24,129,22,112,101,116,101,114,64,101,114,105,120,46,101,114,105,99,115,115,111,110,46,115,101,48,13,6,9,42,134,72,134,247,13,1,1,5,5,0,3,129,129,0,93,11,112,227,121,15,121,179,247,135,110,216,17,197,84,18,149,166,147,142,190,178,0,209,190,0,142,233,144,100,194,205,220,182,73,204,108,42,95,23,48,63,4,120,239,42,194,25,184,35,117,107,96,229,18,45,76,122,125,40,171,210,132,50,146,178,160,55,17,35,255,208,114,30,47,55,185,154,155,165,204,180,14,143,20,234,6,234,201,225,72,235,5,87,61,255,250,23,217,1,144,246,98,221,223,102,49,168,177,13,70,241,26,27,254,251,217,14,244,18,242,197,151,50,186,214,15,42>>).
+
+dsa_pem() ->
+ 'OTP-PUB-KEY':decode('DSAPrivateKey',<<48,130,1,187,2,1,0,2,129,129,0,183,179,230,217,37,99,144,157,21,228,204,162,207,61,246,144,58,139,139,184,184,43,108,206,0,115,173,208,100,233,201,121,21,90,179,119,53,140,25,52,34,202,121,211,164,107,43,56,68,162,159,51,244,232,138,126,164,109,121,89,237,142,57,28,32,188,44,67,253,111,121,104,40,141,211,255,140,118,37,234,150,201,155,160,16,17,51,59,26,249,41,129,16,211,119,128,95,254,182,235,132,0,92,206,93,77,106,217,201,132,203,4,75,201,246,204,216,162,1,84,79,211,10,21,152,195,103,145,2,21,0,213,30,184,86,247,16,247,69,192,241,35,138,84,57,140,3,71,65,206,233,2,129,129,0,148,179,24,63,74,91,128,25,96,29,5,78,223,246,175,0,121,86,54,178,42,231,98,241,147,180,157,60,149,160,50,243,227,76,175,89,234,203,252,242,76,108,9,204,157,182,59,206,227,127,99,215,42,156,194,78,116,25,7,62,243,169,45,5,101,179,247,127,199,144,135,103,23,42,154,125,231,248,154,101,175,155,101,42,232,41,80,41,47,128,208,11,31,106,63,12,202,207,135,80,200,136,250,171,31,118,52,91,200,138,112,111,179,23,214,123,21,118,194,179,0,185,217,52,197,182,236,13,2,129,128,124,66,0,111,121,139,142,209,95,136,95,237,177,150,248,252,49,135,117,100,155,232,138,244,132,89,40,5,70,125,202,96,78,239,76,37,125,149,82,64,107,54,227,73,25,180,227,41,0,234,73,47,80,242,242,129,250,61,68,62,39,38,156,193,146,40,241,247,106,215,223,202,194,110,130,62,186,90,18,28,196,174,99,47,193,61,130,100,150,25,248,115,164,231,153,99,46,69,66,139,33,187,51,49,35,219,234,29,44,172,166,247,42,16,177,187,9,162,81,243,33,26,100,46,78,57,203,135,2,20,89,128,159,14,187,249,182,172,15,88,162,110,211,71,179,209,29,125,217,38>>),
+ 'OTP-PUB-KEY':decode('SubjectPublicKeyInfo',<<48,130,1,183,48,130,1,44,6,7,42,134,72,206,56,4,1,48,130,1,31,2,129,129,0,183,179,230,217,37,99,144,157,21,228,204,162,207,61,246,144,58,139,139,184,184,43,108,206,0,115,173,208,100,233,201,121,21,90,179,119,53,140,25,52,34,202,121,211,164,107,43,56,68,162,159,51,244,232,138,126,164,109,121,89,237,142,57,28,32,188,44,67,253,111,121,104,40,141,211,255,140,118,37,234,150,201,155,160,16,17,51,59,26,249,41,129,16,211,119,128,95,254,182,235,132,0,92,206,93,77,106,217,201,132,203,4,75,201,246,204,216,162,1,84,79,211,10,21,152,195,103,145,2,21,0,213,30,184,86,247,16,247,69,192,241,35,138,84,57,140,3,71,65,206,233,2,129,129,0,148,179,24,63,74,91,128,25,96,29,5,78,223,246,175,0,121,86,54,178,42,231,98,241,147,180,157,60,149,160,50,243,227,76,175,89,234,203,252,242,76,108,9,204,157,182,59,206,227,127,99,215,42,156,194,78,116,25,7,62,243,169,45,5,101,179,247,127,199,144,135,103,23,42,154,125,231,248,154,101,175,155,101,42,232,41,80,41,47,128,208,11,31,106,63,12,202,207,135,80,200,136,250,171,31,118,52,91,200,138,112,111,179,23,214,123,21,118,194,179,0,185,217,52,197,182,236,13,3,129,132,0,2,129,128,124,66,0,111,121,139,142,209,95,136,95,237,177,150,248,252,49,135,117,100,155,232,138,244,132,89,40,5,70,125,202,96,78,239,76,37,125,149,82,64,107,54,227,73,25,180,227,41,0,234,73,47,80,242,242,129,250,61,68,62,39,38,156,193,146,40,241,247,106,215,223,202,194,110,130,62,186,90,18,28,196,174,99,47,193,61,130,100,150,25,248,115,164,231,153,99,46,69,66,139,33,187,51,49,35,219,234,29,44,172,166,247,42,16,177,187,9,162,81,243,33,26,100,46,78,57,203,135>>),
+ 'OTP-PUB-KEY':decode('DSAParams',<<48,130,1,31,2,129,129,0,183,179,230,217,37,99,144,157,21,228,204,162,207,61,246,144,58,139,139,184,184,43,108,206,0,115,173,208,100,233,201,121,21,90,179,119,53,140,25,52,34,202,121,211,164,107,43,56,68,162,159,51,244,232,138,126,164,109,121,89,237,142,57,28,32,188,44,67,253,111,121,104,40,141,211,255,140,118,37,234,150,201,155,160,16,17,51,59,26,249,41,129,16,211,119,128,95,254,182,235,132,0,92,206,93,77,106,217,201,132,203,4,75,201,246,204,216,162,1,84,79,211,10,21,152,195,103,145,2,21,0,213,30,184,86,247,16,247,69,192,241,35,138,84,57,140,3,71,65,206,233,2,129,129,0,148,179,24,63,74,91,128,25,96,29,5,78,223,246,175,0,121,86,54,178,42,231,98,241,147,180,157,60,149,160,50,243,227,76,175,89,234,203,252,242,76,108,9,204,157,182,59,206,227,127,99,215,42,156,194,78,116,25,7,62,243,169,45,5,101,179,247,127,199,144,135,103,23,42,154,125,231,248,154,101,175,155,101,42,232,41,80,41,47,128,208,11,31,106,63,12,202,207,135,80,200,136,250,171,31,118,52,91,200,138,112,111,179,23,214,123,21,118,194,179,0,185,217,52,197,182,236,13>>),
+ 'OTP-PUB-KEY':decode('DSAPublicKey',<<2,129,128,124,66,0,111,121,139,142,209,95,136,95,237,177,150,248,252,49,135,117,100,155,232,138,244,132,89,40,5,70,125,202,96,78,239,76,37,125,149,82,64,107,54,227,73,25,180,227,41,0,234,73,47,80,242,242,129,250,61,68,62,39,38,156,193,146,40,241,247,106,215,223,202,194,110,130,62,186,90,18,28,196,174,99,47,193,61,130,100,150,25,248,115,164,231,153,99,46,69,66,139,33,187,51,49,35,219,234,29,44,172,166,247,42,16,177,187,9,162,81,243,33,26,100,46,78,57,203,135>>),
+ 'OTP-PUB-KEY':encode('DSAParams',{params,{'Dss-Parms',129000451850199666185842362389296595317127259539517666765336291347244303954511451744518587442120964433734460998523119938005801396466878889993179871123036311260456172022864663021425348874648247531097042575063545128239655736096045972718934778583429973433661785691086624069991876932064334822608460064613803976593,1216700114794736143432235288305776850295620488937,104420402274523493329542694749036577763086597934731674202966304958550599470165597750883637440049774107540742087494301536297571301945349213110548764383811017178451900599240379681904765817950545426764751538502808499880604633364255316249231153053427235538288687666086821781456733226598288985591031656134573747213}}),
+ 'OTP-PUB-KEY':encode(
+ 'SubjectPublicKeyInfo',
+ {'SubjectPublicKeyInfo',
+ {'AlgorithmIdentifier',
+ {1,2,840,10040,4,1},
+ <<48,130,1,31,2,129,129,0,183,179,230,217,37,99,144,157,21,228,204,162,207,61,246,144,58,139,139,184,184,43,108,206,0,115,173,208,100,233,201,121,21,90,179,119,53,140,25,52,34,202,121,211,164,107,43,56,68,162,159,51,244,232,138,126,164,109,121,89,237,142,57,28,32,188,44,67,253,111,121,104,40,141,211,255,140,118,37,234,150,201,155,160,16,17,51,59,26,249,41,129,16,211,119,128,95,254,182,235,132,0,92,206,93,77,106,217,201,132,203,4,75,201,246,204,216,162,1,84,79,211,10,21,152,195,103,145,2,21,0,213,30,184,86,247,16,247,69,192,241,35,138,84,57,140,3,71,65,206,233,2,129,129,0,148,179,24,63,74,91,128,25,96,29,5,78,223,246,175,0,121,86,54,178,42,231,98,241,147,180,157,60,149,160,50,243,227,76,175,89,234,203,252,242,76,108,9,204,157,182,59,206,227,127,99,215,42,156,194,78,116,25,7,62,243,169,45,5,101,179,247,127,199,144,135,103,23,42,154,125,231,248,154,101,175,155,101,42,232,41,80,41,47,128,208,11,31,106,63,12,202,207,135,80,200,136,250,171,31,118,52,91,200,138,112,111,179,23,214,123,21,118,194,179,0,185,217,52,197,182,236,13>>},
+ {0,
+ <<2,129,128,124,66,0,111,121,139,142,209,95,136,95,237,177,150,248,252,49,135,117,100,155,232,138,244,132,89,40,5,70,125,202,96,78,239,76,37,125,149,82,64,107,54,227,73,25,180,227,41,0,234,73,47,80,242,242,129,250,61,68,62,39,38,156,193,146,40,241,247,106,215,223,202,194,110,130,62,186,90,18,28,196,174,99,47,193,61,130,100,150,25,248,115,164,231,153,99,46,69,66,139,33,187,51,49,35,219,234,29,44,172,166,247,42,16,177,187,9,162,81,243,33,26,100,46,78,57,203,135>>}}).
diff --git a/lib/asn1/test/ber_decode_error.erl b/lib/asn1/test/ber_decode_error.erl
index 96d6545636..a566e0b07f 100644
--- a/lib/asn1/test/ber_decode_error.erl
+++ b/lib/asn1/test/ber_decode_error.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1999-2010. All Rights Reserved.
+%% Copyright Ericsson AB 1999-2011. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -45,6 +45,10 @@ run([]) ->
run([driver]) ->
%% test of OTP-4797, bad indata to driver does not cause an EXIT
?line {error,_Reason} = asn1rt:decode('Constructed','S3',[3,5]),
+ ok;
+run([nif]) ->
+ %% test of OTP-4797, bad indata to driver does not cause an EXIT
+ ?line {error,_Reason} = asn1rt:decode('Constructed','S3',[3,5]),
ok.
diff --git a/lib/asn1/test/testPrim.erl b/lib/asn1/test/testPrim.erl
index 97f99e7b1c..39c1e4d1d8 100644
--- a/lib/asn1/test/testPrim.erl
+++ b/lib/asn1/test/testPrim.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2010. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2011. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -37,21 +37,10 @@ compile(Config,Rules,Opt) ->
?line DataDir = ?config(data_dir,Config),
?line OutDir = ?config(priv_dir,Config),
?line true = code:add_patha(?config(priv_dir,Config)),
- case Opt of
- [optimize] ->
- ?line ok = asn1ct:compile(DataDir ++ "Prim",
- [Rules,optimize,{outdir,OutDir}]),
- ?line ok = asn1ct:compile(DataDir ++ "Real",
- [Rules,optimize,{outdir,OutDir}]);
- __ ->
- ?line ok = asn1ct:compile(DataDir ++ "Prim",
- [Rules,{outdir,OutDir}]),
- ?line ok = asn1ct:compile(DataDir ++ "Real",
- [Rules,{outdir,OutDir}])
- end.
-
-
-
+ ?line ok = asn1ct:compile(DataDir ++ "Prim",
+ [Rules,{outdir,OutDir}] ++ Opt),
+ ?line ok = asn1ct:compile(DataDir ++ "Real",
+ [Rules,{outdir,OutDir}] ++ Opt).
bool(Rules) ->
diff --git a/lib/common_test/doc/src/Makefile b/lib/common_test/doc/src/Makefile
index 3ea6ae65d5..964f7c76c1 100644
--- a/lib/common_test/doc/src/Makefile
+++ b/lib/common_test/doc/src/Makefile
@@ -138,12 +138,6 @@ man: $(MAN6_FILES) $(MAN3_FILES) $(MAN1_FILES)
debug opt:
-#
-# checkout make.dep before generating new dependecies
-#
-#make_doc_depend: xml
-# docdepend > make.dep
-
clean clean_docs:
rm -f $(CT_XML_FILES)
rm -rf $(HTMLDIR)/*
@@ -176,12 +170,3 @@ release_docs_spec: docs
release_spec:
release_tests_spec:
-
-# ----------------------------------------------------
-# Include dependency
-# ----------------------------------------------------
-
-include make.dep
-# DO NOT DELETE
-
-
diff --git a/lib/common_test/doc/src/ct_hooks.xml b/lib/common_test/doc/src/ct_hooks.xml
index f9fc1858d0..b98c04a850 100644
--- a/lib/common_test/doc/src/ct_hooks.xml
+++ b/lib/common_test/doc/src/ct_hooks.xml
@@ -37,12 +37,6 @@
<description>
- <warning><p>This feature is in alpha release right now. This means that the
- interface may change in the future and that there may be bugs. We
- encourage you to use this feature, but be prepared
- that there might be bugs and that the interface might change
- inbetween releases.</p></warning>
-
<p>The <em>Common Test Hook</em> (henceforth called CTH) framework allows
extensions of the default behaviour of Common Test by means of callbacks
before and after all test suite calls. It is meant for advanced users of
diff --git a/lib/common_test/doc/src/ct_hooks_chapter.xml b/lib/common_test/doc/src/ct_hooks_chapter.xml
index dbb4310040..bac0c4eaa8 100644
--- a/lib/common_test/doc/src/ct_hooks_chapter.xml
+++ b/lib/common_test/doc/src/ct_hooks_chapter.xml
@@ -32,11 +32,6 @@
<marker id="general"></marker>
<section>
<title>General</title>
- <warning><p>This feature is in alpha release right now. This means that the
- interface may change in the future and that there may be bugs. We
- encourage you to use this feature, but be prepared
- that there might be bugs and that the interface might change
- inbetween releases.</p></warning>
<p>
The <em>Common Test Hook</em> (henceforth called CTH) framework allows
extensions of the default behaviour of Common Test by means of hooks
@@ -405,6 +400,38 @@ terminate(State) ->
ok.</code>
</section>
+ <marker id="builtin_cths"/>
+ <section>
+ <title>Built-in CTHs</title>
+ <p>Common Test is delivered with a couple of general purpose CTHs that
+ can be enabled by the user to provide some generic testing functionality.
+ Some of these are enabled by default when starting running common_test,
+ they can be disabled by setting <c>enable_builtin_hooks</c> to
+ <c>false</c> on the command line or in the test specification. In the
+ table below there is a list of all current CTHs which are delivered with
+ Common Test.</p>
+
+ <table>
+ <row>
+ <cell><em>CTH Name</em></cell>
+ <cell><em>Is Built-in</em></cell>
+ <cell><em>Description</em></cell>
+ </row>
+ <row>
+ <cell>cth_log_redirect</cell>
+ <cell>yes</cell>
+ <cell>Captures all error_logger and SASL logging events and prints them
+ to the current test case log. If an event can not be associated with a
+ testcase it will be printed in the common test framework log. This will
+ happen for testcases which are run in parallel and events which occur
+ inbetween testcases. You can configure the level of
+ <seealso marker="sasl:sasl_app">SASL</seealso> events report
+ using the normal SASL mechanisms. </cell>
+ </row>
+ </table>
+
+ </section>
+
</chapter>
diff --git a/lib/common_test/doc/src/filestruct.gif b/lib/common_test/doc/src/filestruct.gif
index 2b06833d0b..2b06833d0b 100755..100644
--- a/lib/common_test/doc/src/filestruct.gif
+++ b/lib/common_test/doc/src/filestruct.gif
Binary files differ
diff --git a/lib/common_test/doc/src/make.dep b/lib/common_test/doc/src/make.dep
deleted file mode 100644
index e34075888d..0000000000
--- a/lib/common_test/doc/src/make.dep
+++ /dev/null
@@ -1,27 +0,0 @@
-# ----------------------------------------------------
-# >>>> Do not edit this file <<<<
-# This file was automaticly generated by
-# /home/otp/bin/docdepend
-# ----------------------------------------------------
-
-
-# ----------------------------------------------------
-# TeX files that the DVI file depend on
-# ----------------------------------------------------
-
-book.dvi: basics_chapter.tex book.tex common_test_app.tex \
- config_file_chapter.tex cover_chapter.tex \
- ct.tex ct_cover.tex ct_ftp.tex ct_master.tex \
- ct_master_chapter.tex ct_rpc.tex ct_snmp.tex \
- ct_ssh.tex ct_telnet.tex dependencies_chapter.tex \
- event_handler_chapter.tex example_chapter.tex \
- install_chapter.tex part.tex ref_man.tex run_test.tex \
- run_test_chapter.tex test_structure_chapter.tex \
- unix_telnet.tex why_test_chapter.tex write_test_chapter.tex
-
-# ----------------------------------------------------
-# Source inlined when transforming from source to LaTeX
-# ----------------------------------------------------
-
-book.tex: ref_man.xml
-
diff --git a/lib/common_test/doc/src/run_test_chapter.xml b/lib/common_test/doc/src/run_test_chapter.xml
index d3c6847d85..57059f0ba2 100644
--- a/lib/common_test/doc/src/run_test_chapter.xml
+++ b/lib/common_test/doc/src/run_test_chapter.xml
@@ -159,6 +159,8 @@
<seealso marker="event_handler_chapter#event_handling">event handlers</seealso> including start arguments.</item>
<item><c><![CDATA[-ct_hooks <ct_hooks>]]></c>, to install
<seealso marker="ct_hooks_chapter#installing">Common Test Hooks</seealso> including start arguments.</item>
+ <item><c><![CDATA[-enable_builtin_hooks <bool>]]></c>, to enable/disable
+ <seealso marker="ct_hooks_chapter#builtin_cths">Built-in Common Test Hooks</seealso>. Default is <c>true</c>.</item>
<item><c><![CDATA[-include]]></c>, specifies include directories (see above).</item>
<item><c><![CDATA[-no_auto_compile]]></c>, disables the automatic test suite compilation feature (see above).</item>
<item><c><![CDATA[-multiply_timetraps <n>]]></c>, extends <seealso marker="write_test_chapter#timetraps">timetrap
@@ -462,6 +464,8 @@
{ct_hooks, CTHModules}.
{ct_hooks, NodeRefs, CTHModules}.
+
+ {enable_builtin_hooks, Bool}.
</pre>
<p>Test terms:</p>
<pre>
@@ -643,7 +647,11 @@
<p>The minor log file contain full details of every single test
case, each one in a separate file. This way the files should
be easy to compare with previous test runs, even if the set of
- test cases change.</p>
+ test cases change. If SASL is running those logs will also be
+ printed there by the
+ <seealso marker="common_test:ct_hooks_chapter#builtin_cths">
+ cth_log_redirect built-in hook</seealso>.
+ </p>
<p>Which information goes where is user configurable via the
test server controller. Three threshold values determine what
diff --git a/lib/common_test/include/ct.hrl b/lib/common_test/include/ct.hrl
index aa1cc832cf..5a77108e1a 100644
--- a/lib/common_test/include/ct.hrl
+++ b/lib/common_test/include/ct.hrl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2003-2010. All Rights Reserved.
+%% Copyright Ericsson AB 2003-2011. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -18,5 +18,4 @@
%%
-include_lib("test_server/include/test_server.hrl").
--compile({parse_transform,ct_line}).
diff --git a/lib/common_test/priv/Makefile.in b/lib/common_test/priv/Makefile.in
index f4a0c181f9..d9033f6ef1 100644
--- a/lib/common_test/priv/Makefile.in
+++ b/lib/common_test/priv/Makefile.in
@@ -59,6 +59,7 @@ ifneq ($(findstring win32,$(TARGET)),win32)
FILES = vts.tool
SCRIPTS =
IMAGES = tile1.jpg
+CSS = ct_default.css
#
# Rules
@@ -85,11 +86,11 @@ include $(ERL_TOP)/make/otp_release_targets.mk
ifeq ($(XNIX),true)
release_spec: opt
$(INSTALL_DIR) $(RELSYSDIR)/priv
- $(INSTALL_DATA) $(FILES) $(IMAGES) $(RELSYSDIR)/priv
+ $(INSTALL_DATA) $(FILES) $(IMAGES) $(CSS) $(RELSYSDIR)/priv
else
release_spec: opt
$(INSTALL_DIR) $(RELSYSDIR)/priv
- $(INSTALL_DATA) $(FILES) $(IMAGES) $(RELSYSDIR)/priv
+ $(INSTALL_DATA) $(FILES) $(IMAGES) $(CSS) $(RELSYSDIR)/priv
endif
release_docs_spec:
@@ -105,6 +106,7 @@ else
#
FILES = vts.tool
IMAGES = tile1.jpg
+CSS = ct_default.css
#
# Rules
@@ -124,7 +126,7 @@ include $(ERL_TOP)/make/otp_release_targets.mk
release_spec: opt
$(INSTALL_DIR) $(RELSYSDIR)/priv
- $(INSTALL_DATA) $(FILES) $(IMAGES) $(RELSYSDIR)/priv
+ $(INSTALL_DATA) $(FILES) $(IMAGES) $(CSS) $(RELSYSDIR)/priv
release_docs_spec:
diff --git a/lib/common_test/priv/ct_default.css b/lib/common_test/priv/ct_default.css
new file mode 100644
index 0000000000..a64e1ec576
--- /dev/null
+++ b/lib/common_test/priv/ct_default.css
@@ -0,0 +1,186 @@
+/* Stylesheet for Common Test */
+
+body {
+ padding: 10px; margin: 10px;
+ -webkit-font-smoothing: antialiased;
+ background-color: #FBFFFC;
+}
+
+a:link {
+ color: #2B507D;
+}
+
+a:visited {
+ color: #85ABD5
+}
+
+h1 {
+ font-family: verdana, arial, sans-serif; font-size: 200%;
+ letter-spacing: -2px; word-spacing: 2px; font-weight: bold;
+ color: #3F3F3F;
+}
+
+h2 {
+ font-family: verdana, arial, sans-serif; font-size: 175%;
+ letter-spacing: -2px; word-spacing: 2px; font-weight: normal;
+ color: #3F3F3F;
+}
+
+h3 {
+ font-family: verdana, arial, sans-serif; font-size: 140%;
+ letter-spacing: -2px; word-spacing: 2px; font-weight: bold;
+ color: #3F3F3F;
+}
+
+h4 {
+ font-family: verdana, arial, sans-serif; font-size: 120%;
+ letter-spacing: -2px; word-spacing: 2px; font-weight: normal;
+ color: #3F3F3F;
+}
+
+p {
+ font-family: "Trebuchet MS", "Lucida Sans Unicode", verdana, arial, sans-serif;
+ font-size: .9em; color: #000000;
+}
+
+ul {
+ list-style-type: none;
+ padding: 0em;
+ margin: 1em;
+}
+li {
+ font-size: 0.95em; color: #000000;
+ margin: .3em 0;
+}
+
+pre {
+ color: black;
+ font-family: "Monaco", "Andale Mono", "Consolas", monospace;
+ font-size: .8em;
+ }
+
+code {
+ color: black;
+ font-family: "Monaco", "Andale Mono", "Consolas", monospace;
+ font-size: .8em;
+}
+
+div.mono_sm {
+ font-family: "Courier New", monospace; font-size: .75em;
+ word-spacing: 1px; color: #000000;
+}
+
+div.mono_la {
+ font-family: "Courier New", monospace; font-size: .8em;
+ color: #000000;
+}
+
+div.copyright {
+ padding: 20px 0px 0px 0px;
+ font-family: "Courier New", monospace; font-size: .7em;
+ color: #000000;
+}
+
+div.ct_internal {
+ background: lightgrey; color: black;
+ font-family: "Monaco", "Andale Mono", "Consolas", monospace;
+ font-size: .95em;
+ margin: .2em 0 0 0;
+}
+
+div.default {
+ background: lightgreen; color: black;
+ font-family: "Monaco", "Andale Mono", "Consolas", monospace;
+ font-size: 1.05em;
+ margin: .2em 0 0 0;
+}
+
+div.label {
+ font-family: verdana, arial, sans-serif; font-size: 200%;
+ letter-spacing: -2.5px; word-spacing: 2px;
+ font-weight: bold; color: #2B507D;
+}
+
+table {
+ border-collapse: collapse; border: 6px solid #3F3F3F;
+ background: #FFFFFF;
+ font: .8em/1.2em "Lucida Sans Unicode", verdana, arial, sans-serif;
+ color: #222;
+}
+
+caption {
+ font-size: 1.3em; font-weight: bold;
+ text-align: center; padding: 1em 4px;
+}
+
+td, th {
+ padding: .5em 7px .5em 7px; line-height: 1.3em;
+ border-bottom: 3px solid #F5C4C1;
+ border-left: 2px dashed #809FFF;
+}
+
+th {
+ background: #3F3F3F; color: #fff;
+ font-family: arial, sans-serif; font-size: 120%;
+ letter-spacing: -0.5px;
+ font-weight: bold; text-align: center;
+ padding-right: .5em; vertical-align: top;
+}
+
+thead th {
+ background: #2C5755; text-align: center;
+}
+
+.odd td {
+ background: #F3F3F3;
+}
+.odd th {
+ background: #F3F3F3;
+}
+
+td a, td a:link {
+ color: #2B507D;
+}
+
+td a:visited {
+ color: #85ABD5;
+}
+
+tr:hover th[scope=row], tr:hover td {
+ background-color: #808080;
+ color: #fff;
+}
+
+td a:hover, td a:focus {
+ color: #85ABD5;
+}
+
+th a, td a:active {
+ color: #85ABD5;
+}
+
+tfoot th, tfoot td {
+ background: #3F3F3F; color: #fff;
+}
+
+th + td {
+ padding-left: .5em;
+}
+
+#button_holder {
+ display: block; float: center;
+ font-family: arial, verdana, sans-serif;
+ font-size: 12px; text-shadow: 1px 1px lightgray;
+}
+
+.btn a {
+ padding: 6px 12px; float: center;
+ text-decoration: none; color: #3F3F3F;
+ font-weight: bold; border: 3px outset #3F3F3F;
+ background-color: #F3F3F3;
+}
+
+.btn a:hover {
+ color: #fff;
+ background-color: #809FFF;
+}
diff --git a/lib/common_test/src/Makefile b/lib/common_test/src/Makefile
index 84b122b5e4..125aa828fb 100644
--- a/lib/common_test/src/Makefile
+++ b/lib/common_test/src/Makefile
@@ -40,7 +40,6 @@ RELSYSDIR = $(RELEASE_PATH)/lib/common_test-$(VSN)
# ----------------------------------------------------
MODULES= \
- ct_line \
ct \
ct_logs \
ct_framework \
@@ -69,9 +68,11 @@ MODULES= \
ct_config_xml \
ct_slave \
ct_hooks\
- ct_hooks_lock
+ ct_hooks_lock\
+ cth_log_redirect
TARGET_MODULES= $(MODULES:%=$(EBIN)/%)
+BEAM_FILES= $(MODULES:%=$(EBIN)/%.$(EMULATOR))
ERL_FILES= $(MODULES:=.erl)
HRL_FILES = \
@@ -97,7 +98,7 @@ ERL_COMPILE_FLAGS += -pa ../ebin -I../include -I $(ERL_TOP)/lib/snmp/include/ \
# ----------------------------------------------------
TARGET_FILES = \
$(GEN_ERL_FILES:%.erl=$(EBIN)/%.$(EMULATOR)) \
- $(MODULES:%=$(EBIN)/%.$(EMULATOR)) \
+ $(BEAM_FILES) \
$(APP_TARGET) $(APPUP_TARGET)
APP_FILE= common_test.app
diff --git a/lib/common_test/src/common_test.app.src b/lib/common_test/src/common_test.app.src
index b42173f412..57606c01db 100644
--- a/lib/common_test/src/common_test.app.src
+++ b/lib/common_test/src/common_test.app.src
@@ -25,7 +25,6 @@
ct_framework,
ct_ftp,
ct_gen_conn,
- ct_line,
ct_logs,
ct_make,
ct_master,
diff --git a/lib/common_test/src/ct.erl b/lib/common_test/src/ct.erl
index f3c2029734..69e15fa246 100644
--- a/lib/common_test/src/ct.erl
+++ b/lib/common_test/src/ct.erl
@@ -148,8 +148,8 @@ run(TestDirs) ->
%%% {auto_compile,Bool} | {multiply_timetraps,M} | {scale_timetraps,Bool} |
%%% {repeat,N} | {duration,DurTime} | {until,StopTime} |
%%% {force_stop,Bool} | {decrypt,DecryptKeyOrFile} |
-%%% {refresh_logs,LogDir} | {logopts,LogOpts} | {basic_html,Bool} |
-%%% {ct_hooks, CTHs}
+%%% {refresh_logs,LogDir} | {logopts,LogOpts} | {basic_html,Bool} |
+%%% {ct_hooks, CTHs} | {enable_builtin_hooks,Bool}
%%% TestDirs = [string()] | string()
%%% Suites = [string()] | [atom()] | string() | atom()
%%% Cases = [atom()] | atom()
diff --git a/lib/common_test/src/ct_framework.erl b/lib/common_test/src/ct_framework.erl
index 482c5242ce..0897675591 100644
--- a/lib/common_test/src/ct_framework.erl
+++ b/lib/common_test/src/ct_framework.erl
@@ -27,7 +27,7 @@
-export([init_tc/3, end_tc/3, end_tc/4, get_suite/2, get_all_cases/1]).
-export([report/2, warn/1, error_notification/4]).
--export([get_logopts/0, format_comment/1, overview_html_header/1]).
+-export([get_logopts/0, format_comment/1, get_html_wrapper/3]).
-export([error_in_suite/1, ct_init_per_group/2, ct_end_per_group/2]).
@@ -1411,30 +1411,6 @@ format_comment(Comment) ->
"<font color=\"green\">" ++ Comment ++ "</font>".
%%%-----------------------------------------------------------------
-%%% @spec overview_html_header(TestName) -> Header
-overview_html_header(TestName) ->
- TestName1 = lists:flatten(io_lib:format("~p", [TestName])),
- Label = case application:get_env(common_test, test_label) of
- {ok,Lbl} when Lbl =/= undefined ->
- "<H1><FONT color=\"green\">" ++ Lbl ++ "</FONT></H1>\n";
- _ ->
- ""
- end,
- Bgr = case ct_logs:basic_html() of
- true ->
- "";
- false ->
- CTPath = code:lib_dir(common_test),
- TileFile = filename:join(filename:join(CTPath,"priv"),"tile1.jpg"),
- " background=\"" ++ TileFile ++ "\""
- end,
-
- ["<html>\n",
- "<head><title>Test ", TestName1, " results</title>\n",
- "<meta http-equiv=\"cache-control\" content=\"no-cache\">\n",
- "</head>\n",
- "<body", Bgr, " bgcolor=\"white\" text=\"black\" ",
- "link=\"blue\" vlink=\"purple\" alink=\"red\">\n",
- Label,
- "<H2>Results from test ", TestName1, "</H2>\n"].
-
+%%% @spec get_html_wrapper(TestName, PrintLabel, Cwd) -> Header
+get_html_wrapper(TestName, PrintLabel, Cwd) ->
+ ct_logs:get_ts_html_wrapper(TestName, PrintLabel, Cwd).
diff --git a/lib/common_test/src/ct_hooks.erl b/lib/common_test/src/ct_hooks.erl
index f243b87f54..ffafc582cf 100644
--- a/lib/common_test/src/ct_hooks.erl
+++ b/lib/common_test/src/ct_hooks.erl
@@ -34,6 +34,12 @@
%% If you change this, remember to update ct_util:look -> stop clause as well.
-define(config_name, ct_hooks).
+%% All of the hooks which are to be started by default. Remove by issuing
+%% -enable_builtin_hooks false to when starting common test.
+-define(BUILTIN_HOOKS,[#ct_hook_config{ module = cth_log_redirect,
+ opts = [],
+ prio = ctfirst }]).
+
-record(ct_hook_config, {id, module, prio, scope, opts = [], state = []}).
%% -------------------------------------------------------------------------
@@ -44,7 +50,8 @@
-spec init(State :: term()) -> ok |
{error, Reason :: term()}.
init(Opts) ->
- call(get_new_hooks(Opts, undefined), ok, init, []).
+ call(get_new_hooks(Opts, undefined) ++ get_builtin_hooks(Opts),
+ ok, init, []).
%% @doc Called after all suites are done.
@@ -283,6 +290,14 @@ get_new_hooks(Config) when is_list(Config) ->
get_new_hooks(_Config) ->
[].
+get_builtin_hooks(Opts) ->
+ case proplists:get_value(enable_builtin_hooks,Opts) of
+ false ->
+ [];
+ _Else ->
+ [{HookConf, call_id, undefined} || HookConf <- ?BUILTIN_HOOKS]
+ end.
+
save_suite_data_async(Hooks) ->
ct_util:save_suite_data_async(?config_name, Hooks).
@@ -290,7 +305,7 @@ get_hooks() ->
lists:keysort(#ct_hook_config.prio,ct_util:read_suite_data(?config_name)).
%% Sort all calls in this order:
-%% call_id < call_init < Hook Priority 1 < .. < Hook Priority N
+%% call_id < call_init < ctfirst < Priority 1 < .. < Priority N < ctlast
%% If Hook Priority is equal, check when it has been installed and
%% sort on that instead.
resort(Calls, Hooks) ->
@@ -311,6 +326,14 @@ resort(Calls, Hooks) ->
%% If priorities are equal, we check the position in the
%% hooks list
pos(Id1,Hooks) < pos(Id2,Hooks);
+ P1 == ctfirst ->
+ true;
+ P2 == ctfirst ->
+ false;
+ P1 == ctlast ->
+ false;
+ P2 == ctlast ->
+ true;
true ->
P1 < P2
end
@@ -331,7 +354,7 @@ catch_apply(M,F,A, Default) ->
catch error:Reason ->
case erlang:get_stacktrace() of
%% Return the default if it was the CTH module which did not have the function.
- [{M,F,A}|_] when Reason == undef ->
+ [{M,F,A,_}|_] when Reason == undef ->
Default;
Trace ->
ct_logs:log("Suite Hook","Call to CTH failed: ~p:~p",
diff --git a/lib/common_test/src/ct_line.erl b/lib/common_test/src/ct_line.erl
deleted file mode 100644
index 4af9da5463..0000000000
--- a/lib/common_test/src/ct_line.erl
+++ /dev/null
@@ -1,266 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2003-2009. All Rights Reserved.
-%%
-%% The contents of this file are subject to the Erlang Public License,
-%% Version 1.1, (the "License"); you may not use this file except in
-%% compliance with the License. You should have received a copy of the
-%% Erlang Public License along with this software. If not, it can be
-%% retrieved online at http://www.erlang.org/.
-%%
-%% Software distributed under the License is distributed on an "AS IS"
-%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
-%% the License for the specific language governing rights and limitations
-%% under the License.
-%%
-%% %CopyrightEnd%
-%%
-
-%%% @doc Parse transform for inserting line numbers
-
--module(ct_line).
-
--record(vars, {module, % atom() Module name
- vsn, % atom()
-
- init_info=[], % [{M,F,A,C,L}]
-
- function, % atom()
- arity, % int()
- clause, % int()
- lines, % [int()]
- depth, % int()
- is_guard=false % boolean
- }).
-
--export([parse_transform/2,
- line/1]).
-
-line(LOC={{Mod,Func},_Line}) ->
- Lines = case get(test_server_loc) of
- [{{Mod,Func},_}|Ls] ->
- Ls;
- Ls when is_list(Ls) ->
- case length(Ls) of
- 10 ->
- [_|T]=lists:reverse(Ls),
- lists:reverse(T);
- _ ->
- Ls
- end;
- _ ->
- []
- end,
- put(test_server_loc,[LOC|Lines]).
-
-parse_transform(Forms, _Options) ->
- transform(Forms, _Options).
-
-%% forms(Fs) -> lists:map(fun (F) -> form(F) end, Fs).
-
-transform(Forms, _Options)->
- Vars0 = #vars{},
- {ok, MungedForms, _Vars} = transform(Forms, [], Vars0),
- MungedForms.
-
-
-transform([Form|Forms], MungedForms, Vars) ->
- case munge(Form, Vars) of
- ignore ->
- transform(Forms, MungedForms, Vars);
- {MungedForm, Vars2} ->
- transform(Forms, [MungedForm|MungedForms], Vars2)
- end;
-transform([], MungedForms, Vars) ->
- {ok, lists:reverse(MungedForms), Vars}.
-
-%% This code traverses the abstract code, stored as the abstract_code
-%% chunk in the BEAM file, as described in absform(3) for Erlang/OTP R8B
-%% (Vsn=abstract_v2).
-%% The abstract format after preprocessing differs slightly from the abstract
-%% format given eg using epp:parse_form, this has been noted in comments.
-munge(Form={attribute,_,module,Module}, Vars) ->
- Vars2 = Vars#vars{module=Module},
- {Form, Vars2};
-
-munge({function,0,module_info,_Arity,_Clauses}, _Vars) ->
- ignore; % module_info will be added again when the forms are recompiled
-munge({function,Line,Function,Arity,Clauses}, Vars) ->
- Vars2 = Vars#vars{function=Function,
- arity=Arity,
- clause=1,
- lines=[],
- depth=1},
- {MungedClauses, Vars3} = munge_clauses(Clauses, Vars2, []),
- {{function,Line,Function,Arity,MungedClauses}, Vars3};
-munge(Form, Vars) -> % attributes
- {Form, Vars}.
-
-munge_clauses([{clause,Line,Pattern,Guards,Body}|Clauses], Vars, MClauses) ->
- {MungedGuards, _Vars} = munge_exprs(Guards, Vars#vars{is_guard=true},[]),
-
- case Vars#vars.depth of
- 1 -> % function clause
- {MungedBody, Vars2} = munge_body(Body, Vars#vars{depth=2}, []),
- ClauseInfo = {Vars2#vars.module,
- Vars2#vars.function,
- Vars2#vars.arity,
- Vars2#vars.clause,
- length(Vars2#vars.lines)},
- InitInfo = [ClauseInfo | Vars2#vars.init_info],
- Vars3 = Vars2#vars{init_info=InitInfo,
- clause=(Vars2#vars.clause)+1,
- lines=[],
- depth=1},
- munge_clauses(Clauses, Vars3,
- [{clause,Line,Pattern,MungedGuards,MungedBody}|
- MClauses]);
-
- 2 -> % receive-, case- or if clause
- {MungedBody, Vars2} = munge_body(Body, Vars, []),
- munge_clauses(Clauses, Vars2,
- [{clause,Line,Pattern,MungedGuards,MungedBody}|
- MClauses])
- end;
-munge_clauses([], Vars, MungedClauses) ->
- {lists:reverse(MungedClauses), Vars}.
-
-munge_body([Expr|Body], Vars, MungedBody) ->
- %% Here is the place to add a call to cover:bump/6!
- Line = element(2, Expr),
- Lines = Vars#vars.lines,
- case lists:member(Line,Lines) of
- true -> % already a bump at this line!
- {MungedExpr, Vars2} = munge_expr(Expr, Vars),
- munge_body(Body, Vars2, [MungedExpr|MungedBody]);
- false ->
- Bump = {call, 0, {remote,0,{atom,0,?MODULE},{atom,0,line}},
- [{tuple,0,[{tuple,0,[{atom,0,Vars#vars.module},
- {atom, 0, Vars#vars.function}]},
- {integer, 0, Line}]}]},
- Lines2 = [Line|Lines],
-
- {MungedExpr, Vars2} = munge_expr(Expr, Vars#vars{lines=Lines2}),
- munge_body(Body, Vars2, [MungedExpr,Bump|MungedBody])
- end;
-munge_body([], Vars, MungedBody) ->
- {lists:reverse(MungedBody), Vars}.
-
-munge_expr({match,Line,ExprL,ExprR}, Vars) ->
- {MungedExprL, Vars2} = munge_expr(ExprL, Vars),
- {MungedExprR, Vars3} = munge_expr(ExprR, Vars2),
- {{match,Line,MungedExprL,MungedExprR}, Vars3};
-munge_expr({tuple,Line,Exprs}, Vars) ->
- {MungedExprs, Vars2} = munge_exprs(Exprs, Vars, []),
- {{tuple,Line,MungedExprs}, Vars2};
-munge_expr({record,Line,Expr,Exprs}, Vars) ->
- %% Only for Vsn=raw_abstract_v1
- {MungedExprName, Vars2} = munge_expr(Expr, Vars),
- {MungedExprFields, Vars3} = munge_exprs(Exprs, Vars2, []),
- {{record,Line,MungedExprName,MungedExprFields}, Vars3};
-munge_expr({record_field,Line,ExprL,ExprR}, Vars) ->
- %% Only for Vsn=raw_abstract_v1
- {MungedExprL, Vars2} = munge_expr(ExprL, Vars),
- {MungedExprR, Vars3} = munge_expr(ExprR, Vars2),
- {{record_field,Line,MungedExprL,MungedExprR}, Vars3};
-munge_expr({cons,Line,ExprH,ExprT}, Vars) ->
- {MungedExprH, Vars2} = munge_expr(ExprH, Vars),
- {MungedExprT, Vars3} = munge_expr(ExprT, Vars2),
- {{cons,Line,MungedExprH,MungedExprT}, Vars3};
-munge_expr({op,Line,Op,ExprL,ExprR}, Vars) ->
- {MungedExprL, Vars2} = munge_expr(ExprL, Vars),
- {MungedExprR, Vars3} = munge_expr(ExprR, Vars2),
- {{op,Line,Op,MungedExprL,MungedExprR}, Vars3};
-munge_expr({op,Line,Op,Expr}, Vars) ->
- {MungedExpr, Vars2} = munge_expr(Expr, Vars),
- {{op,Line,Op,MungedExpr}, Vars2};
-munge_expr({'catch',Line,Expr}, Vars) ->
- {MungedExpr, Vars2} = munge_expr(Expr, Vars),
- {{'catch',Line,MungedExpr}, Vars2};
-munge_expr({call,Line1,{remote,Line2,ExprM,ExprF},Exprs},
- Vars) when Vars#vars.is_guard==false->
- {MungedExprM, Vars2} = munge_expr(ExprM, Vars),
- {MungedExprF, Vars3} = munge_expr(ExprF, Vars2),
- {MungedExprs, Vars4} = munge_exprs(Exprs, Vars3, []),
- {{call,Line1,{remote,Line2,MungedExprM,MungedExprF},MungedExprs}, Vars4};
-munge_expr({call,Line1,{remote,_Line2,_ExprM,ExprF},Exprs},
- Vars) when Vars#vars.is_guard==true ->
- %% Difference in abstract format after preprocessing: BIF calls in guards
- %% are translated to {remote,...} (which is not allowed as source form)
- %% NOT NECESSARY FOR Vsn=raw_abstract_v1
- munge_expr({call,Line1,ExprF,Exprs}, Vars);
-munge_expr({call,Line,Expr,Exprs}, Vars) ->
- {MungedExpr, Vars2} = munge_expr(Expr, Vars),
- {MungedExprs, Vars3} = munge_exprs(Exprs, Vars2, []),
- {{call,Line,MungedExpr,MungedExprs}, Vars3};
-munge_expr({lc,Line,Expr,LC}, Vars) ->
- {MungedExpr, Vars2} = munge_expr(Expr, Vars),
- {MungedLC, Vars3} = munge_lc(LC, Vars2, []),
- {{lc,Line,MungedExpr,MungedLC}, Vars3};
-munge_expr({block,Line,Body}, Vars) ->
- {MungedBody, Vars2} = munge_body(Body, Vars, []),
- {{block,Line,MungedBody}, Vars2};
-munge_expr({'if',Line,Clauses}, Vars) ->
- {MungedClauses,Vars2} = munge_clauses(Clauses, Vars, []),
- {{'if',Line,MungedClauses}, Vars2};
-munge_expr({'case',Line,Expr,Clauses}, Vars) ->
- {MungedExpr,Vars2} = munge_expr(Expr,Vars),
- {MungedClauses,Vars3} = munge_clauses(Clauses, Vars2, []),
- {{'case',Line,MungedExpr,MungedClauses}, Vars3};
-munge_expr({'receive',Line,Clauses}, Vars) ->
- {MungedClauses,Vars2} = munge_clauses(Clauses, Vars, []),
- {{'receive',Line,MungedClauses}, Vars2};
-munge_expr({'receive',Line,Clauses,Expr,Body}, Vars) ->
- {MungedClauses,Vars2} = munge_clauses(Clauses, Vars, []),
- {MungedExpr, Vars3} = munge_expr(Expr, Vars2),
- {MungedBody, Vars4} = munge_body(Body, Vars3, []),
- {{'receive',Line,MungedClauses,MungedExpr,MungedBody}, Vars4};
-munge_expr({'try',Line,Exprs,Clauses,CatchClauses}, Vars) ->
- {MungedExprs, Vars1} = munge_exprs(Exprs, Vars, []),
- {MungedClauses, Vars2} = munge_clauses(Clauses, Vars1, []),
- {MungedCatchClauses, Vars3} = munge_clauses(CatchClauses, Vars2, []),
- {{'try',Line,MungedExprs,MungedClauses,MungedCatchClauses}, Vars3};
-%% Difference in abstract format after preprocessing: Funs get an extra
-%% element Extra.
-%% NOT NECESSARY FOR Vsn=raw_abstract_v1
-munge_expr({'fun',Line,{function,Name,Arity},_Extra}, Vars) ->
- {{'fun',Line,{function,Name,Arity}}, Vars};
-munge_expr({'fun',Line,{clauses,Clauses},_Extra}, Vars) ->
- {MungedClauses,Vars2}=munge_clauses(Clauses, Vars, []),
- {{'fun',Line,{clauses,MungedClauses}}, Vars2};
-munge_expr({'fun',Line,{clauses,Clauses}}, Vars) ->
- %% Only for Vsn=raw_abstract_v1
- {MungedClauses,Vars2}=munge_clauses(Clauses, Vars, []),
- {{'fun',Line,{clauses,MungedClauses}}, Vars2};
-munge_expr(Form, Vars) -> % var|char|integer|float|string|atom|nil|bin|eof
- {Form, Vars}.
-
-munge_exprs([Expr|Exprs], Vars, MungedExprs) when Vars#vars.is_guard==true,
- is_list(Expr) ->
- {MungedExpr, _Vars} = munge_exprs(Expr, Vars, []),
- munge_exprs(Exprs, Vars, [MungedExpr|MungedExprs]);
-munge_exprs([Expr|Exprs], Vars, MungedExprs) ->
- {MungedExpr, Vars2} = munge_expr(Expr, Vars),
- munge_exprs(Exprs, Vars2, [MungedExpr|MungedExprs]);
-munge_exprs([], Vars, MungedExprs) ->
- {lists:reverse(MungedExprs), Vars}.
-
-munge_lc([{generate,Line,Pattern,Expr}|LC], Vars, MungedLC) ->
- {MungedExpr, Vars2} = munge_expr(Expr, Vars),
- munge_lc(LC, Vars2, [{generate,Line,Pattern,MungedExpr}|MungedLC]);
-munge_lc([Expr|LC], Vars, MungedLC) ->
- {MungedExpr, Vars2} = munge_expr(Expr, Vars),
- munge_lc(LC, Vars2, [MungedExpr|MungedLC]);
-munge_lc([], Vars, MungedLC) ->
- {lists:reverse(MungedLC), Vars}.
-
-
-
-
-
-
-
-
-
-
diff --git a/lib/common_test/src/ct_logs.erl b/lib/common_test/src/ct_logs.erl
index faec461775..d66a31d9a5 100644
--- a/lib/common_test/src/ct_logs.erl
+++ b/lib/common_test/src/ct_logs.erl
@@ -29,14 +29,16 @@
-module(ct_logs).
-export([init/1,close/2,init_tc/1,end_tc/1]).
--export([get_log_dir/0,log/3,start_log/1,cont_log/2,end_log/0]).
+-export([get_log_dir/0,get_log_dir/1]).
+-export([log/3,start_log/1,cont_log/2,end_log/0]).
-export([set_stylesheet/2,clear_stylesheet/1]).
-export([add_external_logs/1,add_link/3]).
-export([make_last_run_index/0]).
-export([make_all_suites_index/1,make_all_runs_index/1]).
+-export([get_ts_html_wrapper/3]).
%% Logging stuff directly from testcase
--export([tc_log/3,tc_print/3,tc_pal/3,
+-export([tc_log/3,tc_print/3,tc_pal/3,ct_log/3,
basic_html/0]).
%% Simulate logger process for use without ct environment running
@@ -53,6 +55,7 @@
-define(all_runs_name, "all_runs.html").
-define(index_name, "index.html").
-define(totals_name, "totals.info").
+-define(css_default, "ct_default.css").
-define(table_color1,"#ADD8E6").
-define(table_color2,"#E4F0FE").
@@ -162,7 +165,12 @@ clear_stylesheet(TC) ->
%%%-----------------------------------------------------------------
%%% @spec get_log_dir() -> {ok,Dir} | {error,Reason}
get_log_dir() ->
- call(get_log_dir).
+ call({get_log_dir,false}).
+
+%%%-----------------------------------------------------------------
+%%% @spec get_log_dir(ReturnAbsName) -> {ok,Dir} | {error,Reason}
+get_log_dir(ReturnAbsName) ->
+ call({get_log_dir,ReturnAbsName}).
%%%-----------------------------------------------------------------
%%% make_last_run_index() -> ok
@@ -205,6 +213,7 @@ cast(Msg) ->
%%% <p>This function is called by ct_framework:init_tc/3</p>
init_tc(RefreshLog) ->
call({init_tc,self(),group_leader(),RefreshLog}),
+ io:format(xhtml("", "<br />")),
ok.
%%%-----------------------------------------------------------------
@@ -214,6 +223,7 @@ init_tc(RefreshLog) ->
%%%
%%% <p>This function is called by ct_framework:end_tc/3</p>
end_tc(TCPid) ->
+ io:format(xhtml("<br>", "<br />")),
%% use call here so that the TC process will wait and receive
%% possible exit signals from ct_logs before end_tc returns ok
call({end_tc,TCPid}).
@@ -374,6 +384,23 @@ tc_pal(Category,Format,Args) ->
ok.
+%%%-----------------------------------------------------------------
+%%% @spec tc_pal(Category,Format,Args) -> ok
+%%% Category = atom()
+%%% Format = string()
+%%% Args = list()
+%%%
+%%% @doc Print and log to the ct framework log
+%%%
+%%% <p>This function is called by internal ct functions to
+%%% force logging to the ct framework log</p>
+ct_log(Category,Format,Args) ->
+ cast({ct_log,[{div_header(Category),[]},
+ {Format,Args},
+ {div_footer(),[]}]}),
+ ok.
+
+
%%%=================================================================
%%% Internal functions
int_header() ->
@@ -431,7 +458,6 @@ logger(Parent,Mode) ->
timer:sleep(1000),
Time1 = calendar:local_time(),
Dir1 = make_dirname(Time1),
-
{Time1,Dir1};
false ->
{Time0,Dir0}
@@ -439,8 +465,44 @@ logger(Parent,Mode) ->
%%! <---
file:make_dir(Dir),
+ AbsDir = ?abs(Dir),
+ put(ct_run_dir, AbsDir),
+
+ case basic_html() of
+ true ->
+ put(basic_html, true);
+ BasicHtml ->
+ put(basic_html, BasicHtml),
+ %% copy stylesheet to log dir (both top dir and test run
+ %% dir) so logs are independent of Common Test installation
+ {ok,Cwd} = file:get_cwd(),
+ CTPath = code:lib_dir(common_test),
+ CSSFileSrc = filename:join(filename:join(CTPath, "priv"),
+ ?css_default),
+ CSSFileDestTop = filename:join(Cwd, ?css_default),
+ CSSFileDestRun = filename:join(AbsDir, ?css_default),
+ case file:copy(CSSFileSrc, CSSFileDestTop) of
+ {error,Reason0} ->
+ io:format(user, "ERROR! "++
+ "CSS file ~p could not be copied to ~p. "++
+ "Reason: ~p~n",
+ [CSSFileSrc,CSSFileDestTop,Reason0]),
+ exit({css_file_error,CSSFileDestTop});
+ _ ->
+ case file:copy(CSSFileSrc, CSSFileDestRun) of
+ {error,Reason1} ->
+ io:format(user, "ERROR! "++
+ "CSS file ~p could not be copied to ~p. "++
+ "Reason: ~p~n",
+ [CSSFileSrc,CSSFileDestRun,Reason1]),
+ exit({css_file_error,CSSFileDestRun});
+ _ ->
+ ok
+ end
+ end
+ end,
ct_event:notify(#event{name=start_logging,node=node(),
- data=?abs(Dir)}),
+ data=AbsDir}),
make_all_runs_index(start),
make_all_suites_index(start),
case Mode of
@@ -455,7 +517,7 @@ logger(Parent,Mode) ->
Parent ! {started,self(),{Time,filename:absname("")}},
set_evmgr_gl(CtLogFd),
logger_loop(#logger_state{parent=Parent,
- log_dir=Dir,
+ log_dir=AbsDir,
start_time=Time,
orig_GL=group_leader(),
ct_log_fd=CtLogFd,
@@ -519,12 +581,15 @@ logger_loop(State) ->
set_evmgr_gl(State#logger_state.ct_log_fd),
return(From,ok),
logger_loop(State#logger_state{tc_groupleaders=rm_tc_gl(TCPid,State)});
- {get_log_dir,From} ->
+ {{get_log_dir,true},From} ->
return(From,{ok,State#logger_state.log_dir}),
logger_loop(State);
+ {{get_log_dir,false},From} ->
+ return(From,{ok,filename:basename(State#logger_state.log_dir)}),
+ logger_loop(State);
{make_last_run_index,From} ->
make_last_run_index(State#logger_state.start_time),
- return(From,State#logger_state.log_dir),
+ return(From,filename:basename(State#logger_state.log_dir)),
logger_loop(State);
{set_stylesheet,_,SSFile} when State#logger_state.stylesheet == SSFile ->
logger_loop(State);
@@ -535,7 +600,12 @@ logger_loop(State) ->
{clear_stylesheet,_} when State#logger_state.stylesheet == undefined ->
logger_loop(State);
{clear_stylesheet,_} ->
- logger_loop(State#logger_state{stylesheet=undefined});
+ logger_loop(State#logger_state{stylesheet=undefined});
+ {ct_log, List} ->
+ Fd = State#logger_state.ct_log_fd,
+ [begin io:format(Fd,Str,Args),io:nl(Fd) end ||
+ {Str,Args} <- List],
+ logger_loop(State);
stop ->
io:format(State#logger_state.ct_log_fd,
int_header()++int_footer(),
@@ -635,7 +705,7 @@ set_evmgr_gl(GL) ->
open_ctlog() ->
{ok,Fd} = file:open(?ct_log_name,[write]),
- io:format(Fd,header("Common Test Framework"),[]),
+ io:format(Fd, header("Common Test Framework Log"), []),
case file:consult(ct_run:variables_file_name("../")) of
{ok,Vars} ->
io:format(Fd, config_table(Vars), []);
@@ -650,17 +720,22 @@ open_ctlog() ->
end,
print_style(Fd,undefined),
io:format(Fd,
- "<br><br><h2>Progress Log</h2>\n"
- "<pre>\n",[]),
+ xhtml("<br><br><h2>Progress Log</h2>\n<pre>\n",
+ "<br /><br /><h4>PROGRESS LOG</h4>\n<pre>\n"), []),
Fd.
print_style(Fd,undefined) ->
- io:format(Fd,
- "<style>\n"
- "div.ct_internal { background:lightgrey; color:black }\n"
- "div.default { background:lightgreen; color:black }\n"
- "</style>\n",
- []);
+ case basic_html() of
+ true ->
+ io:format(Fd,
+ "<style>\n"
+ "div.ct_internal { background:lightgrey; color:black; }\n"
+ "div.default { background:lightgreen; color:black; }\n"
+ "</style>\n",
+ []);
+ _ ->
+ ok
+ end;
print_style(Fd,StyleSheet) ->
case file:read_file(StyleSheet) of
@@ -701,7 +776,7 @@ print_style_error(Fd,StyleSheet,Reason) ->
print_style(Fd,undefined).
close_ctlog(Fd) ->
- io:format(Fd,"</pre>",[]),
+ io:format(Fd,"\n</pre>\n",[]),
io:format(Fd,footer(),[]),
file:close(Fd).
@@ -832,8 +907,8 @@ make_one_index_entry1(SuiteName, Link, Label, Success, Fail, UserSkip, AutoSkip,
CrashDumpName = SuiteName ++ "_erl_crash.dump",
case filelib:is_file(CrashDumpName) of
true ->
- ["&nbsp;<A HREF=\"", CrashDumpName,
- "\">(CrashDump)</A>"];
+ ["&nbsp;<a href=\"", CrashDumpName,
+ "\">(CrashDump)</a>"];
false ->
""
end
@@ -847,32 +922,41 @@ make_one_index_entry1(SuiteName, Link, Label, Success, Fail, UserSkip, AutoSkip,
0 -> "-";
_ -> NodeOrDate
end,
- N = ["<TD ALIGN=right><FONT SIZE=-1>",Node1,"</FONT></TD>\n"],
- L = ["<TD ALIGN=center><FONT SIZE=-1><B>",Label,"</FONT></B></TD>\n"],
- T = ["<TD><FONT SIZE=-1>",timestamp(CtRunDir),"</FONT></TD>\n"],
+ TS = timestamp(CtRunDir),
+ N = xhtml(["<td align=right><font size=\"-1\">",Node1,
+ "</font></td>\n"],
+ ["<td align=right>",Node1,"</td>\n"]),
+ L = xhtml(["<td align=center><font size=\"-1\"><b>",Label,
+ "</font></b></td>\n"],
+ ["<td align=center><b>",Label,"</b></td>\n"]),
+ T = xhtml(["<td><font size=\"-1\">",TS,"</font></td>\n"],
+ ["<td>",TS,"</td>\n"]),
CtLogFile = filename:join(CtRunDir,?ct_log_name),
OldRunsLink =
case OldRuns of
[] -> "none";
- _ -> "<A HREF=\""++?all_runs_name++"\">Old Runs</A>"
+ _ -> "<a href=\""++?all_runs_name++"\">Old Runs</a>"
end,
- A=["<TD><FONT SIZE=-1><A HREF=\"",CtLogFile,"\">CT Log</A></FONT></TD>\n",
- "<TD><FONT SIZE=-1>",OldRunsLink,"</FONT></TD>\n"],
+ A = xhtml(["<td><font size=\"-1\"><a href=\"",CtLogFile,
+ "\">CT Log</a></font></td>\n",
+ "<td><font size=\"-1\">",OldRunsLink,"</font></td>\n"],
+ ["<td><a href=\"",CtLogFile,"\">CT Log</a></td>\n",
+ "<td>",OldRunsLink,"</td>\n"]),
{L,T,N,A};
false ->
{"","","",""}
end,
NotBuiltStr =
if NotBuilt == 0 ->
- ["<TD ALIGN=right>",integer_to_list(NotBuilt),"</TD>\n"];
+ ["<td align=right>",integer_to_list(NotBuilt),"</td>\n"];
true ->
- ["<TD ALIGN=right><A HREF=\"",filename:join(CtRunDir,?ct_log_name),"\">",
- integer_to_list(NotBuilt),"</A></TD>\n"]
+ ["<td align=right><a href=\"",filename:join(CtRunDir,?ct_log_name),"\">",
+ integer_to_list(NotBuilt),"</a></td>\n"]
end,
FailStr =
if Fail > 0 ->
- ["<FONT color=\"red\">",
- integer_to_list(Fail),"</FONT>"];
+ ["<font color=\"red\">",
+ integer_to_list(Fail),"</font>"];
true ->
integer_to_list(Fail)
end,
@@ -880,31 +964,33 @@ make_one_index_entry1(SuiteName, Link, Label, Success, Fail, UserSkip, AutoSkip,
if AutoSkip == undefined -> {UserSkip,"?","?"};
true ->
ASStr = if AutoSkip > 0 ->
- ["<FONT color=\"brown\">",
- integer_to_list(AutoSkip),"</FONT>"];
+ ["<font color=\"brown\">",
+ integer_to_list(AutoSkip),"</font>"];
true -> integer_to_list(AutoSkip)
end,
{UserSkip+AutoSkip,integer_to_list(UserSkip),ASStr}
end,
- ["<TR valign=top>\n",
- "<TD><FONT SIZE=-1><A HREF=\"",LogFile,"\">",SuiteName,"</A>",CrashDumpLink,"</FONT></TD>\n",
- Lbl,
- Timestamp,
- "<TD ALIGN=right>",integer_to_list(Success),"</TD>\n",
- "<TD ALIGN=right>",FailStr,"</TD>\n",
- "<TD ALIGN=right>",integer_to_list(AllSkip),
- " (",UserSkipStr,"/",AutoSkipStr,")</TD>\n",
- NotBuiltStr,
- Node,
- AllInfo,
- "</TR>\n"].
+ [xhtml("<tr valign=top>\n",
+ ["<tr class=\"",odd_or_even(),"\">\n"]),
+ xhtml("<td><font size=\"-1\"><a href=\"", "<td><a href=\""),
+ LogFile,"\">",SuiteName,"</a>", CrashDumpLink,
+ xhtml("</font></td>\n", "</td>\n"),
+ Lbl, Timestamp,
+ "<td align=right>",integer_to_list(Success),"</td>\n",
+ "<td align=right>",FailStr,"</td>\n",
+ "<td align=right>",integer_to_list(AllSkip),
+ " (",UserSkipStr,"/",AutoSkipStr,")</td>\n",
+ NotBuiltStr, Node, AllInfo, "</tr>\n"].
+
total_row(Success, Fail, UserSkip, AutoSkip, NotBuilt, All) ->
{Label,TimestampCell,AllInfo} =
case All of
true ->
- {"<TD>&nbsp;</TD>\n",
- "<TD>&nbsp;</TD>\n",
- "<TD>&nbsp;</TD>\n<TD>&nbsp;</TD>\n"};
+ {"<td>&nbsp;</td>\n",
+ "<td>&nbsp;</td>\n",
+ "<td>&nbsp;</td>\n"
+ "<td>&nbsp;</td>\n"
+ "<td>&nbsp;</td>\n"};
false ->
{"","",""}
end,
@@ -914,17 +1000,15 @@ total_row(Success, Fail, UserSkip, AutoSkip, NotBuilt, All) ->
true -> {UserSkip+AutoSkip,
integer_to_list(UserSkip),integer_to_list(AutoSkip)}
end,
- ["<TR valign=top>\n",
- "<TD><B>Total</B></TD>",
- Label,
- TimestampCell,
- "<TD ALIGN=right><B>",integer_to_list(Success),"<B></TD>\n",
- "<TD ALIGN=right><B>",integer_to_list(Fail),"<B></TD>\n",
- "<TD ALIGN=right>",integer_to_list(AllSkip),
- " (",UserSkipStr,"/",AutoSkipStr,")</TD>\n",
- "<TD ALIGN=right><B>",integer_to_list(NotBuilt),"<B></TD>\n",
- AllInfo,
- "</TR>\n"].
+ [xhtml("<tr valign=top>\n",
+ ["<tr class=\"",odd_or_even(),"\">\n"]),
+ "<td><b>Total</b></td>\n", Label, TimestampCell,
+ "<td align=right><b>",integer_to_list(Success),"<b></td>\n",
+ "<td align=right><b>",integer_to_list(Fail),"<b></td>\n",
+ "<td align=right>",integer_to_list(AllSkip),
+ " (",UserSkipStr,"/",AutoSkipStr,")</td>\n",
+ "<td align=right><b>",integer_to_list(NotBuilt),"<b></td>\n",
+ AllInfo, "</tr>\n"].
not_built(_BaseName,_LogDir,_All,[]) ->
0;
@@ -983,41 +1067,52 @@ index_header(Label, StartTime) ->
undefined ->
header("Test Results", format_time(StartTime));
_ ->
- header("Test Results for \"" ++ Label ++ "\"",
+ header("Test Results for '" ++ Label ++ "'",
format_time(StartTime))
end,
[Head |
- ["<CENTER>\n",
- "<P><A HREF=\"",?ct_log_name,"\">Common Test Framework Log</A></P>",
- "<TABLE border=\"3\" cellpadding=\"5\" "
- "BGCOLOR=\"",?table_color3,"\">\n"
- "<th><B>Test Name</B></th>\n",
- "<th><font color=\"",?table_color3,"\">_</font>Ok"
- "<font color=\"",?table_color3,"\">_</font></th>\n"
+ ["<center>\n",
+ xhtml(["<p><a href=\"",?ct_log_name,
+ "\">Common Test Framework Log</a></p>"],
+ ["<br />"
+ "<div id=\"button_holder\" class=\"btn\">\n"
+ "<a href=\"",?ct_log_name,
+ "\">COMMON TEST FRAMEWORK LOG</a>\n</div>"]),
+ xhtml("<br>\n", "<br /><br /><br />\n"),
+ xhtml(["<table border=\"3\" cellpadding=\"5\" "
+ "bgcolor=\"",?table_color3,"\">\n"], "<table>\n"),
+ "<th><b>Test Name</b></th>\n",
+ xhtml(["<th><font color=\"",?table_color3,"\">_</font>Ok"
+ "<font color=\"",?table_color3,"\">_</font></th>\n"],
+ "<th>Ok</th>\n"),
"<th>Failed</th>\n",
- "<th>Skipped<br>(User/Auto)</th>\n"
- "<th>Missing<br>Suites</th>\n"
+ "<th>Skipped", xhtml("<br>", "<br />"), "(User/Auto)</th>\n"
+ "<th>Missing", xhtml("<br>", "<br />"), "Suites</th>\n"
"\n"]].
-
all_suites_index_header() ->
{ok,Cwd} = file:get_cwd(),
all_suites_index_header(Cwd).
all_suites_index_header(IndexDir) ->
LogDir = filename:basename(IndexDir),
- AllRuns = "All test runs in \"" ++ LogDir ++ "\"",
+ AllRuns = xhtml(["All test runs in \"" ++ LogDir ++ "\""],
+ "ALL RUNS"),
+ AllRunsLink = xhtml(["<a href=\"",?all_runs_name,"\">",AllRuns,"</a>\n"],
+ ["<div id=\"button_holder\" class=\"btn\">\n"
+ "<a href=\"",?all_runs_name,"\">",AllRuns,"</a>\n</div>"]),
[header("Test Results") |
- ["<CENTER>\n",
- "<A HREF=\"",?all_runs_name,"\">",AllRuns,"</A>\n",
- "<br><br>\n",
- "<TABLE border=\"3\" cellpadding=\"5\" "
- "BGCOLOR=\"",?table_color2,"\">\n"
+ ["<center>\n",
+ AllRunsLink,
+ xhtml("<br><br>\n", "<br /><br />\n"),
+ xhtml(["<table border=\"3\" cellpadding=\"5\" "
+ "bgcolor=\"",?table_color2,"\">\n"], "<table>\n"),
"<th>Test Name</th>\n",
"<th>Label</th>\n",
"<th>Test Run Started</th>\n",
- "<th><font color=\"",?table_color2,"\">_</font>Ok"
- "<font color=\"",?table_color2,"\">_</font></th>\n"
+ xhtml(["<th><font color=\"",?table_color2,"\">_</font>Ok"
+ "<font color=\"",?table_color2,"\">_</font></th>\n"],
+ "<th>Ok</th>\n"),
"<th>Failed</th>\n",
"<th>Skipped<br>(User/Auto)</th>\n"
"<th>Missing<br>Suites</th>\n"
@@ -1030,17 +1125,25 @@ all_runs_header() ->
{ok,Cwd} = file:get_cwd(),
LogDir = filename:basename(Cwd),
Title = "All test runs in \"" ++ LogDir ++ "\"",
+ IxLink = [xhtml(["<p><a href=\"",?index_name,
+ "\">Test Index Page</a></p>"],
+ ["<div id=\"button_holder\" class=\"btn\">\n"
+ "<a href=\"",?index_name,
+ "\">TEST INDEX PAGE</a>\n</div>"]),
+ xhtml("<br>\n", "<br /><br />\n")],
[header(Title) |
- ["<CENTER><TABLE border=\"3\" cellpadding=\"5\" "
- "BGCOLOR=\"",?table_color1,"\">\n"
- "<th><B>History</B></th>\n"
- "<th><B>Node</B></th>\n"
- "<th><B>Label</B></th>\n"
+ ["<center>\n", IxLink,
+ xhtml(["<table border=\"3\" cellpadding=\"5\" "
+ "bgcolor=\"",?table_color1,"\">\n"], "<table>\n"),
+ "<th><b>History</b></th>\n"
+ "<th><b>Node</b></th>\n"
+ "<th><b>Label</b></th>\n"
"<th>Tests</th>\n"
- "<th><B>Test Names</B></th>\n"
- "<th>Total</th>\n"
- "<th><font color=\"",?table_color1,"\">_</font>Ok"
- "<font color=\"",?table_color1,"\">_</font></th>\n"
+ "<th><b>Test Names</b></th>\n"
+ "<th>Total</th>\n",
+ xhtml(["<th><font color=\"",?table_color1,"\">_</font>Ok"
+ "<font color=\"",?table_color1,"\">_</font></th>\n"],
+ "<th>Ok</th>\n"),
"<th>Failed</th>\n"
"<th>Skipped<br>(User/Auto)</th>\n"
"<th>Missing<br>Suites</th>\n"
@@ -1053,60 +1156,56 @@ header(Title, SubTitle) ->
header1(Title, SubTitle) ->
SubTitleHTML = if SubTitle =/= "" ->
- ["<CENTER>\n",
- "<H2>" ++ SubTitle ++ "</H2>\n",
- "</CENTER>\n<BR>\n"];
- true -> "<BR>\n"
+ ["<center>\n",
+ "<h3>" ++ SubTitle ++ "</h3>\n",
+ xhtml("</center>\n<br>\n", "</center>\n<br />\n")];
+ true -> xhtml("<br>\n", "<br />\n")
end,
- ["<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 3.2 Final//EN\">\n"
- "<!-- autogenerated by '"++atom_to_list(?MODULE)++"'. -->\n"
- "<HTML>\n",
- "<HEAD>\n",
-
- "<TITLE>" ++ Title ++ " " ++ SubTitle ++ "</TITLE>\n",
- "<META HTTP-EQUIV=\"CACHE-CONTROL\" CONTENT=\"NO-CACHE\">\n",
-
- "</HEAD>\n",
-
- body_tag(),
-
- "<!-- ---- DOCUMENT TITLE ---- -->\n",
-
- "<CENTER>\n",
- "<H1>" ++ Title ++ "</H1>\n",
- "</CENTER>\n",
- SubTitleHTML,
-
- "<!-- ---- CONTENT ---- -->\n"].
+ CSSFile = xhtml(fun() -> "" end,
+ fun() -> make_relative(locate_default_css_file()) end),
+ [xhtml(["<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 3.2 Final//EN\">\n",
+ "<html>\n"],
+ ["<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"\n",
+ "\"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n",
+ "<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">\n"]),
+ "<!-- autogenerated by '"++atom_to_list(?MODULE)++"' -->\n",
+ "<head>\n",
+ "<title>" ++ Title ++ " " ++ SubTitle ++ "</title>\n",
+ "<meta http-equiv=\"cache-control\" content=\"no-cache\">\n",
+ xhtml("",
+ ["<link rel=\"stylesheet\" href=\"",CSSFile,"\" type=\"text/css\">"]),
+ "</head>\n",
+ body_tag(),
+ "<center>\n",
+ "<h1>" ++ Title ++ "</h1>\n",
+ "</center>\n",
+ SubTitleHTML,"\n"].
index_footer() ->
- ["</TABLE>\n"
- "</CENTER>\n" | footer()].
+ ["</table>\n"
+ "</center>\n" | footer()].
footer() ->
- ["<P><CENTER>\n"
- "<BR><BR>\n"
- "<HR>\n"
- "<P><FONT SIZE=-1>\n"
+ ["<center>\n",
+ xhtml("<br><br>\n<hr>\n", "<br /><br />\n"),
+ xhtml("<p><font size=\"-1\">\n", "<div class=\"copyright\">"),
"Copyright &copy; ", year(),
- " <A HREF=\"http://erlang.ericsson.se\">Open Telecom Platform</A><BR>\n"
- "Updated: <!date>", current_time(), "<!/date><BR>\n"
- "</FONT>\n"
- "</CENTER>\n"
+ " <a href=\"http://www.erlang.org\">Open Telecom Platform</a>",
+ xhtml("<br>\n", "<br />\n"),
+ "Updated: <!date>", current_time(), "<!/date>",
+ xhtml("<br>\n", "<br />\n"),
+ xhtml("</font></p>\n", "</div>\n"),
+ "</center>\n"
"</body>\n"].
body_tag() ->
- case basic_html() of
- true ->
- "<body bgcolor=\"#FFFFFF\" text=\"#000000\" link=\"#0000FF\" "
- "vlink=\"#800080\" alink=\"#FF0000\">\n";
- false ->
- CTPath = code:lib_dir(common_test),
- TileFile = filename:join(filename:join(CTPath,"priv"),"tile1.jpg"),
- "<body background=\"" ++ TileFile ++ "\" bgcolor=\"#FFFFFF\" text=\"#000000\" link=\"#0000FF\" "
- "vlink=\"#800080\" alink=\"#FF0000\">\n"
- end.
+ CTPath = code:lib_dir(common_test),
+ TileFile = filename:join(filename:join(CTPath,"priv"),"tile1.jpg"),
+ xhtml("<body background=\"" ++ TileFile ++
+ "\" bgcolor=\"#FFFFFF\" text=\"#000000\" link=\"#0000FF\" "
+ "vlink=\"#800080\" alink=\"#FF0000\">\n",
+ "<body>\n").
current_time() ->
format_time(calendar:local_time()).
@@ -1236,20 +1335,25 @@ config_table(Vars) ->
[config_table_header()|config_table1(Vars)].
config_table_header() ->
- ["<h2>Configuration</h2>\n",
- "<table border=\"3\" cellpadding=\"5\" bgcolor=\"",?table_color1,
- "\"\n",
+ [
+ xhtml(["<h2>Configuration</h2>\n"
+ "<table border=\"3\" cellpadding=\"5\" bgcolor=\"",?table_color1,"\"\n"],
+ "<h4>CONFIGURATION</h4>\n<table>\n"),
"<tr><th>Key</th><th>Value</th></tr>\n"].
config_table1([{Key,Value}|Vars]) ->
- ["<tr><td>", atom_to_list(Key), "</td>\n",
- "<td><pre>",io_lib:format("~p",[Value]),"</pre></td></tr>\n" |
+ [xhtml(["<tr><td>", atom_to_list(Key), "</td>\n",
+ "<td><pre>",io_lib:format("~p",[Value]),"</pre></td></tr>\n"],
+ ["<tr class=\"", odd_or_even(), "\">\n",
+ "<td>", atom_to_list(Key), "</td>\n",
+ "<td>", io_lib:format("~p",[Value]), "</td>\n</tr>\n"]) |
config_table1(Vars)];
config_table1([]) ->
["</table>\n"].
make_all_runs_index(When) ->
+ put(basic_html, basic_html()),
AbsName = ?abs(?all_runs_name),
notify_and_lock_file(AbsName),
if When == start -> ok;
@@ -1258,8 +1362,7 @@ make_all_runs_index(When) ->
Dirs = filelib:wildcard(logdir_prefix()++"*.*"),
DirsSorted = (catch sort_all_runs(Dirs)),
Header = all_runs_header(),
- BasicHtml = basic_html(),
- Index = [runentry(Dir, BasicHtml) || Dir <- DirsSorted],
+ Index = [runentry(Dir) || Dir <- DirsSorted],
Result = file:write_file(AbsName,Header++Index++index_footer()),
if When == start -> ok;
true -> io:put_chars("done\n")
@@ -1287,22 +1390,22 @@ sort_all_runs(Dirs) ->
interactive_link() ->
[Dir|_] = lists:reverse(filelib:wildcard(logdir_prefix()++"*.*")),
CtLog = filename:join(Dir,"ctlog.html"),
- Body = ["Log from last interactive run: <A HREF=\"",CtLog,"\">",
- timestamp(Dir),"</A>"],
+ Body = ["Log from last interactive run: <a href=\"",CtLog,"\">",
+ timestamp(Dir),"</a>"],
file:write_file("last_interactive.html",Body),
io:format("~n~nUpdated ~s\n"
"Any CT activities will be logged here\n",
[?abs("last_interactive.html")]).
-runentry(Dir, BasicHtml) ->
+runentry(Dir) ->
TotalsFile = filename:join(Dir,?totals_name),
TotalsStr =
case read_totals_file(TotalsFile) of
{Node,Label,Logs,{TotSucc,TotFail,UserSkip,AutoSkip,NotBuilt}} ->
TotFailStr =
if TotFail > 0 ->
- ["<FONT color=\"red\">",
- integer_to_list(TotFail),"</FONT>"];
+ ["<font color=\"red\">",
+ integer_to_list(TotFail),"</font>"];
true ->
integer_to_list(TotFail)
end,
@@ -1310,8 +1413,8 @@ runentry(Dir, BasicHtml) ->
if AutoSkip == undefined -> {UserSkip,"?","?"};
true ->
ASStr = if AutoSkip > 0 ->
- ["<FONT color=\"brown\">",
- integer_to_list(AutoSkip),"</FONT>"];
+ ["<font color=\"brown\">",
+ integer_to_list(AutoSkip),"</font>"];
true -> integer_to_list(AutoSkip)
end,
{UserSkip+AutoSkip,integer_to_list(UserSkip),ASStr}
@@ -1343,30 +1446,49 @@ runentry(Dir, BasicHtml) ->
lists:flatten(io_lib:format("~s...",[Trunc]))
end,
Total = TotSucc+TotFail+AllSkip,
- A = ["<TD ALIGN=center><FONT SIZE=-1>",Node,"</FONT></TD>\n",
- "<TD ALIGN=center><FONT SIZE=-1><B>",Label,"</B></FONT></TD>\n",
- "<TD ALIGN=right>",NoOfTests,"</TD>\n"],
- B = if BasicHtml ->
- ["<TD ALIGN=center><FONT SIZE=-1>",TestNamesTrunc,"</FONT></TD>\n"];
- true ->
- ["<TD ALIGN=center TITLE='",TestNames,"'><FONT SIZE=-1> ",
- TestNamesTrunc,"</FONT></TD>\n"]
- end,
- C = ["<TD ALIGN=right>",integer_to_list(Total),"</TD>\n",
- "<TD ALIGN=right>",integer_to_list(TotSucc),"</TD>\n",
- "<TD ALIGN=right>",TotFailStr,"</TD>\n",
- "<TD ALIGN=right>",integer_to_list(AllSkip),
- " (",UserSkipStr,"/",AutoSkipStr,")</TD>\n",
- "<TD ALIGN=right>",integer_to_list(NotBuilt),"</TD>\n"],
+ A = xhtml(["<td align=center><font size=\"-1\">",Node,
+ "</font></td>\n",
+ "<td align=center><font size=\"-1\"><b>",Label,
+ "</b></font></td>\n",
+ "<td align=right>",NoOfTests,"</td>\n"],
+ ["<td align=center>",Node,"</td>\n",
+ "<td align=center><b>",Label,"</b></td>\n",
+ "<td align=right>",NoOfTests,"</td>\n"]),
+ B = xhtml(["<td align=center title='",TestNames,"'><font size=\"-1\"> ",
+ TestNamesTrunc,"</font></td>\n"],
+ ["<td align=center title='",TestNames,"'> ",
+ TestNamesTrunc,"</td>\n"]),
+ C = ["<td align=right>",integer_to_list(Total),"</td>\n",
+ "<td align=right>",integer_to_list(TotSucc),"</td>\n",
+ "<td align=right>",TotFailStr,"</td>\n",
+ "<td align=right>",integer_to_list(AllSkip),
+ " (",UserSkipStr,"/",AutoSkipStr,")</td>\n",
+ "<td align=right>",integer_to_list(NotBuilt),"</td>\n"],
A++B++C;
_ ->
- ["<TD ALIGN=center><FONT size=-1 color=\"red\">",
- "Test data missing or corrupt","</FONT></TD>\n"]
+ A = xhtml(["<td align=center><font size=\"-1\" color=\"red\">"
+ "Test data missing or corrupt</font></td>\n",
+ "<td align=center><font size=\"-1\">?</font></td>\n",
+ "<td align=right>?</td>\n"],
+ ["<td align=center><font color=\"red\">"
+ "Test data missing or corrupt</font></td>\n",
+ "<td align=center>?</td>\n",
+ "<td align=right>?</td>\n"]),
+ B = xhtml(["<td align=center><font size=\"-1\">?</font></td>\n"],
+ ["<td align=center>?</td>\n"]),
+ C = ["<td align=right>?</td>\n",
+ "<td align=right>?</td>\n",
+ "<td align=right>?</td>\n",
+ "<td align=right>?</td>\n",
+ "<td align=right>?</td>\n"],
+ A++B++C
end,
Index = filename:join(Dir,?index_name),
- ["<TR>\n"
- "<TD><FONT SIZE=-1><A HREF=\"",Index,"\">",timestamp(Dir),"</A>",TotalsStr,"</FONT></TD>\n"
- "</TR>\n"].
+ [xhtml("<tr>\n", ["<tr class=\"",odd_or_even(),"\">\n"]),
+ xhtml(["<td><font size=\"-1\"><a href=\"",Index,"\">",timestamp(Dir),"</a>",
+ TotalsStr,"</font></td>\n"],
+ ["<td><a href=\"",Index,"\">",timestamp(Dir),"</a>",TotalsStr,"</td>\n"]),
+ "</tr>\n"].
write_totals_file(Name,Label,Logs,Totals) ->
AbsName = ?abs(Name),
@@ -1460,6 +1582,7 @@ timestamp(Dir) ->
%% Creates the top level index file. When == start | refresh.
%% A copy of the dir tree under logdir is cached as a result.
make_all_suites_index(When) when is_atom(When) ->
+ put(basic_html, basic_html()),
AbsIndexName = ?abs(?index_name),
notify_and_lock_file(AbsIndexName),
LogDirs = filelib:wildcard(logdir_prefix()++".*/*"++?logdir_ext),
@@ -1471,6 +1594,7 @@ make_all_suites_index(When) when is_atom(When) ->
%% This updates the top level index file using cached data from
%% the initial index file creation.
make_all_suites_index(NewTestData = {_TestName,DirName}) ->
+ put(basic_html, basic_html()),
%% AllLogDirs = [{TestName,Label,Missing,{LastLogDir,Summary},OldDirs}|...]
{AbsIndexName,LogDirData} = ct_util:get_testdata(test_index),
@@ -1828,6 +1952,38 @@ last_test([], Latest) ->
Latest.
%%%-----------------------------------------------------------------
+%%% @spec xhtml(HTML, XHTML) -> HTML | XHTML
+%%%
+%%% @doc
+%%%
+xhtml(HTML, XHTML) when is_function(HTML),
+ is_function(XHTML) ->
+ case get(basic_html) of
+ true -> HTML();
+ _ -> XHTML()
+ end;
+xhtml(HTML, XHTML) ->
+ case get(basic_html) of
+ true -> HTML;
+ _ -> XHTML
+ end.
+
+%%%-----------------------------------------------------------------
+%%% @spec odd_or_even() -> "odd" | "even"
+%%%
+%%% @doc
+%%%
+odd_or_even() ->
+ case get(odd_or_even) of
+ even ->
+ put(odd_or_even, odd),
+ "even";
+ _ ->
+ put(odd_or_even, even),
+ "odd"
+ end.
+
+%%%-----------------------------------------------------------------
%%% @spec basic_html() -> true | false
%%%
%%% @doc
@@ -1839,3 +1995,149 @@ basic_html() ->
_ ->
false
end.
+
+%%%-----------------------------------------------------------------
+%%% @spec locate_default_css_file() -> CSSFile
+%%%
+%%% @doc
+%%%
+locate_default_css_file() ->
+ {ok,CWD} = file:get_cwd(),
+ CSSFileInCwd = filename:join(CWD, ?css_default),
+ case filelib:is_file(CSSFileInCwd) of
+ true ->
+ CSSFileInCwd;
+ false ->
+ CSSResultFile =
+ case {whereis(?MODULE),self()} of
+ {Self,Self} ->
+ %% executed on the ct_logs process
+ filename:join(get(ct_run_dir), ?css_default);
+ _ ->
+ %% executed on other process than ct_logs
+ {ok,RunDir} = get_log_dir(true),
+ filename:join(RunDir, ?css_default)
+ end,
+ case filelib:is_file(CSSResultFile) of
+ true ->
+ CSSResultFile;
+ false ->
+ %% last resort, try use css file in CT installation
+ CTPath = code:lib_dir(common_test),
+ filename:join(filename:join(CTPath, "priv"), ?css_default)
+ end
+ end.
+
+%%%-----------------------------------------------------------------
+%%% @spec make_relative(AbsDir, Cwd) -> RelDir
+%%%
+%%% @doc Return directory path to File (last element of AbsDir), which
+%%% is the path relative to Cwd. Examples when Cwd == "/ldisk/test/logs":
+%%% make_relative("/ldisk/test/logs/run/trace.log") -> "run/trace.log"
+%%% make_relative("/ldisk/test/trace.log") -> "../trace.log"
+%%% make_relative("/ldisk/test/logs/trace.log") -> "trace.log"
+make_relative(AbsDir) ->
+ {ok,Cwd} = file:get_cwd(),
+ make_relative(AbsDir, Cwd).
+
+make_relative(AbsDir, Cwd) ->
+ DirTokens = filename:split(AbsDir),
+ CwdTokens = filename:split(Cwd),
+ filename:join(make_relative1(DirTokens, CwdTokens)).
+
+make_relative1([T | DirTs], [T | CwdTs]) ->
+ make_relative1(DirTs, CwdTs);
+make_relative1(Last = [_File], []) ->
+ Last;
+make_relative1(Last = [_File], CwdTs) ->
+ Ups = ["../" || _ <- CwdTs],
+ Ups ++ Last;
+make_relative1(DirTs, []) ->
+ DirTs;
+make_relative1(DirTs, CwdTs) ->
+ Ups = ["../" || _ <- CwdTs],
+ Ups ++ DirTs.
+
+%%%-----------------------------------------------------------------
+%%% @spec get_ts_html_wrapper(TestName, PrintLabel, Cwd) -> {Mode,Header,Footer}
+%%%
+%%% @doc
+%%%
+get_ts_html_wrapper(TestName, PrintLabel, Cwd) ->
+ TestName1 = if is_list(TestName) ->
+ lists:flatten(TestName);
+ true ->
+ lists:flatten(io_lib:format("~p", [TestName]))
+ end,
+ Basic = basic_html(),
+ LabelStr =
+ if not PrintLabel ->
+ "";
+ true ->
+ case {Basic,application:get_env(common_test, test_label)} of
+ {true,{ok,Lbl}} when Lbl =/= undefined ->
+ "<h1><font color=\"green\">" ++ Lbl ++ "</font></h1>\n";
+ {_,{ok,Lbl}} when Lbl =/= undefined ->
+ "<div class=\"label\">'" ++ Lbl ++ "'</div>\n";
+ _ ->
+ ""
+ end
+ end,
+ CTPath = code:lib_dir(common_test),
+ {ok,CtLogdir} = get_log_dir(true),
+ AllRuns = make_relative(filename:join(filename:dirname(CtLogdir),
+ ?all_runs_name), Cwd),
+ TestIndex = make_relative(filename:join(filename:dirname(CtLogdir),
+ ?index_name), Cwd),
+ case Basic of
+ true ->
+ TileFile = filename:join(filename:join(CTPath,"priv"),"tile1.jpg"),
+ Bgr = " background=\"" ++ TileFile ++ "\"",
+ Copyright =
+ ["<p><font size=\"-1\">\n",
+ "Copyright &copy; ", year(),
+ " <a href=\"http://www.erlang.org\">",
+ "Open Telecom Platform</a><br>\n",
+ "Updated: <!date>", current_time(), "<!/date>",
+ "<br>\n</font></p>\n"],
+ {basic_html,
+ ["<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 3.2 Final//EN\">\n",
+ "<html>\n",
+ "<head><title>", TestName1, "</title>\n",
+ "<meta http-equiv=\"cache-control\" content=\"no-cache\">\n",
+ "</head>\n",
+ "<body", Bgr, " bgcolor=\"white\" text=\"black\" ",
+ "link=\"blue\" vlink=\"purple\" alink=\"red\">\n",
+ LabelStr, "\n"],
+ ["<center>\n<br><hr><p>\n",
+ "<a href=\"", AllRuns,
+ "\">Test run history\n</a> | ",
+ "<a href=\"", TestIndex,
+ "\">Top level test index\n</a>\n</p>\n",
+ Copyright,"</center>\n</body>\n</html>\n"]};
+ _ ->
+ Copyright =
+ ["<div class=\"copyright\">",
+ "Copyright &copy; ", year(),
+ " <a href=\"http://www.erlang.org\">",
+ "Open Telecom Platform</a><br />\n",
+ "Updated: <!date>", current_time(), "<!/date>",
+ "<br />\n</div>\n"],
+ CSSFile = xhtml(fun() -> "" end,
+ fun() -> make_relative(locate_default_css_file(), Cwd) end),
+ {xhtml,
+ ["<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"\n",
+ "\"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n",
+ "<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">\n",
+ "<head>\n<title>", TestName1, "</title>\n",
+ "<meta http-equiv=\"cache-control\" content=\"no-cache\">\n",
+ "<link rel=\"stylesheet\" href=\"", CSSFile, "\" type=\"text/css\">",
+ "</head>\n","<body>\n",
+ LabelStr, "\n"],
+ ["<center>\n<br /><hr /><p>\n",
+ "<a href=\"", AllRuns,
+ "\">Test run history\n</a> | ",
+ "<a href=\"", TestIndex,
+ "\">Top level test index\n</a>\n</p>\n",
+ Copyright,"</center>\n</body>\n</html>\n"]}
+ end.
diff --git a/lib/common_test/src/ct_run.erl b/lib/common_test/src/ct_run.erl
index 26ca4f3cb4..0a9bb5af67 100644
--- a/lib/common_test/src/ct_run.erl
+++ b/lib/common_test/src/ct_run.erl
@@ -57,6 +57,7 @@
config = [],
event_handlers = [],
ct_hooks = [],
+ enable_builtin_hooks = true,
include = [],
silent_connections,
stylesheet,
@@ -179,6 +180,10 @@ script_start1(Parent, Args) ->
end, false, Args),
EvHandlers = event_handler_args2opts(Args),
CTHooks = ct_hooks_args2opts(Args),
+ EnableBuiltinHooks = get_start_opt(enable_builtin_hooks,
+ fun([CT]) -> list_to_atom(CT);
+ ([]) -> true
+ end, true, Args),
%% check flags and set corresponding application env variables
@@ -245,6 +250,7 @@ script_start1(Parent, Args) ->
logdir = LogDir, logopts = LogOpts,
event_handlers = EvHandlers,
ct_hooks = CTHooks,
+ enable_builtin_hooks = EnableBuiltinHooks,
include = IncludeDirs,
silent_connections = SilentConns,
stylesheet = Stylesheet,
@@ -325,6 +331,11 @@ script_start2(StartOpts = #opts{vts = undefined,
AllCTHooks = merge_vals(
[StartOpts#opts.ct_hooks,
SpecStartOpts#opts.ct_hooks]),
+
+ EnableBuiltinHooks =
+ choose_val(
+ StartOpts#opts.enable_builtin_hooks,
+ SpecStartOpts#opts.enable_builtin_hooks),
AllInclude = merge_vals([StartOpts#opts.include,
SpecStartOpts#opts.include]),
@@ -339,6 +350,8 @@ script_start2(StartOpts = #opts{vts = undefined,
config = SpecStartOpts#opts.config,
event_handlers = AllEvHs,
ct_hooks = AllCTHooks,
+ enable_builtin_hooks =
+ EnableBuiltinHooks,
include = AllInclude,
multiply_timetraps = MultTT,
scale_timetraps = ScaleTT}}
@@ -355,9 +368,7 @@ script_start2(StartOpts = #opts{vts = undefined,
{[],_} ->
{error,no_testspec_specified};
{undefined,_} -> % no testspec used
- case check_and_install_configfiles(InitConfig, TheLogDir,
- Opts#opts.event_handlers,
- Opts#opts.ct_hooks) of
+ case check_and_install_configfiles(InitConfig, TheLogDir, Opts) of
ok -> % go on read tests from start flags
script_start3(Opts#opts{config=InitConfig,
logdir=TheLogDir}, Args);
@@ -367,9 +378,7 @@ script_start2(StartOpts = #opts{vts = undefined,
{_,_} -> % testspec used
%% merge config from start flags with config from testspec
AllConfig = merge_vals([InitConfig, Opts#opts.config]),
- case check_and_install_configfiles(AllConfig, TheLogDir,
- Opts#opts.event_handlers,
- Opts#opts.ct_hooks) of
+ case check_and_install_configfiles(AllConfig, TheLogDir, Opts) of
ok -> % read tests from spec
{Run,Skip} = ct_testspec:prepare_tests(Terms, node()),
do_run(Run, Skip, Opts#opts{config=AllConfig,
@@ -383,9 +392,7 @@ script_start2(StartOpts, Args) ->
%% read config/userconfig from start flags
InitConfig = ct_config:prepare_config_list(Args),
LogDir = which(logdir, StartOpts#opts.logdir),
- case check_and_install_configfiles(InitConfig, LogDir,
- StartOpts#opts.event_handlers,
- StartOpts#opts.ct_hooks) of
+ case check_and_install_configfiles(InitConfig, LogDir, StartOpts) of
ok -> % go on read tests from start flags
script_start3(StartOpts#opts{config=InitConfig,
logdir=LogDir}, Args);
@@ -393,12 +400,17 @@ script_start2(StartOpts, Args) ->
Error
end.
-check_and_install_configfiles(Configs, LogDir, EvHandlers, CTHooks) ->
+check_and_install_configfiles(
+ Configs, LogDir, #opts{
+ event_handlers = EvHandlers,
+ ct_hooks = CTHooks,
+ enable_builtin_hooks = EnableBuiltinHooks} ) ->
case ct_config:check_config_files(Configs) of
false ->
install([{config,Configs},
{event_handler,EvHandlers},
- {ct_hooks,CTHooks}], LogDir);
+ {ct_hooks,CTHooks},
+ {enable_builtin_hooks,EnableBuiltinHooks}], LogDir);
{value,{error,{nofile,File}}} ->
{error,{cant_read_config_file,File}};
{value,{error,{wrong_config,Message}}}->
@@ -490,23 +502,23 @@ script_start4(#opts{label = Label, profile = Profile,
shell = true, config = Config,
event_handlers = EvHandlers,
ct_hooks = CTHooks,
- logdir = LogDir,
logopts = LogOpts,
- testspecs = Specs}, _Args) ->
+ enable_builtin_hooks = EnableBuiltinHooks,
+ logdir = LogDir, testspecs = Specs}, _Args) ->
%% label - used by ct_logs
application:set_env(common_test, test_label, Label),
%% profile - used in ct_util
application:set_env(common_test, profile, Profile),
- InstallOpts = [{config,Config},{event_handler,EvHandlers},
- {ct_hooks, CTHooks}],
if Config == [] ->
ok;
true ->
io:format("\nInstalling: ~p\n\n", [Config])
end,
- case install(InstallOpts) of
+ case install([{config,Config},{event_handler,EvHandlers},
+ {ct_hooks, CTHooks},
+ {enable_builtin_hooks,EnableBuiltinHooks}]) of
ok ->
ct_util:start(interactive, LogDir),
ct_util:set_testdata({logopts, LogOpts}),
@@ -747,6 +759,11 @@ run_test2(StartOpts) ->
%% CT Hooks
CTHooks = get_start_opt(ct_hooks, value, [], StartOpts),
+ EnableBuiltinHooks = get_start_opt(enable_builtin_hooks,
+ fun(EBH) when EBH == true;
+ EBH == false ->
+ EBH
+ end, true, StartOpts),
%% silent connections
SilentConns = get_start_opt(silent_connections,
@@ -820,6 +837,7 @@ run_test2(StartOpts) ->
logopts = LogOpts, config = CfgFiles,
event_handlers = EvHandlers,
ct_hooks = CTHooks,
+ enable_builtin_hooks = EnableBuiltinHooks,
include = Include,
silent_connections = SilentConns,
stylesheet = Stylesheet,
@@ -878,26 +896,29 @@ run_spec_file(Relaxed,
AllCTHooks = merge_vals([Opts#opts.ct_hooks,
SpecOpts#opts.ct_hooks]),
+ EnableBuiltinHooks = choose_val(Opts#opts.enable_builtin_hooks,
+ SpecOpts#opts.enable_builtin_hooks),
application:set_env(common_test, include, AllInclude),
- case check_and_install_configfiles(AllConfig,
- which(logdir,LogDir),
- AllEvHs,
- AllCTHooks) of
+ Opts1 = Opts#opts{label = Label,
+ profile = Profile,
+ cover = Cover,
+ logdir = which(logdir, LogDir),
+ logopts = AllLogOpts,
+ config = AllConfig,
+ event_handlers = AllEvHs,
+ include = AllInclude,
+ testspecs = AbsSpecs,
+ multiply_timetraps = MultTT,
+ scale_timetraps = ScaleTT,
+ ct_hooks = AllCTHooks,
+ enable_builtin_hooks = EnableBuiltinHooks
+ },
+
+ case check_and_install_configfiles(AllConfig,Opts1#opts.logdir,
+ Opts1) of
ok ->
- Opts1 = Opts#opts{label = Label,
- profile = Profile,
- cover = Cover,
- logdir = which(logdir, LogDir),
- logopts = AllLogOpts,
- config = AllConfig,
- event_handlers = AllEvHs,
- include = AllInclude,
- testspecs = AbsSpecs,
- multiply_timetraps = MultTT,
- scale_timetraps = ScaleTT,
- ct_hooks = AllCTHooks},
{Run,Skip} = ct_testspec:prepare_tests(TS, node()),
reformat_result(catch do_run(Run, Skip, Opts1, StartOpts));
{error,GCFReason} ->
@@ -906,13 +927,10 @@ run_spec_file(Relaxed,
end.
run_prepared(Run, Skip, Opts = #opts{logdir = LogDir,
- config = CfgFiles,
- event_handlers = EvHandlers,
- ct_hooks = CTHooks},
+ config = CfgFiles },
StartOpts) ->
LogDir1 = which(logdir, LogDir),
- case check_and_install_configfiles(CfgFiles, LogDir1,
- EvHandlers, CTHooks) of
+ case check_and_install_configfiles(CfgFiles, LogDir1, Opts) of
ok ->
reformat_result(catch do_run(Run, Skip, Opts#opts{logdir = LogDir1},
StartOpts));
@@ -944,7 +962,8 @@ check_config_file(Callback, File)->
run_dir(Opts = #opts{logdir = LogDir,
config = CfgFiles,
event_handlers = EvHandlers,
- ct_hooks = CTHook }, StartOpts) ->
+ ct_hooks = CTHook,
+ enable_builtin_hooks = EnableBuiltinHooks }, StartOpts) ->
LogDir1 = which(logdir, LogDir),
Opts1 = Opts#opts{logdir = LogDir1},
AbsCfgFiles =
@@ -967,7 +986,8 @@ run_dir(Opts = #opts{logdir = LogDir,
end, CfgFiles),
case install([{config,AbsCfgFiles},
{event_handler,EvHandlers},
- {ct_hooks, CTHook}], LogDir1) of
+ {ct_hooks, CTHook},
+ {enable_builtin_hooks,EnableBuiltinHooks}], LogDir1) of
ok -> ok;
{error,IReason} -> exit(IReason)
end,
@@ -1125,9 +1145,8 @@ run_testspec2(TestSpec) ->
end,
application:set_env(common_test, include, AllInclude),
LogDir1 = which(logdir,Opts#opts.logdir),
- case check_and_install_configfiles(Opts#opts.config, LogDir1,
- Opts#opts.event_handlers,
- Opts#opts.ct_hooks) of
+ case check_and_install_configfiles(
+ Opts#opts.config, LogDir1, Opts) of
ok ->
Opts1 = Opts#opts{testspecs = [],
logdir = LogDir1,
@@ -1148,6 +1167,7 @@ get_data_for_node(#testspec{label = Labels,
userconfig = UsrCfgs,
event_handler = EvHs,
ct_hooks = CTHooks,
+ enable_builtin_hooks = EnableBuiltinHooks,
include = Incl,
multiply_timetraps = MTs,
scale_timetraps = STs}, Node) ->
@@ -1177,6 +1197,7 @@ get_data_for_node(#testspec{label = Labels,
config = ConfigFiles,
event_handlers = EvHandlers,
ct_hooks = FiltCTHooks,
+ enable_builtin_hooks = EnableBuiltinHooks,
include = Include,
multiply_timetraps = MT,
scale_timetraps = ST}.
@@ -2254,8 +2275,11 @@ try_get_start_opt(Key, IfExists, IfNotExists, Args) ->
end.
ct_hooks_args2opts(Args) ->
- ct_hooks_args2opts(
- proplists:get_value(ct_hooks, Args, []),[]).
+ lists:foldl(fun({ct_hooks,Hooks}, Acc) ->
+ ct_hooks_args2opts(Hooks,Acc);
+ (_,Acc) ->
+ Acc
+ end,[],Args).
ct_hooks_args2opts([CTH,Arg,Prio,"and"| Rest],Acc) ->
ct_hooks_args2opts(Rest,[{list_to_atom(CTH),
diff --git a/lib/common_test/src/ct_testspec.erl b/lib/common_test/src/ct_testspec.erl
index 2cba1d8410..317910d5c8 100644
--- a/lib/common_test/src/ct_testspec.erl
+++ b/lib/common_test/src/ct_testspec.erl
@@ -670,6 +670,10 @@ add_tests([{ct_hooks, _Node, []}|Ts], Spec) ->
add_tests([{ct_hooks, Hooks}|Ts], Spec) ->
add_tests([{ct_hooks, all_nodes, Hooks}|Ts], Spec);
+%% -- enable_builtin_hooks --
+add_tests([{enable_builtin_hooks,Bool}|Ts],Spec) ->
+ add_tests(Ts, Spec#testspec{ enable_builtin_hooks = Bool });
+
%% --- include ---
add_tests([{include,all_nodes,InclDirs}|Ts],Spec) ->
Tests = lists:map(fun(N) -> {include,N,InclDirs} end, list_nodes(Spec)),
@@ -1130,6 +1134,7 @@ valid_terms() ->
{event_handler,4},
{ct_hooks,2},
{ct_hooks,3},
+ {enable_builtin_hooks,1},
{multiply_timetraps,2},
{multiply_timetraps,3},
{scale_timetraps,2},
diff --git a/lib/common_test/src/ct_util.hrl b/lib/common_test/src/ct_util.hrl
index 73898fe371..bde832811a 100644
--- a/lib/common_test/src/ct_util.hrl
+++ b/lib/common_test/src/ct_util.hrl
@@ -39,6 +39,7 @@
userconfig=[],
event_handler=[],
ct_hooks=[],
+ enable_builtin_hooks=true,
include=[],
multiply_timetraps=[],
scale_timetraps=[],
diff --git a/lib/common_test/src/cth_log_redirect.erl b/lib/common_test/src/cth_log_redirect.erl
new file mode 100644
index 0000000000..14663b7738
--- /dev/null
+++ b/lib/common_test/src/cth_log_redirect.erl
@@ -0,0 +1,111 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2011. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+-module(cth_log_redirect).
+
+%%% @doc Common Test Framework functions handling test specifications.
+%%%
+%%% <p>This module redirects sasl and error logger info to common test log.</p>
+%%% @end
+
+
+%% CTH Callbacks
+-export([id/1, init/2, post_init_per_group/4, pre_end_per_group/3,
+ post_end_per_testcase/4]).
+
+%% Event handler Callbacks
+-export([init/1,
+ handle_event/2, handle_call/2, handle_info/2,
+ terminate/2]).
+
+id(_Opts) ->
+ ?MODULE.
+
+init(?MODULE, _Opts) ->
+ error_logger:add_report_handler(?MODULE),
+ tc_log.
+
+post_init_per_group(Group, Config, Result, tc_log) ->
+ case lists:member(parallel,proplists:get_value(
+ tc_group_properties,Config,[])) of
+ true ->
+ {Result, {set_log_func(ct_log),Group}};
+ false ->
+ {Result, tc_log}
+ end;
+post_init_per_group(_Group, _Config, Result, State) ->
+ {Result, State}.
+
+post_end_per_testcase(_TC, _Config, Result, State) ->
+ %% Make sure that the event queue is flushed
+ %% before ending this test case.
+ gen_event:call(error_logger, ?MODULE, flush),
+ {Result, State}.
+
+pre_end_per_group(Group, Config, {ct_log, Group}) ->
+ {Config, set_log_func(tc_log)};
+pre_end_per_group(_Group, Config, State) ->
+ {Config, State}.
+
+
+%% Copied and modified from sasl_report_tty_h.erl
+init(_Type) ->
+ {ok, tc_log}.
+
+handle_event({_Type, GL, _Msg}, State) when node(GL) /= node() ->
+ {ok, State};
+handle_event(Event, LogFunc) ->
+ case lists:keyfind(sasl, 1, application:which_applications()) of
+ false ->
+ sasl_not_started;
+ _Else ->
+ {ok, ErrLogType} = application:get_env(sasl, errlog_type),
+ SReport = sasl_report:format_report(group_leader(), ErrLogType,
+ tag_event(Event)),
+ if is_list(SReport) ->
+ ct_logs:LogFunc(sasl, SReport, []);
+ true -> %% Report is an atom if no logging is to be done
+ ignore
+ end
+ end,
+ EReport = error_logger_tty_h:write_event(
+ tag_event(Event),io_lib),
+ if is_list(EReport) ->
+ ct_logs:LogFunc(error_logger, EReport, []);
+ true -> %% Report is an atom if no logging is to be done
+ ignore
+ end,
+ {ok, LogFunc}.
+
+
+handle_info(_,State) -> {ok, State}.
+
+handle_call(flush,State) ->
+ {ok, ok, State};
+handle_call({set_logfunc,NewLogFunc},_) ->
+ {ok, NewLogFunc, NewLogFunc};
+handle_call(_Query, _State) -> {error, bad_query}.
+
+terminate(_Reason, _Type) ->
+ [].
+
+tag_event(Event) ->
+ {calendar:local_time(), Event}.
+
+set_log_func(Func) ->
+ gen_event:call(error_logger, ?MODULE, {set_logfunc, Func}).
diff --git a/lib/common_test/test/ct_error_SUITE.erl b/lib/common_test/test/ct_error_SUITE.erl
index d6ee8eed10..c1a455c6d8 100644
--- a/lib/common_test/test/ct_error_SUITE.erl
+++ b/lib/common_test/test/ct_error_SUITE.erl
@@ -303,41 +303,21 @@ test_events(cfg_error) ->
{?eh,tc_start,{cfg_error_2_SUITE,init_per_suite}},
{?eh,tc_done,
{cfg_error_2_SUITE,init_per_suite,
- {failed,{error,{{badmatch,[1,2]},
- [{cfg_error_2_SUITE,init_per_suite,1},
- {test_server,my_apply,3},
- {test_server,ts_tc,3},
- {test_server,run_test_case_eval1,6},
- {test_server,run_test_case_eval,9}]}}}}},
+ {failed,{error,{{badmatch,[1,2]},'_'}}}}},
{?eh,tc_auto_skip,
{cfg_error_2_SUITE,tc1,
{failed,{cfg_error_2_SUITE,init_per_suite,
- {'EXIT',{{badmatch,[1,2]},
- [{cfg_error_2_SUITE,init_per_suite,1},
- {test_server,my_apply,3},
- {test_server,ts_tc,3},
- {test_server,run_test_case_eval1,6},
- {test_server,run_test_case_eval,9}]}}}}}},
+ {'EXIT',{{badmatch,[1,2]},'_'}}}}}},
{?eh,test_stats,{0,0,{0,3}}},
{?eh,tc_auto_skip,
{cfg_error_2_SUITE,tc2,
{failed,{cfg_error_2_SUITE,init_per_suite,
- {'EXIT',{{badmatch,[1,2]},
- [{cfg_error_2_SUITE,init_per_suite,1},
- {test_server,my_apply,3},
- {test_server,ts_tc,3},
- {test_server,run_test_case_eval1,6},
- {test_server,run_test_case_eval,9}]}}}}}},
+ {'EXIT',{{badmatch,[1,2]},'_'}}}}}},
{?eh,test_stats,{0,0,{0,4}}},
{?eh,tc_auto_skip,
{cfg_error_2_SUITE,end_per_suite,
{failed,{cfg_error_2_SUITE,init_per_suite,
- {'EXIT',{{badmatch,[1,2]},
- [{cfg_error_2_SUITE,init_per_suite,1},
- {test_server,my_apply,3},
- {test_server,ts_tc,3},
- {test_server,run_test_case_eval1,6},
- {test_server,run_test_case_eval,9}]}}}}}},
+ {'EXIT',{{badmatch,[1,2]},'_'}}}}}},
{?eh,tc_start,{cfg_error_3_SUITE,init_per_suite}},
{?eh,tc_done,
@@ -396,12 +376,7 @@ test_events(cfg_error) ->
{?eh,tc_done,{cfg_error_6_SUITE,{end_per_group,g1,[]},ok}}],
{?eh,tc_start,{cfg_error_6_SUITE,end_per_suite}},
{?eh,tc_done,{cfg_error_6_SUITE,end_per_suite,
- {failed,{error,{{badmatch,[1,2]},
- [{cfg_error_6_SUITE,end_per_suite,1},
- {test_server,my_apply,3},
- {test_server,ts_tc,3},
- {test_server,run_test_case_eval1,6},
- {test_server,run_test_case_eval,9}]}}}}},
+ {failed,{error,{{badmatch,[1,2]},'_'}}}}},
{?eh,tc_start,{cfg_error_7_SUITE,init_per_suite}},
{?eh,tc_done,{cfg_error_7_SUITE,init_per_suite,ok}},
@@ -450,31 +425,16 @@ test_events(cfg_error) ->
[{?eh,tc_start,{cfg_error_8_SUITE,{init_per_group,g3,[]}}},
{?eh,tc_done,
{cfg_error_8_SUITE,{init_per_group,g3,[]},
- {failed,{error,{{badmatch,42},
- [{cfg_error_8_SUITE,init_per_group,2},
- {test_server,my_apply,3},
- {test_server,ts_tc,3},
- {test_server,run_test_case_eval1,6},
- {test_server,run_test_case_eval,9}]}}}}},
+ {failed,{error,{{badmatch,42},'_'}}}}},
{?eh,tc_auto_skip,
{cfg_error_8_SUITE,tc1,
{failed,{cfg_error_8_SUITE,init_per_group,
- {'EXIT',{{badmatch,42},
- [{cfg_error_8_SUITE,init_per_group,2},
- {test_server,my_apply,3},
- {test_server,ts_tc,3},
- {test_server,run_test_case_eval1,6},
- {test_server,run_test_case_eval,9}]}}}}}},
+ {'EXIT',{{badmatch,42},'_'}}}}}},
{?eh,test_stats,{4,0,{0,13}}},
{?eh,tc_auto_skip,
{cfg_error_8_SUITE,end_per_group,
{failed,{cfg_error_8_SUITE,init_per_group,
- {'EXIT',{{badmatch,42},
- [{cfg_error_8_SUITE,init_per_group,2},
- {test_server,my_apply,3},
- {test_server,ts_tc,3},
- {test_server,run_test_case_eval1,6},
- {test_server,run_test_case_eval,9}]}}}}}}],
+ {'EXIT',{{badmatch,42},'_'}}}}}}],
[{?eh,tc_start,{cfg_error_8_SUITE,{init_per_group,g4,[]}}},
{?eh,tc_done,{cfg_error_8_SUITE,{init_per_group,g4,[]},ok}},
@@ -543,12 +503,7 @@ test_events(cfg_error) ->
{?eh,tc_start,{cfg_error_9_SUITE,tc3}},
{?eh,tc_done,{cfg_error_9_SUITE,tc3,
{skipped,{failed,{cfg_error_9_SUITE,init_per_testcase,
- {{badmatch,undefined},
- [{cfg_error_9_SUITE,init_per_testcase,2},
- {test_server,my_apply,3},
- {test_server,init_per_testcase,3},
- {test_server,run_test_case_eval1,6},
- {test_server,run_test_case_eval,9}]}}}}}},
+ {{badmatch,undefined},'_'}}}}}},
{?eh,test_stats,{9,0,{0,17}}},
{?eh,tc_start,{cfg_error_9_SUITE,tc4}},
{?eh,tc_done,
@@ -668,13 +623,7 @@ test_events(lib_error) ->
{?eh,tc_done,
{lib_error_1_SUITE,lines_error,{failed,
{error,
- {{badmatch,[1,2]},
- [{lib_lines,do_error,0},
- {lib_error_1_SUITE,lines_error,1},
- {test_server,my_apply,3},
- {test_server,ts_tc,3},
- {test_server,run_test_case_eval1,6},
- {test_server,run_test_case_eval,9}]}}}}},
+ {{badmatch,[1,2]},'_'}}}}},
{?eh,test_stats,{0,1,{0,0}}},
{?eh,tc_start,{lib_error_1_SUITE,lines_exit}},
{?eh,tc_done,
@@ -693,13 +642,7 @@ test_events(lib_error) ->
{?eh,tc_done,
{lib_error_1_SUITE,no_lines_error,{failed,
{error,
- {{badmatch,[1,2]},
- [{lib_no_lines,do_error,0},
- {lib_error_1_SUITE,no_lines_error,1},
- {test_server,my_apply,3},
- {test_server,ts_tc,3},
- {test_server,run_test_case_eval1,6},
- {test_server,run_test_case_eval,9}]}}}}},
+ {{badmatch,[1,2]},'_'}}}}},
{?eh,test_stats,{0,5,{0,0}}},
{?eh,tc_start,{lib_error_1_SUITE,no_lines_exit}},
{?eh,tc_done,
diff --git a/lib/common_test/test/ct_repeat_1_SUITE.erl b/lib/common_test/test/ct_repeat_1_SUITE.erl
index 99e3b83ea9..090002d0c2 100644
--- a/lib/common_test/test/ct_repeat_1_SUITE.erl
+++ b/lib/common_test/test/ct_repeat_1_SUITE.erl
@@ -560,12 +560,7 @@ test_events(repeat_cs_until_any_fail) ->
{repeat_1_SUITE,tc_fail_1,
{failed,
{error,
- {{badmatch,2},
- [{repeat_1_SUITE,tc_fail_1,1},
- {test_server,my_apply,3},
- {test_server,ts_tc,3},
- {test_server,run_test_case_eval1,6},
- {test_server,run_test_case_eval,9}]}}}}},
+ {{badmatch,2},'_'}}}}},
{?eh,test_stats,{5,2,{0,0}}},
{?eh,tc_start,{repeat_1_SUITE,tc_fail_2}},
{?eh,tc_done,
diff --git a/lib/common_test/test/ct_skip_SUITE.erl b/lib/common_test/test/ct_skip_SUITE.erl
index 6a8c57a6bd..b8be55f43a 100644
--- a/lib/common_test/test/ct_skip_SUITE.erl
+++ b/lib/common_test/test/ct_skip_SUITE.erl
@@ -197,7 +197,7 @@ test_events(auto_skip) ->
{?eh,tc_done,
{auto_skip_3_SUITE,tc1,
{skipped,{failed,{auto_skip_3_SUITE,init_per_testcase,
- {init_per_testcase,tc1,failed}}}}}},
+ {{init_per_testcase,tc1,failed},'_'}}}}}},
{?eh,test_stats,{0,0,{0,4}}},
{?eh,tc_start,{auto_skip_3_SUITE,tc2}},
{?eh,tc_done,{auto_skip_3_SUITE,tc2,ok}},
@@ -364,12 +364,7 @@ test_events(auto_skip) ->
{?eh,tc_done,
{auto_skip_9_SUITE,tc8,
{skipped,{failed,{auto_skip_9_SUITE,init_per_testcase,
- {{badmatch,undefined},
- [{auto_skip_9_SUITE,init_per_testcase,2},
- {test_server,my_apply,3},
- {test_server,init_per_testcase,3},
- {test_server,run_test_case_eval1,6},
- {test_server,run_test_case_eval,9}]}}}}}},
+ {{badmatch,undefined},'_'}}}}}},
{?eh,tc_start,
{auto_skip_9_SUITE,{end_per_group,g5,[parallel]}}},
{?eh,tc_done,
diff --git a/lib/compiler/doc/src/compile.xml b/lib/compiler/doc/src/compile.xml
index 830c89ae84..522c1dc411 100644
--- a/lib/compiler/doc/src/compile.xml
+++ b/lib/compiler/doc/src/compile.xml
@@ -395,6 +395,14 @@ module.beam: module.erl \
<code>-compile({no_auto_import,[error/1]}).</code>
</item>
+ <tag><c>no_line_info</c></tag>
+
+ <item>
+ <p>Omit line number information in order to produce a slightly
+ smaller output file.
+ </p>
+ </item>
+
</taglist>
<p>If warnings are turned on (the <c>report_warnings</c> option
diff --git a/lib/compiler/doc/src/make.dep b/lib/compiler/doc/src/make.dep
deleted file mode 100644
index f5c097afad..0000000000
--- a/lib/compiler/doc/src/make.dep
+++ /dev/null
@@ -1,19 +0,0 @@
-# ----------------------------------------------------
-# >>>> Do not edit this file <<<<
-# This file was automaticly generated by
-# /home/otp/bin/docdepend
-# ----------------------------------------------------
-
-
-# ----------------------------------------------------
-# TeX files that the DVI file depend on
-# ----------------------------------------------------
-
-book.dvi: book.tex compile.tex ref_man.tex
-
-# ----------------------------------------------------
-# Source inlined when transforming from source to LaTeX
-# ----------------------------------------------------
-
-book.tex: ref_man.xml
-
diff --git a/lib/compiler/src/beam_asm.erl b/lib/compiler/src/beam_asm.erl
index 89d64834cf..4a9c12dfea 100644
--- a/lib/compiler/src/beam_asm.erl
+++ b/lib/compiler/src/beam_asm.erl
@@ -23,7 +23,7 @@
-export([module/4]).
-export([encode/2]).
--import(lists, [map/2,member/2,keymember/3,duplicate/2]).
+-import(lists, [map/2,member/2,keymember/3,duplicate/2,splitwith/2]).
-include("beam_opcodes.hrl").
module(Code, Abst, SourceFile, Opts) ->
@@ -31,22 +31,20 @@ module(Code, Abst, SourceFile, Opts) ->
assemble({Mod,Exp,Attr0,Asm0,NumLabels}, Abst, SourceFile, Opts) ->
{1,Dict0} = beam_dict:atom(Mod, beam_dict:new()),
+ {0,Dict1} = beam_dict:fname(atom_to_list(Mod) ++ ".erl", Dict0),
NumFuncs = length(Asm0),
{Asm,Attr} = on_load(Asm0, Attr0),
- {Code,Dict1} = assemble_1(Asm, Exp, Dict0, []),
- build_file(Code, Attr, Dict1, NumLabels, NumFuncs, Abst, SourceFile, Opts).
+ {Code,Dict2} = assemble_1(Asm, Exp, Dict1, []),
+ build_file(Code, Attr, Dict2, NumLabels, NumFuncs, Abst, SourceFile, Opts).
on_load(Fs0, Attr0) ->
case proplists:get_value(on_load, Attr0) of
undefined ->
{Fs0,Attr0};
[{Name,0}] ->
- Fs = map(fun({function,N,0,Entry,Asm0}) when N =:= Name ->
- [{label,_}=L,
- {func_info,_,_,_}=Fi,
- {label,_}=E|Asm1] = Asm0,
- Asm = [L,Fi,E,on_load|Asm1],
- {function,N,0,Entry,Asm};
+ Fs = map(fun({function,N,0,Entry,Is0}) when N =:= Name ->
+ Is = insert_on_load_instruction(Is0, Entry),
+ {function,N,0,Entry,Is};
(F) ->
F
end, Fs0),
@@ -54,6 +52,13 @@ on_load(Fs0, Attr0) ->
{Fs,Attr}
end.
+insert_on_load_instruction(Is0, Entry) ->
+ {Bef,[{label,Entry}=El|Is]} =
+ splitwith(fun({label,L}) when L =:= Entry -> false;
+ (_) -> true
+ end, Is0),
+ Bef ++ [El,on_load|Is].
+
assemble_1([{function,Name,Arity,Entry,Asm}|T], Exp, Dict0, Acc) ->
Dict1 = case member({Name,Arity}, Exp) of
true ->
@@ -132,14 +137,19 @@ build_file(Code, Attr, Dict, NumLabels, NumFuncs, Abst, SourceFile, Opts) ->
LitTab = iolist_to_binary(zlib:compress(LitTab2)),
chunk(<<"LitT">>, <<(byte_size(LitTab2)):32>>, LitTab)
end,
+
+ %% Create the line chunk.
+ LineChunk = chunk(<<"Line">>, build_line_table(Dict)),
%% Create the attributes and compile info chunks.
Essentials0 = [AtomChunk,CodeChunk,StringChunk,ImportChunk,
ExpChunk,LambdaChunk,LiteralChunk],
- Essentials = [iolist_to_binary(C) || C <- Essentials0],
- {Attributes,Compile} = build_attributes(Opts, SourceFile, Attr, Essentials),
+ Essentials1 = [iolist_to_binary(C) || C <- Essentials0],
+ MD5 = module_md5(Essentials1),
+ Essentials = finalize_fun_table(Essentials1, MD5),
+ {Attributes,Compile} = build_attributes(Opts, SourceFile, Attr, MD5),
AttrChunk = chunk(<<"Attr">>, Attributes),
CompileChunk = chunk(<<"CInf">>, Compile),
@@ -150,11 +160,32 @@ build_file(Code, Attr, Dict, NumLabels, NumFuncs, Abst, SourceFile, Opts) ->
%% Create IFF chunk.
Chunks = case member(slim, Opts) of
- true -> [Essentials,AttrChunk,AbstChunk];
- false -> [Essentials,LocChunk,AttrChunk,CompileChunk,AbstChunk]
+ true ->
+ [Essentials,AttrChunk,AbstChunk];
+ false ->
+ [Essentials,LocChunk,AttrChunk,
+ CompileChunk,AbstChunk,LineChunk]
end,
build_form(<<"BEAM">>, Chunks).
+%% finalize_fun_table(Essentials, MD5) -> FinalizedEssentials
+%% Update the 'old_uniq' field in the entry for each fun in the
+%% 'FunT' chunk. We'll use part of the MD5 for the module as a
+%% unique value.
+
+finalize_fun_table(Essentials, MD5) ->
+ [finalize_fun_table_1(E, MD5) || E <- Essentials].
+
+finalize_fun_table_1(<<"FunT",Keep:8/binary,Table0/binary>>, MD5) ->
+ <<Uniq:27,_:101/bits>> = MD5,
+ Table = finalize_fun_table_2(Table0, Uniq, <<>>),
+ <<"FunT",Keep/binary,Table/binary>>;
+finalize_fun_table_1(Chunk, _) -> Chunk.
+
+finalize_fun_table_2(<<Keep:20/binary,0:32,T/binary>>, Uniq, Acc) ->
+ finalize_fun_table_2(T, Uniq, <<Acc/binary,Keep/binary,Uniq:32>>);
+finalize_fun_table_2(<<>>, _, Acc) -> Acc.
+
%% Build an IFF form.
build_form(Id, Chunks0) when byte_size(Id) =:= 4, is_list(Chunks0) ->
@@ -191,7 +222,7 @@ flatten_exports(Exps) ->
flatten_imports(Imps) ->
list_to_binary(map(fun({M,F,A}) -> <<M:32,F:32,A:32>> end, Imps)).
-build_attributes(Opts, SourceFile, Attr, Essentials) ->
+build_attributes(Opts, SourceFile, Attr, MD5) ->
Misc = case member(slim, Opts) of
false ->
{{Y,Mo,D},{H,Mi,S}} = erlang:universaltime(),
@@ -199,7 +230,32 @@ build_attributes(Opts, SourceFile, Attr, Essentials) ->
true -> []
end,
Compile = [{options,Opts},{version,?COMPILER_VSN}|Misc],
- {term_to_binary(calc_vsn(Attr, Essentials)),term_to_binary(Compile)}.
+ {term_to_binary(set_vsn_attribute(Attr, MD5)),term_to_binary(Compile)}.
+
+build_line_table(Dict) ->
+ {NumLineInstrs,NumFnames0,Fnames0,NumLines,Lines0} =
+ beam_dict:line_table(Dict),
+ NumFnames = NumFnames0 - 1,
+ [_|Fnames1] = Fnames0,
+ Fnames2 = [unicode:characters_to_binary(F) || F <- Fnames1],
+ Fnames = << <<(byte_size(F)):16,F/binary>> || F <- Fnames2 >>,
+ Lines1 = encode_line_items(Lines0, 0),
+ Lines = iolist_to_binary(Lines1),
+ Ver = 0,
+ Bits = 0,
+ <<Ver:32,Bits:32,NumLineInstrs:32,NumLines:32,NumFnames:32,
+ Lines/binary,Fnames/binary>>.
+
+%% encode_line_items([{FnameIndex,Line}], PrevFnameIndex)
+%% Encode the line items compactly. Tag the FnameIndex with
+%% an 'a' tag (atom) and only include it when it has changed.
+%% Tag the line numbers with an 'i' (integer) tag.
+
+encode_line_items([{F,L}|T], F) ->
+ [encode(?tag_i, L)|encode_line_items(T, F)];
+encode_line_items([{F,L}|T], _) ->
+ [encode(?tag_a, F),encode(?tag_i, L)|encode_line_items(T, F)];
+encode_line_items([], _) -> [].
%%
%% If the attributes contains no 'vsn' attribute, we'll insert one
@@ -207,32 +263,30 @@ build_attributes(Opts, SourceFile, Attr, Essentials) ->
%% We'll not change an existing 'vsn' attribute.
%%
-calc_vsn(Attr, Essentials0) ->
+set_vsn_attribute(Attr, MD5) ->
case keymember(vsn, 1, Attr) of
true -> Attr;
false ->
- Essentials = filter_essentials(Essentials0),
- <<Number:128>> = erlang:md5(Essentials),
+ <<Number:128>> = MD5,
[{vsn,[Number]}|Attr]
end.
+module_md5(Essentials0) ->
+ Essentials = filter_essentials(Essentials0),
+ erlang:md5(Essentials).
+
%% filter_essentials([Chunk]) -> [Chunk']
%% Filter essentials so that we obtain the same MD5 as code:module_md5/1 and
-%% beam_lib:md5/1 would calculate for this module.
+%% beam_lib:md5/1 would calculate for this module. Note that at this
+%% point, the 'old_uniq' entry for each fun in the 'FunT' chunk is zeroed,
+%% so there is no need to go through the 'FunT' chunk.
-filter_essentials([<<"FunT",_Sz:4/binary,Entries:4/binary,Table0/binary>>|T]) ->
- Table = filter_funtab(Table0, <<0:32>>),
- [Entries,Table|filter_essentials(T)];
filter_essentials([<<_Tag:4/binary,Sz:32,Data:Sz/binary,_Padding/binary>>|T]) ->
[Data|filter_essentials(T)];
filter_essentials([<<>>|T]) ->
filter_essentials(T);
filter_essentials([]) -> [].
-filter_funtab(<<Important:20/binary,_OldUniq:4/binary,T/binary>>, Zero) ->
- [Important,Zero|filter_funtab(T, Zero)];
-filter_funtab(<<>>, _) -> [].
-
bif_type(fnegate, 1) -> {op,fnegate};
bif_type(fadd, 2) -> {op,fadd};
bif_type(fsub, 2) -> {op,fsub};
@@ -243,6 +297,9 @@ bif_type(_, 2) -> bif2.
make_op({'%',_}, Dict) ->
{[],Dict};
+make_op({line,Location}, Dict0) ->
+ {Index,Dict} = beam_dict:line(Location, Dict0),
+ encode_op(line, [Index], Dict);
make_op({bif, Bif, {f,_}, [], Dest}, Dict) ->
%% BIFs without arguments cannot fail.
encode_op(bif0, [{extfunc, erlang, Bif, 0}, Dest], Dict);
@@ -271,8 +328,8 @@ make_op({test,Cond,Fail,Ops}, Dict) when is_list(Ops) ->
encode_op(Cond, [Fail|Ops], Dict);
make_op({test,Cond,Fail,Live,[Op|Ops],Dst}, Dict) when is_list(Ops) ->
encode_op(Cond, [Fail,Op,Live|Ops++[Dst]], Dict);
-make_op({make_fun2,{f,Lbl},Index,OldUniq,NumFree}, Dict0) ->
- {Fun,Dict} = beam_dict:lambda(Lbl, Index, OldUniq, NumFree, Dict0),
+make_op({make_fun2,{f,Lbl},_Index,_OldUniq,NumFree}, Dict0) ->
+ {Fun,Dict} = beam_dict:lambda(Lbl, NumFree, Dict0),
make_op({make_fun2,Fun}, Dict);
make_op({kill,Y}, Dict) ->
make_op({init,Y}, Dict);
diff --git a/lib/compiler/src/beam_block.erl b/lib/compiler/src/beam_block.erl
index c45874597a..432d1e7eea 100644
--- a/lib/compiler/src/beam_block.erl
+++ b/lib/compiler/src/beam_block.erl
@@ -36,13 +36,14 @@ function({function,Name,Arity,CLabel,Is0}, Lc0) ->
%% Collect basic blocks and optimize them.
Is2 = blockify(Is1),
- Is3 = move_allocates(Is2),
- Is4 = beam_utils:live_opt(Is3),
- Is5 = opt_blocks(Is4),
- Is6 = beam_utils:delete_live_annos(Is5),
+ Is3 = embed_lines(Is2),
+ Is4 = move_allocates(Is3),
+ Is5 = beam_utils:live_opt(Is4),
+ Is6 = opt_blocks(Is5),
+ Is7 = beam_utils:delete_live_annos(Is6),
%% Optimize bit syntax.
- {Is,Lc} = bsm_opt(Is6, Lc0),
+ {Is,Lc} = bsm_opt(Is7, Lc0),
%% Done.
{{function,Name,Arity,CLabel,Is},Lc}
@@ -148,6 +149,24 @@ collect(remove_message) -> {set,[],[],remove_message};
collect({'catch',R,L}) -> {set,[R],[],{'catch',L}};
collect(_) -> error.
+%% embed_lines([Instruction]) -> [Instruction]
+%% Combine blocks that would be split by line/1 instructions.
+%% Also move a line instruction before a block into the block,
+%% but leave the line/1 instruction after a block outside.
+
+embed_lines(Is) ->
+ embed_lines(reverse(Is), []).
+
+embed_lines([{block,B2},{line,_}=Line,{block,B1}|T], Acc) ->
+ B = {block,B1++[{set,[],[],Line}]++B2},
+ embed_lines([B|T], Acc);
+embed_lines([{block,B1},{line,_}=Line|T], Acc) ->
+ B = {block,[{set,[],[],Line}|B1]},
+ embed_lines([B|T], Acc);
+embed_lines([I|Is], Acc) ->
+ embed_lines(Is, [I|Acc]);
+embed_lines([], Acc) -> Acc.
+
opt_blocks([{block,Bl0}|Is]) ->
%% The live annotation at the beginning is not useful.
[{'%live',_}|Bl] = Bl0,
@@ -225,10 +244,12 @@ opt([{set,[Dst],As,{bif,Bif,Fail}}=I1,
RevBif -> [{set,[Dst],As,{bif,RevBif,Fail}}|opt(Is)]
end;
opt([{set,[X],[X],move}|Is]) -> opt(Is);
-opt([{set,[D1],[{integer,Idx1},Reg],{bif,element,{f,0}}}=I1,
+opt([{set,_,_,{line,_}}=Line1,
+ {set,[D1],[{integer,Idx1},Reg],{bif,element,{f,0}}}=I1,
+ {set,_,_,{line,_}}=Line2,
{set,[D2],[{integer,Idx2},Reg],{bif,element,{f,0}}}=I2|Is])
when Idx1 < Idx2, D1 =/= D2, D1 =/= Reg, D2 =/= Reg ->
- opt([I2,I1|Is]);
+ opt([Line2,I2,Line1,I1|Is]);
opt([{set,Ds0,Ss,Op}|Is0]) ->
{Ds,Is} = opt_moves(Ds0, Is0),
[{set,Ds,Ss,Op}|opt(Is)];
diff --git a/lib/compiler/src/beam_bsm.erl b/lib/compiler/src/beam_bsm.erl
index 415864b8e9..1217f7f777 100644
--- a/lib/compiler/src/beam_bsm.erl
+++ b/lib/compiler/src/beam_bsm.erl
@@ -20,7 +20,7 @@
-module(beam_bsm).
-export([module/2,format_error/1]).
--import(lists, [member/2,foldl/3,reverse/1,sort/1,all/2]).
+-import(lists, [member/2,foldl/3,reverse/1,sort/1,all/2,dropwhile/2]).
%%%
%%% We optimize bit syntax matching where the tail end of a binary is
@@ -376,6 +376,8 @@ btb_reaches_match_2([{func_info,_,_,Arity}=I|_], Regs0, D) ->
[] -> D;
_ -> {binary_used_in,I}
end;
+btb_reaches_match_2([{line,_}|Is], Regs, D) ->
+ btb_reaches_match_1(Is, Regs, D);
btb_reaches_match_2([I|_], Regs, _) ->
btb_error({btb_context_regs(Regs),I,not_handled}).
@@ -580,7 +582,10 @@ btb_index(Fs) ->
btb_index_1(Fs, []).
btb_index_1([{function,_,_,Entry,Is0}|Fs], Acc0) ->
- [{label,_},{func_info,_,_,_},{label,Entry}|Is] = Is0,
+ [{label,Entry}|Is] =
+ dropwhile(fun({label,L}) when L =:= Entry -> false;
+ (_) -> true
+ end, Is0),
Acc = btb_index_2(Is, Entry, false, Acc0),
btb_index_1(Fs, Acc);
btb_index_1([], Acc) -> gb_trees:from_orddict(sort(Acc)).
diff --git a/lib/compiler/src/beam_clean.erl b/lib/compiler/src/beam_clean.erl
index 64c93e11f7..a7994ab3b3 100644
--- a/lib/compiler/src/beam_clean.erl
+++ b/lib/compiler/src/beam_clean.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2000-2009. All Rights Reserved.
+%% Copyright Ericsson AB 2000-2011. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -23,9 +23,9 @@
-export([module/2]).
-export([bs_clean_saves/1]).
-export([clean_labels/1]).
--import(lists, [map/2,foldl/3,reverse/1]).
+-import(lists, [map/2,foldl/3,reverse/1,filter/2]).
-module({Mod,Exp,Attr,Fs0,_}, _Opt) ->
+module({Mod,Exp,Attr,Fs0,_}, Opts) ->
Order = [Lbl || {function,_,_,Lbl,_} <- Fs0],
All = foldl(fun({function,_,_,Lbl,_}=Func,D) -> dict:store(Lbl, Func, D) end,
dict:new(), Fs0),
@@ -33,7 +33,8 @@ module({Mod,Exp,Attr,Fs0,_}, _Opt) ->
Used = find_all_used(WorkList, All, sets:from_list(WorkList)),
Fs1 = remove_unused(Order, Used, All),
{Fs2,Lc} = clean_labels(Fs1),
- Fs = bs_fix(Fs2),
+ Fs3 = bs_fix(Fs2),
+ Fs = maybe_remove_lines(Fs3, Opts),
{ok,{Mod,Exp,Attr,Fs,Lc}}.
%% Remove all bs_save2/2 instructions not referenced by a bs_restore2/2.
@@ -375,3 +376,20 @@ bs_clean_saves_1([{bs_save2,_,{_,_}=SavePoint}=I|Is], Needed, Acc) ->
bs_clean_saves_1([I|Is], Needed, Acc) ->
bs_clean_saves_1(Is, Needed, [I|Acc]);
bs_clean_saves_1([], _, Acc) -> reverse(Acc).
+
+%%%
+%%% Remove line instructions if requested.
+%%%
+
+maybe_remove_lines(Fs, Opts) ->
+ case proplists:get_bool(no_line_info, Opts) of
+ false -> Fs;
+ true -> remove_lines(Fs)
+ end.
+
+remove_lines([{function,N,A,Lbl,Is0}|T]) ->
+ Is = filter(fun({line,_}) -> false;
+ (_) -> true
+ end, Is0),
+ [{function,N,A,Lbl,Is}|remove_lines(T)];
+remove_lines([]) -> [].
diff --git a/lib/compiler/src/beam_dead.erl b/lib/compiler/src/beam_dead.erl
index 1365f3d20a..9f81a6ab43 100644
--- a/lib/compiler/src/beam_dead.erl
+++ b/lib/compiler/src/beam_dead.erl
@@ -144,9 +144,9 @@ function({function,Name,Arity,CLabel,Is0}, Lc0) ->
%% Initialize label information with the code
%% for the func_info label. Without it, a register
%% may seem to be live when it is not.
- [{label,L},{func_info,_,_,_}=FI|_] = Is1,
+ [{label,L}|FiIs] = Is1,
D0 = beam_utils:empty_label_index(),
- D = beam_utils:index_label(L, [FI], D0),
+ D = beam_utils:index_label(L, FiIs, D0),
%% Optimize away dead code.
{Is2,Lc} = forward(Is1, Lc0),
@@ -185,6 +185,8 @@ split_block([{set,[R],As,{alloc,Live,{gc_bif,N,{f,Lbl}=Fail}}}|Is], Bl, Acc)
split_block(Is, [], [{gc_bif,N,Fail,Live,As,R}|make_block(Bl, Acc)]);
split_block([{set,[R],[],{'catch',L}}|Is], Bl, Acc) ->
split_block(Is, [], [{'catch',R,L}|make_block(Bl, Acc)]);
+split_block([{set,[],[],{line,_}=Line}|Is], Bl, Acc) ->
+ split_block(Is, [], [Line|make_block(Bl, Acc)]);
split_block([I|Is], Bl, Acc) ->
split_block(Is, [I|Bl], Acc);
split_block([], Bl, Acc) -> make_block(Bl, Acc).
@@ -406,7 +408,7 @@ backward([{test,Op,{f,To0},Live,Ops0,Dst}|Is], D, Acc) ->
end,
I = {test,Op,{f,To},Live,Ops0,Dst},
backward(Is, D, [I|Acc]);
-backward([{kill,_}=I|Is], D, [Exit|_]=Acc) ->
+backward([{kill,_}=I|Is], D, [{line,_},Exit|_]=Acc) ->
case beam_jump:is_exit_instruction(Exit) of
false -> backward(Is, D, [I|Acc]);
true -> backward(Is, D, Acc)
@@ -471,7 +473,7 @@ shortcut_fail_label(To0, Reg, Val, D) ->
shortcut_boolean_label(To0, Reg, Bool0, D) when is_boolean(Bool0) ->
case beam_utils:code_at(To0, D) of
- [{bif,'not',_,[Reg],Reg},{jump,{f,To}}|_] ->
+ [{line,_},{bif,'not',_,[Reg],Reg},{jump,{f,To}}|_] ->
Bool = not Bool0,
{shortcut_select_label(To, Reg, Bool, D),Bool};
_ ->
diff --git a/lib/compiler/src/beam_dict.erl b/lib/compiler/src/beam_dict.erl
index c50ed28aa9..531968b3c8 100644
--- a/lib/compiler/src/beam_dict.erl
+++ b/lib/compiler/src/beam_dict.erl
@@ -22,9 +22,10 @@
-export([new/0,opcode/2,highest_opcode/1,
atom/2,local/4,export/4,import/4,
- string/2,lambda/5,literal/2,
+ string/2,lambda/3,literal/2,line/2,fname/2,
atom_table/1,local_table/1,export_table/1,import_table/1,
- string_table/1,lambda_table/1,literal_table/1]).
+ string_table/1,lambda_table/1,literal_table/1,
+ line_table/1]).
-type label() :: non_neg_integer().
@@ -36,6 +37,9 @@
strings = <<>> :: binary(), %String pool
lambdas = [], %[{...}]
literals = dict:new() :: dict(), %Format: {Literal,Number}
+ fnames = gb_trees:empty() :: gb_tree(), %{Name,Index}
+ lines = gb_trees:empty() :: gb_tree(), %{{Fname,Line},Index}
+ num_lines = 0 :: non_neg_integer(), %Number of line instructions
next_import = 0 :: non_neg_integer(),
string_offset = 0 :: non_neg_integer(),
next_literal = 0 :: non_neg_integer(),
@@ -129,13 +133,18 @@ string(Str, Dict) when is_list(Str) ->
{NextOffset-Offset,Dict}
end.
-%% Returns the index for a funentry (adding it to the table if necessary).
-%% lambda(Lbl, Index, Uniq, NumFree, Dict) -> {Index,Dict'}
--spec lambda(label(), non_neg_integer(), integer(), non_neg_integer(), bdict()) ->
+%% Returns the index for a fun entry.
+%% lambda(Lbl, NumFree, Dict) -> {Index,Dict'}
+-spec lambda(label(), non_neg_integer(), bdict()) ->
{non_neg_integer(), bdict()}.
-lambda(Lbl, Index, OldUniq, NumFree, #asm{lambdas=Lambdas0}=Dict) ->
+lambda(Lbl, NumFree, #asm{lambdas=Lambdas0}=Dict) ->
OldIndex = length(Lambdas0),
+ %% Set Index the same as OldIndex.
+ Index = OldIndex,
+ %% Initialize OldUniq to 0. It will be set to an unique value
+ %% based on the MD5 checksum of the BEAM code for the module.
+ OldUniq = 0,
Lambdas = [{Lbl,{OldIndex,Lbl,Index,NumFree,OldUniq}}|Lambdas0],
{OldIndex,Dict#asm{lambdas=Lambdas}}.
@@ -152,6 +161,36 @@ literal(Lit, #asm{literals=Tab0,next_literal=NextIndex}=Dict) ->
{NextIndex,Dict#asm{literals=Tab,next_literal=NextIndex+1}}
end.
+%% Returns the index for a line instruction (adding information
+%% to the location information table).
+-spec line(list(), bdict()) -> {non_neg_integer(), bdict()}.
+
+line([], #asm{num_lines=N}=Dict) ->
+ %% No location available. Return the special pre-defined
+ %% index 0.
+ {0,Dict#asm{num_lines=N+1}};
+line([{location,Name,Line}], #asm{lines=Lines0,num_lines=N}=Dict0) ->
+ {FnameIndex,Dict1} = fname(Name, Dict0),
+ case gb_trees:lookup({FnameIndex,Line}, Lines0) of
+ {value,Index} ->
+ {Index,Dict1#asm{num_lines=N+1}};
+ none ->
+ Index = gb_trees:size(Lines0) + 1,
+ Lines = gb_trees:insert({FnameIndex,Line}, Index, Lines0),
+ Dict = Dict1#asm{lines=Lines,num_lines=N+1},
+ {Index,Dict}
+ end.
+
+fname(Name, #asm{fnames=Fnames0}=Dict) ->
+ case gb_trees:lookup(Name, Fnames0) of
+ {value,Index} ->
+ {Index,Dict};
+ none ->
+ Index = gb_trees:size(Fnames0),
+ Fnames = gb_trees:insert(Name, Index, Fnames0),
+ {Index,Dict#asm{fnames=Fnames}}
+ end.
+
%% Returns the atom table.
%% atom_table(Dict) -> {LastIndex,[Length,AtomString...]}
-spec atom_table(bdict()) -> {non_neg_integer(), [[non_neg_integer(),...]]}.
@@ -219,6 +258,21 @@ literal_table(#asm{literals=Tab,next_literal=NumLiterals}) ->
my_term_to_binary(Term) ->
term_to_binary(Term, [{minor_version,1}]).
+%% Return the line table.
+-spec line_table(bdict()) ->
+ {non_neg_integer(), %Number of line instructions.
+ non_neg_integer(),[string()],
+ non_neg_integer(),[{non_neg_integer(),non_neg_integer()}]}.
+
+line_table(#asm{fnames=Fnames0,lines=Lines0,num_lines=NumLineInstrs}) ->
+ NumFnames = gb_trees:size(Fnames0),
+ Fnames1 = lists:keysort(2, gb_trees:to_list(Fnames0)),
+ Fnames = [Name || {Name,_} <- Fnames1],
+ NumLines = gb_trees:size(Lines0),
+ Lines1 = lists:keysort(2, gb_trees:to_list(Lines0)),
+ Lines = [L || {L,_} <- Lines1],
+ {NumLineInstrs,NumFnames,Fnames,NumLines,Lines}.
+
%% Search for binary string Str in the binary string pool Pool.
%% old_string(Str, Pool) -> none | Index
-spec old_string(binary(), binary()) -> 'none' | pos_integer().
diff --git a/lib/compiler/src/beam_disasm.erl b/lib/compiler/src/beam_disasm.erl
index 5c4d8e12b5..7103d2390f 100644
--- a/lib/compiler/src/beam_disasm.erl
+++ b/lib/compiler/src/beam_disasm.erl
@@ -296,6 +296,8 @@ get_function_chunks(Code) ->
labels_r([], R) -> {R, []};
labels_r([{label,_}=I|Is], R) ->
labels_r(Is, [I|R]);
+labels_r([{line,_}=I|Is], R) ->
+ labels_r(Is, [I|R]);
labels_r(Is, R) -> {R, Is}.
get_funs({[],[]}) -> [];
@@ -335,20 +337,17 @@ local_labels(Funs) ->
local_labels_1(function__code(F), R)
end, [], Funs)).
-%% The first clause below attempts to provide some (limited form of)
-%% backwards compatibility; it is not needed for .beam files generated
-%% by the R8 compiler. The clause should one fine day be taken out.
-local_labels_1([{label,_}|[{label,_}|_]=Code], R) ->
- local_labels_1(Code, R);
-local_labels_1([{label,_},{func_info,{atom,M},{atom,F},A}|Code], R)
- when is_atom(M), is_atom(F) ->
- local_labels_2(Code, R, M, F, A);
-local_labels_1(Code, _) ->
- ?exit({'local_labels: no label in code',Code}).
+local_labels_1(Code0, R) ->
+ Code1 = lists:dropwhile(fun({label,_}) -> true;
+ ({line,_}) -> true;
+ ({func_info,_,_,_}) -> false
+ end, Code0),
+ [{func_info,{atom,M},{atom,F},A}|Code] = Code1,
+ local_labels_2(Code, R, {M,F,A}).
-local_labels_2([{label,[{u,L}]}|Code], R, M, F, A) ->
- local_labels_2(Code, [{L,{M,F,A}}|R], M, F, A);
-local_labels_2(_, R, _, _, _) -> R.
+local_labels_2([{label,[{u,L}]}|Code], R, MFA) ->
+ local_labels_2(Code, [{L,MFA}|R], MFA);
+local_labels_2(_, R, _) -> R.
%%-----------------------------------------------------------------------
%% Disassembles a single BEAM instruction; most instructions are handled
@@ -1105,6 +1104,12 @@ resolve_inst({recv_set,[Lbl]},_,_,_) ->
{recv_set,Lbl};
%%
+%% R15A.
+%%
+resolve_inst({line,[Index]},_,_,_) ->
+ {line,resolve_arg(Index)};
+
+%%
%% Catches instructions that are not yet handled.
%%
resolve_inst(X,_,_,_) -> ?exit({resolve_inst,X}).
diff --git a/lib/compiler/src/beam_jump.erl b/lib/compiler/src/beam_jump.erl
index 3cab55c4cb..537f8ca81b 100644
--- a/lib/compiler/src/beam_jump.erl
+++ b/lib/compiler/src/beam_jump.erl
@@ -169,7 +169,7 @@ share_1([{label,L}=Lbl|Is], Dict0, Seq, Acc) ->
share_1(Is, Dict0, [], [Lbl,{jump,{f,Label}}|Acc])
end;
share_1([{func_info,_,_,_}=I|Is], _, [], Acc) ->
- Is++[I|Acc];
+ reverse(Is, [I|Acc]);
share_1([I|Is], Dict, Seq, Acc) ->
case is_unreachable_after(I) of
false ->
@@ -206,25 +206,35 @@ is_label(_) -> false.
move(Is) ->
move_1(Is, [], []).
-move_1([I|Is], End, Acc) ->
+move_1([I|Is], End0, Acc0) ->
case is_exit_instruction(I) of
- false -> move_1(Is, End, [I|Acc]);
- true -> move_2(I, Is, End, Acc)
+ false ->
+ move_1(Is, End0, [I|Acc0]);
+ true ->
+ case extract_seq(Acc0, [I|End0]) of
+ no ->
+ move_1(Is, End0, [I|Acc0]);
+ {yes,End,Acc} ->
+ move_1(Is, End, Acc)
+ end
end;
-move_1([], End, Acc) ->
- reverse(Acc, reverse(End)).
-
-move_2(Exit, Is, End, [{block,_},{label,_},{func_info,_,_,_}|_]=Acc) ->
- move_1(Is, End, [Exit|Acc]);
-move_2(Exit, Is, End, [{block,_}=Blk,{label,_}=Lbl,Unreachable|More]) ->
- move_1([Unreachable|Is], [Exit,Blk,Lbl|End], More);
-move_2(Exit, Is, End, [{bs_context_to_binary,_}=Bs,{label,_}=Lbl,
- Unreachable|More]) ->
- move_1([Unreachable|Is], [Exit,Bs,Lbl|End], More);
-move_2(Exit, Is, End, [{label,_}=Lbl,Unreachable|More]) ->
- move_1([Unreachable|Is], [Exit,Lbl|End], More);
-move_2(Exit, Is, End, Acc) ->
- move_1(Is, End, [Exit|Acc]).
+move_1([], End, Acc) -> reverse(Acc, End).
+
+extract_seq([{line,_}=Line|Is], Acc) ->
+ extract_seq(Is, [Line|Acc]);
+extract_seq([{block,_}=Bl|Is], Acc) ->
+ extract_seq_1(Is, [Bl|Acc]);
+extract_seq([{label,_}|_]=Is, Acc) ->
+ extract_seq_1(Is, Acc);
+extract_seq(_, _) -> no.
+
+extract_seq_1([{line,_}=Line|Is], Acc) ->
+ extract_seq_1(Is, [Line|Acc]);
+extract_seq_1([{label,_},{func_info,_,_,_}|_], _) ->
+ no;
+extract_seq_1([{label,_}=Lbl|Is], Acc) ->
+ {yes,[Lbl|Acc],Is};
+extract_seq_1(_, _) -> no.
%%%
%%% (3) (4) (5) (6) Jump and unreachable code optimizations.
@@ -454,6 +464,7 @@ is_label_used_in_2({set,_,_,Info}, Lbl) ->
{put_tuple,_} -> false;
{get_tuple_element,_} -> false;
{set_tuple_element,_} -> false;
+ {line,_} -> false;
_ when is_atom(Info) -> false
end.
@@ -487,6 +498,8 @@ rem_unused([], _, Acc) -> reverse(Acc).
initial_labels(Is) ->
initial_labels(Is, []).
+initial_labels([{line,_}|Is], Acc) ->
+ initial_labels(Is, Acc);
initial_labels([{label,Lbl}|Is], Acc) ->
initial_labels(Is, [Lbl|Acc]);
initial_labels([{func_info,_,_,_},{label,Lbl}|_], Acc) ->
diff --git a/lib/compiler/src/beam_listing.erl b/lib/compiler/src/beam_listing.erl
index be7b14c3dd..2941f6135c 100644
--- a/lib/compiler/src/beam_listing.erl
+++ b/lib/compiler/src/beam_listing.erl
@@ -61,7 +61,7 @@ print_op(Stream, Label) when element(1, Label) == label ->
print_op(Stream, Op) ->
io:format(Stream, " ~p.\n", [Op]).
-function(File, {function,Name,Arity,Args,Body,Vdb}) ->
+function(File, {function,Name,Arity,Args,Body,Vdb,_Anno}) ->
io:nl(File),
io:format(File, "function ~p/~p.\n", [Name,Arity]),
io:format(File, " ~p.\n", [Args]),
diff --git a/lib/compiler/src/beam_receive.erl b/lib/compiler/src/beam_receive.erl
index 9ed44ad5d7..c483d85a97 100644
--- a/lib/compiler/src/beam_receive.erl
+++ b/lib/compiler/src/beam_receive.erl
@@ -175,6 +175,8 @@ opt_update_regs({label,Lbl}, R, L) ->
end;
opt_update_regs({try_end,_}, R, L) ->
{R,L};
+opt_update_regs({line,_}, R, L) ->
+ {R,L};
opt_update_regs(_I, _R, L) ->
%% Unrecognized instruction. Abort the search.
{regs_init(),L}.
diff --git a/lib/compiler/src/beam_trim.erl b/lib/compiler/src/beam_trim.erl
index 790aba0a9a..25e6ffbb73 100644
--- a/lib/compiler/src/beam_trim.erl
+++ b/lib/compiler/src/beam_trim.erl
@@ -222,7 +222,9 @@ remap([{call_last,Ar,Name,N}|Is], Map, Acc) ->
reverse(Acc, [I|Is]);
remap([{call_ext_last,Ar,Name,N}|Is], Map, Acc) ->
I = {call_ext_last,Ar,Name,Map({frame_size,N})},
- reverse(Acc, [I|Is]).
+ reverse(Acc, [I|Is]);
+remap([{line,_}=I|Is], Map, Acc) ->
+ remap(Is, Map, [I|Acc]).
remap_block([{set,Ds0,Ss0,Info}|Is], Map, Acc) ->
Ds = [Map(D) || D <- Ds0],
@@ -230,14 +232,15 @@ remap_block([{set,Ds0,Ss0,Info}|Is], Map, Acc) ->
remap_block(Is, Map, [{set,Ds,Ss,Info}|Acc]);
remap_block([], _, Acc) -> reverse(Acc).
-safe_labels([{label,L},{badmatch,{Tag,_}}|Is], Acc) when Tag =/= y ->
+safe_labels([{label,L},{line,_},{badmatch,{Tag,_}}|Is], Acc) when Tag =/= y ->
safe_labels(Is, [L|Acc]);
-safe_labels([{label,L},{case_end,{Tag,_}}|Is], Acc) when Tag =/= y ->
+safe_labels([{label,L},{line,_},{case_end,{Tag,_}}|Is], Acc) when Tag =/= y ->
safe_labels(Is, [L|Acc]);
-safe_labels([{label,L},if_end|Is], Acc) ->
+safe_labels([{label,L},{line,_},if_end|Is], Acc) ->
safe_labels(Is, [L|Acc]);
safe_labels([{label,L},
{block,[{set,[{x,0}],[{Tag,_}],move}]},
+ {line,_},
{call_ext,1,{extfunc,erlang,error,1}}|Is], Acc) when Tag =/= y ->
safe_labels(Is, [L|Acc]);
safe_labels([_|Is], Acc) ->
@@ -321,6 +324,8 @@ frame_size([{make_fun2,_,_,_,_}|Is], Safe) ->
frame_size([{deallocate,N}|_], _) -> N;
frame_size([{call_last,_,_,N}|_], _) -> N;
frame_size([{call_ext_last,_,_,N}|_], _) -> N;
+frame_size([{line,_}|Is], Safe) ->
+ frame_size(Is, Safe);
frame_size([_|_], _) -> throw(not_possible).
frame_size_branch(0, Is, Safe) ->
diff --git a/lib/compiler/src/beam_type.erl b/lib/compiler/src/beam_type.erl
index f83f73b224..0c51251f1b 100644
--- a/lib/compiler/src/beam_type.erl
+++ b/lib/compiler/src/beam_type.erl
@@ -168,6 +168,8 @@ simplify_float_1([{set,[D0],[A,B],{alloc,_,{gc_bif,Op0,{f,0}}}}=I|Is]=Is0, Ts0,
simplify_float_1([{set,_,_,{'catch',_}}=I|Is]=Is0, _Ts, Rs0, Acc0) ->
Acc = flush_all(Rs0, Is0, Acc0),
simplify_float_1(Is, tdb_new(), Rs0, [I|Acc]);
+simplify_float_1([{set,_,_,{line,_}}=I|Is], Ts, Rs, Acc) ->
+ simplify_float_1(Is, Ts, Rs, [I|Acc]);
simplify_float_1([I|Is]=Is0, Ts0, Rs0, Acc0) ->
Ts = update(I, Ts0),
{Rs,Acc} = flush(Rs0, Is0, Acc0),
@@ -400,6 +402,7 @@ update({call_ext,3,{extfunc,erlang,setelement,3}}, Ts0) ->
update({call,_Arity,_Func}, Ts) -> tdb_kill_xregs(Ts);
update({call_ext,_Arity,_Func}, Ts) -> tdb_kill_xregs(Ts);
update({make_fun2,_,_,_,_}, Ts) -> tdb_kill_xregs(Ts);
+update({line,_}, Ts) -> Ts;
%% The instruction is unknown. Kill all information.
update(_I, _Ts) -> tdb_new().
diff --git a/lib/compiler/src/beam_utils.erl b/lib/compiler/src/beam_utils.erl
index 45cdf8a659..f281ad5eac 100644
--- a/lib/compiler/src/beam_utils.erl
+++ b/lib/compiler/src/beam_utils.erl
@@ -26,7 +26,7 @@
code_at/2,bif_to_test/3,is_pure_test/1,
live_opt/1,delete_live_annos/1,combine_heap_needs/2]).
--import(lists, [member/2,sort/1,reverse/1]).
+-import(lists, [member/2,sort/1,reverse/1,splitwith/2]).
-record(live,
{bl, %Block check fun.
@@ -195,10 +195,14 @@ is_pure_test({test,Op,_,Ops}) ->
%% Also insert {'%live',Live} annotations at the beginning
%% and end of each block.
%%
-live_opt([{label,Fail}=I1,
- {func_info,_,_,Live}=I2|Is]) ->
+live_opt(Is0) ->
+ {[{label,Fail}|_]=Bef,[Fi|Is]} =
+ splitwith(fun({func_info,_,_,_}) -> false;
+ (_) -> true
+ end, Is0),
+ {func_info,_,_,Live} = Fi,
D = gb_trees:insert(Fail, live_call(Live), gb_trees:empty()),
- [I1,I2|live_opt(reverse(Is), 0, D, [])].
+ Bef ++ [Fi|live_opt(reverse(Is), 0, D, [])].
%% delete_live_annos([Instruction]) -> [Instruction].
@@ -499,6 +503,8 @@ check_liveness(R, [{loop_rec,{f,_},{x,0}}|_], St) ->
end;
check_liveness(R, [{loop_rec_end,{f,Fail}}|_], St) ->
check_liveness_at(R, Fail, St);
+check_liveness(R, [{line,_}|Is], St) ->
+ check_liveness(R, Is, St);
check_liveness(_R, Is, St) when is_list(Is) ->
%% case Is of
%% [I|_] ->
@@ -799,6 +805,8 @@ live_opt([{wait,_}=I|Is], Regs, D, Acc) ->
live_opt(Is, Regs, D, [I|Acc]);
live_opt([{wait_timeout,_,{Tag,_}}=I|Is], Regs, D, Acc) when Tag =/= x ->
live_opt(Is, Regs, D, [I|Acc]);
+live_opt([{line,_}=I|Is], Regs, D, Acc) ->
+ live_opt(Is, Regs, D, [I|Acc]);
%% The following instructions can occur if the "compilation" has been
%% started from a .S file using the 'asm' option.
diff --git a/lib/compiler/src/beam_validator.erl b/lib/compiler/src/beam_validator.erl
index fb267b35b6..fe3b1680d9 100644
--- a/lib/compiler/src/beam_validator.erl
+++ b/lib/compiler/src/beam_validator.erl
@@ -166,12 +166,17 @@ validate(Module, Fs) ->
Ft = index_bs_start_match(Fs, []),
validate_0(Module, Fs, Ft).
-index_bs_start_match([{function,_,_,Entry,Code}|Fs], Acc0) ->
+index_bs_start_match([{function,_,_,Entry,Code0}|Fs], Acc0) ->
+ Code = dropwhile(fun({label,L}) when L =:= Entry -> false;
+ (_) -> true
+ end, Code0),
case Code of
- [_,_,{label,Entry}|Is] ->
+ [{label,Entry}|Is] ->
Acc = index_bs_start_match_1(Is, Entry, Acc0),
index_bs_start_match(Fs, Acc);
_ ->
+ %% Something serious is wrong. Ignore it for now.
+ %% It will be detected and diagnosed later.
index_bs_start_match(Fs, Acc0)
end;
index_bs_start_match([], Acc) ->
@@ -292,6 +297,8 @@ labels(Is) ->
labels_1([{label,L}|Is], R) ->
labels_1(Is, [L|R]);
+labels_1([{line,_}|Is], R) ->
+ labels_1(Is, R);
labels_1(Is, R) ->
{lists:reverse(R),Is}.
@@ -433,6 +440,8 @@ valfun_1(remove_message, Vst) ->
Vst;
valfun_1({'%',_}, Vst) ->
Vst;
+valfun_1({line,_}, Vst) ->
+ Vst;
%% Exception generating calls
valfun_1({call_ext,Live,Func}=I, Vst) ->
case return_type(Func, Vst) of
@@ -870,6 +879,8 @@ val_dsetel({set_tuple_element,_,_,_}, #vst{current=#st{setelem=false}}) ->
error(illegal_context_for_set_tuple_element);
val_dsetel({set_tuple_element,_,_,_}, #vst{current=#st{setelem=true}}=Vst) ->
Vst;
+val_dsetel({line,_}, Vst) ->
+ Vst;
val_dsetel(_, #vst{current=#st{setelem=true}=St}=Vst) ->
Vst#vst{current=St#st{setelem=false}};
val_dsetel(_, Vst) -> Vst.
diff --git a/lib/compiler/src/compile.erl b/lib/compiler/src/compile.erl
index e46c667e47..8815cfb26f 100644
--- a/lib/compiler/src/compile.erl
+++ b/lib/compiler/src/compile.erl
@@ -172,9 +172,11 @@ expand_opt(report, Os) ->
expand_opt(return, Os) ->
[return_errors,return_warnings|Os];
expand_opt(r12, Os) ->
- [no_recv_opt|Os];
+ [no_recv_opt,no_line_info|Os];
expand_opt(r13, Os) ->
- [no_recv_opt|Os];
+ [no_recv_opt,no_line_info|Os];
+expand_opt(r14, Os) ->
+ [no_line_info|Os];
expand_opt({debug_info_key,_}=O, Os) ->
[encrypt_debug_info,O|Os];
expand_opt(no_float_opt, Os) ->
@@ -235,7 +237,8 @@ format_error({module_name,Mod,Filename}) ->
code=[],
core_code=[],
abstract_code=[], %Abstract code for debugger.
- options=[] :: [option()],
+ options=[] :: [option()], %Options for compilation
+ mod_options=[] :: [option()], %Options for module_info
errors=[],
warnings=[]}).
@@ -246,10 +249,11 @@ internal(Master, Input, Opts) ->
internal({forms,Forms}, Opts) ->
{_,Ps} = passes(forms, Opts),
- internal_comp(Ps, "", "", #compile{code=Forms,options=Opts});
+ internal_comp(Ps, "", "", #compile{code=Forms,options=Opts,
+ mod_options=Opts});
internal({file,File}, Opts) ->
{Ext,Ps} = passes(file, Opts),
- Compile = #compile{options=Opts},
+ Compile = #compile{options=Opts,mod_options=Opts},
internal_comp(Ps, File, Ext, Compile).
internal_comp(Passes, File, Suffix, St0) ->
@@ -1228,12 +1232,13 @@ beam_unused_labels(#compile{code=Code0}=St) ->
Code = beam_jump:module_labels(Code0),
{ok,St#compile{code=Code}}.
-beam_asm(#compile{ifile=File,code=Code0,abstract_code=Abst,options=Opts0}=St) ->
+beam_asm(#compile{ifile=File,code=Code0,
+ abstract_code=Abst,mod_options=Opts0}=St) ->
Source = filename:absname(File),
Opts1 = lists:map(fun({debug_info_key,_}) -> {debug_info_key,'********'};
(Other) -> Other
end, Opts0),
- Opts2 = [O || O <- Opts1, is_informative_option(O)],
+ Opts2 = [O || O <- Opts1, effects_code_generation(O)],
case beam_asm:module(Code0, Abst, Source, Opts2) of
{ok,Code} -> {ok,St#compile{code=Code,abstract_code=[]}}
end.
@@ -1303,15 +1308,23 @@ embed_native_code(St, {Architecture,NativeCode}) ->
{ok, BeamPlusNative} = beam_lib:build_module(Chunks),
St#compile{code=BeamPlusNative}.
-%% Returns true if the option is informative and therefore should be included
-%% in the option list of the compiled module.
-
-is_informative_option(beam) -> false;
-is_informative_option(report_warnings) -> false;
-is_informative_option(report_errors) -> false;
-is_informative_option(binary) -> false;
-is_informative_option(verbose) -> false;
-is_informative_option(_) -> true.
+%% effects_code_generation(Option) -> true|false.
+%% Determine whether the option could have any effect on the
+%% generated code in the BEAM file (as opposed to how
+%% errors will be reported).
+
+effects_code_generation(Option) ->
+ case Option of
+ beam -> false;
+ report_warnings -> false;
+ report_errors -> false;
+ return_errors-> false;
+ return_warnings-> false;
+ binary -> false;
+ verbose -> false;
+ {cwd,_} -> false;
+ _ -> true
+ end.
save_binary(#compile{code=none}=St) -> {ok,St};
save_binary(#compile{module=Mod,ofile=Outfile,
@@ -1438,6 +1451,8 @@ iofile(File) when is_atom(File) ->
iofile(File) ->
{filename:dirname(File), filename:basename(File, ".erl")}.
+erlfile(".", Base, Suffix) ->
+ Base ++ Suffix;
erlfile(Dir, Base, Suffix) ->
filename:join(Dir, Base ++ Suffix).
@@ -1510,6 +1525,8 @@ restore_expand_module([{attribute,Line,opaque,[Type]}|Fs]) ->
[{attribute,Line,opaque,Type}|restore_expand_module(Fs)];
restore_expand_module([{attribute,Line,spec,[Arg]}|Fs]) ->
[{attribute,Line,spec,Arg}|restore_expand_module(Fs)];
+restore_expand_module([{attribute,Line,callback,[Arg]}|Fs]) ->
+ [{attribute,Line,callback,Arg}|restore_expand_module(Fs)];
restore_expand_module([F|Fs]) ->
[F|restore_expand_module(Fs)];
restore_expand_module([]) -> [].
diff --git a/lib/compiler/src/erl_bifs.erl b/lib/compiler/src/erl_bifs.erl
index f8128702dd..f82a798ceb 100644
--- a/lib/compiler/src/erl_bifs.erl
+++ b/lib/compiler/src/erl_bifs.erl
@@ -72,7 +72,6 @@ is_pure(erlang, binary_to_list, 1) -> true;
is_pure(erlang, binary_to_list, 3) -> true;
is_pure(erlang, bit_size, 1) -> true;
is_pure(erlang, byte_size, 1) -> true;
-is_pure(erlang, concat_binary, 1) -> true;
is_pure(erlang, element, 2) -> true;
is_pure(erlang, float, 1) -> true;
is_pure(erlang, float_to_list, 1) -> true;
@@ -137,6 +136,7 @@ is_pure(math, sinh, 1) -> true;
is_pure(math, sqrt, 1) -> true;
is_pure(math, tan, 1) -> true;
is_pure(math, tanh, 1) -> true;
+is_pure(math, pi, 0) -> true;
is_pure(_, _, _) -> false.
diff --git a/lib/compiler/src/genop.tab b/lib/compiler/src/genop.tab
index 63527bda8f..39c1e8297f 100644
--- a/lib/compiler/src/genop.tab
+++ b/lib/compiler/src/genop.tab
@@ -280,3 +280,7 @@ BEAM_FORMAT_NUMBER=0
150: recv_mark/1
151: recv_set/1
152: gc_bif3/7
+
+# R15A
+
+153: line/1
diff --git a/lib/compiler/src/sys_expand_pmod.erl b/lib/compiler/src/sys_expand_pmod.erl
index 4fee26f2a6..4576dfbf12 100644
--- a/lib/compiler/src/sys_expand_pmod.erl
+++ b/lib/compiler/src/sys_expand_pmod.erl
@@ -317,6 +317,8 @@ expr({'try',Line,Es0,Scs0,Ccs0,As0},St) ->
Ccs1 = icr_clauses(Ccs0,St),
As1 = exprs(As0,St),
{'try',Line,Es1,Scs1,Ccs1,As1};
+expr({'fun',_,{function,_,_,_}}=ExtFun,_St) ->
+ ExtFun;
expr({'fun',Line,Body,Info},St) ->
case Body of
{clauses,Cs0} ->
diff --git a/lib/compiler/src/sys_pre_expand.erl b/lib/compiler/src/sys_pre_expand.erl
index 249bd7a8e7..ba9cde1de0 100644
--- a/lib/compiler/src/sys_pre_expand.erl
+++ b/lib/compiler/src/sys_pre_expand.erl
@@ -31,8 +31,6 @@
-import(ordsets, [from_list/1,add_element/2,union/2]).
-import(lists, [member/2,foldl/3,foldr/3]).
--compile({nowarn_deprecated_function, {erlang,hash,2}}).
-
-include("../include/erl_bits.hrl").
-record(expand, {module=[], %Module name
@@ -43,12 +41,12 @@
mod_imports, %Module Imports
compile=[], %Compile flags
attributes=[], %Attributes
+ callbacks=[], %Callbacks
defined=[], %Defined functions
vcount=0, %Variable counter
func=[], %Current function
arity=[], %Arity for current function
fcount=0, %Local fun count
- fun_index=0, %Global index for funs
bitdefault,
bittypes
}).
@@ -172,10 +170,41 @@ define_functions(Forms, #expand{defined=Predef}=St) ->
end, Predef, Forms),
St#expand{defined=ordsets:from_list(Fs)}.
-module_attrs(St) ->
- {[{attribute,Line,Name,Val} || {Name,Line,Val} <- St#expand.attributes],St}.
+module_attrs(#expand{attributes=Attributes}=St) ->
+ Attrs = [{attribute,Line,Name,Val} || {Name,Line,Val} <- Attributes],
+ Callbacks = [Callback || {_,_,callback,_}=Callback <- Attrs],
+ {Attrs,St#expand{callbacks=Callbacks}}.
module_predef_funcs(St) ->
+ {Mpf1,St1}=module_predef_func_beh_info(St),
+ {Mpf2,St2}=module_predef_funcs_mod_info(St1),
+ {Mpf1++Mpf2,St2}.
+
+module_predef_func_beh_info(#expand{callbacks=[]}=St) ->
+ {[], St};
+module_predef_func_beh_info(#expand{callbacks=Callbacks,defined=Defined,
+ exports=Exports}=St) ->
+ PreDef=[{behaviour_info,1}],
+ PreExp=PreDef,
+ {[gen_beh_info(Callbacks)],
+ St#expand{defined=union(from_list(PreDef), Defined),
+ exports=union(from_list(PreExp), Exports)}}.
+
+gen_beh_info(Callbacks) ->
+ List = make_list(Callbacks),
+ {function,0,behaviour_info,1,
+ [{clause,0,[{atom,0,callbacks}],[],
+ [List]}]}.
+
+make_list([]) -> {nil,0};
+make_list([{_,_,_,[{{Name,Arity},_}]}|Rest]) ->
+ {cons,0,
+ {tuple,0,
+ [{atom,0,Name},
+ {integer,0,Arity}]},
+ make_list(Rest)}.
+
+module_predef_funcs_mod_info(St) ->
PreDef = [{module_info,0},{module_info,1}],
PreExp = PreDef,
{[{function,0,module_info,0,
@@ -506,32 +535,34 @@ lc_tq(_Line, [], St0) ->
%% Transform an "explicit" fun {'fun', Line, {clauses, Cs}} into an
%% extended form {'fun', Line, {clauses, Cs}, Info}, unless it is the
%% name of a BIF (erl_lint has checked that it is not an import).
-%% Process the body sequence directly to get the new and used variables.
%% "Implicit" funs {'fun', Line, {function, F, A}} are not changed.
fun_tq(Lf, {function,F,A}=Function, St0) ->
- {As,St1} = new_vars(A, Lf, St0),
- Cs = [{clause,Lf,As,[],[{call,Lf,{atom,Lf,F},As}]}],
case erl_internal:bif(F, A) of
true ->
+ {As,St1} = new_vars(A, Lf, St0),
+ Cs = [{clause,Lf,As,[],[{call,Lf,{atom,Lf,F},As}]}],
fun_tq(Lf, {clauses,Cs}, St1);
false ->
- Index = St0#expand.fun_index,
- Uniq = erlang:hash(Cs, (1 bsl 27)-1),
- {Fname,St2} = new_fun_name(St1),
- {{'fun',Lf,Function,{Index,Uniq,Fname}},
- St2#expand{fun_index=Index+1}}
+ {Fname,St1} = new_fun_name(St0),
+ Index = Uniq = 0,
+ {{'fun',Lf,Function,{Index,Uniq,Fname}},St1}
end;
-fun_tq(L, {function,M,F,A}, St) ->
- {{call,L,{remote,L,{atom,L,erlang},{atom,L,make_fun}},
- [{atom,L,M},{atom,L,F},{integer,L,A}]},St};
+fun_tq(L, {function,M,F,A}, St) when is_atom(M), is_atom(F), is_integer(A) ->
+ %% This is the old format for external funs, generated by a pre-R15
+ %% compiler. That means that a tool, such as the debugger or xref,
+ %% directly invoked this module with the abstract code from a
+ %% pre-R15 BEAM file. Be helpful, and translate it to the new format.
+ fun_tq(L, {function,{atom,L,M},{atom,L,F},{integer,L,A}}, St);
+fun_tq(Lf, {function,_,_,_}=ExtFun, St) ->
+ {{'fun',Lf,ExtFun},St};
fun_tq(Lf, {clauses,Cs0}, St0) ->
- Uniq = erlang:hash(Cs0, (1 bsl 27)-1),
{Cs1,St1} = fun_clauses(Cs0, St0),
- Index = St1#expand.fun_index,
{Fname,St2} = new_fun_name(St1),
- {{'fun',Lf,{clauses,Cs1},{Index,Uniq,Fname}},
- St2#expand{fun_index=Index+1}}.
+ %% Set dummy values for Index and Uniq -- the real values will
+ %% be assigned by beam_asm.
+ Index = Uniq = 0,
+ {{'fun',Lf,{clauses,Cs1},{Index,Uniq,Fname}},St2}.
fun_clauses([{clause,L,H0,G0,B0}|Cs0], St0) ->
{H,St1} = head(H0, St0),
diff --git a/lib/compiler/src/v3_codegen.erl b/lib/compiler/src/v3_codegen.erl
index 55e3c58d2a..e7dae67085 100644
--- a/lib/compiler/src/v3_codegen.erl
+++ b/lib/compiler/src/v3_codegen.erl
@@ -79,9 +79,10 @@ module({Mod,Exp,Attr,Forms}, Options) ->
functions(Forms, AtomMod) ->
mapfoldl(fun (F, St) -> function(F, AtomMod, St) end, #cg{lcount=1}, Forms).
-function({function,Name,Arity,Asm0,Vb,Vdb}, AtomMod, St0) ->
+function({function,Name,Arity,Asm0,Vb,Vdb,Anno}, AtomMod, St0) ->
try
- {Asm,EntryLabel,St} = cg_fun(Vb, Asm0, Vdb, AtomMod, {Name,Arity}, St0),
+ {Asm,EntryLabel,St} = cg_fun(Vb, Asm0, Vdb, AtomMod,
+ {Name,Arity}, Anno, St0),
Func = {function,Name,Arity,EntryLabel,Asm},
{Func,St}
catch
@@ -93,7 +94,7 @@ function({function,Name,Arity,Asm0,Vb,Vdb}, AtomMod, St0) ->
%% cg_fun([Lkexpr], [HeadVar], Vdb, State) -> {[Ainstr],State}
-cg_fun(Les, Hvs, Vdb, AtomMod, NameArity, St0) ->
+cg_fun(Les, Hvs, Vdb, AtomMod, NameArity, Anno, St0) ->
{Fi,St1} = new_label(St0), %FuncInfo label
{Fl,St2} = local_func_label(NameArity, St1),
@@ -129,7 +130,7 @@ cg_fun(Les, Hvs, Vdb, AtomMod, NameArity, St0) ->
ultimate_failure=UltimateMatchFail,
is_top_block=true}),
{Name,Arity} = NameArity,
- Asm = [{label,Fi},{func_info,AtomMod,{atom,Name},Arity},
+ Asm = [{label,Fi},line(Anno),{func_info,AtomMod,{atom,Name},Arity},
{label,Fl}|B++[{label,UltimateMatchFail},if_end]],
{Asm,Fl,St}.
@@ -307,23 +308,23 @@ match_fail_cg({badmatch,Term}, Le, Vdb, Bef, St) ->
R = cg_reg_arg(Term, Bef),
Int0 = clear_dead(Bef, Le#l.i, Vdb),
{Sis,Int} = adjust_stack(Int0, Le#l.i, Le#l.i+1, Vdb),
- {Sis ++ [{badmatch,R}],
+ {Sis ++ [line(Le),{badmatch,R}],
Int#sr{reg=clear_regs(Int0#sr.reg)},St};
match_fail_cg({case_clause,Reason}, Le, Vdb, Bef, St) ->
R = cg_reg_arg(Reason, Bef),
Int0 = clear_dead(Bef, Le#l.i, Vdb),
{Sis,Int} = adjust_stack(Int0, Le#l.i, Le#l.i+1, Vdb),
- {Sis++[{case_end,R}],
+ {Sis++[line(Le),{case_end,R}],
Int#sr{reg=clear_regs(Bef#sr.reg)},St};
match_fail_cg(if_clause, Le, Vdb, Bef, St) ->
Int0 = clear_dead(Bef, Le#l.i, Vdb),
{Sis,Int1} = adjust_stack(Int0, Le#l.i, Le#l.i+1, Vdb),
- {Sis++[if_end],Int1#sr{reg=clear_regs(Int1#sr.reg)},St};
+ {Sis++[line(Le),if_end],Int1#sr{reg=clear_regs(Int1#sr.reg)},St};
match_fail_cg({try_clause,Reason}, Le, Vdb, Bef, St) ->
R = cg_reg_arg(Reason, Bef),
Int0 = clear_dead(Bef, Le#l.i, Vdb),
{Sis,Int} = adjust_stack(Int0, Le#l.i, Le#l.i+1, Vdb),
- {Sis ++ [{try_case_end,R}],
+ {Sis ++ [line(Le),{try_case_end,R}],
Int#sr{reg=clear_regs(Int0#sr.reg)},St}.
%% bsm_rename_ctx([Clause], Var) -> [Clause]
@@ -1047,7 +1048,7 @@ call_cg({var,_V} = Var, As, Rs, Le, Vdb, Bef, St0) ->
%% Build complete code and final stack/register state.
Arity = length(As),
{Frees,Aft} = free_dead(clear_dead(Int#sr{reg=Reg}, Le#l.i, Vdb)),
- {Sis ++ Frees ++ [{call_fun,Arity}],Aft,
+ {Sis ++ Frees ++ [line(Le),{call_fun,Arity}],Aft,
need_stack_frame(St0)};
call_cg({remote,Mod,Name}, As, Rs, Le, Vdb, Bef, St0)
when element(1, Mod) =:= var;
@@ -1057,11 +1058,10 @@ call_cg({remote,Mod,Name}, As, Rs, Le, Vdb, Bef, St0)
Reg = load_vars(Rs, clear_regs(Int#sr.reg)),
%% Build complete code and final stack/register state.
Arity = length(As),
- Call = {apply,Arity},
St = need_stack_frame(St0),
%%{Call,St1} = build_call(Func, Arity, St0),
{Frees,Aft} = free_dead(clear_dead(Int#sr{reg=Reg}, Le#l.i, Vdb)),
- {Sis ++ Frees ++ [Call],Aft,St};
+ {Sis ++ Frees ++ [line(Le),{apply,Arity}],Aft,St};
call_cg(Func, As, Rs, Le, Vdb, Bef, St0) ->
case St0 of
#cg{bfail=Fail} when Fail =/= 0 ->
@@ -1091,7 +1091,7 @@ call_cg(Func, As, Rs, Le, Vdb, Bef, St0) ->
Arity = length(As),
{Call,St1} = build_call(Func, Arity, St0),
{Frees,Aft} = free_dead(clear_dead(Int#sr{reg=Reg}, Le#l.i, Vdb)),
- {Sis ++ Frees ++ Call,Aft,St1}
+ {Sis ++ Frees ++ [line(Le)|Call],Aft,St1}
end.
build_call({remote,{atom,erlang},{atom,'!'}}, 2, St0) ->
@@ -1118,7 +1118,7 @@ enter_cg({var,_V} = Var, As, Le, Vdb, Bef, St0) ->
{Sis,Int} = cg_setup_call(As++[Var], Bef, Le#l.i, Vdb),
%% Build complete code and final stack/register state.
Arity = length(As),
- {Sis ++ [{call_fun,Arity},return],
+ {Sis ++ [line(Le),{call_fun,Arity},return],
clear_dead(Int#sr{reg=clear_regs(Int#sr.reg)}, Le#l.i, Vdb),
need_stack_frame(St0)};
enter_cg({remote,Mod,Name}, As, Le, Vdb, Bef, St0)
@@ -1127,9 +1127,8 @@ enter_cg({remote,Mod,Name}, As, Le, Vdb, Bef, St0)
{Sis,Int} = cg_setup_call(As++[Mod,Name], Bef, Le#l.i, Vdb),
%% Build complete code and final stack/register state.
Arity = length(As),
- Call = {apply_only,Arity},
St = need_stack_frame(St0),
- {Sis ++ [Call],
+ {Sis ++ [line(Le),{apply_only,Arity}],
clear_dead(Int#sr{reg=clear_regs(Int#sr.reg)}, Le#l.i, Vdb),
St};
enter_cg(Func, As, Le, Vdb, Bef, St0) ->
@@ -1137,7 +1136,8 @@ enter_cg(Func, As, Le, Vdb, Bef, St0) ->
%% Build complete code and final stack/register state.
Arity = length(As),
{Call,St1} = build_enter(Func, Arity, St0),
- {Sis ++ Call,
+ Line = enter_line(Func, Arity, Le),
+ {Sis ++ Line ++ Call,
clear_dead(Int#sr{reg=clear_regs(Int#sr.reg)}, Le#l.i, Vdb),
St1}.
@@ -1153,6 +1153,23 @@ build_enter(Name, Arity, St0) when is_atom(Name) ->
{Lbl,St1} = local_func_label(Name, Arity, St0),
{[{call_only,Arity,{f,Lbl}}],St1}.
+enter_line({remote,{atom,Mod},{atom,Name}}, Arity, Le) ->
+ case erl_bifs:is_safe(Mod, Name, Arity) of
+ false ->
+ %% Tail-recursive call, possibly to a BIF.
+ %% We'll need a line instruction in case the
+ %% BIF call fails.
+ [line(Le)];
+ true ->
+ %% Call to a safe BIF. Since it cannot fail,
+ %% we don't need any line instruction here.
+ []
+ end;
+enter_line(_, _, _) ->
+ %% Tail-recursive call to a local function. A line
+ %% instruction will not be useful.
+ [].
+
%% local_func_label(Name, Arity, State) -> {Label,State'}
%% local_func_label({Name,Arity}, State) -> {Label,State'}
%% Get the function entry label for a local function.
@@ -1226,9 +1243,10 @@ bif_cg(Bif, As, [{var,V}], Le, Vdb, Bef, St0) ->
%% Currently, we are somewhat pessimistic in
%% that we save any variable that will be live after this BIF call.
+ MayFail = not erl_bifs:is_safe(erlang, Bif, length(As)),
{Sis,Int0} = case St0#cg.in_catch andalso
St0#cg.bfail =:= 0 andalso
- not erl_bifs:is_safe(erlang, Bif, length(As)) of
+ MayFail of
true -> adjust_stack(Bef, Le#l.i, Le#l.i+1, Vdb);
false -> {[],Bef}
end,
@@ -1237,7 +1255,14 @@ bif_cg(Bif, As, [{var,V}], Le, Vdb, Bef, St0) ->
Int = Int1#sr{reg=Reg},
Dst = fetch_reg(V, Reg),
BifFail = {f,St0#cg.bfail},
- {Sis++[{bif,Bif,BifFail,Ars,Dst}],
+ %% We need a line instructions for BIFs that may fail in a body.
+ Line = case BifFail of
+ {f,0} when MayFail ->
+ [line(Le)];
+ _ ->
+ []
+ end,
+ {Sis++Line++[{bif,Bif,BifFail,Ars,Dst}],
clear_dead(Int, Le#l.i, Vdb), St0}.
@@ -1266,7 +1291,11 @@ gc_bif_cg(Bif, As, [{var,V}], Le, Vdb, Bef, St0) ->
Int = Int1#sr{reg=Reg},
Dst = fetch_reg(V, Reg),
BifFail = {f,St0#cg.bfail},
- {Sis++[{gc_bif,Bif,BifFail,max_reg(Bef#sr.reg),Ars,Dst}],
+ Line = case BifFail of
+ {f,0} -> [line(Le)];
+ {f,_} -> []
+ end,
+ {Sis++Line++[{gc_bif,Bif,BifFail,max_reg(Bef#sr.reg),Ars,Dst}],
clear_dead(Int, Le#l.i, Vdb), St0}.
%% recv_loop_cg(TimeOut, ReceiveVar, ReceiveMatch, TimeOutExprs,
@@ -1284,7 +1313,7 @@ recv_loop_cg(Te, Rvar, Rm, Tes, Rs, Le, Vdb, Bef, St0) ->
{Wis,Taft,St6} = cg_recv_wait(Te, Tes, Le#l.i, Int1, St5),
Int2 = sr_merge(Raft, Taft), %Merge stack/registers
Reg = load_vars(Rs, Int2#sr.reg),
- {Sis ++ Ris ++ [{label,Tl}] ++ Wis ++ [{label,Bl}],
+ {Sis ++ [line(Le)] ++ Ris ++ [{label,Tl}] ++ Wis ++ [{label,Bl}],
clear_dead(Int2#sr{reg=Reg}, Le#l.i, Vdb),
St6#cg{break=St0#cg.break,recv=St0#cg.recv}}.
@@ -1463,12 +1492,13 @@ cg_binary([{bs_put_binary,Fail,{atom,all},U,_Flags,Src}|PutCode],
{bs_append,Fail,Target,0,MaxRegs,U,Src,BinFlags,Target}
end] ++ PutCode,
cg_bin_opt(Code);
-cg_binary(PutCode, Target, Temp, Fail, MaxRegs, _Anno) ->
+cg_binary(PutCode, Target, Temp, Fail, MaxRegs, Anno) ->
+ Line = line(Anno),
Live = cg_live(Target, MaxRegs),
{InitOp,SzCode} = cg_binary_size(PutCode, Target, Temp, Fail, Live),
- Code = SzCode ++ [{InitOp,Fail,Target,0,MaxRegs,
- {field_flags,[]},Target}|PutCode],
+ Code = [Line|SzCode] ++ [{InitOp,Fail,Target,0,MaxRegs,
+ {field_flags,[]},Target}|PutCode],
cg_bin_opt(Code).
cg_live({x,X}, MaxRegs) when X =:= MaxRegs -> MaxRegs+1;
@@ -2052,6 +2082,38 @@ drop_catch(Tag, [Other|Stk]) -> [Other|drop_catch(Tag, Stk)].
new_label(#cg{lcount=Next}=St) ->
{Next,St#cg{lcount=Next+1}}.
+%% line(Le) -> {line,[] | {location,File,Line}}
+%% Create a line instruction, containing information about
+%% the current filename and line number. A line information
+%% instruction should be placed before any operation that could
+%% cause an exception.
+
+line(#l{a=Anno}) ->
+ line(Anno);
+line([Line,{file,Name}]) when is_integer(Line) ->
+ line_1(Name, Line);
+line([_|_]=A) ->
+ {Name,Line} = find_loc(A, no_file, 0),
+ line_1(Name, Line);
+line([]) ->
+ {line,[]}.
+
+line_1(no_file, _) ->
+ {line,[]};
+line_1(_, 0) ->
+ %% Missing line number or line number 0.
+ {line,[]};
+line_1(Name, Line) ->
+ {line,[{location,Name,abs(Line)}]}.
+
+find_loc([Line|T], File, _) when is_integer(Line) ->
+ find_loc(T, File, Line);
+find_loc([{file,File}|T], _, Line) ->
+ find_loc(T, File, Line);
+find_loc([_|T], File, Line) ->
+ find_loc(T, File, Line);
+find_loc([], File, Line) -> {File,Line}.
+
flatmapfoldl(F, Accu0, [Hd|Tail]) ->
{R,Accu1} = F(Hd, Accu0),
{Rs,Accu2} = flatmapfoldl(F, Accu1, Tail),
diff --git a/lib/compiler/src/v3_core.erl b/lib/compiler/src/v3_core.erl
index 87bb5bec25..6885405ae0 100644
--- a/lib/compiler/src/v3_core.erl
+++ b/lib/compiler/src/v3_core.erl
@@ -180,7 +180,7 @@ body(Cs0, Name, Arity, St0) ->
{Args,St1} = new_vars(Anno, Arity, St0),
{Cs1,St2} = clauses(Cs0, St1),
{Ps,St3} = new_vars(Arity, St2), %Need new variables here
- Fc = function_clause(Ps, {Name,Arity}),
+ Fc = function_clause(Ps, Anno, {Name,Arity}),
{#ifun{anno=#a{anno=Anno},id=[],vars=Args,clauses=Cs1,fc=Fc},St3}.
%% clause(Clause, State) -> {Cclause,State} | noclause.
@@ -507,15 +507,15 @@ expr({block,_,Es0}, St0) ->
{E1,Es1 ++ Eps,St2};
expr({'if',L,Cs0}, St0) ->
{Cs1,St1} = clauses(Cs0, St0),
- Fc = fail_clause([], #c_literal{val=if_clause}),
Lanno = lineno_anno(L, St1),
+ Fc = fail_clause([], Lanno, #c_literal{val=if_clause}),
{#icase{anno=#a{anno=Lanno},args=[],clauses=Cs1,fc=Fc},[],St1};
expr({'case',L,E0,Cs0}, St0) ->
{E1,Eps,St1} = novars(E0, St0),
{Cs1,St2} = clauses(Cs0, St1),
{Fpat,St3} = new_var(St2),
- Fc = fail_clause([Fpat], c_tuple([#c_literal{val=case_clause},Fpat])),
- Lanno = lineno_anno(L, St3),
+ Lanno = lineno_anno(L, St2),
+ Fc = fail_clause([Fpat], Lanno, c_tuple([#c_literal{val=case_clause},Fpat])),
{#icase{anno=#a{anno=Lanno},args=[E1],clauses=Cs1,fc=Fc},Eps,St3};
expr({'receive',L,Cs0}, St0) ->
{Cs1,St1} = clauses(Cs0, St0),
@@ -541,9 +541,10 @@ expr({'try',L,Es0,Cs0,Ecs,[]}, St0) ->
{V,St2} = new_var(St1), %This name should be arbitrary
{Cs1,St3} = clauses(Cs0, St2),
{Fpat,St4} = new_var(St3),
- Fc = fail_clause([Fpat], c_tuple([#c_literal{val=try_clause},Fpat])),
+ Lanno = lineno_anno(L, St4),
+ Fc = fail_clause([Fpat], Lanno,
+ c_tuple([#c_literal{val=try_clause},Fpat])),
{Evs,Hs,St5} = try_exception(Ecs, St4),
- Lanno = lineno_anno(L, St1),
{#itry{anno=#a{anno=lineno_anno(L, St5)},args=Es1,
vars=[V],body=[#icase{anno=#a{anno=Lanno},args=[V],clauses=Cs1,fc=Fc}],
evars=Evs,handler=Hs},
@@ -572,6 +573,13 @@ expr({'catch',L,E0}, St0) ->
expr({'fun',L,{function,F,A},{_,_,_}=Id}, St) ->
Lanno = lineno_anno(L, St),
{#c_var{anno=Lanno++[{id,Id}],name={F,A}},[],St};
+expr({'fun',L,{function,M,F,A}}, St0) ->
+ {As,Aps,St1} = safe_list([M,F,A], St0),
+ Lanno = lineno_anno(L, St1),
+ {#icall{anno=#a{anno=Lanno},
+ module=#c_literal{val=erlang},
+ name=#c_literal{val=make_fun},
+ args=As},Aps,St1};
expr({'fun',L,{clauses,Cs},Id}, St) ->
fun_tq(Id, Cs, L, St);
expr({call,L,{remote,_,M,F},As0}, #core{wanted=Wanted}=St0) ->
@@ -607,8 +615,8 @@ expr({match,L,P0,E0}, St0) ->
Thrown
end,
{Fpat,St4} = new_var(St3),
- Fc = fail_clause([Fpat], c_tuple([#c_literal{val=badmatch},Fpat])),
Lanno = lineno_anno(L, St4),
+ Fc = fail_clause([Fpat], Lanno, c_tuple([#c_literal{val=badmatch},Fpat])),
case P2 of
nomatch ->
St = add_warning(L, nomatch, St4),
@@ -828,8 +836,9 @@ fun_tq({_,_,Name}=Id, Cs0, L, St0) ->
{Cs1,St1} = clauses(Cs0, St0),
{Args,St2} = new_vars(Arity, St1),
{Ps,St3} = new_vars(Arity, St2), %Need new variables here
- Fc = function_clause(Ps, {Name,Arity}),
- Fun = #ifun{anno=#a{anno=lineno_anno(L, St3)},
+ Anno = lineno_anno(L, St3),
+ Fc = function_clause(Ps, Anno, {Name,Arity}),
+ Fun = #ifun{anno=#a{anno=Anno},
id=[{id,Id}], %We KNOW!
vars=Args,clauses=Cs1,fc=Fc},
{Fun,[],St3}.
@@ -929,7 +938,7 @@ lc_tq(Line, E, [{b_generate,Lg,P,G}|Qs0], Mc, St0) ->
[],St};
lc_tq(Line, E, [Fil0|Qs0], Mc, St0) ->
%% Special case sequences guard tests.
- LA = lineno_anno(Line, St0),
+ LA = lineno_anno(element(2, Fil0), St0),
LAnno = #a{anno=LA},
case is_guard_test(Fil0) of
true ->
@@ -945,7 +954,8 @@ lc_tq(Line, E, [Fil0|Qs0], Mc, St0) ->
false ->
{Lc,Lps,St1} = lc_tq(Line, E, Qs0, Mc, St0),
{Fpat,St2} = new_var(St1),
- Fc = fail_clause([Fpat], c_tuple([#c_literal{val=case_clause},Fpat])),
+ Fc = fail_clause([Fpat], LA,
+ c_tuple([#c_literal{val=case_clause},Fpat])),
%% Do a novars little optimisation here.
{Filc,Fps,St3} = novars(Fil0, St2),
{#icase{anno=LAnno,
@@ -1072,7 +1082,7 @@ bc_tq1(Line, E, [{b_generate,Lg,P,G}|Qs0], AccExpr, St0) ->
[],St};
bc_tq1(Line, E, [Fil0|Qs0], AccVar, St0) ->
%% Special case sequences guard tests.
- LA = lineno_anno(Line, St0),
+ LA = lineno_anno(element(2, Fil0), St0),
LAnno = #a{anno=LA},
case is_guard_test(Fil0) of
true ->
@@ -1089,7 +1099,8 @@ bc_tq1(Line, E, [Fil0|Qs0], AccVar, St0) ->
false ->
{Bc,Bps,St1} = bc_tq1(Line, E, Qs0, AccVar, St0),
{Fpat,St2} = new_var(St1),
- Fc = fail_clause([Fpat], c_tuple([#c_literal{val=case_clause},Fpat])),
+ Fc = fail_clause([Fpat], LA,
+ c_tuple([#c_literal{val=case_clause},Fpat])),
%% Do a novars little optimisation here.
{Filc,Fps,St} = novars(Fil0, St2),
{#icase{anno=LAnno,
@@ -1562,17 +1573,11 @@ new_vars_1(N, Anno, St0, Vs) when N > 0 ->
new_vars_1(N-1, Anno, St1, [V|Vs]);
new_vars_1(0, _, St, Vs) -> {Vs,St}.
-function_clause(Ps, Name) ->
- function_clause(Ps, [], Name).
-
function_clause(Ps, LineAnno, Name) ->
- FcAnno = [{function_name,Name}],
+ FcAnno = [{function_name,Name}|LineAnno],
fail_clause(Ps, FcAnno,
ann_c_tuple(LineAnno, [#c_literal{val=function_clause}|Ps])).
-fail_clause(Pats, Arg) ->
- fail_clause(Pats, [], Arg).
-
fail_clause(Pats, Anno, Arg) ->
#iclause{anno=#a{anno=[compiler_generated]},
pats=Pats,guard=[],
diff --git a/lib/compiler/src/v3_kernel.erl b/lib/compiler/src/v3_kernel.erl
index 3b33a08cf7..47e5e49a76 100644
--- a/lib/compiler/src/v3_kernel.erl
+++ b/lib/compiler/src/v3_kernel.erl
@@ -84,8 +84,6 @@
keymember/3,keyfind/3]).
-import(ordsets, [add_element/2,del_element/2,union/2,union/1,subtract/2]).
--compile({nowarn_deprecated_function, {erlang,hash,2}}).
-
-include("core_parse.hrl").
-include("v3_kernel.hrl").
@@ -247,7 +245,7 @@ expr(#c_var{anno=A,name={_Name,Arity}}=Fname, Sub, St) ->
%% instead of one for each occurrence as done now.
Vs = [#c_var{name=list_to_atom("V" ++ integer_to_list(V))} ||
V <- integers(1, Arity)],
- Fun = #c_fun{anno=A,vars=Vs,body=#c_apply{op=Fname,args=Vs}},
+ Fun = #c_fun{anno=A,vars=Vs,body=#c_apply{anno=A,op=Fname,args=Vs}},
expr(Fun, Sub, St);
expr(#c_var{anno=A,name=V}, Sub, St) ->
{#k_var{anno=A,name=get_vsub(V, Sub)},[],St};
@@ -291,7 +289,7 @@ expr(#c_binary{anno=A,segments=Cv}, Sub, St0) ->
Erl = #c_literal{val=erlang},
Name = #c_literal{val=error},
Args = [#c_literal{val=badarg}],
- Error = #c_call{module=Erl,name=Name,args=Args},
+ Error = #c_call{anno=A,module=Erl,name=Name,args=Args},
expr(Error, Sub, St0)
end;
expr(#c_fun{anno=A,vars=Cvs,body=Cb}, Sub0, #kern{ff=OldFF,func=Func}=St0) ->
@@ -1167,9 +1165,7 @@ select_bin_int_1(_, _, _, _) -> throw(not_possible).
select_assert_match_possible(Sz, Val, Fs) ->
EmptyBindings = erl_eval:new_bindings(),
- MatchFun = fun({integer,_,_}, NewV, Bs) when NewV =:= Val ->
- {match,Bs}
- end,
+ MatchFun = match_fun(Val),
EvalFun = fun({integer,_,S}, B) -> {value,S,B} end,
Expr = [{bin_element,0,{integer,0,Val},{integer,0,Sz},[{unit,1}|Fs]}],
{value,Bin,EmptyBindings} = eval_bits:expr_grp(Expr, EmptyBindings, EvalFun),
@@ -1184,6 +1180,11 @@ select_assert_match_possible(Sz, Val, Fs) ->
throw(not_possible)
end.
+match_fun(Val) ->
+ fun(match, {{integer,_,_},NewV,Bs}) when NewV =:= Val ->
+ {match,Bs}
+ end.
+
select_utf8(Val0) ->
try
Bin = <<Val0/utf8>>,
@@ -1655,31 +1656,31 @@ uexpr(#k_catch{anno=A,body=B0}, {break,Rs0}, St0) ->
{Ns,St3} = new_vars(1 - length(Rs0), St2),
Rs1 = Rs0 ++ Ns,
{#k_catch{anno=#k{us=Bu,ns=lit_list_vars(Rs1),a=A},body=B1,ret=Rs1},Bu,St3};
-uexpr(#ifun{anno=A,vars=Vs,body=B0}=IFun, {break,Rs}, St0) ->
+uexpr(#ifun{anno=A,vars=Vs,body=B0}, {break,Rs}, St0) ->
{B1,Bu,St1} = ubody(B0, return, St0), %Return out of new function
Ns = lit_list_vars(Vs),
Free = subtract(Bu, Ns), %Free variables in fun
Fvs = make_vars(Free),
Arity = length(Vs) + length(Free),
- {{Index,Uniq,Fname}, St3} =
+ {Fname,St} =
case lists:keyfind(id, 1, A) of
- {id,Id} ->
- {Id, St1};
+ {id,{_,_,Fname0}} ->
+ {Fname0,St1};
false ->
- %% No id annotation. Must invent one.
- I = St1#kern.fcount,
- U = erlang:hash(IFun, (1 bsl 27)-1),
- {N, St2} = new_fun_name(St1),
- {{I,U,N}, St2}
+ %% No id annotation. Must invent a fun name.
+ new_fun_name(St1)
end,
Fun = #k_fdef{anno=#k{us=[],ns=[],a=A},func=Fname,arity=Arity,
vars=Vs ++ Fvs,body=B1},
+ %% Set dummy values for Index and Uniq -- the real values will
+ %% be assigned by beam_asm.
+ Index = Uniq = 0,
{#k_bif{anno=#k{us=Free,ns=lit_list_vars(Rs),a=A},
op=#k_internal{name=make_fun,arity=length(Free)+3},
args=[#k_atom{val=Fname},#k_int{val=Arity},
#k_int{val=Index},#k_int{val=Uniq}|Fvs],
ret=Rs},
- Free,add_local_function(Fun, St3)};
+ Free,add_local_function(Fun, St)};
uexpr(Lit, {break,Rs}, St) ->
%% Transform literals to puts here.
%%ok = io:fwrite("uexpr ~w:~p~n", [?LINE,Lit]),
diff --git a/lib/compiler/src/v3_life.erl b/lib/compiler/src/v3_life.erl
index a7a4d4dc91..a1d92af9f8 100644
--- a/lib/compiler/src/v3_life.erl
+++ b/lib/compiler/src/v3_life.erl
@@ -65,7 +65,7 @@ functions([], Acc) -> reverse(Acc).
%% function(Kfunc) -> Func.
-function(#k_fdef{func=F,arity=Ar,vars=Vs,body=Kb}) ->
+function(#k_fdef{anno=#k{a=Anno},func=F,arity=Ar,vars=Vs,body=Kb}) ->
try
As = var_list(Vs),
Vdb0 = foldl(fun ({var,N}, Vdb) -> new_var(N, 0, Vdb) end, [], As),
@@ -80,7 +80,7 @@ function(#k_fdef{func=F,arity=Ar,vars=Vs,body=Kb}) ->
put(guard_refc, 0),
{B1,_,Vdb1} = body(B0, 1, Vdb0),
erase(guard_refc),
- {function,F,Ar,As,B1,Vdb1}
+ {function,F,Ar,As,B1,Vdb1,Anno}
catch
Class:Error ->
Stack = erlang:get_stacktrace(),
diff --git a/lib/compiler/test/bs_match_SUITE.erl b/lib/compiler/test/bs_match_SUITE.erl
index 6a795f6634..f8c71a0257 100644
--- a/lib/compiler/test/bs_match_SUITE.erl
+++ b/lib/compiler/test/bs_match_SUITE.erl
@@ -1028,8 +1028,8 @@ haystack_2(Haystack) ->
fc({'EXIT',{function_clause,_}}) -> ok;
fc({'EXIT',{{case_clause,_},_}}) when ?MODULE =:= bs_match_inline_SUITE -> ok.
-fc(Name, Args, {'EXIT',{function_clause,[{?MODULE,Name,Args}|_]}}) -> ok;
-fc(Name, Args, {'EXIT',{function_clause,[{?MODULE,Name,Arity}|_]}})
+fc(Name, Args, {'EXIT',{function_clause,[{?MODULE,Name,Args,_}|_]}}) -> ok;
+fc(Name, Args, {'EXIT',{function_clause,[{?MODULE,Name,Arity,_}|_]}})
when length(Args) =:= Arity ->
true = test_server:is_native(?MODULE);
fc(_, Args, {'EXIT',{{case_clause,ActualArgs},_}})
diff --git a/lib/compiler/test/bs_utf_SUITE.erl b/lib/compiler/test/bs_utf_SUITE.erl
index f30a4d3fef..94549ad0d3 100644
--- a/lib/compiler/test/bs_utf_SUITE.erl
+++ b/lib/compiler/test/bs_utf_SUITE.erl
@@ -264,18 +264,10 @@ literals(Config) when is_list(Config) ->
?line {'EXIT',{badarg,_}} = (catch <<(-1)/utf32,I/utf8>>),
?line {'EXIT',{badarg,_}} = (catch <<(-1)/little-utf32,I/utf8>>),
?line {'EXIT',{badarg,_}} = (catch <<16#D800/utf8,I/utf8>>),
- ?line {'EXIT',{badarg,_}} = (catch <<16#FFFE/utf8,I/utf8>>),
- ?line {'EXIT',{badarg,_}} = (catch <<16#FFFF/utf8,I/utf8>>),
?line {'EXIT',{badarg,_}} = (catch <<16#D800/utf16,I/utf8>>),
?line {'EXIT',{badarg,_}} = (catch <<16#D800/little-utf16,I/utf8>>),
- ?line {'EXIT',{badarg,_}} = (catch <<16#FFFE/utf16,I/utf8>>),
- ?line {'EXIT',{badarg,_}} = (catch <<16#FFFE/little-utf16,I/utf8>>),
- ?line {'EXIT',{badarg,_}} = (catch <<16#FFFF/utf16,I/utf8>>),
- ?line {'EXIT',{badarg,_}} = (catch <<16#FFFF/little-utf16,I/utf8>>),
?line {'EXIT',{badarg,_}} = (catch <<16#D800/utf32,I/utf8>>),
?line {'EXIT',{badarg,_}} = (catch <<16#D800/little-utf32,I/utf8>>),
- ?line {'EXIT',{badarg,_}} = (catch <<16#FFFE/utf32,I/utf8>>),
- ?line {'EXIT',{badarg,_}} = (catch <<16#FFFF/little-utf32,I/utf8>>),
B = 16#10FFFF+1,
?line {'EXIT',{badarg,_}} = (catch <<B/utf8>>),
@@ -286,20 +278,11 @@ literals(Config) when is_list(Config) ->
%% Matching of bad literals.
?line error = bad_literal_match(<<237,160,128>>), %16#D800 in UTF-8
- ?line error = bad_literal_match(<<239,191,190>>), %16#FFFE in UTF-8
- ?line error = bad_literal_match(<<239,191,191>>), %16#FFFF in UTF-8
?line error = bad_literal_match(<<244,144,128,128>>), %16#110000 in UTF-8
- ?line error = bad_literal_match(<<255,254>>), %16#FFFE in UTF-16
- ?line error = bad_literal_match(<<255,255>>), %16#FFFF in UTF-16
-
?line error = bad_literal_match(<<16#D800:32>>),
- ?line error = bad_literal_match(<<16#FFFE:32>>),
- ?line error = bad_literal_match(<<16#FFFF:32>>),
?line error = bad_literal_match(<<16#110000:32>>),
?line error = bad_literal_match(<<16#D800:32/little>>),
- ?line error = bad_literal_match(<<16#FFFE:32/little>>),
- ?line error = bad_literal_match(<<16#FFFF:32/little>>),
?line error = bad_literal_match(<<16#110000:32/little>>),
ok.
@@ -314,11 +297,7 @@ match_literal(<<"bj\366rn"/big-utf16>>) -> bjorn_utf16be;
match_literal(<<"bj\366rn"/little-utf16>>) -> bjorn_utf16le.
bad_literal_match(<<16#D800/utf8>>) -> ok;
-bad_literal_match(<<16#FFFE/utf8>>) -> ok;
-bad_literal_match(<<16#FFFF/utf8>>) -> ok;
bad_literal_match(<<16#110000/utf8>>) -> ok;
-bad_literal_match(<<16#FFFE/utf16>>) -> ok;
-bad_literal_match(<<16#FFFF/utf16>>) -> ok;
bad_literal_match(<<16#D800/utf32>>) -> ok;
bad_literal_match(<<16#110000/utf32>>) -> ok;
bad_literal_match(<<16#D800/little-utf32>>) -> ok;
diff --git a/lib/compiler/test/compile_SUITE.erl b/lib/compiler/test/compile_SUITE.erl
index b3e5376ffd..fedbd98f71 100644
--- a/lib/compiler/test/compile_SUITE.erl
+++ b/lib/compiler/test/compile_SUITE.erl
@@ -77,11 +77,22 @@ file_1(Config) when is_list(Config) ->
?line {Simple, Target} = files(Config, "file_1"),
?line {ok, Cwd} = file:get_cwd(),
?line ok = file:set_cwd(filename:dirname(Target)),
- ?line {ok,simple} = compile:file(Simple), %Smoke test only.
+
+ %% Native from BEAM without compilation info.
?line {ok,simple} = compile:file(Simple, [slim]), %Smoke test only.
- ?line {ok,simple} = compile:file(Simple, [native,report]), %Smoke test.
?line {ok,simple} = compile:file(Target, [native,from_beam]), %Smoke test.
- ?line {ok,simple} = compile:file(Simple, [debug_info]),
+
+ %% Native from BEAM with compilation info.
+ ?line {ok,simple} = compile:file(Simple), %Smoke test only.
+ ?line {ok,simple} = compile:file(Target, [native,from_beam]), %Smoke test.
+
+ ?line {ok,simple} = compile:file(Simple, [native,report]), %Smoke test.
+
+ ?line compile_and_verify(Simple, Target, []),
+ ?line compile_and_verify(Simple, Target, [native]),
+ ?line compile_and_verify(Simple, Target, [debug_info]),
+ ?line {ok,simple} = compile:file(Simple, [no_line_info]), %Coverage
+
?line ok = file:set_cwd(Cwd),
?line true = exists(Target),
?line passed = run(Target, test, []),
@@ -112,10 +123,9 @@ big_file(Config) when is_list(Config) ->
?line Big = filename:join(DataDir, "big.erl"),
?line Target = filename:join(PrivDir, "big.beam"),
?line ok = file:set_cwd(PrivDir),
- ?line {ok,big} = compile:file(Big, []),
- ?line {ok,big} = compile:file(Big, [r9,debug_info]),
- ?line {ok,big} = compile:file(Big, [no_postopt]),
- ?line true = exists(Target),
+ ?line compile_and_verify(Big, Target, []),
+ ?line compile_and_verify(Big, Target, [debug_info]),
+ ?line compile_and_verify(Big, Target, [no_postopt]),
%% Cleanup.
?line ok = file:delete(Target),
@@ -774,3 +784,15 @@ do_asm(Beam, Outdir) ->
[M,Class,Error,erlang:get_stacktrace()]),
error
end.
+
+%%%
+%%% Utilities.
+%%%
+
+compile_and_verify(Name, Target, Opts) ->
+ Mod = list_to_atom(filename:basename(Name, ".erl")),
+ {ok,Mod} = compile:file(Name, Opts),
+ {ok,{Mod,[{compile_info,CInfo}]}} =
+ beam_lib:chunks(Target, [compile_info]),
+ {options,BeamOpts} = lists:keyfind(options, 1, CInfo),
+ Opts = BeamOpts.
diff --git a/lib/compiler/test/fun_SUITE.erl b/lib/compiler/test/fun_SUITE.erl
index 368a5815bf..6067ee8e06 100644
--- a/lib/compiler/test/fun_SUITE.erl
+++ b/lib/compiler/test/fun_SUITE.erl
@@ -20,7 +20,11 @@
-export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1,
init_per_group/2,end_per_group/2,
- test1/1,overwritten_fun/1,otp_7202/1,bif_fun/1]).
+ test1/1,overwritten_fun/1,otp_7202/1,bif_fun/1,
+ external/1]).
+
+%% Internal export.
+-export([call_me/1]).
-include_lib("test_server/include/test_server.hrl").
@@ -28,7 +32,7 @@ suite() -> [{ct_hooks,[ts_install_cth]}].
all() ->
test_lib:recompile(?MODULE),
- [test1, overwritten_fun, otp_7202, bif_fun].
+ [test1,overwritten_fun,otp_7202,bif_fun,external].
groups() ->
[].
@@ -45,7 +49,6 @@ init_per_group(_GroupName, Config) ->
end_per_group(_GroupName, Config) ->
Config.
-
%%% The help functions below are copied from emulator:bs_construct_SUITE.
-define(T(B, L), {B, ??B, L}).
@@ -152,4 +155,47 @@ bif_fun(Config) when is_list(Config) ->
?line F = fun abs/1,
?line 5 = F(-5),
ok.
+
+-define(APPLY(M, F, A), (fun(Fun) -> {ok,{a,b}} = Fun({a,b}) end)(fun M:F/A)).
+-define(APPLY2(M, F, A),
+ (fun(Map) ->
+ Id = fun(I) -> I end,
+ List = [x,y],
+ List = Map(Id, List),
+ {type,external} = erlang:fun_info(Map, type)
+ end)(fun M:F/A)).
+external(Config) when is_list(Config) ->
+ Mod = id(?MODULE),
+ Func = id(call_me),
+ Arity = id(1),
+
+ ?APPLY(?MODULE, call_me, 1),
+ ?APPLY(?MODULE, call_me, Arity),
+ ?APPLY(?MODULE, Func, 1),
+ ?APPLY(?MODULE, Func, Arity),
+ ?APPLY(Mod, call_me, 1),
+ ?APPLY(Mod, call_me, Arity),
+ ?APPLY(Mod, Func, 1),
+ ?APPLY(Mod, Func, Arity),
+
+ ListsMod = id(lists),
+ ListsMap = id(map),
+ ListsArity = id(2),
+
+ ?APPLY2(lists, map, 2),
+ ?APPLY2(lists, map, ListsArity),
+ ?APPLY2(lists, ListsMap, 2),
+ ?APPLY2(lists, ListsMap, ListsArity),
+ ?APPLY2(ListsMod, map, 2),
+ ?APPLY2(ListsMod, map, ListsArity),
+ ?APPLY2(ListsMod, ListsMap, 2),
+ ?APPLY2(ListsMod, ListsMap, ListsArity),
+
+ ok.
+
+call_me(I) ->
+ {ok,I}.
+
+id(I) ->
+ I.
diff --git a/lib/compiler/test/guard_SUITE.erl b/lib/compiler/test/guard_SUITE.erl
index 0e69efba6b..40711783ed 100644
--- a/lib/compiler/test/guard_SUITE.erl
+++ b/lib/compiler/test/guard_SUITE.erl
@@ -32,7 +32,8 @@
t_is_boolean/1,is_function_2/1,
tricky/1,rel_ops/1,literal_type_tests/1,
basic_andalso_orelse/1,traverse_dcd/1,
- check_qlc_hrl/1,andalso_semi/1,t_tuple_size/1,binary_part/1]).
+ check_qlc_hrl/1,andalso_semi/1,t_tuple_size/1,binary_part/1,
+ bad_constants/1]).
suite() -> [{ct_hooks,[ts_install_cth]}].
@@ -44,7 +45,8 @@ all() ->
more_xor_guards, build_in_guard, old_guard_tests, gbif,
t_is_boolean, is_function_2, tricky, rel_ops,
literal_type_tests, basic_andalso_orelse, traverse_dcd,
- check_qlc_hrl, andalso_semi, t_tuple_size, binary_part].
+ check_qlc_hrl, andalso_semi, t_tuple_size, binary_part,
+ bad_constants].
groups() ->
[].
@@ -1517,8 +1519,27 @@ bptest(B,A,C) when erlang:binary_part(B,{A,C}) =:= <<3,3>> ->
bptest(_,_,_) ->
error.
-
-
+-define(FAILING(C),
+ if
+ C -> ?t:fail(should_fail);
+ true -> ok
+ end,
+ if
+ true, C -> ?t:fail(should_fail);
+ true -> ok
+ end).
+
+bad_constants(Config) when is_list(Config) ->
+ ?line ?FAILING(false),
+ ?line ?FAILING([]),
+ ?line ?FAILING([a]),
+ ?line ?FAILING([Config]),
+ ?line ?FAILING({a,b}),
+ ?line ?FAILING({a,Config}),
+ ?line ?FAILING(<<1>>),
+ ?line ?FAILING(42),
+ ?line ?FAILING(3.14),
+ ok.
%% Call this function to turn off constant propagation.
id(I) -> I.
diff --git a/lib/compiler/test/inline_SUITE.erl b/lib/compiler/test/inline_SUITE.erl
index af2b8ec92a..086fba2649 100644
--- a/lib/compiler/test/inline_SUITE.erl
+++ b/lib/compiler/test/inline_SUITE.erl
@@ -263,7 +263,8 @@ my_apply(M, F, A, Init) ->
really_inlined(Config) when is_list(Config) ->
%% Make sure that badarg/2 really gets inlined.
- {'EXIT',{badarg,[{?MODULE,fail_me_now,[]}|_]}} = (catch fail_me_now()),
+ {'EXIT',{badarg,[{?MODULE,fail_me_now,[],_}|_]}} =
+ (catch fail_me_now()),
ok.
fail_me_now() ->
diff --git a/lib/compiler/test/lc_SUITE.erl b/lib/compiler/test/lc_SUITE.erl
index c8908858ba..f5948504b3 100644
--- a/lib/compiler/test/lc_SUITE.erl
+++ b/lib/compiler/test/lc_SUITE.erl
@@ -179,8 +179,8 @@ empty_generator(Config) when is_list(Config) ->
id(I) -> I.
-fc(Args, {'EXIT',{function_clause,[{?MODULE,_,Args}|_]}}) -> ok;
-fc(Args, {'EXIT',{function_clause,[{?MODULE,_,Arity}|_]}})
+fc(Args, {'EXIT',{function_clause,[{?MODULE,_,Args,_}|_]}}) -> ok;
+fc(Args, {'EXIT',{function_clause,[{?MODULE,_,Arity,_}|_]}})
when length(Args) =:= Arity ->
true = test_server:is_native(?MODULE);
fc(Args, {'EXIT',{{case_clause,ActualArgs},_}})
diff --git a/lib/compiler/test/misc_SUITE.erl b/lib/compiler/test/misc_SUITE.erl
index c941a80e61..9b414cade6 100644
--- a/lib/compiler/test/misc_SUITE.erl
+++ b/lib/compiler/test/misc_SUITE.erl
@@ -179,7 +179,7 @@ silly_coverage(Config) when is_list(Config) ->
?line expect_error(fun() -> v3_life:module(BadKernel, []) end),
%% v3_codegen
- CodegenInput = {?MODULE,[{foo,0}],[],[{function,foo,0,[a|b],a,b}]},
+ CodegenInput = {?MODULE,[{foo,0}],[],[{function,foo,0,[a|b],a,b,[]}]},
?line expect_error(fun() -> v3_codegen:module(CodegenInput, []) end),
%% beam_block
@@ -187,7 +187,7 @@ silly_coverage(Config) when is_list(Config) ->
[{function,foo,0,2,
[{label,1},
{func_info,{atom,?MODULE},{atom,foo},0},
- {label,2}|non_proper_list],99}]},
+ {label,2}|non_proper_list]}],99},
?line expect_error(fun() -> beam_block:module(BlockInput, []) end),
%% beam_bool
diff --git a/lib/compiler/test/pmod_SUITE.erl b/lib/compiler/test/pmod_SUITE.erl
index 9a317b5762..5dd09a7245 100644
--- a/lib/compiler/test/pmod_SUITE.erl
+++ b/lib/compiler/test/pmod_SUITE.erl
@@ -96,6 +96,11 @@ basic_1(Config, Opts) ->
?line error = Prop4:bar_bar({s,a,b}),
?line error = Prop4:bar_bar([]),
+ %% Call from a fun.
+ Fun = fun(Arg) -> Prop4:bar(Arg) end,
+ ?line ok = Fun({s,0}),
+
+ [{y,[1,2]},{x,[5,19]}] = Prop4:collapse([{y,[2,1]},{x,[19,5]}]),
ok.
otp_8447(Config) when is_list(Config) ->
diff --git a/lib/compiler/test/pmod_SUITE_data/pmod_basic.erl b/lib/compiler/test/pmod_SUITE_data/pmod_basic.erl
index 0d46cffe00..c6aa2d4655 100644
--- a/lib/compiler/test/pmod_SUITE_data/pmod_basic.erl
+++ b/lib/compiler/test/pmod_SUITE_data/pmod_basic.erl
@@ -21,6 +21,7 @@
-export([lookup/1,or_props/1,prepend/1,append/1,stupid_sum/0]).
-export([bar/1,bar_bar/1]).
-export([bc1/0, bc2/0]).
+-export([collapse/1]).
lookup(Key) ->
proplists:lookup(Key, Props).
@@ -77,3 +78,6 @@ bc1() ->
bc2() ->
<< <<A:1>> || A <- [1,0,1,0] >>.
+
+collapse(L) ->
+ lists:keymap(fun lists:sort/1, 2, L).
diff --git a/lib/compiler/test/trycatch_SUITE.erl b/lib/compiler/test/trycatch_SUITE.erl
index c6e0f8d85d..760cf17225 100644
--- a/lib/compiler/test/trycatch_SUITE.erl
+++ b/lib/compiler/test/trycatch_SUITE.erl
@@ -314,19 +314,19 @@ eclectic(Conf) when is_list(Conf) ->
V = {make_ref(),3.1415926535,[[]|{}]},
?line {{value,{value,V},V},V} =
eclectic_1({foo,{value,{value,V}}}, undefined, {value,V}),
- ?line {{'EXIT',{V,[{?MODULE,foo,1}|_]}},V} =
+ ?line {{'EXIT',{V,[{?MODULE,foo,1,_}|_]}},V} =
eclectic_1({catch_foo,{error,V}}, undefined, {value,V}),
?line {{error,{exit,V},{'EXIT',V}},V} =
eclectic_1({foo,{error,{exit,V}}}, error, {value,V}),
?line {{value,{value,V},V},
- {'EXIT',{badarith,[{?MODULE,my_add,2}|_]}}} =
+ {'EXIT',{badarith,[{?MODULE,my_add,2,_}|_]}}} =
eclectic_1({foo,{value,{value,V}}}, undefined, {'add',{0,a}}),
?line {{'EXIT',V},V} =
eclectic_1({catch_foo,{exit,V}}, undefined, {throw,V}),
- ?line {{error,{'div',{1,0}},{'EXIT',{badarith,[{?MODULE,my_div,2}|_]}}},
+ ?line {{error,{'div',{1,0}},{'EXIT',{badarith,[{?MODULE,my_div,2,_}|_]}}},
{'EXIT',V}} =
eclectic_1({foo,{error,{'div',{1,0}}}}, error, {exit,V}),
- ?line {{{error,V},{'EXIT',{V,[{?MODULE,foo,1}|_]}}},
+ ?line {{{error,V},{'EXIT',{V,[{?MODULE,foo,1,_}|_]}}},
{'EXIT',V}} =
eclectic_1({catch_foo,{throw,{error,V}}}, undefined, {exit,V}),
%%
@@ -336,15 +336,15 @@ eclectic(Conf) when is_list(Conf) ->
eclectic_2({throw,{value,V}}, throw, {value,V}),
?line {{caught,{'EXIT',V}},undefined} =
eclectic_2({value,{value,V}}, undefined, {exit,V}),
- ?line {{caught,{'EXIT',{V,[{?MODULE,foo,1}|_]}}},undefined} =
+ ?line {{caught,{'EXIT',{V,[{?MODULE,foo,1,_}|_]}}},undefined} =
eclectic_2({error,{value,V}}, throw, {error,V}),
- ?line {{caught,{'EXIT',{badarg,[{erlang,abs,[V]}|_]}}},V} =
+ ?line {{caught,{'EXIT',{badarg,[{erlang,abs,[V],_}|_]}}},V} =
eclectic_2({value,{'abs',V}}, undefined, {value,V}),
- ?line {{caught,{'EXIT',{badarith,[{?MODULE,my_add,2}|_]}}},V} =
+ ?line {{caught,{'EXIT',{badarith,[{?MODULE,my_add,2,_}|_]}}},V} =
eclectic_2({exit,{'add',{0,a}}}, exit, {value,V}),
?line {{caught,{'EXIT',V}},undefined} =
eclectic_2({value,{error,V}}, undefined, {exit,V}),
- ?line {{caught,{'EXIT',{V,[{?MODULE,foo,1}|_]}}},undefined} =
+ ?line {{caught,{'EXIT',{V,[{?MODULE,foo,1,_}|_]}}},undefined} =
eclectic_2({throw,{'div',{1,0}}}, throw, {error,V}),
ok.
diff --git a/lib/cosEvent/doc/src/Makefile b/lib/cosEvent/doc/src/Makefile
index 4b76a64b7d..db2f7e6da5 100644
--- a/lib/cosEvent/doc/src/Makefile
+++ b/lib/cosEvent/doc/src/Makefile
@@ -26,13 +26,6 @@ include $(ERL_TOP)/make/$(TARGET)/otp.mk
include ../../vsn.mk
VSN=$(COSEVENT_VSN)
APPLICATION=cosEvent
-# ----------------------------------------------------
-# Include dependency
-# ----------------------------------------------------
-
-ifndef DOCSUPPORT
-include make.dep
-endif
# ----------------------------------------------------
# Release directory specification
@@ -98,32 +91,10 @@ EXTRA_FILES = summary.html.src \
MAN3_FILES = $(XML_REF3_FILES:%.xml=$(MAN3DIR)/%.3)
-ifdef DOCSUPPORT
-
HTML_REF_MAN_FILE = $(HTMLDIR)/index.html
TOP_PDF_FILE = $(PDFDIR)/$(APPLICATION)-$(VSN).pdf
-else
-
-TEX_FILES_BOOK = \
- $(BOOK_FILES:%.xml=%.tex)
-TEX_FILES_REF_MAN = $(XML_REF3_FILES:%.xml=%.tex) \
- $(XML_APPLICATION_FILES:%.xml=%.tex)
-TEX_FILES_USERS_GUIDE = \
- $(XML_CHAPTER_FILES:%.xml=%.tex)
-
-TOP_PDF_FILE = $(APPLICATION)-$(VSN).pdf
-
-TOP_PS_FILE = $(APPLICATION)-$(VSN).ps
-
-$(TOP_PDF_FILE): book.dvi ../../vsn.mk
- $(DVI2PS) $(DVIPS_FLAGS) -f $< | $(DISTILL) $(DISTILL_FLAGS) > $@
-
-$(TOP_PS_FILE): book.dvi ../../vsn.mk
- $(DVI2PS) $(DVIPS_FLAGS) -f $< > $@
-endif
-
# ----------------------------------------------------
# FLAGS
# ----------------------------------------------------
@@ -136,8 +107,6 @@ DVIPS_FLAGS +=
$(HTMLDIR)/%.gif: %.gif
$(INSTALL_DATA) $< $@
-ifdef DOCSUPPORT
-
docs: pdf html man
$(TOP_PDF_FILE): $(XML_FILES)
@@ -153,31 +122,6 @@ clean clean_docs:
rm -f errs core *~
rm -f $(JD_HTML) $(JD_PACK)
-else
-
-ifeq ($(DOCTYPE),pdf)
-docs: pdf
-else
-ifeq ($(DOCTYPE),ps)
-docs: ps
-else
-docs: html gifs man
-endif
-endif
-
-pdf: $(TOP_PDF_FILE)
-
-ps: $(TOP_PS_FILE)
-
-html: $(HTML_FILES) $(INTERNAL_HTML_FILES)
-
-clean clean_docs clean_tex:
- rm -f $(TEX_FILES_USERS_GUIDE) $(TEX_FILES_REF_MAN) $(TEX_FILES_BOOK)
- rm -f $(HTML_FILES) $(MAN3_FILES)
- rm -f $(TOP_PDF_FILE) $(TOP_PS_FILE)
- rm -f errs core *~ *xmls_output *xmls_errs $(LATEX_CLEAN)
-endif
-
man: $(MAN3_FILES)
gifs: $(GIF_FILES:%=$(HTMLDIR)/%)
@@ -192,8 +136,6 @@ debug opt:
# ----------------------------------------------------
include $(ERL_TOP)/make/otp_release_targets.mk
-ifdef DOCSUPPORT
-
release_docs_spec: docs
$(INSTALL_DIR) $(RELSYSDIR)/doc/pdf
$(INSTALL_DATA) $(TOP_PDF_FILE) $(RELSYSDIR)/doc/pdf
@@ -204,30 +146,4 @@ release_docs_spec: docs
$(INSTALL_DIR) $(RELEASE_PATH)/man/man3
$(INSTALL_DATA) $(MAN3DIR)/* $(RELEASE_PATH)/man/man3
-else
-
-ifeq ($(DOCTYPE),pdf)
-release_docs_spec: pdf
- $(INSTALL_DIR) $(RELEASE_PATH)/pdf
- $(INSTALL_DATA) $(TOP_PDF_FILE) $(RELEASE_PATH)/pdf
-else
-ifeq ($(DOCTYPE),ps)
-release_docs_spec: ps
- $(INSTALL_DIR) $(RELEASE_PATH)/ps
- $(INSTALL_DATA) $(TOP_PS_FILE) $(RELEASE_PATH)/ps
-else
-release_docs_spec: docs
- $(INSTALL_DIR) $(RELSYSDIR)/doc/html
- $(INSTALL_DATA) $(GIF_FILES) $(EXTRA_FILES) $(HTML_FILES) \
- $(RELSYSDIR)/doc/html
- $(INSTALL_DATA) $(INFO_FILE) $(RELSYSDIR)
- $(INSTALL_DIR) $(RELEASE_PATH)/man/man3
- $(INSTALL_DATA) $(MAN3_FILES) $(RELEASE_PATH)/man/man3
-
-endif
-endif
-
-endif
-
release_spec:
-
diff --git a/lib/cosEvent/doc/src/make.dep b/lib/cosEvent/doc/src/make.dep
deleted file mode 100644
index b8a95c2d58..0000000000
--- a/lib/cosEvent/doc/src/make.dep
+++ /dev/null
@@ -1,34 +0,0 @@
-# ----------------------------------------------------
-# >>>> Do not edit this file <<<<
-# This file was automaticly generated by
-# /home/otp/bin/docdepend
-# ----------------------------------------------------
-
-
-# ----------------------------------------------------
-# TeX files that the DVI file depend on
-# ----------------------------------------------------
-
-book.dvi: CosEventChannelAdmin.tex CosEventChannelAdmin_ConsumerAdmin.tex \
- CosEventChannelAdmin_EventChannel.tex CosEventChannelAdmin_ProxyPullConsumer.tex \
- CosEventChannelAdmin_ProxyPullSupplier.tex \
- CosEventChannelAdmin_ProxyPushConsumer.tex \
- CosEventChannelAdmin_ProxyPushSupplier.tex \
- CosEventChannelAdmin_SupplierAdmin.tex book.tex \
- ch_contents.tex ch_event_service.tex ch_introduction.tex \
- cosEventApp.tex part.tex ref_man.tex
-
-# ----------------------------------------------------
-# Source inlined when transforming from source to LaTeX
-# ----------------------------------------------------
-
-CosEventChannelAdmin.tex: ../../src/CosEventChannelAdmin.idl
-
-book.tex: ref_man.xml
-
-# ----------------------------------------------------
-# Pictures that the DVI file depend on
-# ----------------------------------------------------
-
-book.dvi: e_s_components.ps e_s_models.ps
-
diff --git a/lib/cosEvent/src/Makefile b/lib/cosEvent/src/Makefile
index a62d47ce74..736b95538a 100644
--- a/lib/cosEvent/src/Makefile
+++ b/lib/cosEvent/src/Makefile
@@ -164,7 +164,7 @@ debug:
@${MAKE} TYPE=debug opt
clean:
- rm -f $(TARGET_FILES) $(GEN_FILES) $(APP_TARGET) $(APPUP_TARGET)
+ rm -f $(TARGET_FILES) $(GEN_FILES) $(APP_TARGET) $(APPUP_TARGET) IDL-GENERATED
rm -f errs core *~
$(APP_TARGET): $(APP_SRC)
@@ -177,16 +177,18 @@ docs:
# ----------------------------------------------------
# Special Build Targets
# ----------------------------------------------------
-$(GEN_ERL_FILES1) $(EXTERNAL_GEN_HRL_FILES1): CosEventChannelAdmin.idl
+
+IDL-GENERATED: CosEventChannelAdmin.idl cosEventApp.idl CosEventComm.idl
erlc $(ERL_IDL_FLAGS) +'{cfgfile,"CosEventChannelAdmin.cfg"}' CosEventChannelAdmin.idl
mv $(GEN_HRL_FILES1) $(EXTERNAL_INC_PATH)
-
-$(GEN_ERL_FILES2) $(GEN_HRL_FILES2): cosEventApp.idl
erlc $(ERL_IDL_FLAGS) +'{cfgfile,"cosEventApp.cfg"}' cosEventApp.idl
-
-$(GEN_ERL_FILES3) $(EXTERNAL_GEN_HRL_FILES3): CosEventComm.idl
erlc $(ERL_IDL_FLAGS) CosEventComm.idl
mv $(GEN_HRL_FILES3) $(EXTERNAL_INC_PATH)
+ >IDL-GENERATED
+
+$(GEN_FILES): IDL-GENERATED
+
+$(TARGET_FILES): IDL-GENERATED
# ----------------------------------------------------
# Release Target
diff --git a/lib/cosEvent/test/Makefile b/lib/cosEvent/test/Makefile
index c59c7ee315..c3f07c156f 100644
--- a/lib/cosEvent/test/Makefile
+++ b/lib/cosEvent/test/Makefile
@@ -121,17 +121,13 @@ docs:
# Special Targets
# ----------------------------------------------------
-#
-# Each IDL file produces many target files so no pattern
-# rule can be used.
-#
-TGT_COS = \
- $(GEN_HRL_COS:%=$(IDLOUTDIR)/%) \
- $(GEN_MOD_COS:%=$(IDLOUTDIR)/%.erl)
+IDL-GENERATED: event_test_server.idl
+ erlc $(ERL_IDL_FLAGS) -o$(IDLOUTDIR) event_test_server.idl
+ >IDL-GENERATED
+$(GEN_FILES): IDL-GENERATED
-$(TGT_COS): event_test_server.idl
- erlc $(ERL_IDL_FLAGS) -o$(IDLOUTDIR) event_test_server.idl
+$(TARGET_FILES): IDL-GENERATED
# ----------------------------------------------------
# Release Targets
diff --git a/lib/cosEventDomain/doc/src/Makefile b/lib/cosEventDomain/doc/src/Makefile
index 6a0d3c353a..b2cdef278a 100644
--- a/lib/cosEventDomain/doc/src/Makefile
+++ b/lib/cosEventDomain/doc/src/Makefile
@@ -28,14 +28,6 @@ VSN=$(COSEVENTDOMAIN_VSN)
APPLICATION=cosEventDomain
# ----------------------------------------------------
-# Include dependency
-# ----------------------------------------------------
-
-ifndef DOCSUPPORT
-include make.dep
-endif
-
-# ----------------------------------------------------
# Release directory specification
# ----------------------------------------------------
RELSYSDIR = $(RELEASE_PATH)/lib/$(APPLICATION)-$(VSN)
@@ -93,33 +85,10 @@ EXTRA_FILES = summary.html.src \
MAN3_FILES = $(XML_REF3_FILES:%.xml=$(MAN3DIR)/%.3)
-ifdef DOCSUPPORT
-
HTML_REF_MAN_FILE = $(HTMLDIR)/index.html
TOP_PDF_FILE = $(PDFDIR)/$(APPLICATION)-$(VSN).pdf
-else
-
-TEX_FILES_BOOK = \
- $(BOOK_FILES:%.xml=%.tex)
-TEX_FILES_REF_MAN = $(XML_REF3_FILES:%.xml=%.tex) \
- $(XML_APPLICATION_FILES:%.xml=%.tex)
-TEX_FILES_USERS_GUIDE = \
- $(XML_CHAPTER_FILES:%.xml=%.tex)
-
-TOP_PDF_FILE = $(APPLICATION)-$(VSN).pdf
-
-TOP_PS_FILE = $(APPLICATION)-$(VSN).ps
-
-$(TOP_PDF_FILE): book.dvi ../../vsn.mk
- $(DVI2PS) $(DVIPS_FLAGS) -f $< | $(DISTILL) $(DISTILL_FLAGS) > $@
-
-$(TOP_PS_FILE): book.dvi ../../vsn.mk
- $(DVI2PS) $(DVIPS_FLAGS) -f $< > $@
-
-endif
-
# ----------------------------------------------------
# FLAGS
# ----------------------------------------------------
@@ -132,8 +101,6 @@ DVIPS_FLAGS +=
$(HTMLDIR)/%.gif: %.gif
$(INSTALL_DATA) $< $@
-ifdef DOCSUPPORT
-
docs: pdf html man
$(TOP_PDF_FILE): $(XML_FILES)
@@ -149,32 +116,6 @@ clean clean_docs:
rm -f errs core *~
rm -f $(JD_HTML) $(JD_PACK)
-else
-
-ifeq ($(DOCTYPE),pdf)
-docs: pdf
-else
-ifeq ($(DOCTYPE),ps)
-docs: ps
-else
-docs: html gifs man
-endif
-endif
-
-pdf: $(TOP_PDF_FILE)
-
-ps: $(TOP_PS_FILE)
-
-html: $(HTML_FILES) $(INTERNAL_HTML_FILES)
-
-clean clean_docs clean_tex:
- rm -f $(TEX_FILES_USERS_GUIDE) $(TEX_FILES_REF_MAN) $(TEX_FILES_BOOK)
- rm -f $(HTML_FILES) $(MAN3_FILES)
- rm -f $(TOP_PDF_FILE) $(TOP_PS_FILE)
- rm -f errs core *~ *xmls_output *xmls_errs $(LATEX_CLEAN)
-
-endif
-
man: $(MAN3_FILES)
gifs: $(GIF_FILES:%=$(HTMLDIR)/%)
@@ -189,9 +130,6 @@ debug opt:
# ----------------------------------------------------
include $(ERL_TOP)/make/otp_release_targets.mk
-
-ifdef DOCSUPPORT
-
release_docs_spec: docs
$(INSTALL_DIR) $(RELSYSDIR)/doc/pdf
$(INSTALL_DATA) $(TOP_PDF_FILE) $(RELSYSDIR)/doc/pdf
@@ -201,30 +139,5 @@ release_docs_spec: docs
$(INSTALL_DATA) $(INFO_FILE) $(RELSYSDIR)
$(INSTALL_DIR) $(RELEASE_PATH)/man/man3
$(INSTALL_DATA) $(MAN3DIR)/* $(RELEASE_PATH)/man/man3
-else
-
-ifeq ($(DOCTYPE),pdf)
-release_docs_spec: pdf
- $(INSTALL_DIR) $(RELEASE_PATH)/pdf
- $(INSTALL_DATA) $(TOP_PDF_FILE) $(RELEASE_PATH)/pdf
-else
-ifeq ($(DOCTYPE),ps)
-release_docs_spec: ps
- $(INSTALL_DIR) $(RELEASE_PATH)/ps
- $(INSTALL_DATA) $(TOP_PS_FILE) $(RELEASE_PATH)/ps
-else
-release_docs_spec: docs
- $(INSTALL_DIR) $(RELSYSDIR)/doc/html
- $(INSTALL_DATA) $(GIF_FILES) $(EXTRA_FILES) $(HTML_FILES) \
- $(RELSYSDIR)/doc/html
- $(INSTALL_DATA) $(INFO_FILE) $(RELSYSDIR)
- $(INSTALL_DIR) $(RELEASE_PATH)/man/man3
- $(INSTALL_DATA) $(MAN3_FILES) $(RELEASE_PATH)/man/man3
-
-endif
-endif
-
-endif
release_spec:
-
diff --git a/lib/cosEventDomain/doc/src/make.dep b/lib/cosEventDomain/doc/src/make.dep
deleted file mode 100644
index 2f3f1ae53d..0000000000
--- a/lib/cosEventDomain/doc/src/make.dep
+++ /dev/null
@@ -1,23 +0,0 @@
-# ----------------------------------------------------
-# >>>> Do not edit this file <<<<
-# This file was automaticly generated by
-# /home/otp/bin/docdepend
-# ----------------------------------------------------
-
-
-# ----------------------------------------------------
-# TeX files that the DVI file depend on
-# ----------------------------------------------------
-
-book.dvi: CosEventDomainAdmin.tex CosEventDomainAdmin_EventDomain.tex \
- CosEventDomainAdmin_EventDomainFactory.tex \
- book.tex ch_QoS.tex ch_contents.tex ch_event_domain_service.tex \
- ch_introduction.tex cosEventDomainApp.tex \
- part.tex ref_man.tex
-
-# ----------------------------------------------------
-# Source inlined when transforming from source to LaTeX
-# ----------------------------------------------------
-
-book.tex: ref_man.xml
-
diff --git a/lib/cosEventDomain/src/Makefile b/lib/cosEventDomain/src/Makefile
index 56a67cd225..5af790c760 100644
--- a/lib/cosEventDomain/src/Makefile
+++ b/lib/cosEventDomain/src/Makefile
@@ -137,7 +137,7 @@ debug:
@${MAKE} TYPE=debug opt
clean:
- rm -f $(TARGET_FILES) $(GEN_FILES) $(APP_TARGET) $(APPUP_TARGET)
+ rm -f $(TARGET_FILES) $(GEN_FILES) $(APP_TARGET) $(APPUP_TARGET) IDL-GENERATED
rm -f errs core *~
$(APP_TARGET): $(APP_SRC)
@@ -150,9 +150,14 @@ docs:
# ----------------------------------------------------
# Special Build Targets
# ----------------------------------------------------
-$(GEN_ERL_FILES) $(EXTERNAL_GEN_HRL_FILES): CosEventDomainAdmin.idl
+IDL-GENERATED: CosEventDomainAdmin.idl
erlc $(ERL_IDL_FLAGS) +'{cfgfile,"CosEventDomainAdmin.cfg"}' CosEventDomainAdmin.idl
mv $(GEN_HRL_FILES) $(EXTERNAL_INC_PATH)
+ >IDL-GENERATED
+
+$(GEN_FILES): IDL-GENERATED
+
+$(TARGET_FILES): IDL-GENERATED
# ----------------------------------------------------
# Release Target
diff --git a/lib/cosFileTransfer/doc/src/Makefile b/lib/cosFileTransfer/doc/src/Makefile
index 2286db43ff..e62738daba 100644
--- a/lib/cosFileTransfer/doc/src/Makefile
+++ b/lib/cosFileTransfer/doc/src/Makefile
@@ -26,14 +26,6 @@ include $(ERL_TOP)/make/$(TARGET)/otp.mk
include ../../vsn.mk
VSN=$(COSFILETRANSFER_VSN)
APPLICATION=cosFileTransfer
-# ----------------------------------------------------
-# Include dependency
-# ----------------------------------------------------
-
-ifndef DOCSUPPORT
-include make.dep
-endif
-
# ----------------------------------------------------
# Release directory specification
@@ -97,33 +89,10 @@ EXTRA_FILES = summary.html.src \
MAN3_FILES = $(XML_REF3_FILES:%.xml=$(MAN3DIR)/%.3)
-ifdef DOCSUPPORT
-
HTML_REF_MAN_FILE = $(HTMLDIR)/index.html
TOP_PDF_FILE = $(PDFDIR)/$(APPLICATION)-$(VSN).pdf
-else
-
-TEX_FILES_BOOK = \
- $(BOOK_FILES:%.xml=%.tex)
-TEX_FILES_REF_MAN = $(XML_REF3_FILES:%.xml=%.tex) \
- $(XML_APPLICATION_FILES:%.xml=%.tex)
-TEX_FILES_USERS_GUIDE = \
- $(XML_CHAPTER_FILES:%.xml=%.tex)
-
-TOP_PDF_FILE = $(APPLICATION)-$(VSN).pdf
-
-TOP_PS_FILE = $(APPLICATION)-$-$(VSN).ps
-
-$(TOP_PDF_FILE): book.dvi ../../vsn.mk
- $(DVI2PS) $(DVIPS_FLAGS) -f $< | $(DISTILL) $(DISTILL_FLAGS) > $@
-
-$(TOP_PS_FILE): book.dvi ../../vsn.mk
- $(DVI2PS) $(DVIPS_FLAGS) -f $< > $@
-
-endif
-
# ----------------------------------------------------
# FLAGS
# ----------------------------------------------------
@@ -136,8 +105,6 @@ DVIPS_FLAGS +=
$(HTMLDIR)/%.gif: %.gif
$(INSTALL_DATA) $< $@
-ifdef DOCSUPPORT
-
docs: pdf html man
$(TOP_PDF_FILE): $(XML_FILES)
@@ -152,32 +119,6 @@ clean clean_docs:
rm -f $(TOP_PDF_FILE) $(TOP_PDF_FILE:%.pdf=%.fo)
rm -f errs core *~
-else
-
-ifeq ($(DOCTYPE),pdf)
-docs: pdf
-else
-ifeq ($(DOCTYPE),ps)
-docs: ps
-else
-docs: html gifs man
-endif
-endif
-
-pdf: $(TOP_PDF_FILE)
-
-ps: $(TOP_PS_FILE)
-
-html: $(HTML_FILES) $(INTERNAL_HTML_FILES)
-
-clean clean_docs clean_tex:
- rm -f $(TEX_FILES_USERS_GUIDE) $(TEX_FILES_REF_MAN) $(TEX_FILES_BOOK)
- rm -f $(HTML_FILES) $(MAN3_FILES)
- rm -f $(TOP_PDF_FILE) $(TOP_PS_FILE)
- rm -f errs core *~ *xmls_output *xmls_errs $(LATEX_CLEAN)
-
-endif
-
man: $(MAN3_FILES)
gifs: $(GIF_FILES:%=$(HTMLDIR)/%)
@@ -192,9 +133,6 @@ debug opt:
# ----------------------------------------------------
include $(ERL_TOP)/make/otp_release_targets.mk
-
-ifdef DOCSUPPORT
-
release_docs_spec: docs
$(INSTALL_DIR) $(RELSYSDIR)/doc/pdf
$(INSTALL_DATA) $(TOP_PDF_FILE) $(RELSYSDIR)/doc/pdf
@@ -204,30 +142,5 @@ release_docs_spec: docs
$(INSTALL_DATA) $(INFO_FILE) $(RELSYSDIR)
$(INSTALL_DIR) $(RELEASE_PATH)/man/man3
$(INSTALL_DATA) $(MAN3DIR)/* $(RELEASE_PATH)/man/man3
-else
-
-ifeq ($(DOCTYPE),pdf)
-release_docs_spec: pdf
- $(INSTALL_DIR) $(RELEASE_PATH)/pdf
- $(INSTALL_DATA) $(TOP_PDF_FILE) $(RELEASE_PATH)/pdf
-else
-ifeq ($(DOCTYPE),ps)
-release_docs_spec: ps
- $(INSTALL_DIR) $(RELEASE_PATH)/ps
- $(INSTALL_DATA) $(TOP_PS_FILE) $(RELEASE_PATH)/ps
-else
-release_docs_spec: docs
- $(INSTALL_DIR) $(RELSYSDIR)/doc/html
- $(INSTALL_DATA) $(GIF_FILES) $(EXTRA_FILES) $(HTML_FILES) \
- $(RELSYSDIR)/doc/html
- $(INSTALL_DATA) $(INFO_FILE) $(RELSYSDIR)
- $(INSTALL_DIR) $(RELEASE_PATH)/man/man3
- $(INSTALL_DATA) $(MAN3_FILES) $(RELEASE_PATH)/man/man3
-
-endif
-endif
-
-endif
release_spec:
-
diff --git a/lib/cosFileTransfer/doc/src/make.dep b/lib/cosFileTransfer/doc/src/make.dep
deleted file mode 100644
index 3be0c185c3..0000000000
--- a/lib/cosFileTransfer/doc/src/make.dep
+++ /dev/null
@@ -1,30 +0,0 @@
-# ----------------------------------------------------
-# >>>> Do not edit this file <<<<
-# This file was automaticly generated by
-# /home/otp/bin/docdepend
-# ----------------------------------------------------
-
-
-# ----------------------------------------------------
-# TeX files that the DVI file depend on
-# ----------------------------------------------------
-
-book.dvi: CosFileTransfer_Directory.tex CosFileTransfer_File.tex \
- CosFileTransfer_FileIterator.tex CosFileTransfer_FileTransferSession.tex \
- CosFileTransfer_VirtualFileSystem.tex book.tex \
- ch_contents.tex ch_example.tex ch_install.tex \
- ch_introduction.tex ch_system.tex cosFileTransferApp.tex \
- part.tex ref_man.tex
-
-# ----------------------------------------------------
-# Source inlined when transforming from source to LaTeX
-# ----------------------------------------------------
-
-book.tex: ref_man.xml
-
-# ----------------------------------------------------
-# Pictures that the DVI file depend on
-# ----------------------------------------------------
-
-book.dvi: CosFileTransfer.ps
-
diff --git a/lib/cosFileTransfer/src/Makefile b/lib/cosFileTransfer/src/Makefile
index 773ed7f6b7..b811ef1106 100644
--- a/lib/cosFileTransfer/src/Makefile
+++ b/lib/cosFileTransfer/src/Makefile
@@ -147,7 +147,7 @@ cleanb:
rm -f errs core *~
clean:
- rm -f $(TARGET_FILES) $(GEN_FILES) $(APP_TARGET) $(APPUP_TARGET)
+ rm -f $(TARGET_FILES) $(GEN_FILES) $(APP_TARGET) $(APPUP_TARGET) IDL-GENERATED
rm -f errs core *~
$(APP_TARGET): $(APP_SRC)
@@ -161,9 +161,14 @@ docs:
# ----------------------------------------------------
# Special Build Targets
# ----------------------------------------------------
-$(GEN_ERL_FILES) $(GEN_HRL_FILES): CosFileTransfer.idl
+IDL-GENERATED: CosFileTransfer.idl
erlc $(ERL_IDL_FLAGS) +'{cfgfile,"CosFileTransfer.cfg"}' CosFileTransfer.idl
mv $(LOCAL_HRL_FILES) $(EXTERNAL_INC_PATH)
+ >IDL-GENERATED
+
+$(GEN_FILES): IDL-GENERATED
+
+$(TARGET_FILES): IDL-GENERATED
# ----------------------------------------------------
# Release Target
diff --git a/lib/cosNotification/doc/src/Makefile b/lib/cosNotification/doc/src/Makefile
index bfdd2f1f8c..2ead9aba7b 100644
--- a/lib/cosNotification/doc/src/Makefile
+++ b/lib/cosNotification/doc/src/Makefile
@@ -28,14 +28,6 @@ VSN=$(COSNOTIFICATION_VSN)
APPLICATION=cosNotification
# ----------------------------------------------------
-# Include dependency
-# ----------------------------------------------------
-
-ifndef DOCSUPPORT
-include make.dep
-endif
-
-# ----------------------------------------------------
# Release directory specification
# ----------------------------------------------------
RELSYSDIR = $(RELEASE_PATH)/lib/$(APPLICATION)-$(VSN)
@@ -122,33 +114,10 @@ EXTRA_FILES = summary.html.src \
MAN3_FILES = $(XML_REF3_FILES:%.xml=$(MAN3DIR)/%.3)
-ifdef DOCSUPPORT
-
HTML_REF_MAN_FILE = $(HTMLDIR)/index.html
TOP_PDF_FILE = $(PDFDIR)/$(APPLICATION)-$(VSN).pdf
-else
-
-TEX_FILES_BOOK = \
- $(BOOK_FILES:%.xml=%.tex)
-TEX_FILES_REF_MAN = $(XML_REF3_FILES:%.xml=%.tex) \
- $(XML_APPLICATION_FILES:%.xml=%.tex)
-TEX_FILES_USERS_GUIDE = \
- $(XML_CHAPTER_FILES:%.xml=%.tex)
-
-TOP_PDF_FILE = $(APPLICATION)-$(VSN).pdf
-
-TOP_PS_FILE = $(APPLICATION)-$(VSN).ps
-
-$(TOP_PDF_FILE): book.dvi ../../vsn.mk
- $(DVI2PS) $(DVIPS_FLAGS) -f $< | $(DISTILL) $(DISTILL_FLAGS) > $@
-
-$(TOP_PS_FILE): book.dvi ../../vsn.mk
- $(DVI2PS) $(DVIPS_FLAGS) -f $< > $@
-
-endif
-
# ----------------------------------------------------
# FLAGS
# ----------------------------------------------------
@@ -161,8 +130,6 @@ DVIPS_FLAGS +=
$(HTMLDIR)/%.gif: %.gif
$(INSTALL_DATA) $< $@
-ifdef DOCSUPPORT
-
docs: pdf html man
$(TOP_PDF_FILE): $(XML_FILES)
@@ -177,32 +144,6 @@ clean clean_docs:
rm -f $(TOP_PDF_FILE) $(TOP_PDF_FILE:%.pdf=%.fo)
rm -f errs core *~
-else
-
-ifeq ($(DOCTYPE),pdf)
-docs: pdf
-else
-ifeq ($(DOCTYPE),ps)
-docs: ps
-else
-docs: html gifs man
-endif
-endif
-
-pdf: $(TOP_PDF_FILE)
-
-ps: $(TOP_PS_FILE)
-
-html: $(HTML_FILES) $(INTERNAL_HTML_FILES)
-
-clean clean_docs clean_tex:
- rm -f $(TEX_FILES_USERS_GUIDE) $(TEX_FILES_REF_MAN) $(TEX_FILES_BOOK)
- rm -f $(HTML_FILES) $(MAN3_FILES)
- rm -f $(TOP_PDF_FILE) $(TOP_PS_FILE)
- rm -f errs core *~ *xmls_output *xmls_errs $(LATEX_CLEAN)
-
-endif
-
man: $(MAN3_FILES)
gifs: $(GIF_FILES:%=$(HTMLDIR)/%)
@@ -217,8 +158,6 @@ debug opt:
# ----------------------------------------------------
include $(ERL_TOP)/make/otp_release_targets.mk
-ifdef DOCSUPPORT
-
release_docs_spec: docs
$(INSTALL_DIR) $(RELSYSDIR)/doc/pdf
$(INSTALL_DATA) $(TOP_PDF_FILE) $(RELSYSDIR)/doc/pdf
@@ -228,30 +167,5 @@ release_docs_spec: docs
$(INSTALL_DATA) $(INFO_FILE) $(RELSYSDIR)
$(INSTALL_DIR) $(RELEASE_PATH)/man/man3
$(INSTALL_DATA) $(MAN3DIR)/* $(RELEASE_PATH)/man/man3
-else
-
-ifeq ($(DOCTYPE),pdf)
-release_docs_spec: pdf
- $(INSTALL_DIR) $(RELEASE_PATH)/pdf
- $(INSTALL_DATA) $(TOP_PDF_FILE) $(RELEASE_PATH)/pdf
-else
-ifeq ($(DOCTYPE),ps)
-release_docs_spec: ps
- $(INSTALL_DIR) $(RELEASE_PATH)/ps
- $(INSTALL_DATA) $(TOP_PS_FILE) $(RELEASE_PATH)/ps
-else
-release_docs_spec: docs
- $(INSTALL_DIR) $(RELSYSDIR)/doc/html
- $(INSTALL_DATA) $(GIF_FILES) $(EXTRA_FILES) $(HTML_FILES) \
- $(RELSYSDIR)/doc/html
- $(INSTALL_DATA) $(INFO_FILE) $(RELSYSDIR)
- $(INSTALL_DIR) $(RELEASE_PATH)/man/man3
- $(INSTALL_DATA) $(MAN3_FILES) $(RELEASE_PATH)/man/man3
-
-endif
-endif
-
-endif
release_spec:
-
diff --git a/lib/cosNotification/doc/src/make.dep b/lib/cosNotification/doc/src/make.dep
deleted file mode 100644
index 031a2b3e98..0000000000
--- a/lib/cosNotification/doc/src/make.dep
+++ /dev/null
@@ -1,48 +0,0 @@
-# ----------------------------------------------------
-# >>>> Do not edit this file <<<<
-# This file was automaticly generated by
-# /home/otp/bin/docdepend
-# ----------------------------------------------------
-
-
-# ----------------------------------------------------
-# TeX files that the DVI file depend on
-# ----------------------------------------------------
-
-book.dvi: CosNotification.tex CosNotification_AdminPropertiesAdmin.tex \
- CosNotification_QoSAdmin.tex CosNotifyChannelAdmin_ConsumerAdmin.tex \
- CosNotifyChannelAdmin_EventChannel.tex CosNotifyChannelAdmin_EventChannelFactory.tex \
- CosNotifyChannelAdmin_ProxyConsumer.tex CosNotifyChannelAdmin_ProxyPullConsumer.tex \
- CosNotifyChannelAdmin_ProxyPullSupplier.tex \
- CosNotifyChannelAdmin_ProxyPushConsumer.tex \
- CosNotifyChannelAdmin_ProxyPushSupplier.tex \
- CosNotifyChannelAdmin_ProxySupplier.tex CosNotifyChannelAdmin_SequenceProxyPullConsumer.tex \
- CosNotifyChannelAdmin_SequenceProxyPullSupplier.tex \
- CosNotifyChannelAdmin_SequenceProxyPushConsumer.tex \
- CosNotifyChannelAdmin_SequenceProxyPushSupplier.tex \
- CosNotifyChannelAdmin_StructuredProxyPullConsumer.tex \
- CosNotifyChannelAdmin_StructuredProxyPullSupplier.tex \
- CosNotifyChannelAdmin_StructuredProxyPushConsumer.tex \
- CosNotifyChannelAdmin_StructuredProxyPushSupplier.tex \
- CosNotifyChannelAdmin_SupplierAdmin.tex CosNotifyComm_NotifyPublish.tex \
- CosNotifyComm_NotifySubscribe.tex CosNotifyFilter_Filter.tex \
- CosNotifyFilter_FilterAdmin.tex CosNotifyFilter_FilterFactory.tex \
- CosNotifyFilter_MappingFilter.tex book.tex \
- ch_BNF.tex ch_QoS.tex ch_contents.tex ch_example.tex \
- ch_install.tex ch_introduction.tex ch_system.tex \
- cosNotificationApp.tex part.tex ref_man.tex
-
-# ----------------------------------------------------
-# Source inlined when transforming from source to LaTeX
-# ----------------------------------------------------
-
-book.tex: ref_man.xml
-
-# ----------------------------------------------------
-# Pictures that the DVI file depend on
-# ----------------------------------------------------
-
-book.dvi: eventstructure.ps
-
-book.dvi: notificationFlow.ps
-
diff --git a/lib/cosNotification/src/Makefile b/lib/cosNotification/src/Makefile
index 637c633e52..be52d1a06f 100644
--- a/lib/cosNotification/src/Makefile
+++ b/lib/cosNotification/src/Makefile
@@ -242,20 +242,26 @@ GEN_OE_EVENTCOMM_HRL_FILES = \
oe_CosNotificationComm.hrl \
oe_CosNotificationComm_Event.hrl
-GEN_ERL_FILES = \
+IDL_GEN_ERL_FILES = \
$(GEN_NOTIFICATION_ERL_FILES) \
$(GEN_OE_EVENTCOMM_ERL_FILES) \
$(GEN_NOTIFYCOMM_ERL_FILES) \
$(GEN_NOTIFYFILTER_ERL_FILES) \
- $(GEN_CHANNELADMIN_ERL_FILES) \
- $(GEN_YECC_ERL_FILES)
+ $(GEN_CHANNELADMIN_ERL_FILES)
-GEN_HRL_FILES = \
+IDL_GEN_HRL_FILES = \
$(EXTERNAL_GEN_NOTIFICATION_HRL_FILES) \
$(GEN_OE_EVENTCOMM_HRL_FILES) \
$(EXTERNAL_GEN_NOTIFYCOMM_HRL_FILES) \
$(EXTERNAL_GEN_NOTIFYFILTER_HRL_FILES) \
- $(EXTERNAL_GEN_CHANNELADMIN_HRL_FILES) \
+ $(EXTERNAL_GEN_CHANNELADMIN_HRL_FILES)
+
+GEN_ERL_FILES = \
+ $(IDL_GEN_ERL_FILES) \
+ $(GEN_YECC_ERL_FILES)
+
+GEN_HRL_FILES = \
+ $(IDL_GEN_HRL_FILES) \
$(GEN_YECC_HRL_FILES)
@@ -322,7 +328,7 @@ cleanb:
rm -f errs core *~
clean:
- rm -f $(TARGET_FILES) $(GEN_FILES) $(APP_TARGET) $(APPUP_TARGET)
+ rm -f $(TARGET_FILES) $(GEN_FILES) $(APP_TARGET) $(APPUP_TARGET) IDL-GENERATED
rm -f errs core *~
$(APP_TARGET): $(APP_SRC)
@@ -336,20 +342,23 @@ docs:
# ----------------------------------------------------
# Special Build Targets
# ----------------------------------------------------
-$(GEN_NOTIFICATION_ERL_FILES) $(EXTERNAL_GEN_NOTIFICATION_HRL_FILES): CosNotification.idl
+IDL-GENERATED: CosNotification.idl CosNotifyChannelAdmin.idl \
+ CosNotifyFilter.idl cosNotificationAppComm.idl CosNotifyComm.idl
erlc $(ERL_IDL_FLAGS) +'{cfgfile,"CosNotification.cfg"}' CosNotification.idl
mv $(GEN_NOTIFICATION_HRL_FILES) $(EXTERNAL_INC_PATH)
-$(GEN_CHANNELADMIN_ERL_FILES) $(EXTERNAL_GEN_CHANNELADMIN_HRL_FILES): CosNotifyChannelAdmin.idl
erlc $(ERL_IDL_FLAGS) +'{cfgfile,"CosNotifyChannelAdmin.cfg"}' CosNotifyChannelAdmin.idl
mv $(GEN_CHANNELADMIN_HRL_FILES) $(EXTERNAL_INC_PATH)
-$(GEN_NOTIFYFILTER_ERL_FILES) $(EXTERNAL_GEN_NOTIFYFILTER_HRL_FILES): CosNotifyFilter.idl
erlc $(ERL_IDL_FLAGS) +'{cfgfile,"CosNotifyFilter.cfg"}' CosNotifyFilter.idl
mv $(GEN_NOTIFYFILTER_HRL_FILES) $(EXTERNAL_INC_PATH)
-$(GEN_OE_EVENTCOMM_ERL_FILES) $(GEN_OE_EVENTCOMM_HRL_FILES): cosNotificationAppComm.idl
erlc $(ERL_IDL_FLAGS) +'{cfgfile,"cosNotificationComm.cfg"}' cosNotificationAppComm.idl
-$(GEN_NOTIFYCOMM_ERL_FILES) $(EXTERNAL_GEN_NOTIFYCOMM_HRL_FILES): CosNotifyComm.idl
erlc $(ERL_IDL_FLAGS) +'{cfgfile,"CosNotifyComm.cfg"}' CosNotifyComm.idl
mv $(GEN_NOTIFYCOMM_HRL_FILES) $(EXTERNAL_INC_PATH)
+ >IDL-GENERATED
+
+$(IDL_GEN_ERL_FILES) $(IDL_GEN_HRL_FILES): IDL-GENERATED
+
+$(TARGET_FILES): IDL-GENERATED
+
$(GEN_YECC_ERL_FILES) $(GEN_YECC_HRL_FILES): cosNotification_Grammar.yrl
# ----------------------------------------------------
diff --git a/lib/cosNotification/test/Makefile b/lib/cosNotification/test/Makefile
index 43f73addae..f509370430 100644
--- a/lib/cosNotification/test/Makefile
+++ b/lib/cosNotification/test/Makefile
@@ -161,13 +161,14 @@ docs:
# Special Targets
# ----------------------------------------------------
-TGT_TEST = \
- $(GEN_HRL_FILES:%=$(IDLOUTDIR)/%) \
- $(GEN_MODULES:%=$(IDLOUTDIR)/%.erl)
-
-$(TGT_TEST): notify_test_server.idl
+IDL-GENERATED: notify_test_server.idl
erlc $(ERL_COMPILE_FLAGS) -o$(IDLOUTDIR) \
+'{cfgfile,"notify_test_server.cfg"}' notify_test_server.idl
+ >IDL-GENERATED
+
+$(GEN_FILES): IDL-GENERATED
+
+$(TARGET_FILES): IDL-GENERATED
# ----------------------------------------------------
# Release Targets
diff --git a/lib/cosProperty/doc/src/Makefile b/lib/cosProperty/doc/src/Makefile
index baf995d35e..d4c89ff44f 100644
--- a/lib/cosProperty/doc/src/Makefile
+++ b/lib/cosProperty/doc/src/Makefile
@@ -28,14 +28,6 @@ VSN=$(COSPROPERTY_VSN)
APPLICATION=cosProperty
# ----------------------------------------------------
-# Include dependency
-# ----------------------------------------------------
-
-ifndef DOCSUPPORT
-include make.dep
-endif
-
-# ----------------------------------------------------
# Release directory specification
# ----------------------------------------------------
RELSYSDIR = $(RELEASE_PATH)/lib/$(APPLICATION)-$(VSN)
@@ -99,35 +91,10 @@ EXTRA_FILES = summary.html.src \
MAN3_FILES = $(XML_REF3_FILES:%.xml=$(MAN3DIR)/%.3)
MAN6_FILES = $(XML_REF6_FILES:%.xml=$(MAN6DIR)/%.6)
-
-ifdef DOCSUPPORT
-
HTML_REF_MAN_FILE = $(HTMLDIR)/index.html
TOP_PDF_FILE = $(PDFDIR)/$(APPLICATION)-$(VSN).pdf
-else
-
-TEX_FILES_BOOK = \
- $(BOOK_FILES:%.xml=%.tex)
-TEX_FILES_REF_MAN = $(XML_REF3_FILES:%.xml=%.tex) \
- $(XML_REF6_FILES:%.xml=%.tex) \
- $(XML_APPLICATION_FILES:%.xml=%.tex)
-TEX_FILES_USERS_GUIDE = \
- $(XML_CHAPTER_FILES:%.xml=%.tex)
-
-TOP_PDF_FILE = $(APPLICATION)-$(VSN).pdf
-
-TOP_PS_FILE = $(APPLICATION)-$(VSN).ps
-
-$(TOP_PDF_FILE): book.dvi ../../vsn.mk
- $(DVI2PS) $(DVIPS_FLAGS) -f $< | $(DISTILL) $(DISTILL_FLAGS) > $@
-
-$(TOP_PS_FILE): book.dvi ../../vsn.mk
- $(DVI2PS) $(DVIPS_FLAGS) -f $< > $@
-
-endif
-
# ----------------------------------------------------
# FLAGS
# ----------------------------------------------------
@@ -140,8 +107,6 @@ DVIPS_FLAGS +=
$(HTMLDIR)/%.gif: %.gif
$(INSTALL_DATA) $< $@
-ifdef DOCSUPPORT
-
docs: pdf html man
$(TOP_PDF_FILE): $(XML_FILES)
@@ -156,42 +121,6 @@ clean clean_docs:
rm -f $(TOP_PDF_FILE) $(TOP_PDF_FILE:%.pdf=%.fo)
rm -f errs core *~
-else
-
-ifeq ($(DOCTYPE),pdf)
-docs: pdf
-else
-ifeq ($(DOCTYPE),ps)
-docs: ps
-else
-docs: html gifs man
-endif
-endif
-
-pdf: $(TOP_PDF_FILE)
-
-ps: $(TOP_PS_FILE)
-
-html: $(HTML_FILES) $(INTERNAL_HTML_FILES)
-
-tex_users_guide: $(TEX_FILES_USERS_GUIDE)
-tex_ref_man: $(TEX_FILES_REF_MAN)
-tex: tex_users_guide tex_ref_man $(TEX_FILES_BOOK)
-
-$(DOCDIR)/latexlog: $(BOOK_FILES:%.xml=%.dvi)
- -fgrep -i "latex warning" $(BOOK_FILES:%.xml=%.log) >$(DOCDIR)/latexlog
-
-clean_tex:
- -rm -f $(TEX_FILES_USERS_GUIDE) $(TEX_FILES_REF_MAN) $(TEX_FILES_BOOK)
-
-clean:
- rm -f ../html/* $(MAN3_FILES) $(MAN6_FILES) $(TEX_FILES_USERS_GUIDE)
- rm -f *xmls_output *xmls_errs
- rm -f $(TOP_PDF_FILE) $(TOP_PS_FILE)
- rm -f errs core *~ $(LATEX_CLEAN)
-
-endif
-
man: $(MAN3_FILES) $(MAN6_FILES)
gifs: $(GIF_FILES:%=$(HTMLDIR)/%)
@@ -206,8 +135,6 @@ debug opt:
# ----------------------------------------------------
include $(ERL_TOP)/make/otp_release_targets.mk
-ifdef DOCSUPPORT
-
release_docs_spec: docs
$(INSTALL_DIR) $(RELSYSDIR)/doc/pdf
$(INSTALL_DATA) $(TOP_PDF_FILE) $(RELSYSDIR)/doc/pdf
@@ -217,30 +144,5 @@ release_docs_spec: docs
$(INSTALL_DATA) $(INFO_FILE) $(RELSYSDIR)
$(INSTALL_DIR) $(RELEASE_PATH)/man/man3
$(INSTALL_DATA) $(MAN3DIR)/* $(RELEASE_PATH)/man/man3
-else
-
-ifeq ($(DOCTYPE),pdf)
-release_docs_spec: pdf
- $(INSTALL_DIR) $(RELEASE_PATH)/pdf
- $(INSTALL_DATA) $(TOP_PDF_FILE) $(RELEASE_PATH)/pdf
-else
-ifeq ($(DOCTYPE),ps)
-release_docs_spec: ps
- $(INSTALL_DIR) $(RELEASE_PATH)/ps
- $(INSTALL_DATA) $(TOP_PS_FILE) $(RELEASE_PATH)/ps
-else
-release_docs_spec: docs
- $(INSTALL_DIR) $(RELSYSDIR)/doc/html
- $(INSTALL_DATA) $(GIF_FILES) $(EXTRA_FILES) $(HTML_FILES) \
- $(RELSYSDIR)/doc/html
- $(INSTALL_DATA) $(INFO_FILE) $(RELSYSDIR)
- $(INSTALL_DIR) $(RELEASE_PATH)/man/man3
- $(INSTALL_DATA) $(MAN3_FILES) $(RELEASE_PATH)/man/man3
-
-endif
-endif
-
-endif
release_spec:
-
diff --git a/lib/cosProperty/doc/src/make.dep b/lib/cosProperty/doc/src/make.dep
deleted file mode 100644
index 383af54244..0000000000
--- a/lib/cosProperty/doc/src/make.dep
+++ /dev/null
@@ -1,26 +0,0 @@
-# ----------------------------------------------------
-# >>>> Do not edit this file <<<<
-# This file was automaticly generated by
-# /home/otp/bin/docdepend
-# ----------------------------------------------------
-
-
-# ----------------------------------------------------
-# TeX files that the DVI file depend on
-# ----------------------------------------------------
-
-book.dvi: CosPropertyService_PropertiesIterator.tex \
- CosPropertyService_PropertyNamesIterator.tex \
- CosPropertyService_PropertySet.tex CosPropertyService_PropertySetDef.tex \
- CosPropertyService_PropertySetDefFactory.tex \
- CosPropertyService_PropertySetFactory.tex \
- book.tex ch_contents.tex ch_example.tex ch_install.tex \
- ch_introduction.tex cosProperty.tex part.tex \
- ref_man.tex
-
-# ----------------------------------------------------
-# Source inlined when transforming from source to LaTeX
-# ----------------------------------------------------
-
-book.tex: ref_man.xml
-
diff --git a/lib/cosProperty/src/Makefile b/lib/cosProperty/src/Makefile
index 1d2119dfb3..b72019f37d 100644
--- a/lib/cosProperty/src/Makefile
+++ b/lib/cosProperty/src/Makefile
@@ -147,7 +147,7 @@ cleanb:
rm -f errs core *~
clean:
- rm -f $(TARGET_FILES) $(GEN_FILES) $(APP_TARGET) $(APPUP_TARGET)
+ rm -f $(TARGET_FILES) $(GEN_FILES) $(APP_TARGET) $(APPUP_TARGET) IDL-GENERATED
rm -f errs core *~
$(APP_TARGET): $(APP_SRC)
@@ -161,10 +161,14 @@ docs:
# ----------------------------------------------------
# Special Build Targets
# ----------------------------------------------------
-$(GEN_ERL_FILES) $(GEN_HRL_FILES): CosProperty.idl
+IDL-GENERATED: CosProperty.idl
erlc $(ERL_IDL_FLAGS) +'{cfgfile,"CosProperty.cfg"}' CosProperty.idl
mv $(LOCAL_HRL_FILES) $(EXTERNAL_INC_PATH)
+ >IDL-GENERATED
+$(GEN_FILES): IDL-GENERATED
+
+$(TARGET_FILES): IDL-GENERATED
# ----------------------------------------------------
# Release Target
diff --git a/lib/cosTime/doc/src/Makefile b/lib/cosTime/doc/src/Makefile
index 83abc5e7c2..af418896aa 100644
--- a/lib/cosTime/doc/src/Makefile
+++ b/lib/cosTime/doc/src/Makefile
@@ -28,14 +28,6 @@ VSN=$(COSTIME_VSN)
APPLICATION=cosTime
# ----------------------------------------------------
-# Include dependency
-# ----------------------------------------------------
-
-ifndef DOCSUPPORT
-include make.dep
-endif
-
-# ----------------------------------------------------
# Release directory specification
# ----------------------------------------------------
RELSYSDIR = $(RELEASE_PATH)/lib/$(APPLICATION)-$(VSN)
@@ -93,33 +85,10 @@ EXTRA_FILES = summary.html.src \
MAN3_FILES = $(XML_REF3_FILES:%.xml=$(MAN3DIR)/%.3)
-ifdef DOCSUPPORT
-
HTML_REF_MAN_FILE = $(HTMLDIR)/index.html
TOP_PDF_FILE = $(PDFDIR)/$(APPLICATION)-$(VSN).pdf
-else
-
-TEX_FILES_BOOK = \
- $(BOOK_FILES:%.xml=%.tex)
-TEX_FILES_REF_MAN = $(XML_REF3_FILES:%.xml=%.tex) \
- $(XML_APPLICATION_FILES:%.xml=%.tex)
-TEX_FILES_USERS_GUIDE = \
- $(XML_CHAPTER_FILES:%.xml=%.tex)
-
-TOP_PDF_FILE = $(APPLICATION)-$(VSN).pdf
-
-TOP_PS_FILE = $(APPLICATION)-$(VSN).ps
-
-$(TOP_PDF_FILE): book.dvi ../../vsn.mk
- $(DVI2PS) $(DVIPS_FLAGS) -f $< | $(DISTILL) $(DISTILL_FLAGS) > $@
-
-$(TOP_PS_FILE): book.dvi ../../vsn.mk
- $(DVI2PS) $(DVIPS_FLAGS) -f $< > $@
-
-endif
-
# ----------------------------------------------------
# FLAGS
# ----------------------------------------------------
@@ -132,8 +101,6 @@ DVIPS_FLAGS +=
$(HTMLDIR)/%.gif: %.gif
$(INSTALL_DATA) $< $@
-ifdef DOCSUPPORT
-
docs: pdf html man
$(TOP_PDF_FILE): $(XML_FILES)
@@ -148,32 +115,6 @@ clean clean_docs:
rm -f $(TOP_PDF_FILE) $(TOP_PDF_FILE:%.pdf=%.fo)
rm -f errs core *~
-else
-
-ifeq ($(DOCTYPE),pdf)
-docs: pdf
-else
-ifeq ($(DOCTYPE),ps)
-docs: ps
-else
-docs: html gifs man
-endif
-endif
-
-pdf: $(TOP_PDF_FILE)
-
-ps: $(TOP_PS_FILE)
-
-html: $(HTML_FILES) $(INTERNAL_HTML_FILES)
-
-clean clean_docs clean_tex:
- rm -f $(TEX_FILES_USERS_GUIDE) $(TEX_FILES_REF_MAN) $(TEX_FILES_BOOK)
- rm -f $(HTML_FILES) $(MAN3_FILES)
- rm -f $(TOP_PDF_FILE) $(TOP_PS_FILE)
- rm -f errs core *~ *xmls_output *xmls_errs $(LATEX_CLEAN)
-
-endif
-
man: $(MAN3_FILES)
gifs: $(GIF_FILES:%=$(HTMLDIR)/%)
@@ -188,8 +129,6 @@ debug opt:
# ----------------------------------------------------
include $(ERL_TOP)/make/otp_release_targets.mk
-ifdef DOCSUPPORT
-
release_docs_spec: docs
$(INSTALL_DIR) $(RELSYSDIR)/doc/pdf
$(INSTALL_DATA) $(TOP_PDF_FILE) $(RELSYSDIR)/doc/pdf
@@ -199,30 +138,5 @@ release_docs_spec: docs
$(INSTALL_DATA) $(INFO_FILE) $(RELSYSDIR)
$(INSTALL_DIR) $(RELEASE_PATH)/man/man3
$(INSTALL_DATA) $(MAN3DIR)/* $(RELEASE_PATH)/man/man3
-else
-
-ifeq ($(DOCTYPE),pdf)
-release_docs_spec: pdf
- $(INSTALL_DIR) $(RELEASE_PATH)/pdf
- $(INSTALL_DATA) $(TOP_PDF_FILE) $(RELEASE_PATH)/pdf
-else
-ifeq ($(DOCTYPE),ps)
-release_docs_spec: ps
- $(INSTALL_DIR) $(RELEASE_PATH)/ps
- $(INSTALL_DATA) $(TOP_PS_FILE) $(RELEASE_PATH)/ps
-else
-release_docs_spec: docs
- $(INSTALL_DIR) $(RELSYSDIR)/doc/html
- $(INSTALL_DATA) $(GIF_FILES) $(EXTRA_FILES) $(HTML_FILES) \
- $(RELSYSDIR)/doc/html
- $(INSTALL_DATA) $(INFO_FILE) $(RELSYSDIR)
- $(INSTALL_DIR) $(RELEASE_PATH)/man/man3
- $(INSTALL_DATA) $(MAN3_FILES) $(RELEASE_PATH)/man/man3
-
-endif
-endif
-
-endif
release_spec:
-
diff --git a/lib/cosTime/doc/src/make.dep b/lib/cosTime/doc/src/make.dep
deleted file mode 100644
index 69a584ab95..0000000000
--- a/lib/cosTime/doc/src/make.dep
+++ /dev/null
@@ -1,22 +0,0 @@
-# ----------------------------------------------------
-# >>>> Do not edit this file <<<<
-# This file was automaticly generated by
-# /home/otp/bin/docdepend
-# ----------------------------------------------------
-
-
-# ----------------------------------------------------
-# TeX files that the DVI file depend on
-# ----------------------------------------------------
-
-book.dvi: CosTime_TIO.tex CosTime_TimeService.tex CosTime_UTO.tex \
- CosTimerEvent_TimerEventHandler.tex CosTimerEvent_TimerEventService.tex \
- book.tex ch_contents.tex ch_example.tex ch_install.tex \
- ch_introduction.tex cosTime.tex part.tex ref_man.tex
-
-# ----------------------------------------------------
-# Source inlined when transforming from source to LaTeX
-# ----------------------------------------------------
-
-book.tex: ref_man.xml
-
diff --git a/lib/cosTime/src/Makefile b/lib/cosTime/src/Makefile
index 3b6f7bae2e..fa456249bd 100644
--- a/lib/cosTime/src/Makefile
+++ b/lib/cosTime/src/Makefile
@@ -162,7 +162,7 @@ cleanb:
rm -f errs core *~
clean:
- rm -f $(TARGET_FILES) $(GEN_FILES) $(APP_TARGET) $(APPUP_TARGET)
+ rm -f $(TARGET_FILES) $(GEN_FILES) $(APP_TARGET) $(APPUP_TARGET) IDL-GENERATED
rm -f errs core *~
$(APP_TARGET): $(APP_SRC)
@@ -176,17 +176,18 @@ docs:
# ----------------------------------------------------
# Special Build Targets
# ----------------------------------------------------
-$(GEN_TIMEBASE_ERL_FILES) $(EXTERNAL_TIMEBASE_HRL_FILES): TimeBase.idl
+IDL-GENERATED: TimeBase.idl CosTime.idl CosTimerEvent.idl
erlc $(ERL_IDL_FLAGS) TimeBase.idl
mv $(GEN_TIMEBASE_HRL_FILES) $(EXTERNAL_INC_PATH)
-
-$(GEN_COSTIME_ERL_FILES) $(EXTERNAL_COSTIME_HRL_FILES): CosTime.idl
erlc $(ERL_IDL_FLAGS) +'{cfgfile,"CosTime.cfg"}' CosTime.idl
mv $(GEN_COSTIME_HRL_FILES) $(EXTERNAL_INC_PATH)
-
-$(GEN_COSTIMEREVENT_ERL_FILES) $(EXTERNAL_COSTIMEREVENT_HRL_FILES): CosTimerEvent.idl
erlc $(ERL_IDL_FLAGS) +'{cfgfile,"CosTimerEvent.cfg"}' CosTimerEvent.idl
mv $(GEN_COSTIMEREVENT_HRL_FILES) $(EXTERNAL_INC_PATH)
+ >IDL-GENERATED
+
+$(GEN_FILES): IDL-GENERATED
+
+$(TARGET_FILES): IDL-GENERATED
# ----------------------------------------------------
# Release Target
diff --git a/lib/cosTransactions/doc/src/Makefile b/lib/cosTransactions/doc/src/Makefile
index 1af9ed24b7..7d959cbc8f 100644
--- a/lib/cosTransactions/doc/src/Makefile
+++ b/lib/cosTransactions/doc/src/Makefile
@@ -28,14 +28,6 @@ VSN=$(COSTRANSACTIONS_VSN)
APPLICATION=cosTransactions
# ----------------------------------------------------
-# Include dependency
-# ----------------------------------------------------
-
-ifndef DOCSUPPORT
-include make.dep
-endif
-
-# ----------------------------------------------------
# Release directory specification
# ----------------------------------------------------
RELSYSDIR = $(RELEASE_PATH)/lib/$(APPLICATION)-$(VSN)
@@ -97,33 +89,10 @@ EXTRA_FILES = summary.html.src \
MAN3_FILES = $(XML_REF3_FILES:%.xml=$(MAN3DIR)/%.3)
-ifdef DOCSUPPORT
-
HTML_REF_MAN_FILE = $(HTMLDIR)/index.html
TOP_PDF_FILE = $(PDFDIR)/$(APPLICATION)-$(VSN).pdf
-else
-
-TEX_FILES_BOOK = \
- $(BOOK_FILES:%.xml=%.tex)
-TEX_FILES_REF_MAN = $(XML_REF3_FILES:%.xml=%.tex) \
- $(XML_APPLICATION_FILES:%.xml=%.tex)
-TEX_FILES_USERS_GUIDE = \
- $(XML_CHAPTER_FILES:%.xml=%.tex)
-
-TOP_PDF_FILE = $(APPLICATION)-$(VSN).pdf
-
-TOP_PS_FILE = $(APPLICATION)-$(VSN).ps
-
-$(TOP_PDF_FILE): book.dvi ../../vsn.mk
- $(DVI2PS) $(DVIPS_FLAGS) -f $< | $(DISTILL) $(DISTILL_FLAGS) > $@
-
-$(TOP_PS_FILE): book.dvi ../../vsn.mk
- $(DVI2PS) $(DVIPS_FLAGS) -f $< > $@
-
-endif
-
# ----------------------------------------------------
# FLAGS
# ----------------------------------------------------
@@ -136,8 +105,6 @@ DVIPS_FLAGS +=
$(HTMLDIR)/%.gif: %.gif
$(INSTALL_DATA) $< $@
-ifdef DOCSUPPORT
-
docs: pdf html man
$(TOP_PDF_FILE): $(XML_FILES)
@@ -152,32 +119,6 @@ clean clean_docs:
rm -f $(TOP_PDF_FILE) $(TOP_PDF_FILE:%.pdf=%.fo)
rm -f errs core *~
-else
-
-ifeq ($(DOCTYPE),pdf)
-docs: pdf
-else
-ifeq ($(DOCTYPE),ps)
-docs: ps
-else
-docs: html gifs man
-endif
-endif
-
-pdf: $(TOP_PDF_FILE)
-
-ps: $(TOP_PS_FILE)
-
-html: $(HTML_FILES) $(INTERNAL_HTML_FILES)
-
-clean clean_docs clean_tex:
- rm -f $(TEX_FILES_USERS_GUIDE) $(TEX_FILES_REF_MAN) $(TEX_FILES_BOOK)
- rm -f $(HTML_FILES) $(MAN3_FILES)
- rm -f $(TOP_PDF_FILE) $(TOP_PS_FILE)
- rm -f errs core *~ *xmls_output *xmls_errs $(LATEX_CLEAN)
-
-endif
-
man: $(MAN3_FILES)
gifs: $(GIF_FILES:%=$(HTMLDIR)/%)
@@ -192,8 +133,6 @@ debug opt:
# ----------------------------------------------------
include $(ERL_TOP)/make/otp_release_targets.mk
-ifdef DOCSUPPORT
-
release_docs_spec: docs
$(INSTALL_DIR) $(RELSYSDIR)/doc/pdf
$(INSTALL_DATA) $(TOP_PDF_FILE) $(RELSYSDIR)/doc/pdf
@@ -203,30 +142,5 @@ release_docs_spec: docs
$(INSTALL_DATA) $(INFO_FILE) $(RELSYSDIR)
$(INSTALL_DIR) $(RELEASE_PATH)/man/man3
$(INSTALL_DATA) $(MAN3DIR)/* $(RELEASE_PATH)/man/man3
-else
-
-ifeq ($(DOCTYPE),pdf)
-release_docs_spec: pdf
- $(INSTALL_DIR) $(RELEASE_PATH)/pdf
- $(INSTALL_DATA) $(TOP_PDF_FILE) $(RELEASE_PATH)/pdf
-else
-ifeq ($(DOCTYPE),ps)
-release_docs_spec: ps
- $(INSTALL_DIR) $(RELEASE_PATH)/ps
- $(INSTALL_DATA) $(TOP_PS_FILE) $(RELEASE_PATH)/ps
-else
-release_docs_spec: docs
- $(INSTALL_DIR) $(RELSYSDIR)/doc/html
- $(INSTALL_DATA) $(GIF_FILES) $(EXTRA_FILES) $(HTML_FILES) \
- $(RELSYSDIR)/doc/html
- $(INSTALL_DATA) $(INFO_FILE) $(RELSYSDIR)
- $(INSTALL_DIR) $(RELEASE_PATH)/man/man3
- $(INSTALL_DATA) $(MAN3_FILES) $(RELEASE_PATH)/man/man3
-
-endif
-endif
-
-endif
release_spec:
-
diff --git a/lib/cosTransactions/doc/src/make.dep b/lib/cosTransactions/doc/src/make.dep
deleted file mode 100644
index bd45aea286..0000000000
--- a/lib/cosTransactions/doc/src/make.dep
+++ /dev/null
@@ -1,27 +0,0 @@
-# ----------------------------------------------------
-# >>>> Do not edit this file <<<<
-# This file was automaticly generated by
-# /home/otp/bin/docdepend
-# ----------------------------------------------------
-
-
-# ----------------------------------------------------
-# TeX files that the DVI file depend on
-# ----------------------------------------------------
-
-book.dvi: CosTransactions_Control.tex CosTransactions_Coordinator.tex \
- CosTransactions_RecoveryCoordinator.tex CosTransactions_Resource.tex \
- CosTransactions_SubtransactionAwareResource.tex \
- CosTransactions_Terminator.tex CosTransactions_TransactionFactory.tex \
- book.tex ch_contents.tex ch_example.tex ch_install.tex \
- ch_introduction.tex ch_skeletons.tex cosTransactions.tex \
- part.tex ref_man.tex
-
-# ----------------------------------------------------
-# Source inlined when transforming from source to LaTeX
-# ----------------------------------------------------
-
-book.tex: ref_man.xml
-
-ch_example.tex: ../../../../system/doc/definitions/term.defs
-
diff --git a/lib/cosTransactions/src/Makefile b/lib/cosTransactions/src/Makefile
index 7e10ec175b..e7d4b0b080 100644
--- a/lib/cosTransactions/src/Makefile
+++ b/lib/cosTransactions/src/Makefile
@@ -141,7 +141,7 @@ debug:
@${MAKE} TYPE=debug
clean:
- rm -f $(TARGET_FILES) $(GEN_FILES) $(APP_TARGET) $(APPUP_TARGET)
+ rm -f $(TARGET_FILES) $(GEN_FILES) $(APP_TARGET) $(APPUP_TARGET) IDL-GENERATED
rm -f errs core *~
$(APP_TARGET): $(APP_SRC)
@@ -155,9 +155,14 @@ docs:
# ----------------------------------------------------
# Special Build Targets
# ----------------------------------------------------
-$(GEN_ERL_FILES) $(EXTERNAL_GEN_HRL_FILES): CosTransactions.idl
+IDL-GENERATED: CosTransactions.idl
erlc $(ERL_IDL_FLAGS) +'{cfgfile,"CosTransactions.cfg"}' CosTransactions.idl
mv $(GEN_HRL_FILES) $(EXTERNAL_INC_PATH)
+ >IDL-GENERATED
+
+$(GEN_FILES): IDL-GENERATED
+
+$(TARGET_FILES): IDL-GENERATED
# ----------------------------------------------------
# Release Target
diff --git a/lib/cosTransactions/test/Makefile b/lib/cosTransactions/test/Makefile
index 44c90e8f84..0bc8c007da 100644
--- a/lib/cosTransactions/test/Makefile
+++ b/lib/cosTransactions/test/Makefile
@@ -121,13 +121,14 @@ docs:
# Special Targets
# ----------------------------------------------------
-TGT_TEST = \
- $(GEN_HRL_FILES:%=$(IDLOUTDIR)/%) \
- $(GEN_MODULES:%=$(IDLOUTDIR)/%.erl)
-
-$(TGT_TEST): etrap_test.idl
+IDL-GENERATED: etrap_test.idl
erlc $(ERL_IDL_FLAGS) -o$(IDLOUTDIR) \
+'{cfgfile,"etrap_test.cfg"}' etrap_test.idl
+ >IDL-GENERATED
+
+$(GEN_FILES): IDL-GENERATED
+
+$(TARGET_FILES): IDL-GENERATED
# ----------------------------------------------------
# Release Targets
diff --git a/lib/crypto/c_src/Makefile.in b/lib/crypto/c_src/Makefile.in
index c2a986c334..285537643e 100644
--- a/lib/crypto/c_src/Makefile.in
+++ b/lib/crypto/c_src/Makefile.in
@@ -95,13 +95,9 @@ endif
# Targets
# ----------------------------------------------------
-debug opt valgrind: $(OBJDIR) $(LIBDIR) $(NIF_LIB)
+_create_dirs := $(shell mkdir -p $(OBJDIR) $(LIBDIR))
-$(OBJDIR):
- -@mkdir -p $(OBJDIR)
-
-$(LIBDIR):
- -@mkdir -p $(LIBDIR)
+debug opt valgrind: $(NIF_LIB)
$(OBJDIR)/%$(TYPEMARKER).o: %.c
$(INSTALL_DIR) $(OBJDIR)
diff --git a/lib/crypto/c_src/crypto.c b/lib/crypto/c_src/crypto.c
index c781ccb302..802c1991de 100644
--- a/lib/crypto/c_src/crypto.c
+++ b/lib/crypto/c_src/crypto.c
@@ -134,8 +134,10 @@ static ERL_NIF_TERM hmac_init(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[
static ERL_NIF_TERM hmac_update(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
static ERL_NIF_TERM hmac_final(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
static ERL_NIF_TERM des_cbc_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+static ERL_NIF_TERM des_cfb_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
static ERL_NIF_TERM des_ecb_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
static ERL_NIF_TERM des_ede3_cbc_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+static ERL_NIF_TERM des_ede3_cfb_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
static ERL_NIF_TERM aes_cfb_128_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
static ERL_NIF_TERM aes_ctr_encrypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
static ERL_NIF_TERM aes_ctr_stream_encrypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
@@ -152,7 +154,7 @@ static ERL_NIF_TERM exor(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
static ERL_NIF_TERM rc4_encrypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
static ERL_NIF_TERM rc4_set_key(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
static ERL_NIF_TERM rc4_encrypt_with_state(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
-static ERL_NIF_TERM rc2_40_cbc_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
+static ERL_NIF_TERM rc2_cbc_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
static ERL_NIF_TERM rsa_sign_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
static ERL_NIF_TERM dss_sign_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
static ERL_NIF_TERM rsa_public_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
@@ -210,8 +212,10 @@ static ErlNifFunc nif_funcs[] = {
{"hmac_final", 1, hmac_final},
{"hmac_final_n", 2, hmac_final},
{"des_cbc_crypt", 4, des_cbc_crypt},
+ {"des_cfb_crypt", 4, des_cfb_crypt},
{"des_ecb_crypt", 3, des_ecb_crypt},
{"des_ede3_cbc_crypt", 6, des_ede3_cbc_crypt},
+ {"des_ede3_cfb_crypt", 6, des_ede3_cfb_crypt},
{"aes_cfb_128_crypt", 4, aes_cfb_128_crypt},
{"aes_ctr_encrypt", 3, aes_ctr_encrypt},
{"aes_ctr_decrypt", 3, aes_ctr_encrypt},
@@ -230,7 +234,7 @@ static ErlNifFunc nif_funcs[] = {
{"rc4_encrypt", 2, rc4_encrypt},
{"rc4_set_key", 1, rc4_set_key},
{"rc4_encrypt_with_state", 2, rc4_encrypt_with_state},
- {"rc2_40_cbc_crypt", 4, rc2_40_cbc_crypt},
+ {"rc2_cbc_crypt", 4, rc2_cbc_crypt},
{"rsa_sign_nif", 3, rsa_sign_nif},
{"dss_sign_nif", 3, dss_sign_nif},
{"rsa_public_crypt", 4, rsa_public_crypt},
@@ -693,6 +697,25 @@ static ERL_NIF_TERM des_cbc_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM a
return ret;
}
+static ERL_NIF_TERM des_cfb_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{/* (Key, Ivec, Text, IsEncrypt) */
+ ErlNifBinary key, ivec, text;
+ DES_key_schedule schedule;
+ DES_cblock ivec_clone; /* writable copy */
+ ERL_NIF_TERM ret;
+
+ if (!enif_inspect_iolist_as_binary(env, argv[0], &key) || key.size != 8
+ || !enif_inspect_binary(env, argv[1], &ivec) || ivec.size != 8
+ || !enif_inspect_iolist_as_binary(env, argv[2], &text)) {
+ return enif_make_badarg(env);
+ }
+ memcpy(&ivec_clone, ivec.data, 8);
+ DES_set_key((const_DES_cblock*)key.data, &schedule);
+ DES_cfb_encrypt(text.data, enif_make_new_binary(env, text.size, &ret),
+ 8, text.size, &schedule, &ivec_clone, (argv[3] == atom_true));
+ return ret;
+}
+
static ERL_NIF_TERM des_ecb_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{/* (Key, Text/Cipher, IsEncrypt) */
ErlNifBinary key, text;
@@ -735,6 +758,31 @@ static ERL_NIF_TERM des_ede3_cbc_crypt(ErlNifEnv* env, int argc, const ERL_NIF_T
return ret;
}
+static ERL_NIF_TERM des_ede3_cfb_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{/* (Key1, Key2, Key3, IVec, Text/Cipher, IsEncrypt) */
+ ErlNifBinary key1, key2, key3, ivec, text;
+ DES_key_schedule schedule1, schedule2, schedule3;
+ DES_cblock ivec_clone; /* writable copy */
+ ERL_NIF_TERM ret;
+
+ if (!enif_inspect_iolist_as_binary(env, argv[0], &key1) || key1.size != 8
+ || !enif_inspect_iolist_as_binary(env, argv[1], &key2) || key2.size != 8
+ || !enif_inspect_iolist_as_binary(env, argv[2], &key3) || key3.size != 8
+ || !enif_inspect_binary(env, argv[3], &ivec) || ivec.size != 8
+ || !enif_inspect_iolist_as_binary(env, argv[4], &text)) {
+ return enif_make_badarg(env);
+ }
+
+ memcpy(&ivec_clone, ivec.data, 8);
+ DES_set_key((const_DES_cblock*)key1.data, &schedule1);
+ DES_set_key((const_DES_cblock*)key2.data, &schedule2);
+ DES_set_key((const_DES_cblock*)key3.data, &schedule3);
+ DES_ede3_cfb_encrypt(text.data, enif_make_new_binary(env,text.size,&ret),
+ 8, text.size, &schedule1, &schedule2, &schedule3,
+ &ivec_clone, (argv[5] == atom_true));
+ return ret;
+}
+
static ERL_NIF_TERM aes_cfb_128_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{/* (Key, IVec, Data, IsEncrypt) */
ErlNifBinary key, ivec, text;
@@ -1189,30 +1237,31 @@ static ERL_NIF_TERM rc4_encrypt_with_state(ErlNifEnv* env, int argc, const ERL_N
return enif_make_tuple2(env,new_state,new_data);
}
-static ERL_NIF_TERM rc2_40_cbc_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+static ERL_NIF_TERM rc2_cbc_crypt(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{/* (Key,IVec,Data,IsEncrypt) */
ErlNifBinary key_bin, ivec_bin, data_bin;
RC2_KEY rc2_key;
ERL_NIF_TERM ret;
-
+ unsigned char iv_copy[8];
+
if (!enif_inspect_iolist_as_binary(env, argv[0], &key_bin)
- || key_bin.size != 5
+ || (key_bin.size != 5 && key_bin.size != 8 && key_bin.size != 16)
|| !enif_inspect_binary(env, argv[1], &ivec_bin)
|| ivec_bin.size != 8
- || !enif_inspect_iolist_as_binary(env, argv[2], &data_bin)) {
-
+ || !enif_inspect_iolist_as_binary(env, argv[2], &data_bin)
+ || data_bin.size % 8 != 0) {
return enif_make_badarg(env);
}
-
- RC2_set_key(&rc2_key, 5, key_bin.data, 40);
+
+ RC2_set_key(&rc2_key, key_bin.size, key_bin.data, key_bin.size*8);
+ memcpy(iv_copy, ivec_bin.data, 8);
RC2_cbc_encrypt(data_bin.data,
- enif_make_new_binary(env, data_bin.size, &ret),
+ enif_make_new_binary(env, data_bin.size, &ret),
data_bin.size, &rc2_key,
- ivec_bin.data,
+ iv_copy,
(argv[3] == atom_true));
-
return ret;
-}
+}
static ERL_NIF_TERM rsa_sign_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
{/* (Type,Data,Key=[E,N,D]) */
diff --git a/lib/crypto/doc/src/crypto.xml b/lib/crypto/doc/src/crypto.xml
index 4c20f81cae..48243fd693 100644
--- a/lib/crypto/doc/src/crypto.xml
+++ b/lib/crypto/doc/src/crypto.xml
@@ -1,4 +1,4 @@
-<?xml version="1.0" encoding="latin1" ?>
+<?xml version="1.0" encoding="iso-8859-1" ?>
<!DOCTYPE erlref SYSTEM "erlref.dtd">
<erlref>
@@ -334,14 +334,16 @@ Mpint() = <![CDATA[<<ByteLen:32/integer-big, Bytes:ByteLen/binary>>]]>
</func>
<func>
<name>sha_mac(Key, Data) -> Mac</name>
+ <name>sha_mac(Key, Data, MacLength) -> Mac</name>
<fsummary>Compute an <c>MD5 MAC</c>message authentification code</fsummary>
<type>
<v>Key = Data = iolist() | binary()</v>
<v>Mac = binary()</v>
+ <v>MacLenength = integer() =&lt; 20 </v>
</type>
<desc>
<p>Computes an <c>SHA MAC</c> message authentification code
- from <c>Key</c> and <c>Data</c>, where the length of the Mac
+ from <c>Key</c> and <c>Data</c>, where the default length of the Mac
is 160 bits (20 bytes).</p>
</desc>
</func>
@@ -404,6 +406,51 @@ Mpint() = <![CDATA[<<ByteLen:32/integer-big, Bytes:ByteLen/binary>>]]>
</desc>
</func>
<func>
+ <name>des_cfb_encrypt(Key, IVec, Text) -> Cipher</name>
+ <fsummary>Encrypt <c>Text</c>according to DES in CFB mode</fsummary>
+ <type>
+ <v>Key = Text = iolist() | binary()</v>
+ <v>IVec = Cipher = binary()</v>
+ </type>
+ <desc>
+ <p>Encrypts <c>Text</c> according to DES in 8-bit CFB
+ mode. <c>Key</c> is the DES key, and <c>IVec</c> is an
+ arbitrary initializing vector. The lengths of <c>Key</c> and
+ <c>IVec</c> must be 64 bits (8 bytes).</p>
+ </desc>
+ </func>
+ <func>
+ <name>des_cfb_decrypt(Key, IVec, Cipher) -> Text</name>
+ <fsummary>Decrypt <c>Cipher</c>according to DES in CFB mode</fsummary>
+ <type>
+ <v>Key = Cipher = iolist() | binary()</v>
+ <v>IVec = Text = binary()</v>
+ </type>
+ <desc>
+ <p>Decrypts <c>Cipher</c> according to DES in 8-bit CFB mode.
+ <c>Key</c> is the DES key, and <c>IVec</c> is an arbitrary
+ initializing vector. <c>Key</c> and <c>IVec</c> must have
+ the same values as those used when encrypting. The lengths of
+ <c>Key</c> and <c>IVec</c> must be 64 bits (8 bytes).</p>
+ </desc>
+ </func>
+ <func>
+ <name>des_cfb_ivec(IVec, Data) -> NextIVec</name>
+ <fsummary>Get <c>IVec</c> to be used in next iteration of
+ <c>des_cfb_[ecrypt|decrypt]</c></fsummary>
+ <type>
+ <v>IVec = iolist() | binary()</v>
+ <v>Data = iolist() | binary()</v>
+ <v>NextIVec = binary()</v>
+ </type>
+ <desc>
+ <p>Returns the <c>IVec</c> to be used in a next iteration of
+ <c>des_cfb_[encrypt|decrypt]</c>. <c>IVec</c> is the vector
+ used in the previous iteration step. <c>Data</c> is the encrypted
+ data from the previous iteration step.</p>
+ </desc>
+ </func>
+ <func>
<name>des3_cbc_encrypt(Key1, Key2, Key3, IVec, Text) -> Cipher</name>
<fsummary>Encrypt <c>Text</c>according to DES3 in CBC mode</fsummary>
<type>
@@ -421,7 +468,7 @@ Mpint() = <![CDATA[<<ByteLen:32/integer-big, Bytes:ByteLen/binary>>]]>
</func>
<func>
<name>des3_cbc_decrypt(Key1, Key2, Key3, IVec, Cipher) -> Text</name>
- <fsummary>Decrypt <c>Cipher</c>according to DES in CBC mode</fsummary>
+ <fsummary>Decrypt <c>Cipher</c>according to DES3 in CBC mode</fsummary>
<type>
<v>Key1 = Key2 = Key3 = Cipher = iolist() | binary()</v>
<v>IVec = Text = binary()</v>
@@ -437,6 +484,38 @@ Mpint() = <![CDATA[<<ByteLen:32/integer-big, Bytes:ByteLen/binary>>]]>
<c>Key3</c>, and <c>IVec</c> must be 64 bits (8 bytes).</p>
</desc>
</func>
+ <func>
+ <name>des3_cfb_encrypt(Key1, Key2, Key3, IVec, Text) -> Cipher</name>
+ <fsummary>Encrypt <c>Text</c>according to DES3 in CFB mode</fsummary>
+ <type>
+ <v>Key1 =Key2 = Key3 Text = iolist() | binary()</v>
+ <v>IVec = Cipher = binary()</v>
+ </type>
+ <desc>
+ <p>Encrypts <c>Text</c> according to DES3 in 8-bit CFB
+ mode. <c>Key1</c>, <c>Key2</c>, <c>Key3</c>, are the DES
+ keys, and <c>IVec</c> is an arbitrary initializing
+ vector. The lengths of each of <c>Key1</c>, <c>Key2</c>,
+ <c>Key3</c> and <c>IVec</c> must be 64 bits (8 bytes).</p>
+ </desc>
+ </func>
+ <func>
+ <name>des3_cfb_decrypt(Key1, Key2, Key3, IVec, Cipher) -> Text</name>
+ <fsummary>Decrypt <c>Cipher</c>according to DES3 in CFB mode</fsummary>
+ <type>
+ <v>Key1 = Key2 = Key3 = Cipher = iolist() | binary()</v>
+ <v>IVec = Text = binary()</v>
+ </type>
+ <desc>
+ <p>Decrypts <c>Cipher</c> according to DES3 in 8-bit CFB mode.
+ <c>Key1</c>, <c>Key2</c>, <c>Key3</c> are the DES key, and
+ <c>IVec</c> is an arbitrary initializing vector.
+ <c>Key1</c>, <c>Key2</c>, <c>Key3</c> and <c>IVec</c> must
+ and <c>IVec</c> must have the same values as those used when
+ encrypting. The lengths of <c>Key1</c>, <c>Key2</c>,
+ <c>Key3</c>, and <c>IVec</c> must be 64 bits (8 bytes).</p>
+ </desc>
+ </func>
<func>
<name>des_ecb_encrypt(Key, Text) -> Cipher</name>
@@ -969,6 +1048,30 @@ Mpint() = <![CDATA[<<ByteLen:32/integer-big, Bytes:ByteLen/binary>>]]>
</func>
<func>
+ <name>rc2_cbc_encrypt(Key, IVec, Text) -> Cipher</name>
+ <fsummary>Encrypt <c>Text</c>according to RC2 in CBC mode</fsummary>
+ <type>
+ <v>Key = Text = iolist() | binary()</v>
+ <v>Ivec = Cipher = binary()</v>
+ </type>
+ <desc>
+ <p>Encrypts <c>Text</c> according to RC2 in CBC mode.</p>
+ </desc>
+ </func>
+
+ <func>
+ <name>rc2_cbc_decrypt(Key, IVec, Cipher) -> Text</name>
+ <fsummary>Decrypts <c>Cipher</c>according to RC2 in CBC mode</fsummary>
+ <type>
+ <v>Key = Text = iolist() | binary()</v>
+ <v>Ivec = Cipher = binary()</v>
+ </type>
+ <desc>
+ <p>Decrypts <c>Cipher</c> according to RC2 in CBC mode.</p>
+ </desc>
+ </func>
+
+ <func>
<name>rc4_encrypt(Key, Data) -> Result</name>
<fsummary>Encrypt data using RC4</fsummary>
<type>
diff --git a/lib/crypto/doc/src/make.dep b/lib/crypto/doc/src/make.dep
deleted file mode 100644
index 73b090bbb6..0000000000
--- a/lib/crypto/doc/src/make.dep
+++ /dev/null
@@ -1,20 +0,0 @@
-# ----------------------------------------------------
-# >>>> Do not edit this file <<<<
-# This file was automaticly generated by
-# /home/otp/bin/docdepend
-# ----------------------------------------------------
-
-
-# ----------------------------------------------------
-# TeX files that the DVI file depend on
-# ----------------------------------------------------
-
-book.dvi: book.tex crypto.tex crypto_app.tex licenses.tex \
- ref_man.tex usersguide.tex
-
-# ----------------------------------------------------
-# Source inlined when transforming from source to LaTeX
-# ----------------------------------------------------
-
-book.tex: ref_man.xml
-
diff --git a/lib/crypto/src/crypto.erl b/lib/crypto/src/crypto.erl
index c3e13d6b91..0714cb686d 100644
--- a/lib/crypto/src/crypto.erl
+++ b/lib/crypto/src/crypto.erl
@@ -27,11 +27,13 @@
-export([sha/1, sha_init/0, sha_update/2, sha_final/1]).
%-export([sha256/1, sha256_init/0, sha256_update/2, sha256_final/1]).
%-export([sha512/1, sha512_init/0, sha512_update/2, sha512_final/1]).
--export([md5_mac/2, md5_mac_96/2, sha_mac/2, sha_mac_96/2]).
+-export([md5_mac/2, md5_mac_96/2, sha_mac/2, sha_mac/3, sha_mac_96/2]).
-export([hmac_init/2, hmac_update/2, hmac_final/1, hmac_final_n/2]).
-export([des_cbc_encrypt/3, des_cbc_decrypt/3, des_cbc_ivec/1]).
-export([des_ecb_encrypt/2, des_ecb_decrypt/2]).
+-export([des_cfb_encrypt/3, des_cfb_decrypt/3, des_cfb_ivec/2]).
-export([des3_cbc_encrypt/5, des3_cbc_decrypt/5]).
+-export([des3_cfb_encrypt/5, des3_cfb_decrypt/5]).
-export([blowfish_ecb_encrypt/2, blowfish_ecb_decrypt/2]).
-export([blowfish_cbc_encrypt/3, blowfish_cbc_decrypt/3]).
-export([blowfish_cfb64_encrypt/3, blowfish_cfb64_decrypt/3]).
@@ -40,7 +42,7 @@
-export([aes_cfb_128_encrypt/3, aes_cfb_128_decrypt/3]).
-export([exor/2]).
-export([rc4_encrypt/2, rc4_set_key/1, rc4_encrypt_with_state/2]).
--export([rc2_40_cbc_encrypt/3, rc2_40_cbc_decrypt/3]).
+-export([rc2_cbc_encrypt/3, rc2_cbc_decrypt/3, rc2_40_cbc_encrypt/3, rc2_40_cbc_decrypt/3]).
-export([dss_verify/3, dss_verify/4, rsa_verify/3, rsa_verify/4]).
-export([dss_sign/2, dss_sign/3, rsa_sign/2, rsa_sign/3]).
-export([rsa_public_encrypt/3, rsa_private_decrypt/3]).
@@ -68,8 +70,10 @@
sha_mac, sha_mac_96,
sha_mac_init, sha_mac_update, sha_mac_final,
des_cbc_encrypt, des_cbc_decrypt,
+ des_cfb_encrypt, des_cfb_decrypt,
des_ecb_encrypt, des_ecb_decrypt,
des_ede3_cbc_encrypt, des_ede3_cbc_decrypt,
+ des_ede3_cfb_encrypt, des_ede3_cfb_decrypt,
aes_cfb_128_encrypt, aes_cfb_128_decrypt,
rand_bytes,
strong_rand_bytes,
@@ -79,7 +83,7 @@
dss_verify,dss_sign,
rsa_verify,rsa_sign,
rsa_public_encrypt,rsa_private_decrypt,
- rsa_private_encrypt,rsa_public_decrypt,
+ rsa_private_encrypt,rsa_public_decrypt,
dh_generate_key, dh_compute_key,
aes_cbc_128_encrypt, aes_cbc_128_decrypt,
exor,
@@ -87,7 +91,7 @@
rc2_40_cbc_encrypt, rc2_40_cbc_decrypt,
%% idea_cbc_encrypt, idea_cbc_decrypt,
aes_cbc_256_encrypt, aes_cbc_256_decrypt,
- aes_ctr_encrypt, aes_ctr_decrypt,
+ aes_ctr_encrypt, aes_ctr_decrypt,
aes_ctr_stream_init, aes_ctr_stream_encrypt, aes_ctr_stream_decrypt,
info_lib]).
@@ -256,6 +260,9 @@ md5_mac_n(_Key,_Data,_MacSz) -> ?nif_stub.
sha_mac(Key, Data) ->
sha_mac_n(Key,Data,20).
+sha_mac(Key, Data, Size) ->
+ sha_mac_n(Key, Data, Size).
+
sha_mac_96(Key, Data) ->
sha_mac_n(Key,Data,12).
@@ -294,6 +301,33 @@ des_cbc_ivec(Data) when is_list(Data) ->
des_cbc_ivec(list_to_binary(Data)).
%%
+%% DES - in 8-bits cipher feedback mode (CFB)
+%%
+-spec des_cfb_encrypt(iodata(), binary(), iodata()) -> binary().
+-spec des_cfb_decrypt(iodata(), binary(), iodata()) -> binary().
+
+des_cfb_encrypt(Key, IVec, Data) ->
+ des_cfb_crypt(Key, IVec, Data, true).
+
+des_cfb_decrypt(Key, IVec, Data) ->
+ des_cfb_crypt(Key, IVec, Data, false).
+
+des_cfb_crypt(_Key, _IVec, _Data, _IsEncrypt) -> ?nif_stub.
+
+%%
+%% dec_cfb_ivec(IVec, Data) -> binary()
+%%
+%% Returns the IVec to be used in the next iteration of
+%% des_cfb_[encrypt|decrypt].
+%%
+-spec des_cfb_ivec(iodata(), iodata()) -> binary().
+
+des_cfb_ivec(IVec, Data) ->
+ IVecAndData = list_to_binary([IVec, Data]),
+ {_, NewIVec} = split_binary(IVecAndData, byte_size(IVecAndData) - 8),
+ NewIVec.
+
+%%
%% DES - in electronic codebook mode (ECB)
%%
-spec des_ecb_encrypt(iodata(), iodata()) -> binary().
@@ -326,6 +360,26 @@ des_ede3_cbc_decrypt(Key1, Key2, Key3, IVec, Data) ->
des_ede3_cbc_crypt(_Key1, _Key2, _Key3, _IVec, _Data, _IsEncrypt) -> ?nif_stub.
%%
+%% DES3 - in 8-bits cipher feedback mode (CFB)
+%%
+-spec des3_cfb_encrypt(iodata(), iodata(), iodata(), binary(), iodata()) ->
+ binary().
+-spec des3_cfb_decrypt(iodata(), iodata(), iodata(), binary(), iodata()) ->
+ binary().
+
+des3_cfb_encrypt(Key1, Key2, Key3, IVec, Data) ->
+ des_ede3_cfb_encrypt(Key1, Key2, Key3, IVec, Data).
+des_ede3_cfb_encrypt(Key1, Key2, Key3, IVec, Data) ->
+ des_ede3_cfb_crypt(Key1, Key2, Key3, IVec, Data, true).
+
+des3_cfb_decrypt(Key1, Key2, Key3, IVec, Data) ->
+ des_ede3_cfb_decrypt(Key1, Key2, Key3, IVec, Data).
+des_ede3_cfb_decrypt(Key1, Key2, Key3, IVec, Data) ->
+ des_ede3_cfb_crypt(Key1, Key2, Key3, IVec, Data, false).
+
+des_ede3_cfb_crypt(_Key1, _Key2, _Key3, _IVec, _Data, _IsEncrypt) -> ?nif_stub.
+
+%%
%% Blowfish
%%
-spec blowfish_ecb_encrypt(iodata(), iodata()) -> binary().
@@ -638,16 +692,25 @@ rc4_encrypt(_Key, _Data) -> ?nif_stub.
rc4_set_key(_Key) -> ?nif_stub.
rc4_encrypt_with_state(_State, _Data) -> ?nif_stub.
+
+%% RC2 block cipher
+
+rc2_cbc_encrypt(Key, IVec, Data) ->
+ rc2_cbc_crypt(Key,IVec,Data,true).
+
+rc2_cbc_decrypt(Key, IVec, Data) ->
+ rc2_cbc_crypt(Key,IVec,Data,false).
+
+rc2_cbc_crypt(_Key, _IVec, _Data, _IsEncrypt) -> ?nif_stub.
+
%%
-%% RC2 - 40 bits block cipher
+%% RC2 - 40 bits block cipher - Backwards compatibility not documented.
%%
-rc2_40_cbc_encrypt(Key, IVec, Data) ->
- rc2_40_cbc_crypt(Key,IVec,Data,true).
-
-rc2_40_cbc_decrypt(Key, IVec, Data) ->
- rc2_40_cbc_crypt(Key,IVec,Data,false).
+rc2_40_cbc_encrypt(Key, IVec, Data) when erlang:byte_size(Key) == 5 ->
+ rc2_cbc_crypt(Key,IVec,Data,true).
-rc2_40_cbc_crypt(_Key, _IVec, _Data, _IsEncrypt) -> ?nif_stub.
+rc2_40_cbc_decrypt(Key, IVec, Data) when erlang:byte_size(Key) == 5 ->
+ rc2_cbc_crypt(Key,IVec,Data,false).
%%
%% DH Diffie-Hellman functions
diff --git a/lib/crypto/test/crypto_SUITE.erl b/lib/crypto/test/crypto_SUITE.erl
index 486751766b..86acdc27df 100644
--- a/lib/crypto/test/crypto_SUITE.erl
+++ b/lib/crypto/test/crypto_SUITE.erl
@@ -44,7 +44,12 @@
md5_mac_io/1,
des_cbc/1,
des_cbc_iter/1,
+ des_cfb/1,
+ des_cfb_iter/1,
des_ecb/1,
+ des3_cbc/1,
+ des3_cfb/1,
+ rc2_cbc/1,
aes_cfb/1,
aes_cbc/1,
aes_cbc_iter/1,
@@ -75,7 +80,9 @@ all() ->
md5_mac_io, sha, sha_update,
hmac_update_sha, hmac_update_sha_n, hmac_update_md5_n, hmac_update_md5_io, hmac_update_md5,
%% sha256, sha256_update, sha512,sha512_update,
- des_cbc, aes_cfb, aes_cbc,
+ des_cbc, des_cfb, des3_cbc, des3_cfb, rc2_cbc, aes_cfb, aes_cbc,
+ aes_cbc_iter, aes_ctr, aes_ctr_stream, des_cbc_iter, des_cfb_iter, des_ecb,
+ des_cbc, rc2_cbc, aes_cfb, aes_cbc,
aes_cbc_iter, aes_ctr, aes_ctr_stream, des_cbc_iter, des_ecb,
rand_uniform_test, strong_rand_test,
rsa_verify_test, dsa_verify_test, rsa_sign_test,
@@ -292,7 +299,7 @@ sha(Config) when is_list(Config) ->
hexstr2bin("84983E441C3BD26EBAAE4AA1F95129E5E54670F1")).
-%%
+%%
hmac_update_sha_n(doc) ->
["Request a larger-than-allowed SHA1 HMAC using hmac_init, hmac_update, and hmac_final_n. "
"Expected values for examples are generated using crypto:sha_mac." ];
@@ -343,7 +350,7 @@ hmac_update_md5(Config) when is_list(Config) ->
Key2 = "A fine speach by a fine man!",
?line Long1 = "Four score and seven years ago our fathers brought forth on this continent a new nation, conceived in liberty, and dedicated to the proposition that all men are created equal.",
?line Long2 = "Now we are engaged in a great civil war, testing whether that nation, or any nation, so conceived and so dedicated, can long endure. We are met on a great battle-field of that war. We have come to dedicate a portion of that field, as a final resting place for those who here gave their lives that that nation might live. It is altogether fitting and proper that we should do this.",
- ?line Long3 = "But, in a larger sense, we can not dedicate, we can not consecrate, we can not hallow this ground. The brave men, living and dead, who struggled here, have consecrated it, far above our poor power to add or detract. The world will little note, nor long remember what we say here, but it can never forget what they did here. It is for us the living, rather, to be dedicated here to the unfinished work which they who fought here have thus far so nobly advanced. It is rather for us to be here dedicated to the great task remaining before us-that from these honored dead we take increased devotion to that cause for which they gave the last full measure of devotion—that we here highly resolve that these dead shall not have died in vain-that this nation, under God, shall have a new birth of freedom-and that government of the people, by the people, for the people, shall not perish from the earth.",
+ ?line Long3 = "But, in a larger sense, we can not dedicate, we can not consecrate, we can not hallow this ground. The brave men, living and dead, who struggled here, have consecrated it, far above our poor power to add or detract. The world will little note, nor long remember what we say here, but it can never forget what they did here. It is for us the living, rather, to be dedicated here to the unfinished work which they who fought here have thus far so nobly advanced. It is rather for us to be here dedicated to the great task remaining before us-that from these honored dead we take increased devotion to that cause for which they gave the last full measure of devotion that we here highly resolve that these dead shall not have died in vain-that this nation, under God, shall have a new birth of freedom-and that government of the people, by the people, for the people, shall not perish from the earth.",
?line CtxA = crypto:hmac_init(md5, Key2),
?line CtxB = crypto:hmac_update(CtxA, Long1),
?line CtxC = crypto:hmac_update(CtxB, Long2),
@@ -547,6 +554,40 @@ des_cbc_iter(Config) when is_list(Config) ->
%%
%%
+des_cfb(doc) ->
+ "Encrypt and decrypt according to CFB DES. and check the result. "
+ "Example is from FIPS-81.";
+des_cfb(suite) ->
+ [];
+des_cfb(Config) when is_list(Config) ->
+ ?line Key = hexstr2bin("0123456789abcdef"),
+ ?line IVec = hexstr2bin("1234567890abcdef"),
+ ?line Plain = "Now is the",
+ ?line Cipher = crypto:des_cfb_encrypt(Key, IVec, Plain),
+ ?line m(Cipher, hexstr2bin("f31fda07011462ee187f")),
+ ?line m(list_to_binary(Plain),
+ crypto:des_cfb_decrypt(Key, IVec, Cipher)).
+
+%%
+%%
+des_cfb_iter(doc) ->
+ "Encrypt and decrypt according to CFB DES in two steps, and "
+ "check the result. Example is from FIPS-81.";
+des_cfb_iter(suite) ->
+ [];
+des_cfb_iter(Config) when is_list(Config) ->
+ ?line Key = hexstr2bin("0123456789abcdef"),
+ ?line IVec = hexstr2bin("1234567890abcdef"),
+ ?line Plain1 = "Now i",
+ ?line Plain2 = "s the",
+ ?line Cipher1 = crypto:des_cfb_encrypt(Key, IVec, Plain1),
+ ?line IVec2 = crypto:des_cfb_ivec(IVec, Cipher1),
+ ?line Cipher2 = crypto:des_cfb_encrypt(Key, IVec2, Plain2),
+ ?line Cipher = list_to_binary([Cipher1, Cipher2]),
+ ?line m(Cipher, hexstr2bin("f31fda07011462ee187f")).
+
+%%
+%%
des_ecb(doc) ->
"Encrypt and decrypt according to ECB DES and check the result. "
"Example are from FIPS-81.";
@@ -566,6 +607,81 @@ des_ecb(Config) when is_list(Config) ->
?line m(Cipher5, <<"he time ">>),
?line Cipher6 = crypto:des_ecb_decrypt(Key, hexstr2bin("893d51ec4b563b53")),
?line m(Cipher6, <<"for all ">>).
+%%
+%%
+rc2_cbc(doc) ->
+ "Encrypt and decrypt according to RC2 CBC and check the result. "
+ "Example stripped out from public_key application test";
+rc2_cbc(Config) when is_list(Config) ->
+
+ Key = <<146,210,160,124,215,227,153,239,227,17,222,140,3,93,27,191>>,
+ IV = <<72,91,135,182,25,42,35,210>>,
+
+ Cipher = <<36,245,206,158,168,230,58,69,148,137,32,192,250,41,237,181,181,251, 192,2,175,135,177,171,57,30,111,117,159,149,15,28,88,158,28,81,28,115, 85,219,241,82,117,222,91,85,73,117,164,25,182,52,191,64,123,57,26,19, 211,27,253,31,194,219,231,104,247,240,172,130,119,21,225,154,101,247, 32,216,42,216,133,169,78,22,97,27,227,26,196,224,172,168,17,9,148,55, 203,91,252,40,61,226,236,221,215,160,78,63,13,181,68,57,196,241,185, 207, 116,129,152,237,60,139,247,153,27,146,161,246,222,98,185,222,152, 187,135, 236,86,34,7,110,91,230,173,34,160,242,202,222,121,127,181,140, 101,203,195, 190,88,250,86,147,127,87,72,126,171,16,71,47,110,248,88, 14,29,143,161,152, 129,236,148,22,152,186,208,119,70,8,174,193,203,100, 193,203,200,117,102,242, 134,142,96,125,135,200,217,190,76,117,50,70, 209,186,101,241,200,91,40,193,54, 90,195,38,47,59,197,38,234,86,223,16, 51,253,204,129,20,171,66,21,241,26,135,216, 196,114,110,91,15,53,40, 164,201,136,113,95,247,51,181,208,241,68,168,98,151,36, 155,72,24,57, 42,191,14,125,204,10,167,214,233,138,115,125,234,121,134,227,26,247, 77,200,117,110,117,111,168,156,206,67,159,149,189,173,150,193,91,199, 216,153,22, 189,137,185,89,160,13,131,132,58,109,28,110,246,252,251,14, 232,91,38,52,29,101,188,69,123,50,0,130,178,93,73,239,118,7,77,35,59, 253,10,159,45,86,142,37,78,232,48>>,
+ Text = <<48,130,1,85,2,1,0,48,13,6,9,42,134,72,134,247,13,1,1,1,5,0,4,130,1,63,48,130, 1,59,2,1,0,2,65,0,222,187,252,44,9,214,27,173,162,169,70,47,36,34,78,84,204, 107,60,192,117,95,21,206,49,142,245,126,121,223,23,2,107,106,133,204,161,36, 40,2,114,69,4,93,242,5,42,50,154,47,154,211,209,123,120,161,5,114,173,155,34, 191,52,59,2,3,1,0,1,2,64,45,144,169,106,220,236,71,39,67,82,123,192,35,21,61, 143,13,110,150,180,12,142,210,40,39,109,70,125,132,51,6,66,159,134,112,85, 155,243,118,221,65,133,127,99,151,194,252,141,149,224,229,62,214,45,228,32, 184,85,67,14,228,161,184,161,2,33,0,255,202,240,131,130,57,49,224,115,255,83, 79,6,165,212,21,179,212,20,188,97,74,69,68,163,223,247,237,39,24,23,235,2,33, 0,222,234,48,36,33,23,219,45,59,136,55,245,143,29,165,48,255,131,207,146,131, 104,13,163,54,131,236,78,88,54,16,241,2,33,0,230,2,99,129,173,176,166,131, 241,106,143,76,9,107,70,41,121,185,228,39,124,200,159,62,216,169,5,180,111, 169,255,159,2,33,0,151,193,70,212,209,210,179,219,175,83,165,4,255,81,103,76, 92,39,24,0,222,132,208,3,244,241,10,198,171,54,227,129,2,32,43,250,20,31,16, 189,168,116,225,1,125,132,94,130,118,124,28,56,232,39,69,218,244,33,240,200, 205,9,215,101,35,135,7,7,7,7,7,7,7>>,
+
+ Text = crypto:rc2_cbc_decrypt(Key, IV, Cipher),
+ Cipher = crypto:rc2_cbc_encrypt(Key, IV, Text).
+
+%%
+%%
+des3_cbc(doc) ->
+ "Encrypt and decrypt according to CBC 3DES, and check the result.";
+des3_cbc(suite) ->
+ [];
+des3_cbc(Config) when is_list(Config) ->
+ ?line Key1 = hexstr2bin("0123456789abcdef"),
+ ?line Key2 = hexstr2bin("fedcba9876543210"),
+ ?line Key3 = hexstr2bin("0f2d4b6987a5c3e1"),
+ ?line IVec = hexstr2bin("1234567890abcdef"),
+ ?line Plain = "Now is the time for all ",
+ ?line Cipher = crypto:des3_cbc_encrypt(Key1, Key2, Key3, IVec, Plain),
+ ?line m(Cipher, hexstr2bin("8a2667ee5577267cd9b1af2c5a0480"
+ "0bac1ae66970fb2b89")),
+ ?line m(list_to_binary(Plain),
+ crypto:des3_cbc_decrypt(Key1, Key2, Key3, IVec, Cipher)),
+ ?line Plain2 = "7654321 Now is the time for " ++ [0, 0, 0, 0],
+ ?line Cipher2 = crypto:des3_cbc_encrypt(Key1, Key2, Key3, IVec, Plain2),
+ ?line m(Cipher2, hexstr2bin("eb33ec6ede2c8e90f6877e77b95d5"
+ "4c83cee22907f7f0041ca1b7abe202bfafe")),
+ ?line m(list_to_binary(Plain2),
+ crypto:des3_cbc_decrypt(Key1, Key2, Key3, IVec, Cipher2)),
+
+ ?line Key = hexstr2bin("0123456789abcdef"),
+ ?line DESCipher = crypto:des3_cbc_encrypt(Key, Key, Key, IVec, Plain),
+ ?line m(DESCipher, hexstr2bin("e5c7cdde872bf27c43e934008c389c"
+ "0f683788499a7c05f6")),
+ ?line m(list_to_binary(Plain),
+ crypto:des3_cbc_decrypt(Key, Key, Key, IVec, DESCipher)),
+ ?line DESCipher2 = crypto:des3_cbc_encrypt(Key, Key, Key, IVec, Plain2),
+ ?line m(DESCipher2, hexstr2bin("b9916b8ee4c3da64b4f44e3cbefb9"
+ "9484521388fa59ae67d58d2e77e86062733")),
+ ?line m(list_to_binary(Plain2),
+ crypto:des3_cbc_decrypt(Key, Key, Key, IVec, DESCipher2)).
+
+%%
+%%
+des3_cfb(doc) ->
+ "Encrypt and decrypt according to CFB 3DES, and check the result.";
+des3_cfb(suite) ->
+ [];
+des3_cfb(Config) when is_list(Config) ->
+ ?line Key1 = hexstr2bin("0123456789abcdef"),
+ ?line Key2 = hexstr2bin("fedcba9876543210"),
+ ?line Key3 = hexstr2bin("0f2d4b6987a5c3e1"),
+ ?line IVec = hexstr2bin("1234567890abcdef"),
+ ?line Plain = "Now is the time for all ",
+ ?line Cipher = crypto:des3_cfb_encrypt(Key1, Key2, Key3, IVec, Plain),
+ ?line m(Cipher, hexstr2bin("fc0ba7a20646ba53cc8bff263f0937"
+ "1deab42a00666db02c")),
+ ?line m(list_to_binary(Plain),
+ crypto:des3_cfb_decrypt(Key1, Key2, Key3, IVec, Cipher)),
+ ?line Plain2 = "7654321 Now is the time for " ++ [0, 0, 0, 0],
+ ?line Cipher2 = crypto:des3_cfb_encrypt(Key1, Key2, Key3, IVec, Plain2),
+ ?line m(Cipher2, hexstr2bin("8582c59ac01897422632c0accb66c"
+ "e413f5efab838fce7e41e2ba67705bad5bc")),
+ ?line m(list_to_binary(Plain2),
+ crypto:des3_cfb_decrypt(Key1, Key2, Key3, IVec, Cipher2)).
%%
%%
@@ -1233,8 +1349,8 @@ rc4_test(doc) ->
rc4_test(suite) ->
[];
rc4_test(Config) when is_list(Config) ->
- CT1 = <<"hej p� dig">>,
- R1 = <<71,112,14,44,140,33,212,144,155,47>>,
+ CT1 = <<"Yo baby yo">>,
+ R1 = <<118,122,68,110,157,166,141,212,139,39>>,
K = "apaapa",
R1 = crypto:rc4_encrypt(K, CT1),
CT1 = crypto:rc4_encrypt(K, R1),
@@ -1248,14 +1364,14 @@ rc4_stream_test(doc) ->
rc4_stream_test(suite) ->
[];
rc4_stream_test(Config) when is_list(Config) ->
- CT1 = <<"hej">>,
- CT2 = <<" p� dig">>,
+ CT1 = <<"Yo ">>,
+ CT2 = <<"baby yo">>,
K = "apaapa",
State0 = crypto:rc4_set_key(K),
{State1, R1} = crypto:rc4_encrypt_with_state(State0, CT1),
{_State2, R2} = crypto:rc4_encrypt_with_state(State1, CT2),
R = list_to_binary([R1, R2]),
- <<71,112,14,44,140,33,212,144,155,47>> = R,
+ <<118,122,68,110,157,166,141,212,139,39>> = R,
ok.
blowfish_cfb64(doc) -> ["Test Blowfish encrypt/decrypt."];
diff --git a/lib/debugger/doc/src/debugger_chapter.xml b/lib/debugger/doc/src/debugger_chapter.xml
index 1f5d4dd5ff..2d812b0236 100644
--- a/lib/debugger/doc/src/debugger_chapter.xml
+++ b/lib/debugger/doc/src/debugger_chapter.xml
@@ -254,19 +254,17 @@ c_break(Bindings) ->
used, for example, if an error occurs:</p>
<pre>
1> <input>catch a+1.</input>
-{'EXIT',{badarith,[{erlang,'+',[a,1]},
- {erl_eval,do_apply,5},
- {erl_eval,expr,5},
- {shell,exprs,6},
- {shell,eval_exprs,6},
- {shell,eval_loop,3}]}}</pre>
-
- <p>In the case above, the stack trace shows that the function called
- last was <c>erl_eval:eval_op/3</c>. See <em>Erlang Reference
- Manual, Errors and Error handling</em>, for more information
- about stack trace.</p>
-
- <p>Debugger emulates the stack trace by keeping track of recently
+{'EXIT',{badarith,[{erlang,'+',[a,1],[]},
+ {erl_eval,do_apply,5,[{file,"erl_eval.erl"},{line,562}]},
+ {erl_eval,expr,5,[{file,"erl_eval.erl"},{line,359}]},
+ {shell,exprs,7,[{file,"shell.erl"},{line,668}]},
+ {shell,eval_exprs,7,[{file,"shell.erl"},{line,623}]},
+ {shell,eval_loop,3,[{file,"shell.erl"},{line,608}]}]}}</pre>
+
+ <p>See the <em>Erlang Reference Manual, Errors and Error handling</em>,
+ for more information about the stack trace.</p>
+
+ <p>The Debugger emulates the stack trace by keeping track of recently
called interpreted functions. (The real stack trace cannot be
used, as it shows which functions of the Debugger have been
called, rather than which interpreted functions).</p>
@@ -276,17 +274,15 @@ c_break(Bindings) ->
<seealso marker="#attach">the Attach Process window</seealso>.
</p>
- <p>By default, the Debugger saves information about all current
+ <p>By default, the Debugger only saves information about recursive
function calls, that is, function calls that have not yet returned
- a value (option 'Stack On, Tail').</p>
-
- <p>This means, however, that information is saved also for tail
- recursive calls. For example, repeated calls to the <c>loop</c>
- function of an Erlang process. This may consume unnecessary
- amounts of memory for debugged processes with long lifetimes and
- many tail recursive calls. It is therefore possible to set
- the option 'Stack On, no tail', in which case information about
- previous calls are discarded when a tail recursive call is made.
+ a value (option 'Stack On, No Tail').</p>
+
+ <p>Sometimes, however, it can be useful to save all calls, even
+ tail-recursive calls. That can be done with the 'Stack On, Tail'
+ option. Note that this option will consume more memory and slow
+ down execution of interpreted functions when there are many
+ tail-recursive calls.
</p>
<p>It is also possible to turn off the Debugger stack trace
diff --git a/lib/debugger/doc/src/int.xml b/lib/debugger/doc/src/int.xml
index 8b55461a44..c9d815755d 100644
--- a/lib/debugger/doc/src/int.xml
+++ b/lib/debugger/doc/src/int.xml
@@ -284,12 +284,12 @@ spawn(Module, Name, [Pid | Args])
<list>
<item><c>all</c> - save information about all current calls,
that is, function calls that have not yet returned a value.
- This is the default.</item>
+ </item>
<item><c>no_tail</c> - save information about current calls,
but discard previous information when a tail recursive call
is made. This option consumes less memory and may be
necessary to use for processes with long lifetimes and many
- tail recursive calls.</item>
+ tail recursive calls. This is the default.</item>
<item><c>false</c> - do not save any information about current
calls.</item>
</list>
diff --git a/lib/debugger/doc/src/make.dep b/lib/debugger/doc/src/make.dep
deleted file mode 100644
index c11fd3c21c..0000000000
--- a/lib/debugger/doc/src/make.dep
+++ /dev/null
@@ -1,29 +0,0 @@
-# ----------------------------------------------------
-# >>>> Do not edit this file <<<<
-# This file was automaticly generated by
-# /home/otp/bin/docdepend
-# ----------------------------------------------------
-
-
-# ----------------------------------------------------
-# TeX files that the DVI file depend on
-# ----------------------------------------------------
-
-book.dvi: book.tex debugger.tex debugger_chapter.tex \
- i.tex int.tex part.tex ref_man.tex
-
-# ----------------------------------------------------
-# Source inlined when transforming from source to LaTeX
-# ----------------------------------------------------
-
-book.tex: part.xml ref_man.xml
-
-# ----------------------------------------------------
-# Pictures that the DVI file depend on
-# ----------------------------------------------------
-
-book.dvi: images/attach.ps images/cond_break_dialog.ps \
- images/function_break_dialog.ps images/interpret.ps \
- images/line_break_dialog.ps images/monitor.ps \
- images/view.ps
-
diff --git a/lib/debugger/src/Makefile b/lib/debugger/src/Makefile
index 8551fe887d..6dc7d0d783 100644
--- a/lib/debugger/src/Makefile
+++ b/lib/debugger/src/Makefile
@@ -44,6 +44,7 @@ MODULES= \
dbg_ieval \
dbg_iload \
dbg_iserver \
+ dbg_istk \
dbg_ui_break \
dbg_ui_break_win \
dbg_ui_edit \
diff --git a/lib/debugger/src/dbg_debugged.erl b/lib/debugger/src/dbg_debugged.erl
index 3732c40c73..18dcd92ff3 100644
--- a/lib/debugger/src/dbg_debugged.erl
+++ b/lib/debugger/src/dbg_debugged.erl
@@ -76,8 +76,8 @@ msg_loop(Meta, Mref, SaveStacktrace) ->
msg_loop(Meta, Mref, SaveStacktrace);
%% Meta needs something evaluated within context of real process
- {sys, Meta, {command, Command, Stacktrace}} ->
- Reply = handle_command(Command, Stacktrace),
+ {sys, Meta, {command,Command}} ->
+ Reply = handle_command(Command),
Meta ! {sys, self(), Reply},
msg_loop(Meta, Mref, SaveStacktrace);
@@ -93,11 +93,12 @@ msg_loop(Meta, Mref, SaveStacktrace) ->
end
end.
-handle_command(Command, Stacktrace) ->
- try reply(Command)
+handle_command(Command) ->
+ try
+ reply(Command)
catch Class:Reason ->
- Stacktrace2 = stacktrace_f(erlang:get_stacktrace()),
- {exception, {Class,Reason,Stacktrace2++Stacktrace}}
+ Stacktrace = stacktrace_f(erlang:get_stacktrace()),
+ {exception,{Class,Reason,Stacktrace}}
end.
reply({apply,M,F,As}) ->
@@ -116,5 +117,5 @@ demonitor(Mref) ->
%% Fix stacktrace - keep all above call to this module.
%%
stacktrace_f([]) -> [];
-stacktrace_f([{?MODULE,_,_}|_]) -> [];
+stacktrace_f([{?MODULE,_,_,_}|_]) -> [];
stacktrace_f([F|S]) -> [F|stacktrace_f(S)].
diff --git a/lib/debugger/src/dbg_icmd.erl b/lib/debugger/src/dbg_icmd.erl
index e9502eaa2b..b230efaa7a 100644
--- a/lib/debugger/src/dbg_icmd.erl
+++ b/lib/debugger/src/dbg_icmd.erl
@@ -273,7 +273,7 @@ handle_int_msg({old_code,Mod}, Status, Bs,
erase([Mod|db]),
put(cache, []);
true ->
- case dbg_ieval:in_use_p(Mod, M) of
+ case dbg_istk:in_use_p(Mod, M) of
true ->
%% A call to Mod is on the stack (or might be),
%% so we must terminate.
@@ -342,11 +342,11 @@ handle_user_msg({set,stack_trace,Flag}, _Status, _Bs, _Ieval) ->
handle_user_msg({get,bindings,From,SP}, _Status, Bs, _Ieval) ->
reply(From, bindings, bindings(Bs, SP));
handle_user_msg({get,stack_frame,From,{Dir,SP}}, _Status, _Bs,_Ieval) ->
- reply(From, stack_frame, dbg_ieval:stack_frame(Dir, SP));
+ reply(From, stack_frame, dbg_istk:stack_frame(Dir, SP));
handle_user_msg({get,messages,From,_}, _Status, _Bs, _Ieval) ->
reply(From, messages, messages());
-handle_user_msg({get,backtrace,From,N}, _Status, _Bs, _Ieval) ->
- reply(From, backtrace, dbg_ieval:backtrace(N)).
+handle_user_msg({get,backtrace,From,N}, _Status, _Bs, Ieval) ->
+ reply(From, backtrace, dbg_istk:backtrace(N, Ieval)).
set_stack_trace(true) ->
set_stack_trace(all);
@@ -366,11 +366,11 @@ reply(From, Tag, Reply) ->
bindings(Bs, nostack) ->
Bs;
bindings(Bs, SP) ->
- case dbg_ieval:stack_level() of
+ case dbg_istk:stack_level() of
Le when SP > Le ->
Bs;
_ ->
- dbg_ieval:bindings(SP)
+ dbg_istk:bindings(SP)
end.
messages() ->
@@ -422,7 +422,7 @@ eval_nonrestricted({From, _Mod, Cmd, _SP}, Bs,
eval_nonrestricted_1({match,_,{var,_,Var},Expr}, Bs, Ieval) ->
{value,Res,Bs2} =
- dbg_ieval:eval_expr(Expr, Bs, Ieval#ieval{last_call=false}),
+ dbg_ieval:eval_expr(Expr, Bs, Ieval#ieval{top=false}),
Bs3 = case lists:keyfind(Var, 1, Bs) of
{Var,_Value} ->
lists:keyreplace(Var, 1, Bs2, {Var,Res});
@@ -437,7 +437,7 @@ eval_nonrestricted_1({var,_,Var}, Bs, _Ieval) ->
{Res,Bs};
eval_nonrestricted_1(Expr, Bs, Ieval) ->
{value,Res,Bs2} =
- dbg_ieval:eval_expr(Expr, Bs, Ieval#ieval{last_call=false}),
+ dbg_ieval:eval_expr(Expr, Bs, Ieval#ieval{top=false}),
{Res,Bs2}.
mark_running(LineNo, Le) ->
diff --git a/lib/debugger/src/dbg_ieval.erl b/lib/debugger/src/dbg_ieval.erl
index 306323f8ea..2e88c35741 100644
--- a/lib/debugger/src/dbg_ieval.erl
+++ b/lib/debugger/src/dbg_ieval.erl
@@ -20,8 +20,7 @@
-export([eval/3,exit_info/5]).
-export([eval_expr/3]).
--export([check_exit_msg/3,exception/4,in_use_p/2]).
--export([stack_level/0, bindings/1, stack_frame/2, backtrace/1]).
+-export([check_exit_msg/3,exception/4]).
-include("dbg_ieval.hrl").
@@ -71,13 +70,12 @@ exit_info(Int, AttPid, OrigPid, Reason, ExitInfo) ->
case ExitInfo of
{{Mod,Line},Bs,S} ->
- Stack = binary_to_term(S),
- put(stack, Stack),
- Le = stack_level(Stack),
+ dbg_istk:from_external(S),
+ Le = dbg_istk:stack_level(),
dbg_icmd:tell_attached({exit_at, {Mod, Line}, Reason, Le}),
exit_loop(OrigPid, Reason, Bs,#ieval{module=Mod,line=Line});
{} ->
- put(stack, []),
+ dbg_istk:init(),
dbg_icmd:tell_attached({exit_at, null, Reason, 1}),
exit_loop(OrigPid, Reason, erl_eval:new_bindings(),#ieval{})
end.
@@ -142,12 +140,12 @@ check_exit_msg({'DOWN',_,_,_,Reason}, Bs,
undefined when Le =:= 1 -> % died outside interpreted code
{};
undefined when Le > 1 ->
- StackBin = term_to_binary(get(stack)),
- {{Mod, Li}, Bs, StackBin};
+ StackExternal = (dbg_istk:delayed_to_external())(),
+ {{Mod, Li}, Bs, StackExternal};
%% Debugged has terminated due to an exception
- ExitInfo0 ->
- ExitInfo0
+ ExitInfo0 when is_function(ExitInfo0, 0) ->
+ ExitInfo0()
end,
dbg_iserver:cast(get(int), {set_exit_info,self(),ExitInfo}),
@@ -170,30 +168,26 @@ check_exit_msg(_Msg, _Bs, _Ieval) ->
%% and then raise the exception.
%%--------------------------------------------------------------------
exception(Class, Reason, Bs, Ieval) ->
- exception(Class, Reason, fix_stacktrace(1), Bs, Ieval).
-
-exception(Class, Reason, Stacktrace, Bs, #ieval{module=M, line=Line}) ->
- ExitInfo = {{M,Line}, Bs, term_to_binary(get(stack))},
+ exception(Class, Reason, Bs, Ieval, false).
+
+exception(Class, Reason, Bs, Ieval, false) ->
+ do_exception(Class, Reason,
+ dbg_istk:delayed_stacktrace(no_args, Ieval),
+ Bs, Ieval);
+exception(Class, Reason, Bs, Ieval, true) ->
+ do_exception(Class, Reason,
+ dbg_istk:delayed_stacktrace(include_args, Ieval),
+ Bs, Ieval).
+
+do_exception(Class, Reason, Stacktrace, Bs, #ieval{module=M, line=Line}) ->
+ StackFun = dbg_istk:delayed_to_external(),
+ ExitInfo = fun() ->
+ {{M,Line},Bs,StackFun()}
+ end,
put(exit_info, ExitInfo),
put(stacktrace, Stacktrace),
erlang:Class(Reason).
-%%--------------------------------------------------------------------
-%% in_use_p(Mod, Cm) -> boolean()
-%% Mod = Cm = atom()
-%% Returns true if Mod is found on the stack, otherwise false.
-%%--------------------------------------------------------------------
-in_use_p(Mod, Mod) -> true;
-in_use_p(Mod, _Cm) ->
- case get(trace_stack) of
- false -> true;
- _ -> % all | no_tail
- lists:any(fun({_,{M,_,_,_}}) when M =:= Mod -> true;
- (_) -> false
- end,
- get(stack))
- end.
-
%%====================================================================
%% Internal functions
%%====================================================================
@@ -225,7 +219,7 @@ meta(Int, Debugged, M, F, As) ->
put(cache, []),
put(next_break, Status), % break | running (other values later)
put(self, Debugged), % pid() interpreted process
- put(stack, []),
+ dbg_istk:init(),
put(stacktrace, []),
put(trace_stack, dbg_iserver:call(Int, get_stack_trace)),
put(trace, false), % bool() Trace on/off
@@ -243,8 +237,7 @@ meta(Int, Debugged, M, F, As) ->
debugged_cmd(Cmd, Bs, Ieval) ->
Debugged = get(self),
- Stacktrace = fix_stacktrace(2),
- Debugged ! {sys, self(), {command,Cmd,Stacktrace}},
+ Debugged ! {sys, self(), {command,Cmd}},
meta_loop(Debugged, Bs, Ieval).
meta_loop(Debugged, Bs, #ieval{level=Le} = Ieval) ->
@@ -257,12 +250,17 @@ meta_loop(Debugged, Bs, #ieval{level=Le} = Ieval) ->
{value, Val, Bs};
{sys, Debugged, {value,Val,Bs2}} ->
{value, Val, Bs2};
- {sys, Debugged, {exception,{Class,Reason,Stacktrace}}} ->
+ {sys, Debugged, {exception,{Class,Reason,Stk}}} ->
case get(exit_info) of
- %% Error occured outside interpreted code
+ %% Error occurred outside of interpreted code.
undefined ->
- exception(Class,Reason,Stacktrace,Bs,Ieval);
+ MakeStk0 = dbg_istk:delayed_stacktrace(),
+ MakeStk = fun(Depth0) ->
+ Depth = max(0, Depth0 - length(Stk)),
+ Stk ++ MakeStk0(Depth)
+ end,
+ do_exception(Class, Reason, MakeStk, Bs, Ieval);
%% Error must have occured within a re-entry to
%% interpreted code, simply raise the exception
@@ -275,7 +273,7 @@ meta_loop(Debugged, Bs, #ieval{level=Le} = Ieval) ->
%% Reset process dictionary
%% This is really only necessary if the process left
%% interpreted code at a call level > 1
- put(stack, []),
+ dbg_istk:init(),
put(stacktrace, []),
put(exit_info, undefined),
@@ -313,177 +311,6 @@ exit_loop(OrigPid, Reason, Bs, Ieval) ->
exit_loop(OrigPid, Reason, Bs, Ieval)
end.
-%%--Stack emulation---------------------------------------------------
-
-%% We keep track of a call stack that is used for
-%% 1) saving stack frames that can be inspected from an Attached
-%% Process GUI (using dbg_icmd:get(Meta, stack_frame, {Dir, SP})
-%% 2) generate an approximation of regular stacktrace -- sent to
-%% Debugged when it should raise an exception or evaluate a
-%% function (since it might possible raise an exception)
-%%
-%% Stack = [Entry]
-%% Entry = {Le, {MFA, Where, Bs}}
-%% Le = int() % current call level
-%% MFA = {M,F,Args} % called function (or fun)
-%% | {Fun,Args} %
-%% Where = {M,Li} % from where (module+line) function is called
-%% Bs = bindings() % current variable bindings
-%%
-%% How to push depends on the "Stack Trace" option (value saved in
-%% process dictionary item 'trace_stack').
-%% all - everything is pushed
-%% no_tail - tail recursive push
-%% false - nothing is pushed
-%% Whenever a function returns, the corresponding call frame is popped.
-
-push(MFA, Bs, #ieval{level=Le,module=Cm,line=Li,last_call=Lc}) ->
- Entry = {Le, {MFA, {Cm,Li}, Bs}},
- case get(trace_stack) of
- false -> ignore;
- no_tail when Lc ->
- case get(stack) of
- [] -> put(stack, [Entry]);
- [_Entry|Entries] -> put(stack, [Entry|Entries])
- end;
- _ -> % all | no_tail when Lc =:= false
- put(stack, [Entry|get(stack)])
- end.
-
-pop() ->
- case get(trace_stack) of
- false -> ignore;
- _ -> % all � no_tail
- case get(stack) of
- [_Entry|Entries] ->
- put(stack, Entries);
- [] ->
- ignore
- end
- end.
-
-pop(Le) ->
- case get(trace_stack) of
- false -> ignore;
- _ -> % all | no_tail
- put(stack, pop(Le, get(stack)))
- end.
-
-pop(Level, [{Le, _}|Stack]) when Level=<Le ->
- pop(Level, Stack);
-pop(_Level, Stack) ->
- Stack.
-
-
-%% stack_level() -> Le
-%% stack_level(Stack) -> Le
-%% Top call level
-stack_level() ->
- stack_level(get(stack)).
-
-stack_level([]) -> 1;
-stack_level([{Le,_}|_]) -> Le.
-
-%% fix_stacktrace(Start) -> Stacktrace
-%% Start = 1|2
-%% Stacktrace = [{M,F,Args|Arity} | {Fun,Args}]
-%% Convert internal stack format to imitation of regular stacktrace.
-%% Max three elements, no repeated (recursive) calls to the same
-%% function and convert argument lists to arity for all but topmost
-%% entry (and funs).
-%% 'Start' indicates where at get(stack) to start. This somewhat ugly
-%% solution is because fix_stacktrace has two uses: 1) to imitate
-%% the stacktrace in the case of an exception in the interpreted code,
-%% in which case the current call (top of the stack = first of the list)
-%% should be included, and 2) to send a current stacktrace to Debugged
-%% when evaluation passes into non-interpreted code, in which case
-%% the current call should NOT be included (as it is Debugged which
-%% will make the actual function call).
-fix_stacktrace(Start) ->
- case fix_stacktrace2(sublist(get(stack), Start, 3)) of
- [] ->
- [];
- [H|T] ->
- [H|args2arity(T)]
- end.
-
-sublist([], _Start, _Length) ->
- []; % workaround, lists:sublist([],2,3) fails
-sublist(L, Start, Length) ->
- lists:sublist(L, Start, Length).
-
-fix_stacktrace2([{_,{{M,F,As1},_,_}}, {_,{{M,F,As2},_,_}}|_])
- when length(As1) =:= length(As2) ->
- [{M,F,As1}];
-fix_stacktrace2([{_,{{Fun,As1},_,_}}, {_,{{Fun,As2},_,_}}|_])
- when length(As1) =:= length(As2) ->
- [{Fun,As1}];
-fix_stacktrace2([{_,{MFA,_,_}}|Entries]) ->
- [MFA|fix_stacktrace2(Entries)];
-fix_stacktrace2([]) ->
- [].
-
-args2arity([{M,F,As}|Entries]) when is_list(As) ->
- [{M,F,length(As)}|args2arity(Entries)];
-args2arity([Entry|Entries]) ->
- [Entry|args2arity(Entries)];
-args2arity([]) ->
- [].
-
-%% bindings(SP) -> Bs
-%% SP = Le % stack pointer
-%% Return the bindings for the specified call level
-bindings(SP) ->
- bindings(SP, get(stack)).
-
-bindings(SP, [{SP,{_MFA,_Wh,Bs}}|_]) ->
- Bs;
-bindings(SP, [_Entry|Entries]) ->
- bindings(SP, Entries);
-bindings(_SP, []) ->
- erl_eval:new_bindings().
-
-%% stack_frame(Dir, SP) -> {Le, Where, Bs} | top | bottom
-%% Dir = up | down
-%% Where = {Cm, Li}
-%% Cm = Module | undefined % module
-%% Li = int() | -1 % line number
-%% Bs = bindings()
-%% Return stack frame info one step up/down from given stack pointer
-%% up = to lower call levels
-%% down = to higher call levels
-stack_frame(up, SP) ->
- stack_frame(SP, up, get(stack));
-stack_frame(down, SP) ->
- stack_frame(SP, down, lists:reverse(get(stack))).
-
-stack_frame(SP, up, [{Le, {_MFA,Where,Bs}}|_]) when Le<SP ->
- {Le, Where, Bs};
-stack_frame(SP, down, [{Le, {_MFA,Where,Bs}}|_]) when Le>SP ->
- {Le, Where, Bs};
-stack_frame(SP, Dir, [{SP, _}|Stack]) ->
- case Stack of
- [{Le, {_MFA,Where,Bs}}|_] ->
- {Le, Where, Bs};
- [] when Dir =:= up ->
- top;
- [] when Dir =:= down ->
- bottom
- end;
-stack_frame(SP, Dir, [_Entry|Stack]) ->
- stack_frame(SP, Dir, Stack).
-
-%% backtrace(HowMany) -> Backtrace
-%% HowMany = all | int()
-%% Backtrace = {Le, MFA}
-%% Return all/the last N called functions, in reversed call order
-backtrace(HowMany) ->
- Stack = case HowMany of
- all -> get(stack);
- N -> lists:sublist(get(stack), N)
- end,
- [{Le, MFA} || {Le,{MFA,_Wh,_Bs}} <- Stack].
-
%%--Trace function----------------------------------------------------
%%--------------------------------------------------------------------
@@ -558,7 +385,7 @@ format_args1([]) ->
%% Mimic catch behaviour
catch_value(error, Reason) ->
- {'EXIT',{Reason,get(stacktrace)}};
+ {'EXIT',{Reason,get_stacktrace()}};
catch_value(exit, Reason) ->
{'EXIT',Reason};
catch_value(throw, Reason) ->
@@ -570,11 +397,13 @@ catch_value(throw, Reason) ->
%% Top level function of meta evaluator.
%% Return message to be replied to the target process.
%%--------------------------------------------------------------------
-eval_mfa(Debugged, M, F, As, Ieval) ->
+eval_mfa(Debugged, M, F, As, #ieval{level=Le}=Ieval0) ->
Int = get(int),
Bs = erl_eval:new_bindings(),
- try eval_function(M,F,As,Bs,extern,Ieval#ieval{last_call=true}) of
+ Ieval = Ieval0#ieval{level=Le+1,top=true},
+ try do_eval_function(M, F, As, Bs, extern, Ieval) of
{value, Val, _Bs} ->
+ trace(return, {Le,Val}),
{ready, Val}
catch
exit:{Debugged, Reason} ->
@@ -582,76 +411,68 @@ eval_mfa(Debugged, M, F, As, Ieval) ->
exit:{Int, Reason} ->
exit(Reason);
Class:Reason ->
- {exception, {Class, Reason, get(stacktrace)}}
+ {exception, {Class, Reason, get_stacktrace()}}
end.
-eval_function(Mod, Fun, As0, Bs0, _Called, Ieval) when is_function(Fun);
- Mod =:= ?MODULE,
- Fun =:= eval_fun ->
- #ieval{level=Le, line=Li, last_call=Lc} = Ieval,
+eval_function(Mod, Name, As, Bs, Called, Ieval0, Lc) ->
+ Tail = Lc andalso get(trace_stack) =:= no_tail,
+ case Tail of
+ false ->
+ Ieval = dbg_istk:push(Bs, Ieval0, Lc),
+ {value,Val,_} = do_eval_function(Mod, Name, As, Bs, Called, Ieval),
+ dbg_istk:pop(),
+ trace(return, {Ieval#ieval.level,Val}),
+ {value,Val,Bs};
+ true ->
+ do_eval_function(Mod, Name, As, Bs, Called, Ieval0)
+ end.
+
+do_eval_function(Mod, Fun, As0, Bs0, _, Ieval0) when is_function(Fun);
+ Mod =:= ?MODULE,
+ Fun =:= eval_fun ->
+ #ieval{level=Le,line=Li,top=Top} = Ieval0,
case lambda(Fun, As0) of
- {Cs,Module,Name,As,Bs} ->
- push({Module,Name,As}, Bs0, Ieval),
+ {[{clause,Fc,_,_,_}|_]=Cs,Module,Name,As,Bs} ->
+ Ieval = Ieval0#ieval{module=Module,function=Name,
+ arguments=As0,line=Fc},
trace(call_fun, {Le,Li,Name,As}),
- {value, Val, _Bs} =
- fnk_clauses(Cs, Module, Name, As, Bs,
- Ieval#ieval{level=Le+1}),
- pop(),
- trace(return, {Le,Val}),
- {value, Val, Bs0};
+ fnk_clauses(Cs, As, Bs, Ieval);
- not_interpreted when Lc -> % We are leaving interpreted code
+ not_interpreted when Top -> % We are leaving interpreted code
trace(call_fun, {Le,Li,Fun,As0}),
{value, {dbg_apply,erlang,apply,[Fun,As0]}, Bs0};
not_interpreted ->
- push({Fun,As0}, Bs0, Ieval),
trace(call_fun, {Le,Li,Fun,As0}),
- {value, Val, _Bs} =
- debugged_cmd({apply,erlang,apply,[Fun,As0]},Bs0,
- Ieval#ieval{level=Le+1}),
- pop(),
- trace(return, {Le,Val}),
- {value, Val, Bs0};
+ debugged_cmd({apply,erlang,apply,[Fun,As0]}, Bs0, Ieval0);
{error,Reason} ->
%% It's ok not to push anything in this case, the error
%% reason contains information about the culprit
%% ({badarity,{{Mod,Name},As}})
- exception(error, Reason, Bs0, Ieval)
+ exception(error, Reason, Bs0, Ieval0)
end;
%% Common Test adaptation
-eval_function(ct_line, line, As, Bs, extern, #ieval{level=Le}=Ieval) ->
+do_eval_function(ct_line, line, As, Bs, extern, #ieval{level=Le}=Ieval) ->
debugged_cmd({apply,ct_line,line,As}, Bs, Ieval#ieval{level=Le+1}),
{value, ignore, Bs};
-eval_function(Mod, Name, As0, Bs0, Called, Ieval) ->
- #ieval{level=Le, line=Li, last_call=Lc} = Ieval,
-
- push({Mod,Name,As0}, Bs0, Ieval),
+do_eval_function(Mod, Name, As0, Bs0, Called, Ieval0) ->
+ #ieval{level=Le,line=Li,top=Top} = Ieval0,
trace(call, {Called, {Le,Li,Mod,Name,As0}}),
-
+ Ieval = Ieval0#ieval{module=Mod,function=Name,arguments=As0},
case get_function(Mod, Name, As0, Called) of
- Cs when is_list(Cs) ->
- {value, Val, _Bs} =
- fnk_clauses(Cs, Mod, Name, As0, erl_eval:new_bindings(),
- Ieval#ieval{level=Le+1}),
- pop(),
- trace(return, {Le,Val}),
- {value, Val, Bs0};
+ [{clause,FcLine,_,_,_}|_]=Cs ->
+ fnk_clauses(Cs, As0, erl_eval:new_bindings(),
+ Ieval#ieval{line=FcLine});
- not_interpreted when Lc -> % We are leaving interpreted code
+ not_interpreted when Top -> % We are leaving interpreted code
{value, {dbg_apply,Mod,Name,As0}, Bs0};
not_interpreted ->
- {value, Val, _Bs} =
- debugged_cmd({apply,Mod,Name,As0}, Bs0,
- Ieval#ieval{level=Le+1}),
- pop(),
- trace(return, {Le,Val}),
- {value, Val, Bs0};
+ debugged_cmd({apply,Mod,Name,As0}, Bs0, Ieval);
undef ->
- exception(error, undef, Bs0, Ieval)
+ exception(error, undef, Bs0, Ieval, true)
end.
lambda(eval_fun, [Cs,As,Bs,{Mod,Name}=F]) ->
@@ -752,23 +573,21 @@ cached(Key) ->
%% Try to find a matching function clause
%% #ieval.level is set, the other fields must be set in this function
-fnk_clauses([{clause,Line,Pars,Gs,Body}|Cs], M, F, As, Bs0, Ieval) ->
+fnk_clauses([{clause,Line,Pars,Gs,Body}|Cs], As, Bs0, Ieval) ->
case head_match(Pars, As, [], Bs0) of
{match,Bs1} ->
Bs = add_bindings(Bs1, Bs0),
case guard(Gs, Bs) of
true ->
- seq(Body, Bs,
- Ieval#ieval{line=Line,
- module=M,function=F,arguments=As});
+ seq(Body, Bs, Ieval#ieval{line=Line});
false ->
- fnk_clauses(Cs, M, F, As, Bs0, Ieval)
+ fnk_clauses(Cs, As, Bs0, Ieval)
end;
nomatch ->
- fnk_clauses(Cs, M, F, As, Bs0, Ieval)
+ fnk_clauses(Cs, As, Bs0, Ieval)
end;
-fnk_clauses([], _M, _F, _As, Bs, Ieval) ->
- exception(error, function_clause, Bs, Ieval).
+fnk_clauses([], _As, Bs, Ieval) ->
+ exception(error, function_clause, Bs, Ieval, true).
seq([E], Bs0, Ieval) ->
case dbg_icmd:cmd(E, Bs0, Ieval) of
@@ -782,7 +601,7 @@ seq([E|Es], Bs0, Ieval) ->
{skip,Bs} ->
seq(Es, Bs, Ieval);
Bs1 ->
- {value,_,Bs} = expr(E, Bs1, Ieval#ieval{last_call=false}),
+ {value,_,Bs} = expr(E, Bs1, Ieval#ieval{top=false}),
seq(Es, Bs, Ieval)
end;
seq([], Bs, _) ->
@@ -804,10 +623,9 @@ expr({value,Val}, Bs, _Ieval) -> % Special case straight values
%% List
expr({cons,Line,H0,T0}, Bs0, Ieval0) ->
- Ieval = Ieval0#ieval{line=Line},
- Ieval1 = Ieval#ieval{last_call=false},
- {value,H,Bs1} = expr(H0,Bs0,Ieval1),
- {value,T,Bs2} = expr(T0,Bs0,Ieval1),
+ Ieval = Ieval0#ieval{line=Line,top=false},
+ {value,H,Bs1} = expr(H0, Bs0, Ieval),
+ {value,T,Bs2} = expr(T0, Bs0, Ieval),
{value,[H|T],merge_bindings(Bs2, Bs1, Ieval)};
%% Tuple
@@ -821,12 +639,12 @@ expr({block,Line,Es},Bs,Ieval) ->
%% Catch statement
expr({'catch',Line,Expr}, Bs0, Ieval) ->
- try expr(Expr, Bs0, Ieval#ieval{line=Line, last_call=false})
+ try expr(Expr, Bs0, Ieval#ieval{line=Line, top=false})
catch
Class:Reason ->
%% Exception caught, reset exit info
put(exit_info, undefined),
- pop(Ieval#ieval.level),
+ dbg_istk:pop(Ieval#ieval.level),
Value = catch_value(Class, Reason),
trace(return, {Ieval#ieval.level,Value}),
{value, Value, Bs0}
@@ -835,7 +653,7 @@ expr({'catch',Line,Expr}, Bs0, Ieval) ->
%% Try-catch statement
expr({'try',Line,Es,CaseCs,CatchCs,[]}, Bs0, Ieval0) ->
Ieval = Ieval0#ieval{line=Line},
- try seq(Es, Bs0, Ieval#ieval{last_call=false}) of
+ try seq(Es, Bs0, Ieval#ieval{top=false}) of
{value,Val,Bs} = Value ->
case CaseCs of
[] -> Value;
@@ -848,7 +666,7 @@ expr({'try',Line,Es,CaseCs,CatchCs,[]}, Bs0, Ieval0) ->
end;
expr({'try',Line,Es,CaseCs,CatchCs,As}, Bs0, Ieval0) ->
Ieval = Ieval0#ieval{line=Line},
- try seq(Es, Bs0, Ieval#ieval{last_call=false}) of
+ try seq(Es, Bs0, Ieval#ieval{top=false}) of
{value,Val,Bs} = Value ->
case CaseCs of
[] -> Value;
@@ -859,13 +677,13 @@ expr({'try',Line,Es,CaseCs,CatchCs,As}, Bs0, Ieval0) ->
Class:Reason when CatchCs =/= [] ->
catch_clauses({Class,Reason,[]}, CatchCs, Bs0, Ieval)
after
- seq(As, Bs0, Ieval#ieval{last_call=false})
+ seq(As, Bs0, Ieval#ieval{top=false})
end;
%% Case statement
expr({'case',Line,E,Cs}, Bs0, Ieval) ->
{value,Val,Bs} =
- expr(E, Bs0, Ieval#ieval{line=Line, last_call=false}),
+ expr(E, Bs0, Ieval#ieval{line=Line, top=false}),
case_clauses(Val, Cs, Bs, case_clause, Ieval#ieval{line=Line});
%% If statement
@@ -874,20 +692,20 @@ expr({'if',Line,Cs}, Bs, Ieval) ->
%% Andalso/orelse
expr({'andalso',Line,E1,E2}, Bs, Ieval) ->
- case expr(E1, Bs, Ieval#ieval{line=Line, last_call=false}) of
+ case expr(E1, Bs, Ieval#ieval{line=Line, top=false}) of
{value,false,_}=Res ->
Res;
{value,true,_} ->
- expr(E2, Bs, Ieval#ieval{line=Line, last_call=false});
+ expr(E2, Bs, Ieval#ieval{line=Line, top=false});
{value,Val,Bs} ->
exception(error, {badarg,Val}, Bs, Ieval)
end;
expr({'orelse',Line,E1,E2}, Bs, Ieval) ->
- case expr(E1, Bs, Ieval#ieval{line=Line, last_call=false}) of
+ case expr(E1, Bs, Ieval#ieval{line=Line, top=false}) of
{value,true,_}=Res ->
Res;
{value,false,_} ->
- expr(E2, Bs, Ieval#ieval{line=Line, last_call=false});
+ expr(E2, Bs, Ieval#ieval{line=Line, top=false});
{value,Val,_} ->
exception(error, {badarg,Val}, Bs, Ieval)
end;
@@ -895,7 +713,7 @@ expr({'orelse',Line,E1,E2}, Bs, Ieval) ->
%% Matching expression
expr({match,Line,Lhs,Rhs0}, Bs0, Ieval0) ->
Ieval = Ieval0#ieval{line=Line},
- {value,Rhs,Bs1} = expr(Rhs0, Bs0, Ieval#ieval{last_call=false}),
+ {value,Rhs,Bs1} = expr(Rhs0, Bs0, Ieval#ieval{top=false}),
case match(Lhs, Rhs, Bs1) of
{match,Bs} ->
{value,Rhs,Bs};
@@ -950,22 +768,37 @@ expr({make_fun,Line,Name,Cs}, Bs, #ieval{module=Module}=Ieval) ->
end,
{value,Fun,Bs};
+%% Construct an external fun.
+expr({make_ext_fun,Line,MFA0}, Bs0, Ieval0) ->
+ {[M,F,A],Bs} = eval_list(MFA0, Bs0, Ieval0),
+ try erlang:make_fun(M, F, A) of
+ Value ->
+ {value,Value,Bs}
+ catch
+ error:badarg ->
+ Ieval1 = Ieval0#ieval{line=Line},
+ Ieval2 = dbg_istk:push(Bs0, Ieval1, false),
+ Ieval = Ieval2#ieval{module=erlang,function=make_fun,
+ arguments=[M,F,A],line=-1},
+ exception(error, badarg, Bs, Ieval, true)
+ end;
+
%% Common test adaptation
-expr({call_remote,0,ct_line,line,As0}, Bs0, Ieval0) ->
+expr({call_remote,0,ct_line,line,As0,Lc}, Bs0, Ieval0) ->
{As,_Bs} = eval_list(As0, Bs0, Ieval0),
- eval_function(ct_line, line, As, Bs0, extern, Ieval0);
+ eval_function(ct_line, line, As, Bs0, extern, Ieval0, Lc);
%% Local function call
-expr({local_call,Line,F,As0}, Bs0, #ieval{module=M} = Ieval0) ->
+expr({local_call,Line,F,As0,Lc}, Bs0, #ieval{module=M} = Ieval0) ->
Ieval = Ieval0#ieval{line=Line},
{As,Bs} = eval_list(As0, Bs0, Ieval),
- eval_function(M, F, As, Bs, local, Ieval);
+ eval_function(M, F, As, Bs, local, Ieval, Lc);
%% Remote function call
-expr({call_remote,Line,M,F,As0}, Bs0, Ieval0) ->
+expr({call_remote,Line,M,F,As0,Lc}, Bs0, Ieval0) ->
Ieval = Ieval0#ieval{line=Line},
{As,Bs} = eval_list(As0, Bs0, Ieval),
- eval_function(M, F, As, Bs, extern, Ieval);
+ eval_function(M, F, As, Bs, extern, Ieval, Lc);
%% Emulated semantics of some BIFs
expr({dbg,Line,self,[]}, Bs, #ieval{level=Le}) ->
@@ -975,9 +808,28 @@ expr({dbg,Line,self,[]}, Bs, #ieval{level=Le}) ->
{value,Self,Bs};
expr({dbg,Line,get_stacktrace,[]}, Bs, #ieval{level=Le}) ->
trace(bif, {Le,Line,erlang,get_stacktrace,[]}),
- Stacktrace = get(stacktrace),
+ Stacktrace = get_stacktrace(),
trace(return, {Le,Stacktrace}),
{value,Stacktrace,Bs};
+expr({dbg,Line,raise,As0}, Bs0, #ieval{level=Le}=Ieval0) ->
+ %% Since erlang:get_stacktrace/0 is emulated, we will
+ %% need to emulate erlang:raise/3 too so that we can
+ %% capture the stacktrace.
+ Ieval = Ieval0#ieval{line=Line},
+ {[Class,Reason,Stk0]=As,Bs} = eval_list(As0, Bs0, Ieval),
+ trace(bif, {Le,Line,erlang,raise,As}),
+ try
+ %% Evaluate raise/3 for error checking and
+ %% truncating of the stacktrace to the correct depth.
+ Error = erlang:raise(Class, Reason, Stk0),
+ trace(return, {Le,Error}),
+ {value,Error,Bs}
+ catch
+ _:_ ->
+ Stk = erlang:get_stacktrace(), %Possibly truncated.
+ StkFun = fun(_) -> Stk end,
+ do_exception(Class, Reason, StkFun, Bs, Ieval)
+ end;
expr({dbg,Line,throw,As0}, Bs0, #ieval{level=Le}=Ieval0) ->
Ieval = Ieval0#ieval{line=Line},
{[Term],Bs} = eval_list(As0, Bs0, Ieval),
@@ -988,11 +840,6 @@ expr({dbg,Line,error,As0}, Bs0, #ieval{level=Le}=Ieval0) ->
{[Term],Bs} = eval_list(As0, Bs0, Ieval),
trace(bif, {Le,Line,erlang,error,[Term]}),
exception(error, Term, Bs, Ieval);
-expr({dbg,Line,fault,As0}, Bs0, #ieval{level=Le}=Ieval0) ->
- Ieval = Ieval0#ieval{line=Line},
- {[Term],Bs} = eval_list(As0, Bs0, Ieval),
- trace(bif, {Le,Line,erlang,fault,[Term]}),
- exception(fault, Term, Bs, Ieval);
expr({dbg,Line,exit,As0}, Bs0, #ieval{level=Le}=Ieval0) ->
Ieval = Ieval0#ieval{line=Line},
{[Term],Bs} = eval_list(As0, Bs0, Ieval),
@@ -1001,36 +848,26 @@ expr({dbg,Line,exit,As0}, Bs0, #ieval{level=Le}=Ieval0) ->
%% Call to "safe" BIF, ie a BIF that can be executed in Meta process
expr({safe_bif,Line,M,F,As0}, Bs0, #ieval{level=Le}=Ieval0) ->
- Ieval = Ieval0#ieval{line=Line},
- {As,Bs} = eval_list(As0, Bs0, Ieval),
+ Ieval1 = Ieval0#ieval{line=Line},
+ {As,Bs} = eval_list(As0, Bs0, Ieval1),
trace(bif, {Le,Line,M,F,As}),
- push({M,F,As}, Bs0, Ieval),
+ Ieval2 = dbg_istk:push(Bs0, Ieval1, false),
+ Ieval = Ieval2#ieval{module=M,function=F,arguments=As,line=-1},
{_,Value,_} = Res = safe_bif(M, F, As, Bs, Ieval),
trace(return, {Le,Value}),
- pop(),
+ dbg_istk:pop(),
Res;
%% Call to a BIF that must be evaluated in the correct process
expr({bif,Line,M,F,As0}, Bs0, #ieval{level=Le}=Ieval0) ->
- Ieval = Ieval0#ieval{line=Line},
- {As,Bs} = eval_list(As0, Bs0, Ieval),
+ Ieval1 = Ieval0#ieval{line=Line},
+ {As,Bs} = eval_list(As0, Bs0, Ieval1),
trace(bif, {Le,Line,M,F,As}),
- push({M,F,As}, Bs0, Ieval),
- {_,Value,_} =
- Res = debugged_cmd({apply,M,F,As}, Bs, Ieval#ieval{level=Le+1}),
+ Ieval2 = dbg_istk:push(Bs0, Ieval1, false),
+ Ieval = Ieval2#ieval{module=M,function=F,arguments=As,line=-1},
+ {_,Value,_} = Res = debugged_cmd({apply,M,F,As}, Bs, Ieval),
trace(return, {Le,Value}),
- pop(),
- Res;
-
-%% Call to a BIF that spawns a new process
-expr({spawn_bif,Line,M,F,As0}, Bs0, #ieval{level=Le}=Ieval0) ->
- Ieval = Ieval0#ieval{line=Line},
- {As,Bs} = eval_list(As0, Bs0, Ieval),
- trace(bif, {Le,Line,M,F,As}),
- push({M,F,As}, Bs0, Ieval),
- Res = debugged_cmd({apply,M,F,As}, Bs,Ieval#ieval{level=Le+1}),
- trace(return, {Le,Res}),
- pop(),
+ dbg_istk:pop(),
Res;
%% Call to an operation
@@ -1046,7 +883,7 @@ expr({op,Line,Op,As0}, Bs0, Ieval0) ->
end;
%% apply/2 (fun)
-expr({apply_fun,Line,Fun0,As0}, Bs0, #ieval{level=Le}=Ieval0) ->
+expr({apply_fun,Line,Fun0,As0,Lc}, Bs0, #ieval{level=Le}=Ieval0) ->
Ieval = Ieval0#ieval{line=Line},
FunValue = case expr(Fun0, Bs0, Ieval) of
{value,{dbg_apply,Mx,Fx,Asx},Bsx} ->
@@ -1058,31 +895,20 @@ expr({apply_fun,Line,Fun0,As0}, Bs0, #ieval{level=Le}=Ieval0) ->
case FunValue of
{value,Fun,Bs1} when is_function(Fun) ->
{As,Bs} = eval_list(As0, Bs1, Ieval),
- eval_function(undefined, Fun, As, Bs, extern, Ieval);
+ eval_function(undefined, Fun, As, Bs, extern, Ieval, Lc);
{value,{M,F},Bs1} when is_atom(M), is_atom(F) ->
{As,Bs} = eval_list(As0, Bs1, Ieval),
- eval_function(M, F, As, Bs, extern, Ieval);
+ eval_function(M, F, As, Bs, extern, Ieval, Lc);
{value,BadFun,Bs1} ->
exception(error, {badfun,BadFun}, Bs1, Ieval)
end;
%% apply/3
-expr({apply,Line,As0}, Bs0, Ieval0) ->
+expr({apply,Line,As0,Lc}, Bs0, Ieval0) ->
Ieval = Ieval0#ieval{line=Line},
{[M,F,As],Bs} = eval_list(As0, Bs0, Ieval),
- eval_function(M, F, As, Bs, extern, Ieval);
+ eval_function(M, F, As, Bs, extern, Ieval, Lc);
-%% Mod:module_info/0,1
-expr({module_info_0,_,Mod}, Bs, _Ieval) ->
- {value,[{compile,module_info(Mod,compile)},
- {attributes,module_info(Mod,attributes)},
- {imports,module_info(Mod,imports)},
- {exports,module_info(Mod,exports)}],Bs};
-expr({module_info_1,Line,Mod,[As0]}, Bs0, Ieval0) ->
- Ieval = Ieval0#ieval{line=Line},
- {value,What,Bs} = expr(As0, Bs0, Ieval),
- {value,module_info(Mod, What),Bs};
-
%% Receive statement
expr({'receive',Line,Cs}, Bs0, #ieval{level=Le}=Ieval) ->
trace(receivex, {Le,false}),
@@ -1091,7 +917,7 @@ expr({'receive',Line,Cs}, Bs0, #ieval{level=Le}=Ieval) ->
%% Receive..after statement
expr({'receive',Line,Cs,To,ToExprs}, Bs0, #ieval{level=Le}=Ieval0) ->
Ieval = Ieval0#ieval{line=Line},
- {value,ToVal,ToBs} = expr(To, Bs0, Ieval#ieval{last_call=false}),
+ {value,ToVal,ToBs} = expr(To, Bs0, Ieval#ieval{top=false}),
trace(receivex, {Le,true}),
check_timeoutvalue(ToVal, ToBs, To, Ieval),
{Stamp,_} = statistics(wall_clock),
@@ -1101,7 +927,7 @@ expr({'receive',Line,Cs,To,ToExprs}, Bs0, #ieval{level=Le}=Ieval0) ->
%% Send (!)
expr({send,Line,To0,Msg0}, Bs0, Ieval0) ->
Ieval = Ieval0#ieval{line=Line},
- Ieval1 = Ieval#ieval{last_call=false},
+ Ieval1 = Ieval#ieval{top=false},
{value,To,Bs1} = expr(To0, Bs0, Ieval1),
{value,Msg,Bs2} = expr(Msg0, Bs0, Ieval1),
Bs = merge_bindings(Bs2, Bs1, Ieval),
@@ -1110,10 +936,15 @@ expr({send,Line,To0,Msg0}, Bs0, Ieval0) ->
%% Binary
expr({bin,Line,Fs}, Bs0, Ieval0) ->
Ieval = Ieval0#ieval{line=Line},
- eval_bits:expr_grp(Fs, Bs0,
- fun (E, B) -> expr(E, B, Ieval) end,
- [],
- false);
+ try
+ eval_bits:expr_grp(Fs, Bs0,
+ fun (E, B) -> expr(E, B, Ieval) end,
+ [],
+ false)
+ catch
+ Class:Reason ->
+ exception(Class, Reason, Bs0, Ieval)
+ end;
%% List comprehension
expr({lc,_Line,E,Qs}, Bs, Ieval) ->
@@ -1138,12 +969,12 @@ eval_lc(E, Qs, Bs, Ieval) ->
eval_lc1(E, [{generate,Line,P,L0}|Qs], Bs0, Ieval0) ->
Ieval = Ieval0#ieval{line=Line},
- {value,L1,Bs1} = expr(L0, Bs0, Ieval#ieval{last_call=false}),
+ {value,L1,Bs1} = expr(L0, Bs0, Ieval#ieval{top=false}),
CompFun = fun(NewBs) -> eval_lc1(E, Qs, NewBs, Ieval) end,
eval_generate(L1, P, Bs1, CompFun, Ieval);
eval_lc1(E, [{b_generate,Line,P,L0}|Qs], Bs0, Ieval0) ->
Ieval = Ieval0#ieval{line=Line},
- {value,Bin,_} = expr(L0, Bs0, Ieval#ieval{last_call=false}),
+ {value,Bin,_} = expr(L0, Bs0, Ieval#ieval{top=false}),
CompFun = fun(NewBs) -> eval_lc1(E, Qs, NewBs, Ieval) end,
eval_b_generate(Bin, P, Bs0, CompFun, Ieval);
eval_lc1(E, [{guard,Q}|Qs], Bs0, Ieval) ->
@@ -1152,13 +983,13 @@ eval_lc1(E, [{guard,Q}|Qs], Bs0, Ieval) ->
false -> []
end;
eval_lc1(E, [Q|Qs], Bs0, Ieval) ->
- case expr(Q, Bs0, Ieval#ieval{last_call=false}) of
+ case expr(Q, Bs0, Ieval#ieval{top=false}) of
{value,true,Bs} -> eval_lc1(E, Qs, Bs, Ieval);
{value,false,_Bs} -> [];
{value,V,Bs} -> exception(error, {bad_filter,V}, Bs, Ieval)
end;
eval_lc1(E, [], Bs, Ieval) ->
- {value,V,_} = expr(E, Bs, Ieval#ieval{last_call=false}),
+ {value,V,_} = expr(E, Bs, Ieval#ieval{top=false}),
[V].
%% eval_bc(Expr,[Qualifier],Bindings,IevalState) ->
@@ -1171,12 +1002,12 @@ eval_bc(E, Qs, Bs, Ieval) ->
eval_bc1(E, [{generate,Line,P,L0}|Qs], Bs0, Ieval0) ->
Ieval = Ieval0#ieval{line=Line},
- {value,L1,Bs1} = expr(L0, Bs0, Ieval#ieval{last_call=false}),
+ {value,L1,Bs1} = expr(L0, Bs0, Ieval#ieval{top=false}),
CompFun = fun(NewBs) -> eval_bc1(E, Qs, NewBs, Ieval) end,
eval_generate(L1, P, Bs1, CompFun, Ieval);
eval_bc1(E, [{b_generate,Line,P,L0}|Qs], Bs0, Ieval0) ->
Ieval = Ieval0#ieval{line=Line},
- {value,Bin,_} = expr(L0, Bs0, Ieval#ieval{last_call=false}),
+ {value,Bin,_} = expr(L0, Bs0, Ieval#ieval{top=false}),
CompFun = fun(NewBs) -> eval_bc1(E, Qs, NewBs, Ieval) end,
eval_b_generate(Bin, P, Bs0, CompFun, Ieval);
eval_bc1(E, [{guard,Q}|Qs], Bs0, Ieval) ->
@@ -1185,13 +1016,13 @@ eval_bc1(E, [{guard,Q}|Qs], Bs0, Ieval) ->
false -> []
end;
eval_bc1(E, [Q|Qs], Bs0, Ieval) ->
- case expr(Q, Bs0, Ieval#ieval{last_call=false}) of
+ case expr(Q, Bs0, Ieval#ieval{top=false}) of
{value,true,Bs} -> eval_bc1(E, Qs, Bs, Ieval);
{value,false,_Bs} -> [];
{value,V,Bs} -> exception(error, {bad_filter,V}, Bs, Ieval)
end;
eval_bc1(E, [], Bs, Ieval) ->
- {value,V,_} = expr(E, Bs, Ieval#ieval{last_call=false}),
+ {value,V,_} = expr(E, Bs, Ieval#ieval{top=false}),
[V].
eval_generate([V|Rest], P, Bs0, CompFun, Ieval) ->
@@ -1208,7 +1039,7 @@ eval_generate(Term, _P, Bs, _CompFun, Ieval) ->
exception(error, {bad_generator,Term}, Bs, Ieval).
eval_b_generate(<<_/bitstring>>=Bin, P, Bs0, CompFun, Ieval) ->
- Mfun = fun(L, R, Bs) -> match1(L, R, Bs, Bs0) end,
+ Mfun = match_fun(Bs0),
Efun = fun(Exp, Bs) -> expr(Exp, Bs, #ieval{}) end,
case eval_bits:bin_gen(P, Bin, erl_eval:new_bindings(), Bs0, Mfun, Efun) of
{match,Rest,Bs1} ->
@@ -1222,24 +1053,13 @@ eval_b_generate(<<_/bitstring>>=Bin, P, Bs0, CompFun, Ieval) ->
eval_b_generate(Term, _P, Bs, _CompFun, Ieval) ->
exception(error, {bad_generator,Term}, Bs, Ieval).
-module_info(Mod, module) -> Mod;
-module_info(_Mod, compile) -> [];
-module_info(Mod, attributes) ->
- {ok, Attr} = dbg_iserver:call(get(int), {lookup, Mod, attributes}),
- Attr;
-module_info(_Mod, imports) -> [];
-module_info(Mod, exports) ->
- {ok, Exp} = dbg_iserver:call(get(int), {lookup, Mod, exports}),
- Exp;
-module_info(_Mod, functions) -> [].
-
safe_bif(M, F, As, Bs, Ieval) ->
try apply(M, F, As) of
Value ->
{value,Value,Bs}
catch
Class:Reason ->
- exception(Class, Reason, Bs, Ieval)
+ exception(Class, Reason, Bs, Ieval, true)
end.
eval_send(To, Msg, Bs, Ieval) ->
@@ -1408,12 +1228,12 @@ flush_traces(Debugged) ->
%% eval_list(ExpressionList, Bindings, Ieval)
%% Evaluate a list of expressions "in parallel" at the same level.
eval_list(Es, Bs, Ieval) ->
- eval_list(Es, [], Bs, Bs, Ieval).
+ eval_list_1(Es, [], Bs, Bs, Ieval#ieval{top=false}).
-eval_list([E|Es], Vs, BsOrig, Bs0, Ieval) ->
- {value,V,Bs1} = expr(E, BsOrig, Ieval#ieval{last_call=false}),
- eval_list(Es, [V|Vs], BsOrig, merge_bindings(Bs1,Bs0,Ieval), Ieval);
-eval_list([], Vs, _, Bs, _Ieval) ->
+eval_list_1([E|Es], Vs, BsOrig, Bs0, Ieval) ->
+ {value,V,Bs1} = expr(E, BsOrig, Ieval),
+ eval_list_1(Es, [V|Vs], BsOrig, merge_bindings(Bs1, Bs0, Ieval), Ieval);
+eval_list_1([], Vs, _, Bs, _Ieval) ->
{lists:reverse(Vs,[]),Bs}.
%% if_clauses(Clauses, Bindings, Ieval)
@@ -1453,7 +1273,7 @@ catch_clauses(Exception, [{clause,_,[P],G,B}|CatchCs], Bs0, Ieval) ->
true ->
%% Exception caught, reset exit info
put(exit_info, undefined),
- pop(Ieval#ieval.level),
+ dbg_istk:pop(Ieval#ieval.level),
seq(B, Bs, Ieval);
false ->
catch_clauses(Exception, CatchCs, Bs0, Ieval)
@@ -1588,11 +1408,9 @@ match1({cons,_,H,T}, [H1|T1], Bs0, BBs) ->
match1({tuple,_,Elts}, Tuple, Bs, BBs)
when length(Elts) =:= tuple_size(Tuple) ->
match_tuple(Elts, Tuple, 1, Bs, BBs);
-match1({bin,_,Fs}, B, Bs0, BBs0) when is_bitstring(B) ->
- Bs1 = lists:sort(Bs0), %Kludge.
- BBs = lists:sort(BBs0),
- try eval_bits:match_bits(Fs, B, Bs1, BBs,
- fun(L, R, Bs) -> match1(L, R, Bs, BBs) end,
+match1({bin,_,Fs}, B, Bs0, BBs) when is_bitstring(B) ->
+ try eval_bits:match_bits(Fs, B, Bs0, BBs,
+ match_fun(BBs),
fun(E, Bs) -> expr(E, Bs, #ieval{}) end,
false)
catch
@@ -1601,6 +1419,12 @@ match1({bin,_,Fs}, B, Bs0, BBs0) when is_bitstring(B) ->
match1(_,_,_,_) ->
throw(nomatch).
+match_fun(BBs) ->
+ fun(match, {L,R,Bs}) -> match1(L, R, Bs, BBs);
+ (binding, {Name,Bs}) -> binding(Name, Bs);
+ (add_binding, {Name,Val,Bs}) -> add_binding(Name, Val, Bs)
+ end.
+
match_tuple([E|Es], Tuple, I, Bs0, BBs) ->
{match,Bs} = match1(E, element(I, Tuple), Bs0, BBs),
match_tuple(Es, Tuple, I+1, Bs, BBs);
@@ -1731,3 +1555,19 @@ add_binding(N,Val,[B1|Bs]) ->
[B1|add_binding(N,Val,Bs)];
add_binding(N,Val,[]) ->
[{N,Val}].
+
+%% get_stacktrace() -> Stacktrace
+%% Return the latest stacktrace for the process.
+get_stacktrace() ->
+ case get(stacktrace) of
+ MakeStk when is_function(MakeStk, 1) ->
+ %% The stacktrace has not been constructed before.
+ %% Construct it and remember the result.
+ Depth = erlang:system_flag(backtrace_depth, 8),
+ erlang:system_flag(backtrace_depth, Depth),
+ Stk = MakeStk(Depth),
+ put(stacktrace, Stk),
+ Stk;
+ Stk when is_list(Stk) ->
+ Stk
+ end.
diff --git a/lib/debugger/src/dbg_ieval.hrl b/lib/debugger/src/dbg_ieval.hrl
index a344748f48..ea6189ad02 100644
--- a/lib/debugger/src/dbg_ieval.hrl
+++ b/lib/debugger/src/dbg_ieval.hrl
@@ -21,6 +21,8 @@
module, % MFA which called the currently
function, % interpreted function
arguments, %
- last_call = false % True if current expression is
- }). % the VERY last to be evaluated
- % (ie at all, not only in a clause)
+
+ %% True if the current expression is at the top level
+ %% (i.e. the next call will leave interpreted code).
+ top = false
+ }).
diff --git a/lib/debugger/src/dbg_iload.erl b/lib/debugger/src/dbg_iload.erl
index 2ae0c333da..3c95ef8068 100644
--- a/lib/debugger/src/dbg_iload.erl
+++ b/lib/debugger/src/dbg_iload.erl
@@ -62,22 +62,23 @@ load_mod1(Mod, File, Binary, Db) ->
store_module(Mod, File, Binary, Db) ->
{interpreter_module, Exp, Abst, Src, MD5} = binary_to_term(Binary),
Forms = case abstr(Abst) of
- {abstract_v1,Forms0} -> Forms0;
- {abstract_v2,Forms0} -> Forms0;
+ {abstract_v1,_} ->
+ exit({Mod,too_old_beam_file});
+ {abstract_v2,_} ->
+ exit({Mod,too_old_beam_file});
{raw_abstract_v1,Code0} ->
Code = interpret_file_attribute(Code0),
{_,_,Forms0,_} = sys_pre_expand:module(Code, []),
Forms0
end,
dbg_idb:insert(Db, mod_file, File),
- dbg_idb:insert(Db, exports, Exp),
dbg_idb:insert(Db, defs, []),
put(vcount, 0),
put(fun_count, 0),
put(funs, []),
put(mod_md5, MD5),
- Attr = store_forms(Forms, Mod, Db, Exp, []),
+ store_forms(Forms, Mod, Db, Exp),
erase(mod_md5),
erase(current_function),
%% store_funs(Db, Mod),
@@ -85,11 +86,10 @@ store_module(Mod, File, Binary, Db) ->
erase(funs),
erase(fun_count),
- dbg_idb:insert(Db, attributes, Attr),
NewBinary = store_mod_line_no(Mod, Db, binary_to_list(Src)),
dbg_idb:insert(Db, mod_bin, NewBinary),
- dbg_idb:insert(Db, mod_raw, <<Src/binary,0:8>>), %% Add eos
- dbg_idb:insert(Db, module, Mod).
+ dbg_idb:insert(Db, mod_raw, <<Src/binary,0:8>>). %% Add eos
+
%% Adjust line numbers using the file/2 attribute.
%% Also take the absolute value of line numbers.
%% This simple fix will make the marker point at the correct line
@@ -111,27 +111,19 @@ abstr(Term) -> Term.
% store_funs_1(Fs, Db, Mod);
% store_funs_1([], _, _) -> ok.
-store_forms([{function,_,module_info,0,_}|Fs], Mod, Db, Exp, Attr) ->
- Cs = [{clause,0,[],[], [{module_info_0,0,Mod}]}],
- dbg_idb:insert(Db, {Mod,module_info,0,true}, Cs),
- store_forms(Fs, Mod, Db, Exp, Attr);
-store_forms([{function,_,module_info,1,_}|Fs], Mod, Db, Exp, Attr) ->
- Cs = [{clause,0,[{var,0,'What'}],[], [{module_info_1,0,Mod,[{var,0,'What'}]}]}],
- dbg_idb:insert(Db, {Mod,module_info,1,true}, Cs),
- store_forms(Fs, Mod, Db, Exp, Attr);
-store_forms([{function,_,Name,Arity,Cs0}|Fs], Mod, Db, Exp, Attr) ->
+store_forms([{function,_,Name,Arity,Cs0}|Fs], Mod, Db, Exp) ->
FA = {Name,Arity},
put(current_function, FA),
Cs = clauses(Cs0),
Exported = lists:member(FA, Exp),
dbg_idb:insert(Db, {Mod,Name,Arity,Exported}, Cs),
- store_forms(Fs, Mod, Db, Exp, Attr);
-store_forms([{attribute,_,Name,Val}|Fs], Mod, Db, Exp, Attr) ->
- store_forms(Fs, Mod, Db, Exp, [{Name,Val}|Attr]);
-store_forms([F|_], _Mod, _Db, _Exp, _Attr) ->
+ store_forms(Fs, Mod, Db, Exp);
+store_forms([{attribute,_,_Name,_Val}|Fs], Mod, Db, Exp) ->
+ store_forms(Fs, Mod, Db, Exp);
+store_forms([F|_], _Mod, _Db, _Exp) ->
exit({unknown_form,F});
-store_forms([], _, _, _, Attr) ->
- lists:reverse(Attr).
+store_forms([], _, _, _) ->
+ ok.
store_mod_line_no(Mod, Db, Contents) ->
store_mod_line_no(Mod, Db, Contents, 1, 0, []).
@@ -164,14 +156,14 @@ get_nl([],Pos,Head) -> {lists:reverse(Head),[],Pos}.
%%% to interpret.
clauses([C0|Cs]) ->
- C1 = clause(C0),
+ C1 = clause(C0, true),
[C1|clauses(Cs)];
clauses([]) -> [].
-clause({clause,Line,H0,G0,B0}) ->
+clause({clause,Line,H0,G0,B0}, Lc) ->
H1 = head(H0),
G1 = guard(G0),
- B1 = exprs(B0),
+ B1 = exprs(B0, Lc),
{clause,Line,H1,G1,B1}.
head(Ps) -> patterns(Ps).
@@ -219,7 +211,7 @@ pattern({bin,Line,Grp}) ->
{bin,Line,Grp1};
pattern({bin_element,Line,Expr,Size,Type}) ->
Expr1 = pattern(Expr),
- Size1 = expr(Size),
+ Size1 = expr(Size, false),
{bin_element,Line,Expr1,Size1,Type}.
%% These patterns are processed "in parallel" for purposes of variable
@@ -235,8 +227,6 @@ guard([G0|Gs]) ->
[G1|guard(Gs)];
guard([]) -> [].
-and_guard([{atom,_,true}|Gs]) ->
- and_guard(Gs);
and_guard([G0|Gs]) ->
G1 = guard_test(G0),
[G1|and_guard(Gs)];
@@ -244,12 +234,7 @@ and_guard([]) -> [].
guard_test({call,Line,{remote,_,{atom,_,erlang},{atom,_,F}},As0}) ->
As = gexpr_list(As0),
- case map_guard_bif(F, length(As0)) of
- {ok,Name} ->
- {safe_bif,Line,erlang,Name,As};
- error ->
- {safe_bif,Line,erlang,F,As}
- end;
+ {safe_bif,Line,erlang,F,As};
guard_test({op,Line,Op,L0}) ->
true = erl_internal:arith_op(Op, 1) orelse %Assertion.
erl_internal:bool_op(Op, 1),
@@ -266,25 +251,18 @@ guard_test({op,Line,Op,L0,R0}) ->
L1 = gexpr(L0),
R1 = gexpr(R0), %They see the same variables
{safe_bif,Line,erlang,Op,[L1,R1]};
-guard_test({integer,_,_}=I) -> I;
-guard_test({char,_,_}=C) -> C;
-guard_test({float,_,_}=F) -> F;
-guard_test({atom,_,_}=A) -> A;
-guard_test({nil,_}=N) -> N;
-guard_test({var,_,_}=V) ->V. % Boolean var
-
-map_guard_bif(integer, 1) -> {ok,is_integer};
-map_guard_bif(float, 1) -> {ok,is_float};
-map_guard_bif(number, 1) -> {ok,is_number};
-map_guard_bif(atom, 1) -> {ok,is_atom};
-map_guard_bif(list, 1) -> {ok,is_list};
-map_guard_bif(tuple, 1) -> {ok,is_tuple};
-map_guard_bif(pid, 1) -> {ok,is_pid};
-map_guard_bif(reference, 1) -> {ok,is_reference};
-map_guard_bif(port, 1) -> {ok,is_port};
-map_guard_bif(binary, 1) -> {ok,is_binary};
-map_guard_bif(function, 1) -> {ok,is_function};
-map_guard_bif(_, _) -> error.
+guard_test({var,_,_}=V) ->V; % Boolean var
+guard_test({atom,Line,true}) -> {value,Line,true};
+%% All other constants at this level means false.
+guard_test({atom,Line,_}) -> {value,Line,false};
+guard_test({integer,Line,_}) -> {value,Line,false};
+guard_test({char,Line,_}) -> {value,Line,false};
+guard_test({float,Line,_}) -> {value,Line,false};
+guard_test({string,Line,_}) -> {value,Line,false};
+guard_test({nil,Line}) -> {value,Line,false};
+guard_test({cons,Line,_,_}) -> {value,Line,false};
+guard_test({tuple,Line,_}) -> {value,Line,false};
+guard_test({bin,Line,_}) -> {value,Line,false}.
gexpr({var,Line,V}) -> {var,Line,V};
gexpr({integer,Line,I}) -> {value,Line,I};
@@ -341,186 +319,187 @@ gexpr_list([]) -> [].
%% These expressions are processed "sequentially" for purposes of variable
%% definition etc.
-exprs([E0|Es]) ->
- E1 = expr(E0),
- [E1|exprs(Es)];
-exprs([]) -> [].
-
-expr({var,Line,V}) -> {var,Line,V};
-expr({integer,Line,I}) -> {value,Line,I};
-expr({char,Line,I}) -> {value,Line,I};
-expr({float,Line,F}) -> {value,Line,F};
-expr({atom,Line,A}) -> {value,Line,A};
-expr({string,Line,S}) -> {value,Line,S};
-expr({nil,Line}) -> {value,Line,[]};
-expr({cons,Line,H0,T0}) ->
- case {expr(H0),expr(T0)} of
+exprs([E], Lc) ->
+ [expr(E, Lc)];
+exprs([E0|Es], Lc) ->
+ E1 = expr(E0, false),
+ [E1|exprs(Es, Lc)];
+exprs([], _Lc) -> [].
+
+expr({var,Line,V}, _Lc) -> {var,Line,V};
+expr({integer,Line,I}, _Lc) -> {value,Line,I};
+expr({char,Line,I}, _Lc) -> {value,Line,I};
+expr({float,Line,F}, _Lc) -> {value,Line,F};
+expr({atom,Line,A}, _Lc) -> {value,Line,A};
+expr({string,Line,S}, _Lc) -> {value,Line,S};
+expr({nil,Line}, _Lc) -> {value,Line,[]};
+expr({cons,Line,H0,T0}, _Lc) ->
+ case {expr(H0, false),expr(T0, false)} of
{{value,Line,H1},{value,Line,T1}} -> {value,Line,[H1|T1]};
{H1,T1} -> {cons,Line,H1,T1}
end;
-expr({tuple,Line,Es0}) ->
+expr({tuple,Line,Es0}, _Lc) ->
Es1 = expr_list(Es0),
{tuple,Line,Es1};
-expr({block,Line,Es0}) ->
+expr({block,Line,Es0}, Lc) ->
%% Unfold block into a sequence.
- Es1 = exprs(Es0),
+ Es1 = exprs(Es0, Lc),
{block,Line,Es1};
-expr({'if',Line,Cs0}) ->
- Cs1 = icr_clauses(Cs0),
+expr({'if',Line,Cs0}, Lc) ->
+ Cs1 = icr_clauses(Cs0, Lc),
{'if',Line,Cs1};
-expr({'case',Line,E0,Cs0}) ->
- E1 = expr(E0),
- Cs1 = icr_clauses(Cs0),
+expr({'case',Line,E0,Cs0}, Lc) ->
+ E1 = expr(E0, false),
+ Cs1 = icr_clauses(Cs0, Lc),
{'case',Line,E1,Cs1};
-expr({'receive',Line,Cs0}) ->
- Cs1 = icr_clauses(Cs0),
+expr({'receive',Line,Cs0}, Lc) ->
+ Cs1 = icr_clauses(Cs0, Lc),
{'receive',Line,Cs1};
-expr({'receive',Line,Cs0,To0,ToEs0}) ->
- To1 = expr(To0),
- ToEs1 = exprs(ToEs0),
- Cs1 = icr_clauses(Cs0),
+expr({'receive',Line,Cs0,To0,ToEs0}, Lc) ->
+ To1 = expr(To0, false),
+ ToEs1 = exprs(ToEs0, Lc),
+ Cs1 = icr_clauses(Cs0, Lc),
{'receive',Line,Cs1,To1,ToEs1};
-expr({'fun',Line,{clauses,Cs0},{_,_,Name}}) when is_atom(Name) ->
+expr({'fun',Line,{clauses,Cs0},{_,_,Name}}, _Lc) when is_atom(Name) ->
%% New R10B-2 format (abstract_v2).
Cs = fun_clauses(Cs0),
{make_fun,Line,Name,Cs};
-expr({'fun',Line,{clauses,Cs0},{_,_,_,_,Name}}) when is_atom(Name) ->
- %% New R8 format (abstract_v2).
- Cs = fun_clauses(Cs0),
- {make_fun,Line,Name,Cs};
-expr({'fun',Line,{function,F,A},{_Index,_OldUniq,Name}}) ->
+expr({'fun',Line,{function,F,A},{_Index,_OldUniq,Name}}, _Lc) ->
%% New R8 format (abstract_v2).
As = new_vars(A, Line),
- Cs = [{clause,Line,As,[],[{local_call,Line,F,As}]}],
+ Cs = [{clause,Line,As,[],[{local_call,Line,F,As,true}]}],
{make_fun,Line,Name,Cs};
-expr({'fun',_,{clauses,_},{_OldUniq,_Hvss,_Free}}) ->
- %% Old format (abstract_v1).
- exit({?MODULE,old_funs});
-expr({call,Line,{remote,_,{atom,_,erlang},{atom,_,self}},[]}) ->
+expr({'fun',Line,{function,{atom,_,M},{atom,_,F},{integer,_,A}}}, _Lc)
+ when 0 =< A, A =< 255 ->
+ %% New format in R15 for fun M:F/A (literal values).
+ {value,Line,erlang:make_fun(M, F, A)};
+expr({'fun',Line,{function,M,F,A}}, _Lc) ->
+ %% New format in R15 for fun M:F/A (one or more variables).
+ MFA = expr_list([M,F,A]),
+ {make_ext_fun,Line,MFA};
+expr({call,Line,{remote,_,{atom,_,erlang},{atom,_,self}},[]}, _Lc) ->
{dbg,Line,self,[]};
-expr({call,Line,{remote,_,{atom,_,erlang},{atom,_,get_stacktrace}},[]}) ->
+expr({call,Line,{remote,_,{atom,_,erlang},{atom,_,get_stacktrace}},[]}, _Lc) ->
{dbg,Line,get_stacktrace,[]};
-expr({call,Line,{remote,_,{atom,_,erlang},{atom,_,throw}},[_]=As}) ->
+expr({call,Line,{remote,_,{atom,_,erlang},{atom,_,throw}},[_]=As}, _Lc) ->
{dbg,Line,throw,expr_list(As)};
-expr({call,Line,{remote,_,{atom,_,erlang},{atom,_,error}},[_]=As}) ->
+expr({call,Line,{remote,_,{atom,_,erlang},{atom,_,error}},[_]=As}, _Lc) ->
{dbg,Line,error,expr_list(As)};
-expr({call,Line,{remote,_,{atom,_,erlang},{atom,_,fault}},[_]=As}) ->
- {dbg,Line,fault,expr_list(As)};
-expr({call,Line,{remote,_,{atom,_,erlang},{atom,_,exit}},[_]=As}) ->
+expr({call,Line,{remote,_,{atom,_,erlang},{atom,_,exit}},[_]=As}, _Lc) ->
{dbg,Line,exit,expr_list(As)};
-expr({call,Line,{remote,_,{atom,_,erlang},{atom,_,apply}},[_,_,_]=As0}) ->
+expr({call,Line,{remote,_,{atom,_,erlang},{atom,_,raise}},[_,_,_]=As}, _Lc) ->
+ {dbg,Line,raise,expr_list(As)};
+expr({call,Line,{remote,_,{atom,_,erlang},{atom,_,apply}},[_,_,_]=As0}, Lc) ->
As = expr_list(As0),
- {apply,Line,As};
-expr({call,Line,{remote,_,{atom,_,Mod},{atom,_,Func}},As0}) ->
+ {apply,Line,As,Lc};
+expr({call,Line,{remote,_,{atom,_,Mod},{atom,_,Func}},As0}, Lc) ->
As = expr_list(As0),
case erlang:is_builtin(Mod, Func, length(As)) of
false ->
- {call_remote,Line,Mod,Func,As};
+ {call_remote,Line,Mod,Func,As,Lc};
true ->
- case bif_type(Mod, Func) of
+ case bif_type(Mod, Func, length(As0)) of
safe -> {safe_bif,Line,Mod,Func,As};
- spawn -> {spawn_bif,Line,Mod,Func,As};
unsafe ->{bif,Line,Mod,Func,As}
end
end;
-expr({call,Line,{remote,_,Mod0,Func0},As0}) ->
+expr({call,Line,{remote,_,Mod0,Func0},As0}, Lc) ->
%% New R8 format (abstract_v2).
- Mod = expr(Mod0),
- Func = expr(Func0),
+ Mod = expr(Mod0, false),
+ Func = expr(Func0, false),
As = consify(expr_list(As0)),
- {apply,Line,[Mod,Func,As]};
-expr({call,Line,{atom,_,Func},As0}) ->
+ {apply,Line,[Mod,Func,As],Lc};
+expr({call,Line,{atom,_,Func},As0}, Lc) ->
As = expr_list(As0),
- {local_call,Line,Func,As};
-expr({call,Line,Fun0,As0}) ->
- Fun = expr(Fun0),
+ {local_call,Line,Func,As,Lc};
+expr({call,Line,Fun0,As0}, Lc) ->
+ Fun = expr(Fun0, false),
As = expr_list(As0),
- {apply_fun,Line,Fun,As};
-expr({'catch',Line,E0}) ->
+ {apply_fun,Line,Fun,As,Lc};
+expr({'catch',Line,E0}, _Lc) ->
%% No new variables added.
- E1 = expr(E0),
+ E1 = expr(E0, false),
{'catch',Line,E1};
-expr({'try',Line,Es0,CaseCs0,CatchCs0,As0}) ->
+expr({'try',Line,Es0,CaseCs0,CatchCs0,As0}, Lc) ->
%% No new variables added.
Es = expr_list(Es0),
- CaseCs = icr_clauses(CaseCs0),
- CatchCs = icr_clauses(CatchCs0),
+ CaseCs = icr_clauses(CaseCs0, Lc),
+ CatchCs = icr_clauses(CatchCs0, Lc),
As = expr_list(As0),
{'try',Line,Es,CaseCs,CatchCs,As};
-expr({'query', Line, E0}) ->
- E = expr(E0),
- {'query', Line, E};
-expr({lc,Line,E0,Gs0}) -> %R8.
+expr({lc,Line,E0,Gs0}, _Lc) -> %R8.
Gs = lists:map(fun ({generate,L,P0,Qs}) ->
- {generate,L,expr(P0),expr(Qs)};
+ {generate,L,expr(P0, false),expr(Qs, false)};
({b_generate,L,P0,Qs}) -> %R12.
- {b_generate,L,expr(P0),expr(Qs)};
+ {b_generate,L,expr(P0, false),expr(Qs, false)};
(Expr) ->
- case is_guard_test(Expr) of
- true -> {guard,[[guard_test(Expr)]]};
- false -> expr(Expr)
+ case is_guard(Expr) of
+ true -> {guard,guard([[Expr]])};
+ false -> expr(Expr, false)
end
end, Gs0),
- {lc,Line,expr(E0),Gs};
-expr({bc,Line,E0,Gs0}) -> %R12.
+ {lc,Line,expr(E0, false),Gs};
+expr({bc,Line,E0,Gs0}, _Lc) -> %R12.
Gs = lists:map(fun ({generate,L,P0,Qs}) ->
- {generate,L,expr(P0),expr(Qs)};
+ {generate,L,expr(P0, false),expr(Qs, false)};
({b_generate,L,P0,Qs}) -> %R12.
- {b_generate,L,expr(P0),expr(Qs)};
+ {b_generate,L,expr(P0, false),expr(Qs, false)};
(Expr) ->
- case is_guard_test(Expr) of
- true -> {guard,[[guard_test(Expr)]]};
- false -> expr(Expr)
+ case is_guard(Expr) of
+ true -> {guard,guard([[Expr]])};
+ false -> expr(Expr, false)
end
end, Gs0),
- {bc,Line,expr(E0),Gs};
-expr({match,Line,P0,E0}) ->
- E1 = expr(E0),
+ {bc,Line,expr(E0, false),Gs};
+expr({match,Line,P0,E0}, _Lc) ->
+ E1 = expr(E0, false),
P1 = pattern(P0),
{match,Line,P1,E1};
-expr({op,Line,Op,A0}) ->
- A1 = expr(A0),
+expr({op,Line,Op,A0}, _Lc) ->
+ A1 = expr(A0, false),
{op,Line,Op,[A1]};
-expr({op,Line,'++',L0,R0}) ->
- L1 = expr(L0),
- R1 = expr(R0), %They see the same variables
+expr({op,Line,'++',L0,R0}, _Lc) ->
+ L1 = expr(L0, false),
+ R1 = expr(R0, false), %They see the same variables
{op,Line,append,[L1,R1]};
-expr({op,Line,'--',L0,R0}) ->
- L1 = expr(L0),
- R1 = expr(R0), %They see the same variables
+expr({op,Line,'--',L0,R0}, _Lc) ->
+ L1 = expr(L0, false),
+ R1 = expr(R0, false), %They see the same variables
{op,Line,subtract,[L1,R1]};
-expr({op,Line,'!',L0,R0}) ->
- L1 = expr(L0),
- R1 = expr(R0), %They see the same variables
+expr({op,Line,'!',L0,R0}, _Lc) ->
+ L1 = expr(L0, false),
+ R1 = expr(R0, false), %They see the same variables
{send,Line,L1,R1};
-expr({op,Line,Op,L0,R0}) when Op =:= 'andalso'; Op =:= 'orelse' ->
- L1 = expr(L0),
- R1 = expr(R0), %They see the same variables
+expr({op,Line,Op,L0,R0}, _Lc) when Op =:= 'andalso'; Op =:= 'orelse' ->
+ L1 = expr(L0, false),
+ R1 = expr(R0, false), %They see the same variables
{Op,Line,L1,R1};
-expr({op,Line,Op,L0,R0}) ->
- L1 = expr(L0),
- R1 = expr(R0), %They see the same variables
+expr({op,Line,Op,L0,R0}, _Lc) ->
+ L1 = expr(L0, false),
+ R1 = expr(R0, false), %They see the same variables
{op,Line,Op,[L1,R1]};
-expr({bin,Line,Grp}) ->
+expr({bin,Line,Grp}, _Lc) ->
Grp1 = expr_list(Grp),
{bin,Line,Grp1};
-expr({bin_element,Line,Expr,Size,Type}) ->
- Expr1 = expr(Expr),
- Size1 = expr(Size),
+expr({bin_element,Line,Expr,Size,Type}, _Lc) ->
+ Expr1 = expr(Expr, false),
+ Size1 = expr(Size, false),
{bin_element,Line,Expr1,Size1,Type};
-expr(Other) ->
+expr(Other, _Lc) ->
exit({?MODULE,{unknown_expr,Other}}).
-%% is_guard_test(Expression) -> true | false.
-%% Test if a general expression is a guard test. Cannot use erl_lint
-%% here as sys_pre_expand has transformed source.
+%% is_guard(Expression) -> true | false.
+%% Test if a general expression is a guard test or guard BIF.
+%% Cannot use erl_lint here as sys_pre_expand has transformed source.
-is_guard_test({op,_,Op,L,R}) ->
+is_guard({op,_,Op,L,R}) ->
erl_internal:comp_op(Op, 2) andalso is_gexpr_list([L,R]);
-is_guard_test({call,_,{remote,_,{atom,_,erlang},{atom,_,Test}},As}) ->
- erl_internal:type_test(Test, length(As)) andalso is_gexpr_list(As);
-is_guard_test({atom,_,true}) -> true;
-is_guard_test(_) -> false.
+is_guard({call,_,{remote,_,{atom,_,erlang},{atom,_,Test}},As}) ->
+ Arity = length(As),
+ (erl_internal:guard_bif(Test, Arity) orelse
+ erl_internal:old_type_test(Test, Arity)) andalso is_gexpr_list(As);
+is_guard({atom,_,true}) -> true;
+is_guard(_) -> false.
is_gexpr({var,_,_}) -> true;
is_gexpr({atom,_,_}) -> true;
@@ -555,17 +534,17 @@ consify([]) -> {value,0,[]}.
%% definition etc.
expr_list([E0|Es]) ->
- E1 = expr(E0),
+ E1 = expr(E0, false),
[E1|expr_list(Es)];
expr_list([]) -> [].
-icr_clauses([C0|Cs]) ->
- C1 = clause(C0),
- [C1|icr_clauses(Cs)];
-icr_clauses([]) -> [].
+icr_clauses([C0|Cs], Lc) ->
+ C1 = clause(C0, Lc),
+ [C1|icr_clauses(Cs, Lc)];
+icr_clauses([], _) -> [].
fun_clauses([{clause,L,H,G,B}|Cs]) ->
- [{clause,L,head(H),guard(G),exprs(B)}|fun_clauses(Cs)];
+ [{clause,L,head(H),guard(G),exprs(B, true)}|fun_clauses(Cs)];
fun_clauses([]) -> [].
%% new_var_name() -> VarName.
@@ -585,24 +564,21 @@ new_vars(N, L, Vs) when N > 0 ->
new_vars(N-1, L, [V|Vs]);
new_vars(0, _, Vs) -> Vs.
-bif_type(erlang, Name) -> bif_type(Name);
-bif_type(_, _) -> unsafe.
+bif_type(erlang, Name, Arity) ->
+ case erl_internal:guard_bif(Name, Arity) of
+ true ->
+ %% Guard BIFs are safe (except for self/0, but it is
+ %% handled with a special instruction anyway).
+ safe;
+ false ->
+ bif_type(Name)
+ end;
+bif_type(_, _, _) -> unsafe.
bif_type(register) -> safe;
bif_type(unregister) -> safe;
bif_type(whereis) -> safe;
bif_type(registered) -> safe;
-bif_type(abs) -> safe;
-bif_type(float) -> safe;
-bif_type(trunc) -> safe;
-bif_type(round) -> safe;
-bif_type(math) -> safe;
-bif_type(node) -> safe;
-bif_type(length) -> safe;
-bif_type(hd) -> safe;
-bif_type(tl) -> safe;
-bif_type(size) -> safe;
-bif_type(element) -> safe;
bif_type(setelement) -> safe;
bif_type(atom_to_list) -> safe;
bif_type(list_to_atom) -> safe;
@@ -627,22 +603,14 @@ bif_type(list_to_pid) -> safe;
bif_type(module_loaded) -> safe;
bif_type(binary_to_term) -> safe;
bif_type(term_to_binary) -> safe;
-bif_type(alive) -> safe;
-bif_type(notalive) -> safe;
bif_type(nodes) -> safe;
bif_type(is_alive) -> safe;
bif_type(disconnect_node) -> safe;
bif_type(binary_to_list) -> safe;
bif_type(list_to_binary) -> safe;
bif_type(split_binary) -> safe;
-bif_type(concat_binary) -> safe;
-bif_type(term_to_atom) -> safe;
bif_type(hash) -> safe;
bif_type(pre_loaded) -> safe;
-bif_type(info) -> safe;
bif_type(set_cookie) -> safe;
bif_type(get_cookie) -> safe;
-bif_type(spawn) -> spawn;
-bif_type(spawn_link) -> spawn;
-bif_type(spawn_opt) -> spawn;
bif_type(_) -> unsafe.
diff --git a/lib/debugger/src/dbg_iserver.erl b/lib/debugger/src/dbg_iserver.erl
index 212bc2b8ab..1bb73a43b9 100644
--- a/lib/debugger/src/dbg_iserver.erl
+++ b/lib/debugger/src/dbg_iserver.erl
@@ -97,13 +97,10 @@ ensure_started() ->
%%
%% Key Value
%% --- -----
-%% attributes Attr
-%% exports Exp
%% defs []
%% mod_bin Binary
%% mod_raw Raw Binary
%% mod_file File
-%% module Mod
%% {Mod,Name,Arity,Exported} Cs
%% {'fun',Mod,Index,Uniq} {Name,Arity,Cs}
%% Line {Pos,PosNL}
@@ -117,7 +114,7 @@ init([]) ->
process_flag(trap_exit, true),
global:register_name(?MODULE, self()),
Db = ets:new(?MODULE, [ordered_set, protected]),
- {ok, #state{db=Db, auto=false, stack=all}}.
+ {ok, #state{db=Db, auto=false, stack=no_tail}}.
%% Attaching to a process
handle_call({attached, AttPid, Pid}, _From, State) ->
diff --git a/lib/debugger/src/dbg_istk.erl b/lib/debugger/src/dbg_istk.erl
new file mode 100644
index 0000000000..c6922a80e4
--- /dev/null
+++ b/lib/debugger/src/dbg_istk.erl
@@ -0,0 +1,245 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2011. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+-module(dbg_istk).
+-export([init/0,delayed_to_external/0,from_external/1,
+ push/3,pop/0,pop/1,stack_level/0,
+ delayed_stacktrace/0,delayed_stacktrace/2,
+ bindings/1,stack_frame/2,backtrace/2,
+ in_use_p/2]).
+
+-include("dbg_ieval.hrl").
+
+-define(STACK, ?MODULE).
+
+-record(e,
+ {level, %Level
+ mfa, %{Mod,Func,Args|Arity}|{Fun,Args}
+ line, %Line called from
+ bindings,
+ lc %Last call (true|false)
+ }).
+
+init() ->
+ init([]).
+
+delayed_to_external() ->
+ Stack = get(?STACK),
+ fun() -> {stack,term_to_binary(Stack)} end.
+
+from_external({stack,Stk}) ->
+ put(?STACK, binary_to_term(Stk)).
+
+init(Stack) ->
+ put(?STACK, Stack).
+
+%% We keep track of a call stack that is used for
+%% 1) saving stack frames that can be inspected from an Attached
+%% Process GUI (using dbg_icmd:get(Meta, stack_frame, {Dir, SP})
+%% 2) generate an approximation of regular stacktrace -- sent to
+%% Debugged when it should raise an exception or evaluate a
+%% function (since it might possible raise an exception)
+%%
+%% How to push depends on the "Stack Trace" option (value saved in
+%% process dictionary item 'trace_stack').
+%% all - everything is pushed
+%% no_tail - tail recursive push
+%% false - nothing is pushed
+%% Whenever a function returns, the corresponding call frame is popped.
+
+push(Bs, #ieval{level=Le,module=Mod,function=Name,
+ arguments=As,line=Li}=Ieval, Lc) ->
+ Entry = #e{level=Le,mfa={Mod,Name,As},line=Li,bindings=Bs,lc=Lc},
+ case get(trace_stack) of
+ false ->
+ Ieval#ieval{level=Le+1};
+ no_tail when Lc ->
+ Ieval;
+ _ -> % all | no_tail when Lc =:= false
+ put(?STACK, [Entry|get(?STACK)]),
+ Ieval#ieval{level=Le+1}
+ end.
+
+pop() ->
+ case get(trace_stack) of
+ false -> ignore;
+ _ -> % all ¦ no_tail
+ case get(?STACK) of
+ [_Entry|Entries] ->
+ put(?STACK, Entries);
+ [] ->
+ ignore
+ end
+ end.
+
+pop(Le) ->
+ case get(trace_stack) of
+ false -> ignore;
+ _ -> % all | no_tail
+ put(?STACK, pop(Le, get(?STACK)))
+ end.
+
+pop(Level, [#e{level=Le}|Stack]) when Level =< Le ->
+ pop(Level, Stack);
+pop(_Level, Stack) ->
+ Stack.
+
+%% stack_level() -> Le
+%% stack_level(Stack) -> Le
+%% Top call level
+stack_level() ->
+ stack_level(get(?STACK)).
+
+stack_level([]) -> 1;
+stack_level([#e{level=Le}|_]) -> Le.
+
+%% delayed_stacktrace() -> CreateStacktraceFun
+%% delayed_stacktrace(ArgFlag, #ieval{}) -> CreateStacktraceFun
+%% ArgFlag = no_args | include_args
+%% CreateStacktraceFun = fun(NumberOfEntries)
+%%
+%% Return a fun that can convert the internal stack format to
+%% an imitation of the regular stacktrace.
+
+delayed_stacktrace() ->
+ Stack0 = get(?STACK),
+ fun(NumEntries) ->
+ Stack = stacktrace(NumEntries, Stack0, []),
+ [finalize(ArityOnly) || {ArityOnly,_} <- Stack]
+ end.
+
+delayed_stacktrace(include_args, Ieval) ->
+ #ieval{module=Mod,function=Name,arguments=As,line=Li} = Ieval,
+ Stack0 = [#e{mfa={Mod,Name,As},line=Li}|get(?STACK)],
+ fun(NumEntries) ->
+ case stacktrace(NumEntries, Stack0, []) of
+ [] ->
+ [];
+ [{_,WithArgs}|Stack] ->
+ [finalize(WithArgs) |
+ [finalize(ArityOnly) || {ArityOnly,_} <- Stack]]
+ end
+ end;
+delayed_stacktrace(no_args, Ieval) ->
+ #ieval{module=Mod,function=Name,arguments=As,line=Li} = Ieval,
+ Stack0 = [#e{mfa={Mod,Name,As},line=Li}|get(?STACK)],
+ fun(NumEntries) ->
+ Stack = stacktrace(NumEntries, Stack0, []),
+ [finalize(ArityOnly) || {ArityOnly,_} <- Stack]
+ end.
+
+stacktrace(N, [#e{lc=true}|T], Acc) ->
+ stacktrace(N, T, Acc);
+stacktrace(N, [E|T], []) ->
+ stacktrace(N-1, T, [normalize(E)]);
+stacktrace(N, [E|T], [{P,_}|_]=Acc) when N > 0 ->
+ case normalize(E) of
+ {P,_} ->
+ stacktrace(N, T, Acc);
+ New ->
+ stacktrace(N-1, T, [New|Acc])
+ end;
+stacktrace(_, _, Acc) ->
+ lists:reverse(Acc).
+
+normalize(#e{mfa={M,Fun,As},line=Li}) when is_function(Fun) ->
+ Loc = {M,Li},
+ {{Fun,length(As),Loc},{Fun,As,Loc}};
+normalize(#e{mfa={M,F,As},line=Li}) ->
+ Loc = {M,Li},
+ {{M,F,length(As),Loc},{M,F,As,Loc}}.
+
+finalize({M,F,A,Loc}) -> {M,F,A,line(Loc)};
+finalize({Fun,A,Loc}) -> {Fun,A,line(Loc)}.
+
+line({Mod,Line}) when Line > 0 ->
+ [{file,atom_to_list(Mod)++".erl"},{line,Line}];
+line(_) -> [].
+
+%% bindings(SP) -> Bs
+%% SP = Le % stack pointer
+%% Return the bindings for the specified call level
+bindings(SP) ->
+ bindings(SP, get(?STACK)).
+
+bindings(SP, [#e{level=SP,bindings=Bs}|_]) ->
+ Bs;
+bindings(SP, [_Entry|Entries]) ->
+ bindings(SP, Entries);
+bindings(_SP, []) ->
+ erl_eval:new_bindings().
+
+%% stack_frame(Dir, SP) -> {Le, Where, Bs} | top | bottom
+%% Dir = up | down
+%% Where = {Cm, Li}
+%% Cm = Module | undefined % module
+%% Li = int() | -1 % line number
+%% Bs = bindings()
+%% Return stack frame info one step up/down from given stack pointer
+%% up = to lower call levels
+%% down = to higher call levels
+stack_frame(up, SP) ->
+ stack_frame(SP, up, get(?STACK));
+stack_frame(down, SP) ->
+ stack_frame(SP, down, lists:reverse(get(?STACK))).
+
+stack_frame(SP, up, [#e{level=Le,mfa={Cm,_,_},line=Li,bindings=Bs}|_])
+ when Le < SP ->
+ {Le,{Cm,Li},Bs};
+stack_frame(SP, down, [#e{level=Le,mfa={Cm,_,_},line=Li,bindings=Bs}|_])
+ when Le > SP ->
+ {Le,{Cm,Li},Bs};
+stack_frame(SP, Dir, [#e{level=SP}|Stack]) ->
+ case Stack of
+ [#e{level=Le,mfa={Cm,_,_},line=Li,bindings=Bs}|_] ->
+ {Le,{Cm,Li},Bs};
+ [] when Dir =:= up ->
+ top;
+ [] when Dir =:= down ->
+ bottom
+ end;
+stack_frame(SP, Dir, [_Entry|Stack]) ->
+ stack_frame(SP, Dir, Stack).
+
+%% backtrace(HowMany) -> Backtrace
+%% HowMany = all | int()
+%% Backtrace = {Le, MFA}
+%% Return all/the last N called functions, in reversed call order
+backtrace(HowMany, Ieval) ->
+ #ieval{level=Level,module=Mod,function=Name,arguments=As} = Ieval,
+ Stack0 = [#e{level=Level,mfa={Mod,Name,As}}|get(?STACK)],
+ Stack = case HowMany of
+ all -> Stack0;
+ N -> lists:sublist(Stack0, N)
+ end,
+ [{Le,MFA} || #e{level=Le,mfa=MFA} <- Stack].
+
+%%--------------------------------------------------------------------
+%% in_use_p(Mod, Cm) -> boolean()
+%% Mod = Cm = atom()
+%% Returns true if Mod is found on the stack, otherwise false.
+%%--------------------------------------------------------------------
+in_use_p(Mod, Mod) -> true;
+in_use_p(Mod, _Cm) ->
+ case get(trace_stack) of
+ false -> true;
+ _ -> % all | no_tail
+ lists:any(fun(#e{mfa={M,_,_}}) when M =:= Mod -> true;
+ (_) -> false
+ end, get(?STACK))
+ end.
diff --git a/lib/debugger/src/dbg_ui_break_win.erl b/lib/debugger/src/dbg_ui_break_win.erl
index 4039bf785f..abbec158b0 100644
--- a/lib/debugger/src/dbg_ui_break_win.erl
+++ b/lib/debugger/src/dbg_ui_break_win.erl
@@ -81,12 +81,12 @@ create_win(GS, {X, Y}, function, Mod, _Line) ->
{pack_x, 2}, {pack_y, 3},
{selectmode, multiple}]),
- %% Add Ok and Cancel buttons
- {Wbtn, Hbtn} = dbg_ui_win:min_size(["Ok","Cancel"], 70, 30),
+ %% Add OK and Cancel buttons
+ {Wbtn, Hbtn} = dbg_ui_win:min_size(["OK","Cancel"], 70, 30),
Bot = gs:frame(Frm, [{pack_x, {1, 3}}, {pack_y, 4}]),
- Ok = gs:button(Bot, [{x, Pad}, {y, Pad},
+ OK = gs:button(Bot, [{x, Pad}, {y, Pad},
{width, Wbtn}, {height, Hbtn},
- {label, {text,"Ok"}}, {font, Font}]),
+ {label, {text,"OK"}}, {font, Font}]),
Cancel = gs:button(Bot, [{x, W-Pad-Wbtn}, {y, Pad},
{width, Wbtn}, {height, Hbtn},
{label, {text,"Cancel"}}, {font, Font}]),
@@ -95,7 +95,7 @@ create_win(GS, {X, Y}, function, Mod, _Line) ->
gs:config(Win, [{width, Wfrm}, {height, Hfrm}, {map, true}]),
#winInfo{type=function, win=Win,
packer=Frm, entries=Entries, trigger=enable,
- ok=Ok, cancel=Cancel, listbox=Lb, funcs=[]};
+ ok=OK, cancel=Cancel, listbox=Lb, funcs=[]};
create_win(GS, {X, Y}, Type, Mod, Line) ->
Pad = 8,
W = 230,
@@ -161,12 +161,12 @@ create_win(GS, {X, Y}, Type, Mod, Line) ->
{align, w}, {group, Grp},
{data, {trigger, delete}}]),
- %% Add Ok and Cancel buttons
- {Wbtn, Hbtn} = dbg_ui_win:min_size(["Ok","Cancel"], 70, 30),
+ %% Add OK and Cancel buttons
+ {Wbtn, Hbtn} = dbg_ui_win:min_size(["OK","Cancel"], 70, 30),
Ybtn = Yacc + Pad + Hfrm + Pad,
- Ok = gs:button(Win, [{x, Pad}, {y, Ybtn},
+ OK = gs:button(Win, [{x, Pad}, {y, Ybtn},
{width, Wbtn}, {height, Hbtn},
- {label, {text,"Ok"}}, {font, Font}]),
+ {label, {text,"OK"}}, {font, Font}]),
gs:button(Win, [{x, W-Pad-Wbtn}, {y, Ybtn},
{width, Wbtn}, {height, Hbtn},
{label, {text,"Cancel"}}, {font, Font}]),
@@ -175,7 +175,7 @@ create_win(GS, {X, Y}, Type, Mod, Line) ->
gs:config(Win, [{width, W}, {height, Hwin}, {map, true}]),
#winInfo{type=Type, win=Win,
- entries=Entries, trigger=enable, ok=Ok}.
+ entries=Entries, trigger=enable, ok=OK}.
%%--------------------------------------------------------------------
%% update_functions(WinInfo, Funcs) -> WinInfo
@@ -229,7 +229,7 @@ handle_event({gs, LB, keypress, window, [Key|_]}, WinInfo) ->
Key/='Tab', Key/='Return' ->
ignore;
true ->
- handle_event({gs, LB, click, listbox, ["Ok"]}, WinInfo)
+ handle_event({gs, LB, click, listbox, ["OK"]}, WinInfo)
end;
handle_event({gs, Ent, keypress, Data, [Key|_]}, WinInfo) ->
case WinInfo#winInfo.type of
@@ -249,14 +249,14 @@ handle_event({gs, Ent, keypress, Data, [Key|_]}, WinInfo) ->
case next_entry(Ent, WinInfo#winInfo.entries) of
last ->
gs:config(WinInfo#winInfo.ok, flash),
- handle_event({gs, Ent, click, Data, ["Ok"]}, WinInfo);
+ handle_event({gs, Ent, click, Data, ["OK"]}, WinInfo);
Next ->
gs:config(Next, {setfocus, true}),
ignore
end;
_Type -> ignore
end;
-handle_event({gs, _Id, click, _Data, ["Ok"|_]}, WinInfo) ->
+handle_event({gs, _Id, click, _Data, ["OK"|_]}, WinInfo) ->
case check_input(WinInfo#winInfo.entries) of
error -> ignore;
Data when WinInfo#winInfo.type/=function ->
diff --git a/lib/debugger/src/dbg_ui_edit_win.erl b/lib/debugger/src/dbg_ui_edit_win.erl
index badaf4bef4..82f784aa83 100644
--- a/lib/debugger/src/dbg_ui_edit_win.erl
+++ b/lib/debugger/src/dbg_ui_edit_win.erl
@@ -64,13 +64,13 @@ create_win(GS, {X, Y}, Title, Prompt, {Type, Value}) ->
{text, Value},
{keypress, true}]),
- %% Ok and Cancel buttons
+ %% OK and Cancel buttons
W = Pad + Wlbl + Went + Pad,
{Wbtn, Hbtn} = dbg_ui_win:min_size(["Cancel"], 70, 30),
Ybtn = Pad + Hlbl + Pad,
Btn = gs:button(Win, [{x, Pad}, {y, Ybtn},
{width, Wbtn}, {height, Hbtn},
- {label, {text,"Ok"}}, {font, Font}]),
+ {label, {text,"OK"}}, {font, Font}]),
gs:button(Win, [{x, W-Pad-Wbtn}, {y, Ybtn},
{width, Wbtn}, {height, Hbtn},
{label, {text,"Cancel"}}, {font, Font}]),
@@ -100,8 +100,8 @@ handle_event({gs, _Id, destroy, _Data, _Arg}, _WinInfo) ->
stopped;
handle_event({gs, Id, keypress, Data, ['Return'|_]}, WinInfo) ->
gs:config(WinInfo#winInfo.button, flash),
- handle_event({gs, Id, click, Data, ["Ok"]}, WinInfo);
-handle_event({gs, _Id, click, _Data, ["Ok"|_]}, WinInfo) ->
+ handle_event({gs, Id, click, Data, ["OK"]}, WinInfo);
+handle_event({gs, _Id, click, _Data, ["OK"|_]}, WinInfo) ->
Ent = WinInfo#winInfo.entry,
Str = gs:read(Ent, text),
Type = WinInfo#winInfo.type,
diff --git a/lib/debugger/src/dbg_ui_filedialog_win.erl b/lib/debugger/src/dbg_ui_filedialog_win.erl
index 3203991c1f..1eced1104d 100644
--- a/lib/debugger/src/dbg_ui_filedialog_win.erl
+++ b/lib/debugger/src/dbg_ui_filedialog_win.erl
@@ -100,7 +100,7 @@ create_win(GS, Title, {X,Y}, Mode, Filter, Extra, FileName) ->
Opts = [{y, Y4}, {width, Wbtn}, {height, Hbtn}, {font, Font}],
case Mode of
normal ->
- gs:button(Win, [{label, {text,"Ok"}}, {x, Pad},
+ gs:button(Win, [{label, {text,"OK"}}, {x, Pad},
{data, select} | Opts]),
gs:button(Win, [{label, {text,"Filter"}}, {x, Wlb/2-Wbtn/2},
{data, filter} | Opts]),
diff --git a/lib/debugger/src/dbg_ui_interpret.erl b/lib/debugger/src/dbg_ui_interpret.erl
index 952e73b537..079eaeb634 100644
--- a/lib/debugger/src/dbg_ui_interpret.erl
+++ b/lib/debugger/src/dbg_ui_interpret.erl
@@ -145,7 +145,7 @@ interpret_all(State, Dir, [File0|Files]) ->
Window = dbg_ui_filedialog_win:get_window(State#state.win),
Error = format_error(int:interpretable(File)),
Msg = ["Error when interpreting:", File, Error,
- "Ok to continue?"],
+ "OK to continue?"],
case tool_utils:confirm(Window, Msg) of
ok -> interpret_all(State, Dir, Files);
cancel -> true
diff --git a/lib/debugger/src/dbg_ui_settings.erl b/lib/debugger/src/dbg_ui_settings.erl
index 146aa7e239..38b2ec424f 100644
--- a/lib/debugger/src/dbg_ui_settings.erl
+++ b/lib/debugger/src/dbg_ui_settings.erl
@@ -136,8 +136,8 @@ default_settings_dir(GS) ->
{ok, CWD} = file:get_cwd(),
Msg = ["Default directory", DefDir, "does not exist.",
- "Click Ok to create it or",
- "Cancel to use other directory!"],
+ "Click OK to create it or",
+ "Cancel to use other directory."],
case tool_utils:confirm(GS, Msg) of
ok ->
ToolsDir = filename:dirname(DefDir),
diff --git a/lib/debugger/src/dbg_wx_break_win.erl b/lib/debugger/src/dbg_wx_break_win.erl
index 7ac82c8fb4..062da3937a 100644
--- a/lib/debugger/src/dbg_wx_break_win.erl
+++ b/lib/debugger/src/dbg_wx_break_win.erl
@@ -82,8 +82,8 @@ create_win(Parent, Pos, function, Mod, _Line) ->
wxComboBox:connect(Text, command_text_updated),
wxListBox:connect(LB, command_listbox_selected),
wxListBox:connect(LB, command_listbox_doubleclicked),
- OkId = wxDialog:getAffirmativeId(Win),
- OKButt = wxWindow:findWindowById(OkId, [{parent, Win}]),
+ OKId = wxDialog:getAffirmativeId(Win),
+ OKButt = wxWindow:findWindowById(OKId, [{parent, Win}]),
wxWindow:disable(OKButt),
wxDialog:centreOnParent(Win),
wxDialog:show(Win),
@@ -141,8 +141,8 @@ create_win(Parent, Pos, Type, Mod, Line) ->
wxComboBox:setFocus(ModT),
wxDialog:connect(Win, command_button_clicked),
wxDialog:connect(Win, command_text_updated),
- OkId = wxDialog:getAffirmativeId(Win),
- OKButt = wxWindow:findWindowById(OkId),
+ OKId = wxDialog:getAffirmativeId(Win),
+ OKButt = wxWindow:findWindowById(OKId),
wxWindow:disable(OKButt),
wxDialog:centreOnParent(Win),
wxDialog:show(Win),
@@ -180,30 +180,30 @@ handle_event(#wx{id=?wxID_CANCEL}, #winInfo{win=Win}) ->
wxDialog:destroy(Win),
stopped;
handle_event(#wx{event=#wxCommand{type=command_text_updated}},
- #winInfo{type=function, text=Text, ok=Ok}) ->
+ #winInfo{type=function, text=Text, ok=OK}) ->
Module = wxComboBox:getValue(Text),
- wxWindow:disable(Ok),
+ wxWindow:disable(OK),
{module, list_to_atom(Module)};
handle_event(#wx{event=#wxCommand{type=command_text_updated}},
- #winInfo{text=Text, ok=Ok, entries=Es}) ->
+ #winInfo{text=Text, ok=OK, entries=Es}) ->
Module = wxComboBox:getValue(Text),
case check_input(Es) of
- error -> wxWindow:disable(Ok);
- _Data when Module =/= "" -> wxWindow:enable(Ok);
- _ -> wxWindow:disable(Ok)
+ error -> wxWindow:disable(OK);
+ _Data when Module =/= "" -> wxWindow:enable(OK);
+ _ -> wxWindow:disable(OK)
end,
ignore;
handle_event(#wx{event=#wxCommand{type=command_listbox_selected}},
- #winInfo{type=function, listbox=LB, ok=Ok}) ->
+ #winInfo{type=function, listbox=LB, ok=OK}) ->
case wxListBox:getSelections(LB) of
- {N,_} when N > 0 -> wxWindow:enable(Ok);
- _ -> wxWindow:disable(Ok)
+ {N,_} when N > 0 -> wxWindow:enable(OK);
+ _ -> wxWindow:disable(OK)
end,
ignore;
-handle_event(#wx{id=OKorListBox, event=#wxCommand{type=OkorDoubleClick}},
+handle_event(#wx{id=OKorListBox, event=#wxCommand{type=OKorDoubleClick}},
#winInfo{type=function,win=Win,listbox=LB,funcs=Funcs,text=Text})
when OKorListBox =:= ?wxID_OK;
- OkorDoubleClick =:= command_listbox_doubleclicked ->
+ OKorDoubleClick =:= command_listbox_doubleclicked ->
Mod = wxComboBox:getValue(Text),
{_, IndexL} = wxListBox:getSelections(LB),
Breaks = [[list_to_atom(Mod)|lists:nth(Index+1, Funcs)] || Index <- IndexL],
diff --git a/lib/debugger/src/dbg_wx_filedialog_win.erl b/lib/debugger/src/dbg_wx_filedialog_win.erl
index 9687efa981..9f45ad0c47 100644
--- a/lib/debugger/src/dbg_wx_filedialog_win.erl
+++ b/lib/debugger/src/dbg_wx_filedialog_win.erl
@@ -151,7 +151,7 @@ init([Parent, Id, Options0]) ->
Bott = wxDialog:createButtonSizer(Dlg, ?wxCANCEL bor ?wxOK),
wxDialog:connect(Dlg, command_button_clicked),
- %% Ok done
+ %% OK done
Box = wxBoxSizer:new(?wxVERTICAL),
wxSizer:add(Box, Top, [{border, 2}, {flag,?wxALL bor ?wxEXPAND}]),
wxSizer:add(Box, Dir, [{border, 2}, {flag,?wxALL bor ?wxEXPAND}]),
diff --git a/lib/debugger/src/dbg_wx_settings.erl b/lib/debugger/src/dbg_wx_settings.erl
index 8f87815949..bc88bdf7da 100644
--- a/lib/debugger/src/dbg_wx_settings.erl
+++ b/lib/debugger/src/dbg_wx_settings.erl
@@ -83,9 +83,9 @@ default_settings_dir(Win) ->
false ->
{ok, CWD} = file:get_cwd(),
- Msg = ["Default directory", DefDir, "does not exist.",
- "Click Ok to create it or",
- "Cancel to use other directory!"],
+ Msg = ["Default directory ", DefDir, " does not exist. ",
+ "Click OK to create it or ",
+ "Cancel to use other directory."],
case dbg_wx_win:confirm(Win, Msg) of
ok ->
ToolsDir = filename:dirname(DefDir),
diff --git a/lib/debugger/src/dbg_wx_trace_win.erl b/lib/debugger/src/dbg_wx_trace_win.erl
index 720b913024..720b913024 100755..100644
--- a/lib/debugger/src/dbg_wx_trace_win.erl
+++ b/lib/debugger/src/dbg_wx_trace_win.erl
diff --git a/lib/debugger/src/dbg_wx_winman.erl b/lib/debugger/src/dbg_wx_winman.erl
index 79dcc47f6f..79dcc47f6f 100755..100644
--- a/lib/debugger/src/dbg_wx_winman.erl
+++ b/lib/debugger/src/dbg_wx_winman.erl
diff --git a/lib/debugger/src/debugger.app.src b/lib/debugger/src/debugger.app.src
index 21cf59a2e1..5538f66260 100644
--- a/lib/debugger/src/debugger.app.src
+++ b/lib/debugger/src/debugger.app.src
@@ -26,6 +26,7 @@
dbg_ieval,
dbg_iload,
dbg_iserver,
+ dbg_istk,
dbg_ui_break,
dbg_ui_break_win,
dbg_ui_edit,
diff --git a/lib/debugger/test/Makefile b/lib/debugger/test/Makefile
index 2296bd0ae6..3dfbed31ff 100644
--- a/lib/debugger/test/Makefile
+++ b/lib/debugger/test/Makefile
@@ -43,6 +43,7 @@ MODULES= \
exception_SUITE \
fun_SUITE \
lc_SUITE \
+ line_number_SUITE \
record_SUITE \
trycatch_SUITE \
test_lib \
diff --git a/lib/debugger/test/bs_construct_SUITE.erl b/lib/debugger/test/bs_construct_SUITE.erl
index 5c7d49e951..187c9f53b0 100644
--- a/lib/debugger/test/bs_construct_SUITE.erl
+++ b/lib/debugger/test/bs_construct_SUITE.erl
@@ -19,18 +19,31 @@
-module(bs_construct_SUITE).
+%% Copied from bs_construct_SUITE in the emulator test suite.
+%% The following test cases have been omitted since they don't
+%% make much sense for the debugger:
+%% bs_add
+%% kostis
+
-export([all/0, suite/0,groups/0,init_per_group/2,end_per_group/2,
init_per_testcase/2,end_per_testcase/2,
init_per_suite/1,end_per_suite/1,
- test1/1, test2/1, test3/1, test4/1, test5/1, testf/1, not_used/1, in_guard/1,
- coerce_to_float/1]).
+ test1/1, test2/1, test3/1, test4/1, test5/1, testf/1,
+ not_used/1, in_guard/1,
+ mem_leak/1, coerce_to_float/1, bjorn/1,
+ huge_float_field/1, huge_binary/1, system_limit/1, badarg/1,
+ copy_writable_binary/1, dynamic/1,
+ otp_7422/1, zero_width/1]).
-include_lib("test_server/include/test_server.hrl").
suite() -> [{ct_hooks,[ts_install_cth]}].
all() ->
- cases().
+ [test1, test2, test3, test4, test5, testf, not_used,
+ in_guard, mem_leak, coerce_to_float, bjorn,
+ huge_float_field, huge_binary, system_limit, badarg,
+ copy_writable_binary, dynamic, otp_7422, zero_width].
groups() ->
[].
@@ -41,11 +54,6 @@ init_per_group(_GroupName, Config) ->
end_per_group(_GroupName, Config) ->
Config.
-
-cases() ->
- [test1, test2, test3, test4, test5, testf, not_used,
- in_guard, coerce_to_float].
-
init_per_testcase(_Case, Config) ->
test_lib:interpret(?MODULE),
Dog = test_server:timetrap(?t:minutes(1)),
@@ -75,7 +83,9 @@ r(L) ->
-define(T(B, L), {B, ??B, L}).
-define(N(B), {B, ??B, unknown}).
--define(FAIL(Expr), ?line {'EXIT',{badarg,_}} = (catch Expr)).
+-define(FAIL(Expr), ?line fail_check(catch Expr, ??Expr, [])).
+
+-define(FAIL_VARS(Expr, Vars), ?line fail_check(catch Expr, ??Expr, Vars)).
l(I_13, I_big1) ->
[
@@ -143,7 +153,13 @@ l(I_13, I_big1) ->
native_3798()),
?T(<<32978297842987249827298387697777669766334937:128/native-integer>>,
- native_bignum())
+ native_bignum()),
+
+ %% Unit tests.
+ ?T(<<<<5:3>>/bitstring>>, <<5:3>>),
+ ?T(<<42,<<7:4>>/binary-unit:4>>, <<42,7:4>>),
+ ?T(<<<<344:17>>/binary-unit:17>>, <<344:17>>),
+ ?T(<<<<42,3,7656:16>>/binary-unit:16>>, <<42,3,7656:16>>)
].
@@ -179,7 +195,7 @@ eval_list([{C_bin, Str, Bytes} | Rest], Vars) ->
[{C_bin, E_bin, Str, Bytes} | eval_list(Rest, Vars)]
end.
-one_test({C_bin, E_bin, Str, Bytes}) when list(Bytes) ->
+one_test({C_bin, E_bin, Str, Bytes}) when is_list(Bytes) ->
io:format(" ~s, ~p~n", [Str, Bytes]),
Bin = list_to_binary(Bytes),
if
@@ -222,7 +238,7 @@ one_test({C_bin, E_bin, Str, Result}) ->
ok;
%% For situations where the final bits may not matter, like
%% for floats:
- N when integer(N) ->
+ N when is_integer(N) ->
io:format("Info: compiled and interpreted differ in the"
" last bytes:~n ~p, ~p.~n",
[binary_to_list(C_bin), binary_to_list(E_bin)]),
@@ -248,9 +264,22 @@ equal_lists(A, B, R) ->
false
end.
+fail_check({'EXIT',{badarg,_}}, Str, Vars) ->
+ try evaluate(Str, Vars) of
+ Res ->
+ io:format("Interpreted result: ~p", [Res]),
+ ?t:fail(did_not_fail_in_intepreted_code)
+ catch
+ error:badarg ->
+ ok
+ end;
+fail_check(Res, _, _) ->
+ io:format("Compiled result: ~p", [Res]),
+ ?t:fail(did_not_fail_in_compiled_code).
+
%%% Simple working cases
test1(suite) -> [];
-test1(Config) when list(Config) ->
+test1(Config) when is_list(Config) ->
?line I_13 = i(13),
?line I_big1 = big(1),
?line Vars = [{'I_13', I_13},
@@ -272,7 +301,7 @@ gen_l(N, S, A) ->
[?T(<<A:S/little, A:(N-S)/little>>, comp(N, A, S))].
test2(suite) -> [];
-test2(Config) when list(Config) ->
+test2(Config) when is_list(Config) ->
?line test2(0, 8, 2#10101010101010101),
?line test2(0, 8, 2#1111111111).
@@ -300,7 +329,7 @@ t3() ->
].
test3(suite) -> [];
-test3(Config) when list(Config) ->
+test3(Config) when is_list(Config) ->
?line Vars = [],
?line lists:foreach(fun one_test/1, eval_list(t3(), Vars)).
@@ -311,7 +340,7 @@ gen_u_l(N, S, A) ->
[?N(<<A:S/little, A:(N-S)/little>>)].
test4(suite) -> [];
-test4(Config) when list(Config) ->
+test4(Config) when is_list(Config) ->
?line test4(0, 16, 2#10101010101010101),
?line test4(0, 16, 2#1111111111).
@@ -333,7 +362,7 @@ gen_b(N, S, A) ->
test5(suite) -> [];
test5(doc) -> ["OTP-3995"];
-test5(Config) when list(Config) ->
+test5(Config) when is_list(Config) ->
?line test5(0, 8, <<73>>),
?line test5(0, 8, <<68>>).
@@ -350,40 +379,63 @@ test5(S, A) ->
%%% Failure cases
testf(suite) -> [];
-testf(Config) when list(Config) ->
- ?FAIL(<<3.14>>),
- ?FAIL(<<<<1,2>>>>),
-
- ?FAIL(<<2.71/binary>>),
- ?FAIL(<<24334/binary>>),
- ?FAIL(<<24334344294788947129487129487219847/binary>>),
-
- ?FAIL(<<<<1,2,3>>/float>>),
+testf(Config) when is_list(Config) ->
+ ?line ?FAIL(<<3.14>>),
+ ?line ?FAIL(<<<<1,2>>>>),
+
+ ?line ?FAIL(<<2.71/binary>>),
+ ?line ?FAIL(<<24334/binary>>),
+ ?line ?FAIL(<<24334344294788947129487129487219847/binary>>),
+ BigInt = id(24334344294788947129487129487219847),
+ ?line ?FAIL_VARS(<<BigInt/binary>>, [{'BigInt',BigInt}]),
+ ?line ?FAIL_VARS(<<42,BigInt/binary>>, [{'BigInt',BigInt}]),
+ ?line ?FAIL_VARS(<<BigInt:2/binary>>, [{'BigInt',BigInt}]),
+
+ %% One negative field size, but the sum of field sizes will be 1 byte.
+ %% Make sure that we reject that properly.
+ I_minus_777 = id(-777),
+ I_minus_2047 = id(-2047),
+ ?line ?FAIL_VARS(<<I_minus_777:2048/unit:8,57:I_minus_2047/unit:8>>,
+ ordsets:from_list([{'I_minus_777',I_minus_777},
+ {'I_minus_2047',I_minus_2047}])),
+ ?line ?FAIL(<<<<1,2,3>>/float>>),
%% Negative field widths.
- testf_1(-8, <<1,2,3,4,5>>),
-
- ?FAIL(<<42:(-16)>>),
- ?FAIL(<<3.14:(-8)/float>>),
- ?FAIL(<<<<23,56,0,2>>:(-16)/binary>>),
- ?FAIL(<<<<23,56,0,2>>:(2.5)/binary>>),
- ?FAIL(<<<<23,56,0,2>>:(anka)>>),
+ ?line testf_1(-8, <<1,2,3,4,5>>),
+ ?line ?FAIL(<<0:(-(1 bsl 100))>>),
+
+ ?line ?FAIL(<<42:(-16)>>),
+ ?line ?FAIL(<<3.14:(-8)/float>>),
+ ?line ?FAIL(<<<<23,56,0,2>>:(-16)/binary>>),
+ ?line ?FAIL(<<<<23,56,0,2>>:(2.5)/binary>>),
+ ?line ?FAIL(<<<<23,56,0,2>>:(anka)>>),
+ ?line ?FAIL(<<<<23,56,0,2>>:(anka)>>),
+
+ %% Unit failures.
+ ?line ?FAIL(<<<<1:1>>/binary>>),
+ Sz = id(1),
+ ?line ?FAIL_VARS(<<<<1:Sz>>/binary>>, [{'Sz',Sz}]),
+ ?line {'EXIT',{badarg,_}} = (catch <<<<1:(id(1))>>/binary>>),
+ ?line ?FAIL(<<<<7,8,9>>/binary-unit:16>>),
+ ?line ?FAIL(<<<<7,8,9,3:7>>/binary-unit:16>>),
+ ?line ?FAIL(<<<<7,8,9,3:7>>/binary-unit:17>>),
ok.
testf_1(W, B) ->
- ?FAIL(<<42:W>>),
- ?FAIL(<<3.14:W/float>>),
- ?FAIL(<<B:W/binary>>).
+ Vars = [{'W',W}],
+ ?FAIL_VARS(<<42:W>>, Vars),
+ ?FAIL_VARS(<<3.14:W/float>>, Vars),
+ ?FAIL_VARS(<<B:W/binary>>, [{'B',B}|Vars]).
not_used(doc) ->
"Test that constructed binaries that are not used will still give an exception.";
not_used(Config) when is_list(Config) ->
?line ok = not_used1(3, <<"dum">>),
- ?line ?FAIL(not_used1(3, "dum")),
- ?line ?FAIL(not_used2(444, -2)),
- ?line ?FAIL(not_used2(444, anka)),
- ?line ?FAIL(not_used3(444)),
+ ?line {'EXIT',{badarg,_}} = (catch not_used1(3, "dum")),
+ ?line {'EXIT',{badarg,_}} = (catch not_used2(444, -2)),
+ ?line {'EXIT',{badarg,_}} = (catch not_used2(444, anka)),
+ ?line {'EXIT',{badarg,_}} = (catch not_used3(444)),
ok.
not_used1(I, BinString) ->
@@ -398,7 +450,7 @@ not_used3(I) ->
<<I:(-8)>>,
ok.
-in_guard(Config) when list(Config) ->
+in_guard(Config) when is_list(Config) ->
?line 1 = in_guard(<<16#74ad:16>>, 16#e95, 5),
?line 2 = in_guard(<<16#3A,16#F7,"hello">>, 16#3AF7, <<"hello">>),
?line 3 = in_guard(<<16#FBCD:14,3.1415/float,3:2>>, 16#FBCD, 3.1415),
@@ -415,6 +467,36 @@ in_guard(Bin, A, B) when <<A:14,B/float,3:2>> == Bin -> 3;
in_guard(Bin, A, B) when {a,b,<<A:14,B/float,3:2>>} == Bin -> cant_happen;
in_guard(_, _, _) -> nope.
+mem_leak(doc) -> "Make sure that construction has no memory leak";
+mem_leak(Config) when is_list(Config) ->
+ ?line B = make_bin(16, <<0>>),
+ ?line mem_leak(1024, B),
+ ok.
+
+mem_leak(0, _) -> ok;
+mem_leak(N, B) ->
+ ?line big_bin(B, <<23>>),
+ ?line {'EXIT',{badarg,_}} = (catch big_bin(B, bad)),
+ maybe_gc(),
+ mem_leak(N-1, B).
+
+big_bin(B1, B2) ->
+ <<B1/binary,B1/binary,B1/binary,B1/binary,
+ B1/binary,B1/binary,B1/binary,B1/binary,
+ B1/binary,B1/binary,B1/binary,B1/binary,
+ B1/binary,B1/binary,B1/binary,B1/binary,
+ B2/binary>>.
+
+make_bin(0, Acc) -> Acc;
+make_bin(N, Acc) -> make_bin(N-1, <<Acc/binary,Acc/binary>>).
+
+maybe_gc() ->
+ case erlang:system_info(heap_type) of
+ shared -> erlang:garbage_collect();
+ hybrid -> erlang:garbage_collect();
+ private -> ok
+ end.
+
-define(COF(Int0),
?line (fun(Int) ->
true = <<Int:32/float>> =:= <<(float(Int)):32/float>>,
@@ -431,7 +513,7 @@ in_guard(_, _, _) -> nope.
nonliteral(X) -> X.
-coerce_to_float(Config) when list(Config) ->
+coerce_to_float(Config) when is_list(Config) ->
?COF(0),
?COF(-1),
?COF(1),
@@ -444,3 +526,232 @@ coerce_to_float(Config) when list(Config) ->
?COF64(298748888888888888888888888883478264866528467367364766666666666666663),
?COF64(-367546729879999999999947826486652846736736476555566666663),
ok.
+
+bjorn(Config) when is_list(Config) ->
+ ?line error = bjorn_1(),
+ ok.
+
+bjorn_1() ->
+ Bitstr = <<7:13>>,
+ try
+ do_something()
+ catch
+ throw:blurf ->
+ ignore
+ end,
+ do_more(Bitstr, 13).
+
+do_more(Bin, Sz) ->
+ %% Previous bug in the bs_bits_to_bytes instruction: The exeption code
+ %% was not set - the previous exception (throw:blurf) would be used,
+ %% causing the catch to slip.
+ try <<Bin:Sz/binary>> of
+ _V -> ok
+ catch
+ error:_ ->
+ error
+ end.
+
+do_something() ->
+ throw(blurf).
+
+huge_float_field(Config) when is_list(Config) ->
+ ?line {'EXIT',{badarg,_}} = (catch <<0.0:9/float-unit:8>>),
+ ?line huge_float_check(catch <<0.0:67108865/float-unit:64>>),
+ ?line huge_float_check(catch <<0.0:((1 bsl 26)+1)/float-unit:64>>),
+ ?line huge_float_check(catch <<0.0:(id(67108865))/float-unit:64>>),
+%% ?line huge_float_check(catch <<0.0:((1 bsl 60)+1)/float-unit:64>>),
+ ?line huge_float_check(catch <<3839739387439387383739387987347983:((1 bsl 26)+1)/float-unit:64>>),
+%% ?line huge_float_check(catch <<3839739387439387383739387987347983:((1 bsl 60)+1)/float-unit:64>>),
+ ok.
+
+huge_float_check({'EXIT',{system_limit,_}}) -> ok;
+huge_float_check({'EXIT',{badarg,_}}) -> ok.
+
+huge_binary(Config) when is_list(Config) ->
+ ?line 16777216 = size(<<0:(id(1 bsl 26)),(-1):(id(1 bsl 26))>>),
+ ok.
+
+system_limit(Config) when is_list(Config) ->
+ WordSize = erlang:system_info(wordsize),
+ BitsPerWord = WordSize * 8,
+ ?line {'EXIT',{system_limit,_}} =
+ (catch <<0:(id(0)),42:(id(1 bsl BitsPerWord))>>),
+ ?line {'EXIT',{system_limit,_}} =
+ (catch <<42:(id(1 bsl BitsPerWord)),0:(id(0))>>),
+ ?line {'EXIT',{system_limit,_}} =
+ (catch <<(id(<<>>))/binary,0:(id(1 bsl 100))>>),
+
+ case WordSize of
+ 4 ->
+ system_limit_32();
+ 8 ->
+ ok
+ end.
+
+system_limit_32() ->
+ ?line {'EXIT',{badarg,_}} = (catch <<42:(-1)>>),
+ ?line {'EXIT',{badarg,_}} = (catch <<42:(id(-1))>>),
+ ?line {'EXIT',{badarg,_}} = (catch <<42:(id(-389739873536870912))/unit:8>>),
+ ?line {'EXIT',{system_limit,_}} = (catch <<42:536870912/unit:8>>),
+ ?line {'EXIT',{system_limit,_}} = (catch <<42:(id(536870912))/unit:8>>),
+ ?line {'EXIT',{system_limit,_}} = (catch <<0:(id(8)),42:536870912/unit:8>>),
+ ?line {'EXIT',{system_limit,_}} =
+ (catch <<0:(id(8)),42:(id(536870912))/unit:8>>),
+ ok.
+
+badarg(Config) when is_list(Config) ->
+ %% BEAM will generate a badarg exception for:
+ %% <<0:(id(1 bsl 100)),0:(id(-1))>>
+ %% but the debugger will generate a system_limit exception.
+ %% It does not seems worthwhile to fix the debugger.
+
+ ?line {'EXIT',{badarg,_}} =
+ (catch <<(id(<<>>))/binary,0:(id(-(1 bsl 100)))>>),
+
+ ok.
+
+copy_writable_binary(Config) when is_list(Config) ->
+ ?line [copy_writable_binary_1(I) || I <- lists:seq(0, 256)],
+ ok.
+
+copy_writable_binary_1(_) ->
+ ?line Bin0 = <<(id(<<>>))/binary,0,1,2,3,4,5,6,7>>,
+ ?line SubBin = make_sub_bin(Bin0),
+ ?line id(<<42,34,55,Bin0/binary>>), %Make reallocation likelier.
+ ?line Pid = spawn(fun() ->
+ copy_writable_binary_holder(Bin0, SubBin)
+ end),
+ ?line Tab = ets:new(holder, []),
+ ?line ets:insert(Tab, {17,Bin0}),
+ ?line ets:insert(Tab, {42,SubBin}),
+ ?line id(<<Bin0/binary,0:(64*1024*8)>>),
+ ?line Pid ! self(),
+ ?line [{17,Bin0}] = ets:lookup(Tab, 17),
+ ?line [{42,Bin0}] = ets:lookup(Tab, 42),
+ receive
+ {Pid,Bin0,Bin0} -> ok;
+ Other ->
+ io:format("Unexpected message: ~p", [Other]),
+ ?line ?t:fail()
+ end,
+ ok.
+
+copy_writable_binary_holder(Bin, SubBin) ->
+ receive
+ Pid ->
+ Pid ! {self(),Bin,SubBin}
+ end.
+
+make_sub_bin(Bin0) ->
+ N = bit_size(Bin0),
+ <<_:17,Bin:N/bitstring,_:5>> = <<(-1):17,Bin0/bitstring,(-1):5>>,
+ Bin = Bin0, %Assertion.
+ Bin.
+
+%% Test that different ways of using bit syntax instructions
+%% give the same result.
+
+dynamic(Config) when is_list(Config) ->
+ ?line dynamic_1(fun dynamic_big/5),
+ ?line dynamic_1(fun dynamic_little/5),
+ ok.
+
+dynamic_1(Dynamic) ->
+ <<Lpad:128>> = erlang:md5([0]),
+ <<Rpad:128>> = erlang:md5([1]),
+ <<Int:128>> = erlang:md5([2]),
+ 8385 = dynamic_2(0, {Int,Lpad,Rpad,Dynamic}, 0).
+
+dynamic_2(129, _, Count) -> Count;
+dynamic_2(Bef, Data, Count0) ->
+ Count = dynamic_3(Bef, 128-Bef, Data, Count0),
+ dynamic_2(Bef+1, Data, Count).
+
+dynamic_3(_, -1, _, Count) -> Count;
+dynamic_3(Bef, N, {Int0,Lpad,Rpad,Dynamic}=Data, Count) ->
+ Int1 = Int0 band ((1 bsl (N+3))-1),
+ Dynamic(Bef, N, Int1, Lpad, Rpad),
+ Dynamic(Bef, N, -Int1, Lpad, Rpad),
+
+ %% OTP-7085: Test a small number in a wide field.
+ Int2 = Int0 band 16#FFFFFF,
+ Dynamic(Bef, N, Int2, Lpad, Rpad),
+ Dynamic(Bef, N, -Int2, Lpad, Rpad),
+ dynamic_3(Bef, N-1, Data, Count+1).
+
+dynamic_big(Bef, N, Int, Lpad, Rpad) ->
+ NumBin = id(<<Int:N>>),
+ MaskedInt = Int band ((1 bsl N) - 1),
+ <<MaskedInt:N>> = NumBin,
+
+ %% Construct the binary in two different ways.
+ Bin = id(<<Lpad:Bef,NumBin/bitstring,Rpad:(128-Bef-N)>>),
+ Bin = <<Lpad:Bef,Int:N,Rpad:(128-Bef-N)>>,
+
+ %% Further verify the result by matching.
+ LpadMasked = Lpad band ((1 bsl Bef) - 1),
+ RpadMasked = Rpad band ((1 bsl (128-Bef-N)) - 1),
+ Rbits = (128-Bef-N),
+ <<LpadMasked:Bef,MaskedInt:N,RpadMasked:Rbits>> = id(Bin),
+ ok.
+
+dynamic_little(Bef, N, Int, Lpad, Rpad) ->
+ NumBin = id(<<Int:N/little>>),
+ MaskedInt = Int band ((1 bsl N) - 1),
+ <<MaskedInt:N/little>> = NumBin,
+
+ %% Construct the binary in two different ways.
+ Bin = id(<<Lpad:Bef/little,NumBin/bitstring,Rpad:(128-Bef-N)/little>>),
+ Bin = <<Lpad:Bef/little,Int:N/little,Rpad:(128-Bef-N)/little>>,
+
+ %% Further verify the result by matching.
+ LpadMasked = Lpad band ((1 bsl Bef) - 1),
+ RpadMasked = Rpad band ((1 bsl (128-Bef-N)) - 1),
+ Rbits = (128-Bef-N),
+ <<LpadMasked:Bef/little,MaskedInt:N/little,RpadMasked:Rbits/little>> = id(Bin),
+ ok.
+
+otp_7422(Config) when is_list(Config) ->
+ otp_7422_int(0),
+ otp_7422_bin(0).
+
+otp_7422_int(N) when N < 512 ->
+ T = erlang:make_tuple(N, []),
+ spawn_link(fun() ->
+ id(T),
+ %% A size of field 0 would write one byte beyond
+ %% the current position in the binary. It could
+ %% overwrite the continuation pointer stored on
+ %% the stack if HTOP was equal to E (the stack pointer).
+ id(<<0:(id(0))>>)
+ end),
+ otp_7422_int(N+1);
+otp_7422_int(_) -> ok.
+
+otp_7422_bin(N) when N < 512 ->
+ T = erlang:make_tuple(N, []),
+ Z = id(<<>>),
+ spawn_link(fun() ->
+ id(T),
+ id(<<Z:(id(0))/bits>>)
+ end),
+ otp_7422_bin(N+1);
+otp_7422_bin(_) -> ok.
+
+zero_width(Config) when is_list(Config) ->
+ ?line Z = id(0),
+ Small = id(42),
+ Big = id(1 bsl 128),
+ ?line <<>> = <<Small:Z>>,
+ ?line <<>> = <<Small:0>>,
+ ?line <<>> = <<Big:Z>>,
+ ?line <<>> = <<Big:0>>,
+
+ ?line {'EXIT',{badarg,_}} = (catch <<not_a_number:0>>),
+ ?line {'EXIT',{badarg,_}} = (catch <<(id(not_a_number)):Z>>),
+ ?line {'EXIT',{badarg,_}} = (catch <<(id(not_a_number)):0>>),
+
+ ok.
+
+id(I) -> I.
diff --git a/lib/debugger/test/bs_match_bin_SUITE.erl b/lib/debugger/test/bs_match_bin_SUITE.erl
index b42b84aef2..5a7c30f16b 100644
--- a/lib/debugger/test/bs_match_bin_SUITE.erl
+++ b/lib/debugger/test/bs_match_bin_SUITE.erl
@@ -24,14 +24,14 @@
-export([all/0, suite/0,groups/0,init_per_group/2,end_per_group/2,
init_per_testcase/2,end_per_testcase/2,
init_per_suite/1,end_per_suite/1,
- byte_split_binary/1,bit_split_binary/1]).
+ byte_split_binary/1,bit_split_binary/1,match_huge_bin/1]).
-include_lib("test_server/include/test_server.hrl").
suite() -> [{ct_hooks,[ts_install_cth]}].
all() ->
- cases().
+ [byte_split_binary, bit_split_binary, match_huge_bin].
groups() ->
[].
@@ -42,10 +42,6 @@ init_per_group(_GroupName, Config) ->
end_per_group(_GroupName, Config) ->
Config.
-
-cases() ->
- [byte_split_binary, bit_split_binary].
-
init_per_testcase(_Case, Config) ->
test_lib:interpret(?MODULE),
Dog = test_server:timetrap(?t:minutes(1)),
@@ -65,11 +61,12 @@ end_per_suite(Config) when is_list(Config) ->
ok.
byte_split_binary(doc) -> "Tries to split a binary at all byte-aligned positions.";
-byte_split_binary(suite) -> [];
-byte_split_binary(Config) when list(Config) ->
+byte_split_binary(Config) when is_list(Config) ->
?line L = lists:seq(0, 57),
?line B = mkbin(L),
- ?line byte_split(L, B, size(B)).
+ ?line byte_split(L, B, size(B)),
+ ?line Unaligned = make_unaligned_sub_binary(B),
+ ?line byte_split(L, Unaligned, size(Unaligned)).
byte_split(L, B, Pos) when Pos >= 0 ->
?line Sz1 = Pos,
@@ -78,18 +75,19 @@ byte_split(L, B, Pos) when Pos >= 0 ->
?line B1 = list_to_binary(lists:sublist(L, 1, Pos)),
?line B2 = list_to_binary(lists:nthtail(Pos, L)),
?line byte_split(L, B, Pos-1);
-byte_split(_L, _B, _) -> ok.
+byte_split(_, _, _) -> ok.
bit_split_binary(doc) -> "Tries to split a binary at all positions.";
-bit_split_binary(suite) -> [];
-bit_split_binary(Config) when list(Config) ->
+bit_split_binary(Config) when is_list(Config) ->
Fun = fun(Bin, List, SkipBef, N) ->
?line SkipAft = 8*size(Bin) - N - SkipBef,
- io:format("~p, ~p, ~p", [SkipBef,N,SkipAft]),
- ?line <<_I1:SkipBef,OutBin:N/binary-unit:1,_I2:SkipAft>> = Bin,
+ %%io:format("~p, ~p, ~p", [SkipBef,N,SkipAft]),
+ ?line <<_:SkipBef,OutBin:N/binary-unit:1,_:SkipAft>> = Bin,
?line OutBin = make_bin_from_list(List, N)
end,
?line bit_split_binary1(Fun, erlang:md5(<<1,2,3>>)),
+ ?line bit_split_binary1(Fun,
+ make_unaligned_sub_binary(erlang:md5(<<1,2,3>>))),
ok.
bit_split_binary1(Action, Bin) ->
@@ -99,24 +97,23 @@ bit_split_binary1(Action, Bin) ->
bit_split_binary2(Action, Bin, [_|T]=List, Bef) ->
bit_split_binary3(Action, Bin, List, Bef, size(Bin)*8),
bit_split_binary2(Action, Bin, T, Bef+1);
-bit_split_binary2(_Action, _Bin, [], _Bef) -> ok.
+bit_split_binary2(_, _, [], _) -> ok.
bit_split_binary3(Action, Bin, List, Bef, Aft) when Bef =< Aft ->
Action(Bin, List, Bef, (Aft-Bef) div 8 * 8),
bit_split_binary3(Action, Bin, List, Bef, Aft-8);
bit_split_binary3(_, _, _, _, _) -> ok.
-make_bin_from_list(_List, 0) ->
- mkbin([]);
+make_bin_from_list(_, 0) -> mkbin([]);
make_bin_from_list(List, N) ->
list_to_binary([make_int(List, 8, 0),
make_bin_from_list(lists:nthtail(8, List), N-8)]).
-make_int(_List, 0, Acc) -> Acc;
+make_int(_, 0, Acc) -> Acc;
make_int([H|T], N, Acc) -> make_int(T, N-1, Acc bsl 1 bor H).
-bits_to_list([_H|T], 0) -> bits_to_list(T, 16#80);
+bits_to_list([_|T], 0) -> bits_to_list(T, 16#80);
bits_to_list([H|_]=List, Mask) ->
[case H band Mask of
0 -> 0;
@@ -124,5 +121,109 @@ bits_to_list([H|_]=List, Mask) ->
end|bits_to_list(List, Mask bsr 1)];
bits_to_list([], _) -> [].
+mkbin(L) when is_list(L) -> list_to_binary(L).
+
+make_unaligned_sub_binary(Bin0) ->
+ Bin1 = <<0:3,Bin0/binary,31:5>>,
+ Sz = size(Bin0),
+ <<0:3,Bin:Sz/binary,31:5>> = id(Bin1),
+ Bin.
+
+id(I) -> I.
+
+match_huge_bin(Config) when is_list(Config) ->
+ ?line Bin = <<0:(1 bsl 27),13:8>>,
+ ?line skip_huge_bin_1(1 bsl 27, Bin),
+ ?line 16777216 = match_huge_bin_1(1 bsl 27, Bin),
+
+ %% Test overflowing the size of a binary field.
+ ?line nomatch = overflow_huge_bin_skip_32(Bin),
+ ?line nomatch = overflow_huge_bin_32(Bin),
+ ?line nomatch = overflow_huge_bin_skip_64(Bin),
+ ?line nomatch = overflow_huge_bin_64(Bin),
+
+ %% Size in variable
+ ?line ok = overflow_huge_bin(Bin, lists:seq(25, 32)++lists:seq(50, 64)),
+ ?line ok = overflow_huge_bin_unit128(Bin, lists:seq(25, 32)++lists:seq(50, 64)),
+
+ ok.
+
+overflow_huge_bin(Bin, [Sz0|Sizes]) ->
+ Sz = id(1 bsl Sz0),
+ case Bin of
+ <<_:Sz/binary-unit:8,0,_/binary>> ->
+ {error,Sz};
+ _ ->
+ case Bin of
+ <<NewBin:Sz/binary-unit:8,0,_/binary>> ->
+ {error,Sz,size(NewBin)};
+ _ ->
+ overflow_huge_bin(Bin, Sizes)
+ end
+ end;
+overflow_huge_bin(_, []) -> ok.
+
+overflow_huge_bin_unit128(Bin, [Sz0|Sizes]) ->
+ Sz = id(1 bsl Sz0),
+ case Bin of
+ <<_:Sz/binary-unit:128,0,_/binary>> ->
+ {error,Sz};
+ _ ->
+ case Bin of
+ <<NewBin:Sz/binary-unit:128,0,_/binary>> ->
+ {error,Sz,size(NewBin)};
+ _ ->
+ overflow_huge_bin_unit128(Bin, Sizes)
+ end
+ end;
+overflow_huge_bin_unit128(_, []) -> ok.
+
+skip_huge_bin_1(I, Bin) ->
+ <<_:I/binary-unit:1,13>> = Bin,
+ ok.
-mkbin(L) when list(L) -> list_to_binary(L).
+match_huge_bin_1(I, Bin) ->
+ case Bin of
+ <<Val:I/binary-unit:1,13>> -> size(Val);
+ _ -> nomatch
+ end.
+
+overflow_huge_bin_skip_32(<<_:4294967296/binary,0,_/binary>>) -> 1; % 1 bsl 32
+overflow_huge_bin_skip_32(<<_:33554432/binary-unit:128,0,_/binary>>) -> 2; % 1 bsl 25
+overflow_huge_bin_skip_32(<<_:67108864/binary-unit:64,0,_/binary>>) -> 3; % 1 bsl 26
+overflow_huge_bin_skip_32(<<_:134217728/binary-unit:32,0,_/binary>>) -> 4; % 1 bsl 27
+overflow_huge_bin_skip_32(<<_:268435456/binary-unit:16,0,_/binary>>) -> 5; % 1 bsl 28
+overflow_huge_bin_skip_32(<<_:536870912/binary-unit:8,0,_/binary>>) -> 6; % 1 bsl 29
+overflow_huge_bin_skip_32(<<_:1073741824/binary-unit:8,0,_/binary>>) -> 7; % 1 bsl 30
+overflow_huge_bin_skip_32(<<_:2147483648/binary-unit:8,0,_/binary>>) -> 8; % 1 bsl 31
+overflow_huge_bin_skip_32(_) -> nomatch.
+
+overflow_huge_bin_32(<<Bin:4294967296/binary,_/binary>>) -> {1,Bin}; % 1 bsl 32
+overflow_huge_bin_32(<<Bin:33554432/binary-unit:128,0,_/binary>>) -> {2,Bin}; % 1 bsl 25
+overflow_huge_bin_32(<<Bin:67108864/binary-unit:128,0,_/binary>>) -> {3,Bin}; % 1 bsl 26
+overflow_huge_bin_32(<<Bin:134217728/binary-unit:128,0,_/binary>>) -> {4,Bin}; % 1 bsl 27
+overflow_huge_bin_32(<<Bin:268435456/binary-unit:128,0,_/binary>>) -> {5,Bin}; % 1 bsl 28
+overflow_huge_bin_32(<<Bin:536870912/binary-unit:128,0,_/binary>>) -> {6,Bin}; % 1 bsl 29
+overflow_huge_bin_32(<<Bin:1073741824/binary-unit:128,0,_/binary>>) -> {7,Bin}; % 1 bsl 30
+overflow_huge_bin_32(<<Bin:2147483648/binary-unit:128,0,_/binary>>) -> {8,Bin}; % 1 bsl 31
+overflow_huge_bin_32(_) -> nomatch.
+
+overflow_huge_bin_skip_64(<<_:18446744073709551616/binary,0,_/binary>>) -> 1; % 1 bsl 64
+overflow_huge_bin_skip_64(<<_:144115188075855872/binary-unit:128,0,_/binary>>) -> 2; % 1 bsl 57
+overflow_huge_bin_skip_64(<<_:288230376151711744/binary-unit:64,0,_/binary>>) -> 3; % 1 bsl 58
+overflow_huge_bin_skip_64(<<_:576460752303423488/binary-unit:32,0,_/binary>>) -> 4; % 1 bsl 59
+overflow_huge_bin_skip_64(<<_:1152921504606846976/binary-unit:16,0,_/binary>>) -> 5; % 1 bsl 60
+overflow_huge_bin_skip_64(<<_:2305843009213693952/binary-unit:8,0,_/binary>>) -> 6; % 1 bsl 61
+overflow_huge_bin_skip_64(<<_:4611686018427387904/binary-unit:8,0,_/binary>>) -> 7; % 1 bsl 62
+overflow_huge_bin_skip_64(<<_:9223372036854775808/binary-unit:8,_/binary>>) -> 8; % 1 bsl 63
+overflow_huge_bin_skip_64(_) -> nomatch.
+
+overflow_huge_bin_64(<<Bin:18446744073709551616/binary,_/binary>>) -> {1,Bin}; % 1 bsl 64
+overflow_huge_bin_64(<<Bin:144115188075855872/binary-unit:128,0,_/binary>>) -> {2,Bin}; % 1 bsl 57
+overflow_huge_bin_64(<<Bin:288230376151711744/binary-unit:128,0,_/binary>>) -> {3,Bin}; % 1 bsl 58
+overflow_huge_bin_64(<<Bin:576460752303423488/binary-unit:128,0,_/binary>>) -> {4,Bin}; % 1 bsl 59
+overflow_huge_bin_64(<<Bin:1152921504606846976/binary-unit:128,0,_/binary>>) -> {5,Bin}; % 1 bsl 60
+overflow_huge_bin_64(<<Bin:2305843009213693952/binary-unit:128,0,_/binary>>) -> {6,Bin}; % 1 bsl 61
+overflow_huge_bin_64(<<Bin:4611686018427387904/binary-unit:128,0,_/binary>>) -> {7,Bin}; % 1 bsl 62
+overflow_huge_bin_64(<<Bin:9223372036854775808/binary-unit:128,0,_/binary>>) -> {8,Bin}; % 1 bsl 63
+overflow_huge_bin_64(_) -> nomatch.
diff --git a/lib/debugger/test/bs_match_int_SUITE.erl b/lib/debugger/test/bs_match_int_SUITE.erl
index 745368fdfc..bff5f8ff65 100644
--- a/lib/debugger/test/bs_match_int_SUITE.erl
+++ b/lib/debugger/test/bs_match_int_SUITE.erl
@@ -19,11 +19,11 @@
-module(bs_match_int_SUITE).
--author('[email protected]').
-export([all/0, suite/0,groups/0,init_per_group/2,end_per_group/2,
init_per_testcase/2,end_per_testcase/2,
init_per_suite/1,end_per_suite/1,
- integer/1,signed_integer/1,dynamic/1,more_dynamic/1,mml/1]).
+ integer/1,signed_integer/1,dynamic/1,more_dynamic/1,mml/1,
+ match_huge_int/1,bignum/1,unaligned_32_bit/1]).
-include_lib("test_server/include/test_server.hrl").
@@ -32,7 +32,8 @@
suite() -> [{ct_hooks,[ts_install_cth]}].
all() ->
- [cases()].
+ [integer, signed_integer, dynamic, more_dynamic, mml,
+ match_huge_int, bignum, unaligned_32_bit].
groups() ->
[].
@@ -43,10 +44,6 @@ init_per_group(_GroupName, Config) ->
end_per_group(_GroupName, Config) ->
Config.
-
-cases() ->
- [integer, signed_integer, dynamic, more_dynamic, mml].
-
init_per_testcase(_Case, Config) ->
test_lib:interpret(?MODULE),
Dog = test_server:timetrap(?t:minutes(4)),
@@ -65,8 +62,7 @@ init_per_suite(Config) when is_list(Config) ->
end_per_suite(Config) when is_list(Config) ->
ok.
-integer(suite) -> [];
-integer(Config) when list(Config) ->
+integer(Config) when is_list(Config) ->
?line 0 = get_int(mkbin([])),
?line 0 = get_int(mkbin([0])),
?line 42 = get_int(mkbin([42])),
@@ -78,22 +74,33 @@ integer(Config) when list(Config) ->
?line 65534 = get_int(mkbin([255,254])),
?line 16776455 = get_int(mkbin([255,253,7])),
?line 4245492555 = get_int(mkbin([253,13,19,75])),
+ ?line 4294967294 = get_int(mkbin([255,255,255,254])),
+ ?line 4294967295 = get_int(mkbin([255,255,255,255])),
?line Eight = [200,1,19,128,222,42,97,111],
?line cmp128(Eight, uint(Eight)),
?line fun_clause(catch get_int(mkbin(seq(1,5)))),
ok.
-get_int(<<I:0>>) -> I;
-get_int(<<I:8>>) -> I;
-get_int(<<I:16>>) -> I;
-get_int(<<I:24>>) -> I;
-get_int(<<I:32>>) -> I.
+get_int(Bin) ->
+ I = get_int1(Bin),
+ get_int(Bin, I).
+
+get_int(Bin0, I) when size(Bin0) < 4 ->
+ Bin = <<0,Bin0/binary>>,
+ I = get_int1(Bin),
+ get_int(Bin, I);
+get_int(_, I) -> I.
+
+get_int1(<<I:0>>) -> I;
+get_int1(<<I:8>>) -> I;
+get_int1(<<I:16>>) -> I;
+get_int1(<<I:24>>) -> I;
+get_int1(<<I:32>>) -> I.
cmp128(<<I:128>>, I) -> equal;
-cmp128(_B, _I) -> not_equal.
+cmp128(_, _) -> not_equal.
-signed_integer(suite) -> [];
-signed_integer(Config) when list(Config) ->
+signed_integer(Config) when is_list(Config) ->
?line {no_match,_} = sint(mkbin([])),
?line {no_match,_} = sint(mkbin([1,2,3])),
?line 127 = sint(mkbin([127])),
@@ -113,7 +120,7 @@ uint(L) -> uint(L, 0).
uint([H|T], Acc) -> uint(T, Acc bsl 8 bor H);
uint([], Acc) -> Acc.
-dynamic(Config) when list(Config) ->
+dynamic(Config) when is_list(Config) ->
dynamic(mkbin([255]), 8),
dynamic(mkbin([255,255]), 16),
dynamic(mkbin([255,255,255]), 24),
@@ -124,7 +131,7 @@ dynamic(Bin, S1) when S1 >= 0 ->
S2 = size(Bin) * 8 - S1,
dynamic(Bin, S1, S2, (1 bsl S1) - 1, (1 bsl S2) - 1),
dynamic(Bin, S1-1);
-dynamic(_Bin, _) -> ok.
+dynamic(_, _) -> ok.
dynamic(Bin, S1, S2, A, B) ->
% io:format("~p ~p ~p ~p\n", [S1,S2,A,B]),
@@ -132,25 +139,24 @@ dynamic(Bin, S1, S2, A, B) ->
<<A:S1,B:S2>> ->
io:format("~p ~p ~p ~p\n", [S1,S2,A,B]),
ok;
- _Other ->
- erlang:error(badmatch, [Bin,S1,S2,A,B])
+ _Other -> erlang:error(badmatch, [Bin,S1,S2,A,B])
end.
more_dynamic(doc) -> "Extract integers at different alignments and of different sizes.";
-more_dynamic(Config) when list(Config) ->
+more_dynamic(Config) when is_list(Config) ->
% Unsigned big-endian numbers.
Unsigned = fun(Bin, List, SkipBef, N) ->
SkipAft = 8*size(Bin) - N - SkipBef,
- <<_I1:SkipBef,Int:N,_I2:SkipAft>> = Bin,
+ <<_:SkipBef,Int:N,_:SkipAft>> = Bin,
Int = make_int(List, N, 0)
end,
?line more_dynamic1(Unsigned, funny_binary(42)),
- % Signed big-endian numbers.
+ %% Signed big-endian numbers.
Signed = fun(Bin, List, SkipBef, N) ->
SkipAft = 8*size(Bin) - N - SkipBef,
- <<_I1:SkipBef,Int:N/signed,_I2:SkipAft>> = Bin,
+ <<_:SkipBef,Int:N/signed,_:SkipAft>> = Bin,
case make_signed_int(List, N) of
Int -> ok;
Other ->
@@ -162,18 +168,18 @@ more_dynamic(Config) when list(Config) ->
end,
?line more_dynamic1(Signed, funny_binary(43)),
- % Unsigned little-endian numbers.
+ %% Unsigned little-endian numbers.
UnsLittle = fun(Bin, List, SkipBef, N) ->
SkipAft = 8*size(Bin) - N - SkipBef,
- <<_I1:SkipBef,Int:N/little,_I2:SkipAft>> = Bin,
+ <<_:SkipBef,Int:N/little,_:SkipAft>> = Bin,
Int = make_int(big_to_little(List, N), N, 0)
end,
?line more_dynamic1(UnsLittle, funny_binary(44)),
- % Signed little-endian numbers.
+ %% Signed little-endian numbers.
SignLittle = fun(Bin, List, SkipBef, N) ->
SkipAft = 8*size(Bin) - N - SkipBef,
- <<_I1:SkipBef,Int:N/signed-little,_I2:SkipAft>> = Bin,
+ <<_:SkipBef,Int:N/signed-little,_:SkipAft>> = Bin,
Little = big_to_little(List, N),
Int = make_signed_int(Little, N)
end,
@@ -181,11 +187,6 @@ more_dynamic(Config) when list(Config) ->
ok.
-funny_binary(N) ->
- B0 = erlang:md5([N]),
- {B1,_B2} = split_binary(B0, size(B0) div 2),
- B1.
-
more_dynamic1(Action, Bin) ->
BitList = bits_to_list(binary_to_list(Bin), 16#80),
more_dynamic2(Action, Bin, BitList, 0).
@@ -193,7 +194,7 @@ more_dynamic1(Action, Bin) ->
more_dynamic2(Action, Bin, [_|T]=List, Bef) ->
more_dynamic3(Action, Bin, List, Bef, size(Bin)*8),
more_dynamic2(Action, Bin, T, Bef+1);
-more_dynamic2(_Action, _Bin, [], _Bef) -> ok.
+more_dynamic2(_, _, [], _) -> ok.
more_dynamic3(Action, Bin, List, Bef, Aft) when Bef =< Aft ->
%% io:format("~p, ~p", [Bef,Aft-Bef]),
@@ -208,8 +209,8 @@ big_to_little([B0,B1,B2,B3,B4,B5,B6,B7|T], N, Acc) when N >= 8 ->
big_to_little(List, N, Acc) -> lists:sublist(List, 1, N) ++ Acc.
make_signed_int(_List, 0) -> 0;
-make_signed_int([0|_T]=List, N) -> make_int(List, N, 0);
-make_signed_int([1|_T]=List0, N) ->
+make_signed_int([0|_]=List, N) -> make_int(List, N, 0);
+make_signed_int([1|_]=List0, N) ->
List1 = reversed_sublist(List0, N, []),
List2 = two_complement_and_reverse(List1, 1, []),
-make_int(List2, length(List2), 0).
@@ -225,7 +226,7 @@ two_complement_and_reverse([], Carry, Acc) -> [Carry|Acc].
make_int(_List, 0, Acc) -> Acc;
make_int([H|T], N, Acc) -> make_int(T, N-1, Acc bsl 1 bor H).
-bits_to_list([_H|T], 0) -> bits_to_list(T, 16#80);
+bits_to_list([_|T], 0) -> bits_to_list(T, 16#80);
bits_to_list([H|_]=List, Mask) ->
[case H band Mask of
0 -> 0;
@@ -234,11 +235,134 @@ bits_to_list([H|_]=List, Mask) ->
bits_to_list([], _) -> [].
fun_clause({'EXIT',{function_clause,_}}) -> ok.
-mkbin(L) when list(L) -> list_to_binary(L).
+mkbin(L) when is_list(L) -> list_to_binary(L).
+
+funny_binary(N) ->
+ B0 = erlang:md5([N]),
+ {B1,_B2} = split_binary(B0, byte_size(B0) div 3),
+ B1.
-mml(Config) when list(Config) ->
+mml(Config) when is_list(Config) ->
?line single_byte_binary = mml_choose(<<42>>),
?line multi_byte_binary = mml_choose(<<42,43>>).
mml_choose(<<_A:8>>) -> single_byte_binary;
-mml_choose(<<_A:8, _T/binary>>) -> multi_byte_binary.
+mml_choose(<<_A:8,_T/binary>>) -> multi_byte_binary.
+
+match_huge_int(Config) when is_list(Config) ->
+ Sz = 1 bsl 27,
+ ?line Bin = <<0:Sz,13:8>>,
+ ?line skip_huge_int_1(Sz, Bin),
+ ?line 0 = match_huge_int_1(Sz, Bin),
+
+ %% Test overflowing the size of an integer field.
+ ?line nomatch = overflow_huge_int_skip_32(Bin),
+ case erlang:system_info(wordsize) of
+ 4 ->
+ ?line nomatch = overflow_huge_int_32(Bin);
+ 8 ->
+ %% An attempt will be made to allocate heap space for
+ %% the bignum (which will probably fail); only if the
+ %% allocation succeds will the matching fail because
+ %% the binary is too small.
+ ok
+ end,
+ ?line nomatch = overflow_huge_int_skip_64(Bin),
+ ?line nomatch = overflow_huge_int_64(Bin),
+
+ %% Test overflowing the size of an integer field using variables as sizes.
+ ?line Sizes = case erlang:system_info(wordsize) of
+ 4 -> lists:seq(25, 32);
+ 8 -> []
+ end ++ lists:seq(50, 64),
+ ?line ok = overflow_huge_int_unit128(Bin, Sizes),
+
+ ok.
+
+overflow_huge_int_unit128(Bin, [Sz0|Sizes]) ->
+ Sz = id(1 bsl Sz0),
+ case Bin of
+ <<_:Sz/unit:128,0,_/binary>> ->
+ {error,Sz};
+ _ ->
+ case Bin of
+ <<Var:Sz/unit:128,0,_/binary>> ->
+ {error,Sz,Var};
+ _ ->
+ overflow_huge_int_unit128(Bin, Sizes)
+ end
+ end;
+overflow_huge_int_unit128(_, []) -> ok.
+
+match_huge_int_1(I, Bin) ->
+ <<Int:I,13>> = Bin,
+ Int.
+
+skip_huge_int_1(I, Bin) ->
+ <<_:I,13>> = Bin.
+
+overflow_huge_int_skip_32(<<_:4294967296,0,_/binary>>) -> 1; % 1 bsl 32
+overflow_huge_int_skip_32(<<_:33554432/unit:128,0,_/binary>>) -> 2; % 1 bsl 25
+overflow_huge_int_skip_32(<<_:67108864/unit:64,0,_/binary>>) -> 3; % 1 bsl 26
+overflow_huge_int_skip_32(<<_:134217728/unit:32,0,_/binary>>) -> 4; % 1 bsl 27
+overflow_huge_int_skip_32(<<_:268435456/unit:16,0,_/binary>>) -> 5; % 1 bsl 28
+overflow_huge_int_skip_32(<<_:536870912/unit:8,0,_/binary>>) -> 6; % 1 bsl 29
+overflow_huge_int_skip_32(<<_:1073741824/unit:8,0,_/binary>>) -> 7; % 1 bsl 30
+overflow_huge_int_skip_32(<<_:2147483648/unit:8,0,_/binary>>) -> 8; % 1 bsl 31
+overflow_huge_int_skip_32(_) -> nomatch.
+
+overflow_huge_int_32(<<Int:4294967296,_/binary>>) -> {1,Int}; % 1 bsl 32
+overflow_huge_int_32(<<Int:33554432/unit:128,0,_/binary>>) -> {2,Int}; % 1 bsl 25
+overflow_huge_int_32(<<Int:67108864/unit:128,0,_/binary>>) -> {3,Int}; % 1 bsl 26
+overflow_huge_int_32(<<Int:134217728/unit:128,0,_/binary>>) -> {4,Int}; % 1 bsl 27
+overflow_huge_int_32(<<Int:268435456/unit:128,0,_/binary>>) -> {5,Int}; % 1 bsl 28
+overflow_huge_int_32(<<Int:536870912/unit:128,0,_/binary>>) -> {6,Int}; % 1 bsl 29
+overflow_huge_int_32(<<Int:1073741824/unit:128,0,_/binary>>) -> {7,Int}; % 1 bsl 30
+overflow_huge_int_32(<<Int:2147483648/unit:128,0,_/binary>>) -> {8,Int}; % 1 bsl 31
+overflow_huge_int_32(_) -> nomatch.
+
+overflow_huge_int_skip_64(<<_:18446744073709551616,_/binary>>) -> 1; % 1 bsl 64
+overflow_huge_int_skip_64(<<_:144115188075855872/unit:128,0,_/binary>>) -> 2; % 1 bsl 57
+overflow_huge_int_skip_64(<<_:288230376151711744/unit:64,0,_/binary>>) -> 3; % 1 bsl 58
+overflow_huge_int_skip_64(<<_:576460752303423488/unit:32,0,_/binary>>) -> 4; % 1 bsl 59
+overflow_huge_int_skip_64(<<_:1152921504606846976/unit:16,0,_/binary>>) -> 5; % 1 bsl 60
+overflow_huge_int_skip_64(<<_:2305843009213693952/unit:8,0,_/binary>>) -> 6; % 1 bsl 61
+overflow_huge_int_skip_64(<<_:4611686018427387904/unit:8,0,_/binary>>) -> 7; % 1 bsl 62
+overflow_huge_int_skip_64(<<_:9223372036854775808/unit:8,0,_/binary>>) -> 8; % 1 bsl 63
+overflow_huge_int_skip_64(_) -> nomatch.
+
+overflow_huge_int_64(<<Int:18446744073709551616,_/binary>>) -> {1,Int}; % 1 bsl 64
+overflow_huge_int_64(<<Int:144115188075855872/unit:128,0,_/binary>>) -> {2,Int}; % 1 bsl 57
+overflow_huge_int_64(<<Int:288230376151711744/unit:128,0,_/binary>>) -> {3,Int}; % 1 bsl 58
+overflow_huge_int_64(<<Int:576460752303423488/unit:128,0,_/binary>>) -> {4,Int}; % 1 bsl 59
+overflow_huge_int_64(<<Int:1152921504606846976/unit:128,0,_/binary>>) -> {5,Int}; % 1 bsl 60
+overflow_huge_int_64(<<Int:2305843009213693952/unit:128,0,_/binary>>) -> {6,Int}; % 1 bsl 61
+overflow_huge_int_64(<<Int:4611686018427387904/unit:128,0,_/binary>>) -> {7,Int}; % 1 bsl 62
+overflow_huge_int_64(<<Int:9223372036854775808/unit:128,0,_/binary>>) -> {8,Int}; % 1 bsl 63
+overflow_huge_int_64(_) -> nomatch.
+
+bignum(Config) when is_list(Config) ->
+ ?line Bin = id(<<42,0:1024/unit:8,43>>),
+ ?line <<42:1025/little-integer-unit:8,_:8>> = Bin,
+ ?line <<_:8,43:1025/integer-unit:8>> = Bin,
+
+ ?line BignumBin = id(<<0:512/unit:8,258254417031933722623:9/unit:8>>),
+ ?line <<258254417031933722623:(512+9)/unit:8>> = BignumBin,
+ erlang:garbage_collect(), %Search for holes in debug-build.
+ ok.
+
+unaligned_32_bit(Config) when is_list(Config) ->
+ %% There used to be a risk for heap overflow (fixed in R11B-5).
+ ?line L = unaligned_32_bit_1(<<-1:(64*1024)>>),
+ ?line unaligned_32_bit_verify(L, 1638).
+
+unaligned_32_bit_1(<<1:1,U:32,_:7,T/binary>>) ->
+ [U|unaligned_32_bit_1(T)];
+unaligned_32_bit_1(_) ->
+ [].
+
+unaligned_32_bit_verify([], 0) -> ok;
+unaligned_32_bit_verify([4294967295|T], N) when N > 0 ->
+ unaligned_32_bit_verify(T, N-1).
+
+id(I) -> I.
diff --git a/lib/debugger/test/bs_match_misc_SUITE.erl b/lib/debugger/test/bs_match_misc_SUITE.erl
index 53d11ba179..89fce263f5 100644
--- a/lib/debugger/test/bs_match_misc_SUITE.erl
+++ b/lib/debugger/test/bs_match_misc_SUITE.erl
@@ -19,18 +19,24 @@
-module(bs_match_misc_SUITE).
--author('[email protected]').
-export([all/0, suite/0,groups/0,init_per_group/2,end_per_group/2,
init_per_testcase/2,end_per_testcase/2,
init_per_suite/1,end_per_suite/1,
- bound_var/1,bound_tail/1,t_float/1,little_float/1,sean/1]).
+ bound_var/1,bound_tail/1,t_float/1,little_float/1,sean/1,
+ kenneth/1,encode_binary/1,native/1,happi/1,
+ size_var/1,wiger/1,x0_context/1,huge_float_field/1,
+ writable_binary_matched/1,otp_7198/1,
+ unordered_bindings/1]).
-include_lib("test_server/include/test_server.hrl").
suite() -> [{ct_hooks,[ts_install_cth]}].
all() ->
- cases().
+ [bound_var, bound_tail, t_float, little_float, sean,
+ kenneth, encode_binary, native, happi, size_var, wiger,
+ x0_context, huge_float_field, writable_binary_matched,
+ otp_7198, unordered_bindings].
groups() ->
[].
@@ -41,9 +47,13 @@ init_per_group(_GroupName, Config) ->
end_per_group(_GroupName, Config) ->
Config.
+init_per_suite(Config) when is_list(Config) ->
+ ?line test_lib:interpret(?MODULE),
+ ?line true = lists:member(?MODULE, int:interpreted()),
+ Config.
-cases() ->
- [bound_var, bound_tail, t_float, little_float, sean].
+end_per_suite(Config) when is_list(Config) ->
+ ok.
init_per_testcase(_Case, Config) ->
test_lib:interpret(?MODULE),
@@ -55,16 +65,8 @@ end_per_testcase(_Case, Config) ->
?t:timetrap_cancel(Dog),
ok.
-init_per_suite(Config) when is_list(Config) ->
- ?line test_lib:interpret(?MODULE),
- ?line true = lists:member(?MODULE, int:interpreted()),
- Config.
-
-end_per_suite(Config) when is_list(Config) ->
- ok.
-
bound_var(doc) -> "Test matching of bound variables.";
-bound_var(Config) when list(Config) ->
+bound_var(Config) when is_list(Config) ->
?line ok = bound_var(42, 13, <<42,13>>),
?line nope = bound_var(42, 13, <<42,255>>),
?line nope = bound_var(42, 13, <<154,255>>),
@@ -74,7 +76,7 @@ bound_var(A, B, <<A:8,B:8>>) -> ok;
bound_var(_, _, _) -> nope.
bound_tail(doc) -> "Test matching of a bound tail.";
-bound_tail(Config) when list(Config) ->
+bound_tail(Config) when is_list(Config) ->
?line ok = bound_tail(<<>>, <<13,14>>),
?line ok = bound_tail(<<2,3>>, <<1,1,2,3>>),
?line nope = bound_tail(<<2,3>>, <<1,1,2,7>>),
@@ -85,7 +87,7 @@ bound_tail(Config) when list(Config) ->
bound_tail(T, <<_:16,T/binary>>) -> ok;
bound_tail(_, _) -> nope.
-t_float(Config) when list(Config) ->
+t_float(Config) when is_list(Config) ->
F = f1(),
G = f_one(),
@@ -98,6 +100,10 @@ t_float(Config) when list(Config) ->
?line fcmp(F, match_float(<<1:1,F:64/float,127:7>>, 64, 1)),
?line fcmp(F, match_float(<<1:13,F:32/float,127:3>>, 32, 13)),
?line fcmp(F, match_float(<<1:13,F:64/float,127:3>>, 64, 13)),
+
+ ?line {'EXIT',{{badmatch,_},_}} = (catch match_float(<<0,0>>, 16, 0)),
+ ?line {'EXIT',{{badmatch,_},_}} = (catch match_float(<<0,0>>, 16#7fffffff, 0)),
+
ok.
@@ -110,7 +116,7 @@ match_float(Bin0, Fsz, I) ->
<<_:I,F:Fsz/float,_:Tsz>> = Bin,
F.
-little_float(Config) when list(Config) ->
+little_float(Config) when is_list(Config) ->
F = f2(),
G = f_one(),
@@ -149,7 +155,7 @@ f2() ->
f_one() ->
1.0.
-sean(Config) when list(Config) ->
+sean(Config) when is_list(Config) ->
?line small = sean1(<<>>),
?line small = sean1(<<1>>),
?line small = sean1(<<1,2>>),
@@ -162,5 +168,414 @@ sean(Config) when list(Config) ->
?line {'EXIT',{function_clause,_}} = (catch sean1(<<4,5,6,7>>)),
ok.
-sean1(<<B/binary>>) when size(B) < 4 -> small;
+sean1(<<B/binary>>) when byte_size(B) < 4 -> small;
sean1(<<1, _B/binary>>) -> large.
+
+kenneth(Config) when is_list(Config) ->
+ {ok,[145,148,113,129,0,0,0,0]} =
+ msisdn_internal_storage(<<145,148,113,129,0,0,0,0>>, []).
+
+msisdn_internal_storage(<<>>,MSISDN) ->
+ {ok,lists:reverse(MSISDN)};
+msisdn_internal_storage(<<2#11111111:8,_Rest/binary>>,MSISDN) ->
+ {ok,lists:reverse(MSISDN)};
+msisdn_internal_storage(<<2#1111:4,DigitN:4,_Rest/binary>>,MSISDN) when
+ DigitN < 10 ->
+ {ok,lists:reverse([(DigitN bor 2#11110000)|MSISDN])};
+msisdn_internal_storage(<<DigitNplus1:4,DigitN:4,Rest/binary>>,MSISDN) when
+ DigitNplus1 < 10,
+ DigitN < 10 ->
+ NewMSISDN=[((DigitNplus1 bsl 4) bor DigitN)|MSISDN],
+ msisdn_internal_storage(Rest,NewMSISDN);
+msisdn_internal_storage(_Rest,_MSISDN) ->
+ {fault}. %% Mandatory IE incorrect
+
+encode_binary(Config) when is_list(Config) ->
+ "C2J2QiSc" = encodeBinary(<<11,98,118,66,36,156>>, []),
+ ok.
+
+encodeBinary(<<>>, Output) ->
+ lists:reverse(Output);
+encodeBinary(<<Data:1/binary>>, Output) ->
+ <<DChar1:6, DChar2:2>> = Data,
+ Char1 = getBase64Char(DChar1),
+ Char2 = getBase64Char(DChar2),
+ Char3 = "=",
+ Char4 = "=",
+ NewOutput = Char4 ++ Char3 ++ Char2 ++ Char1 ++ Output,
+ encodeBinary(<<>>, NewOutput);
+encodeBinary(<<Data:2/binary>>, Output) ->
+ <<DChar1:6, DChar2:6, DChar3:4>> = Data,
+ Char1 = getBase64Char(DChar1),
+ Char2 = getBase64Char(DChar2),
+ Char3 = getBase64Char(DChar3),
+ Char4 = "=",
+ NewOutput = Char4 ++ Char3 ++ Char2 ++ Char1 ++ Output,
+ encodeBinary(<<>>, NewOutput);
+encodeBinary(<<Data:3/binary, Rest/binary>>, Output) ->
+ <<DChar1:6, DChar2:6, DChar3:6, DChar4:6>> = Data,
+ Char1 = getBase64Char(DChar1),
+ Char2 = getBase64Char(DChar2),
+ Char3 = getBase64Char(DChar3),
+ Char4 = getBase64Char(DChar4),
+ NewOutput = Char4 ++ Char3 ++ Char2 ++ Char1 ++ Output,
+ encodeBinary(Rest, NewOutput);
+encodeBinary(_Data, _) ->
+ error.
+
+getBase64Char(0) -> "A";
+getBase64Char(1) -> "B";
+getBase64Char(2) -> "C";
+getBase64Char(3) -> "D";
+getBase64Char(4) -> "E";
+getBase64Char(5) -> "F";
+getBase64Char(6) -> "G";
+getBase64Char(7) -> "H";
+getBase64Char(8) -> "I";
+getBase64Char(9) -> "J";
+getBase64Char(10) -> "K";
+getBase64Char(11) -> "L";
+getBase64Char(12) -> "M";
+getBase64Char(13) -> "N";
+getBase64Char(14) -> "O";
+getBase64Char(15) -> "P";
+getBase64Char(16) -> "Q";
+getBase64Char(17) -> "R";
+getBase64Char(18) -> "S";
+getBase64Char(19) -> "T";
+getBase64Char(20) -> "U";
+getBase64Char(21) -> "V";
+getBase64Char(22) -> "W";
+getBase64Char(23) -> "X";
+getBase64Char(24) -> "Y";
+getBase64Char(25) -> "Z";
+getBase64Char(26) -> "a";
+getBase64Char(27) -> "b";
+getBase64Char(28) -> "c";
+getBase64Char(29) -> "d";
+getBase64Char(30) -> "e";
+getBase64Char(31) -> "f";
+getBase64Char(32) -> "g";
+getBase64Char(33) -> "h";
+getBase64Char(34) -> "i";
+getBase64Char(35) -> "j";
+getBase64Char(36) -> "k";
+getBase64Char(37) -> "l";
+getBase64Char(38) -> "m";
+getBase64Char(39) -> "n";
+getBase64Char(40) -> "o";
+getBase64Char(41) -> "p";
+getBase64Char(42) -> "q";
+getBase64Char(43) -> "r";
+getBase64Char(44) -> "s";
+getBase64Char(45) -> "t";
+getBase64Char(46) -> "u";
+getBase64Char(47) -> "v";
+getBase64Char(48) -> "w";
+getBase64Char(49) -> "x";
+getBase64Char(50) -> "y";
+getBase64Char(51) -> "z";
+getBase64Char(52) -> "0";
+getBase64Char(53) -> "1";
+getBase64Char(54) -> "2";
+getBase64Char(55) -> "3";
+getBase64Char(56) -> "4";
+getBase64Char(57) -> "5";
+getBase64Char(58) -> "6";
+getBase64Char(59) -> "7";
+getBase64Char(60) -> "8";
+getBase64Char(61) -> "9";
+getBase64Char(62) -> "+";
+getBase64Char(63) -> "/";
+getBase64Char(_Else) ->
+ %% This is an illegal input.
+% cgLogEM:log(error, ?MODULE, getBase64Char, [Else],
+% "illegal input",
+% ?LINE, version()),
+ "**".
+
+-define(M(F), <<F>> = <<F>>).
+
+native(Config) when is_list(Config) ->
+ ?line ?M(3.14:64/native-float),
+ ?line ?M(333:16/native),
+ ?line ?M(38658345:32/native),
+ case <<1:16/native>> of
+ <<0,1>> -> native_big();
+ <<1,0>> -> native_little()
+ end.
+
+native_big() ->
+ ?line <<37.33:64/native-float>> = <<37.33:64/big-float>>,
+ ?line <<3974:16/native-integer>> = <<3974:16/big-integer>>,
+ {comment,"Big endian"}.
+
+native_little() ->
+ ?line <<37869.32343:64/native-float>> = <<37869.32343:64/little-float>>,
+ ?line <<7974:16/native-integer>> = <<7974:16/little-integer>>,
+ {comment,"Little endian"}.
+
+happi(Config) when is_list(Config) ->
+ Bin = <<".123">>,
+ ?line <<"123">> = lex_digits1(Bin, 1, []),
+ ?line <<"123">> = lex_digits2(Bin, 1, []),
+ ok.
+
+lex_digits1(<<$., Rest/binary>>,_Val,_Acc) ->
+ Rest;
+lex_digits1(<<N, Rest/binary>>,Val, Acc) when N >= $0 , N =< $9 ->
+ lex_digits1(Rest,Val*10+dec(N),Acc);
+lex_digits1(_Other,_Val,_Acc) ->
+ not_ok.
+
+lex_digits2(<<N, Rest/binary>>,Val, Acc) when N >= $0 , N =< $9 ->
+ lex_digits2(Rest,Val*10+dec(N),Acc);
+lex_digits2(<<$., Rest/binary>>,_Val,_Acc) ->
+ Rest;
+lex_digits2(_Other,_Val,_Acc) ->
+ not_ok.
+
+dec(A) ->
+ A-$0.
+
+size_var(Config) when is_list(Config) ->
+ ?line {<<45>>,<<>>} = split(<<1:16,45>>),
+ ?line {<<45>>,<<46,47>>} = split(<<1:16,45,46,47>>),
+ ?line {<<45,46>>,<<47>>} = split(<<2:16,45,46,47>>),
+
+ ?line {<<45,46,47>>,<<48>>} = split_2(<<16:8,3:16,45,46,47,48>>),
+
+ ?line {<<45,46>>,<<47>>} = split(2, <<2:16,45,46,47>>),
+ ?line {'EXIT',{function_clause,_}} = (catch split(42, <<2:16,45,46,47>>)),
+
+ ?line <<"cdef">> = skip(<<2:8,"abcdef">>),
+
+ ok.
+
+split(<<N:16,B:N/binary,T/binary>>) ->
+ {B,T}.
+
+split(N, <<N:16,B:N/binary,T/binary>>) ->
+ {B,T}.
+
+split_2(<<N0:8,N:N0,B:N/binary,T/binary>>) ->
+ {B,T}.
+
+skip(<<N:8,_:N/binary,T/binary>>) -> T.
+
+wiger(Config) when is_list(Config) ->
+ ?line ok1 = wcheck(<<3>>),
+ ?line ok2 = wcheck(<<1,2,3>>),
+ ?line ok3 = wcheck(<<4>>),
+ ?line {error,<<1,2,3,4>>} = wcheck(<<1,2,3,4>>),
+ ?line {error,<<>>} = wcheck(<<>>),
+ ok.
+
+wcheck(<<A>>) when A==3->
+ ok1;
+wcheck(<<_,_:2/binary>>) ->
+ ok2;
+wcheck(<<_>>) ->
+ ok3;
+wcheck(Other) ->
+ {error,Other}.
+
+%% Test that having the match context in x(0) works.
+
+x0_context(Config) when is_list(Config) ->
+ x0_0([], <<3.0:64/float,42:16,123456:32>>).
+
+x0_0(_, Bin) ->
+ <<3.0:64/float,42:16,_/binary>> = Bin,
+ x0_1([], Bin, 64, 16, 2).
+
+x0_1(_, Bin, FloatSz, IntSz, BinSz) ->
+ <<_:FloatSz/float,42:IntSz,B:BinSz/binary,C:1/binary,D/binary>> = Bin,
+ id({B,C,D}),
+ <<_:FloatSz/float,42:IntSz,B:BinSz/binary,_/binary>> = Bin,
+ x0_2([], Bin).
+
+x0_2(_, Bin) ->
+ <<_:64,0:7,42:9,_/binary>> = Bin,
+ x0_3([], Bin).
+
+x0_3(_, Bin) ->
+ case Bin of
+ <<_:72,7:8,_/binary>> ->
+ ?line ?t:fail();
+ <<_:64,0:16,_/binary>> ->
+ ?line ?t:fail();
+ <<_:64,42:16,123456:32,_/binary>> ->
+ ok
+ end.
+
+
+huge_float_field(Config) when is_list(Config) ->
+ Sz = 1 bsl 27,
+ ?line Bin = <<0:Sz>>,
+
+ ?line nomatch = overflow_huge_float_skip_32(Bin),
+ ?line nomatch = overflow_huge_float_32(Bin),
+
+ ?line ok = overflow_huge_float(Bin, lists:seq(25, 32)++lists:seq(50, 64)),
+ ?line ok = overflow_huge_float_unit128(Bin, lists:seq(25, 32)++lists:seq(50, 64)),
+ ok.
+
+overflow_huge_float_skip_32(<<_:4294967296/float,0,_/binary>>) -> 1; % 1 bsl 32
+overflow_huge_float_skip_32(<<_:33554432/float-unit:128,0,_/binary>>) -> 2; % 1 bsl 25
+overflow_huge_float_skip_32(<<_:67108864/float-unit:64,0,_/binary>>) -> 3; % 1 bsl 26
+overflow_huge_float_skip_32(<<_:134217728/float-unit:32,0,_/binary>>) -> 4; % 1 bsl 27
+overflow_huge_float_skip_32(<<_:268435456/float-unit:16,0,_/binary>>) -> 5; % 1 bsl 28
+overflow_huge_float_skip_32(<<_:536870912/float-unit:8,0,_/binary>>) -> 6; % 1 bsl 29
+overflow_huge_float_skip_32(<<_:1073741824/float-unit:8,0,_/binary>>) -> 7; % 1 bsl 30
+overflow_huge_float_skip_32(<<_:2147483648/float-unit:8,0,_/binary>>) -> 8; % 1 bsl 31
+overflow_huge_float_skip_32(_) -> nomatch.
+
+overflow_huge_float_32(<<F:4294967296/float,_/binary>>) -> {1,F}; % 1 bsl 32
+overflow_huge_float_32(<<F:33554432/float-unit:128,0,_/binary>>) -> {2,F}; % 1 bsl 25
+overflow_huge_float_32(<<F:67108864/float-unit:128,0,_/binary>>) -> {3,F}; % 1 bsl 26
+overflow_huge_float_32(<<F:134217728/float-unit:128,0,_/binary>>) -> {4,F}; % 1 bsl 27
+overflow_huge_float_32(<<F:268435456/float-unit:128,0,_/binary>>) -> {5,F}; % 1 bsl 28
+overflow_huge_float_32(<<F:536870912/float-unit:128,0,_/binary>>) -> {6,F}; % 1 bsl 29
+overflow_huge_float_32(<<F:1073741824/float-unit:128,0,_/binary>>) -> {7,F}; % 1 bsl 30
+overflow_huge_float_32(<<F:2147483648/float-unit:128,0,_/binary>>) -> {8,F}; % 1 bsl 31
+overflow_huge_float_32(_) -> nomatch.
+
+
+overflow_huge_float(Bin, [Sz0|Sizes]) ->
+ Sz = id(1 bsl Sz0),
+ case Bin of
+ <<_:Sz/float-unit:8,0,_/binary>> ->
+ {error,Sz};
+ _ ->
+ case Bin of
+ <<Var:Sz/float-unit:8,0,_/binary>> ->
+ {error,Sz,Var};
+ _ ->
+ overflow_huge_float(Bin, Sizes)
+ end
+ end;
+overflow_huge_float(_, []) -> ok.
+
+overflow_huge_float_unit128(Bin, [Sz0|Sizes]) ->
+ Sz = id(1 bsl Sz0),
+ case Bin of
+ <<_:Sz/float-unit:128,0,_/binary>> ->
+ {error,Sz};
+ _ ->
+ case Bin of
+ <<Var:Sz/float-unit:128,0,_/binary>> ->
+ {error,Sz,Var};
+ _ ->
+ overflow_huge_float_unit128(Bin, Sizes)
+ end
+ end;
+overflow_huge_float_unit128(_, []) -> ok.
+
+
+%%
+%% Test that a writable binary can be safely matched.
+%%
+
+writable_binary_matched(Config) when is_list(Config) ->
+ ?line WritableBin = create_writeable_binary(),
+ ?line writable_binary_matched(WritableBin, WritableBin, 500).
+
+writable_binary_matched(<<0>>, _, N) ->
+ if
+ N =:= 0 -> ok;
+ true ->
+ put(grow_heap, [N|get(grow_heap)]),
+ ?line WritableBin = create_writeable_binary(),
+ ?line writable_binary_matched(WritableBin, WritableBin, N-1)
+ end;
+writable_binary_matched(<<B:8,T/binary>>, WritableBin0, N) ->
+ ?line WritableBin = writable_binary(WritableBin0, B),
+ writable_binary_matched(T, WritableBin, N).
+
+writable_binary(WritableBin0, B) when is_binary(WritableBin0) ->
+ %% Heavy append to force the binary to move.
+ ?line WritableBin = <<WritableBin0/binary,0:(size(WritableBin0))/unit:8,B>>,
+ ?line id(<<(id(0)):128/unit:8>>),
+ WritableBin.
+
+create_writeable_binary() ->
+ <<(id(<<>>))/binary,1,2,3,4,5,6,0>>.
+
+otp_7198(Config) when is_list(Config) ->
+ %% When a match context was reused, and grown at the same time to
+ %% increase the number of saved positions, the thing word was not updated
+ %% to account for the new size. Therefore, if there was a garbage collection,
+ %% the new slots would be included in the garbage collection.
+ ?line [do_otp_7198(FillerSize) || FillerSize <- lists:seq(0, 256)],
+ ok.
+
+do_otp_7198(FillerSize) ->
+ Filler = erlang:make_tuple(FillerSize, 42),
+ {Pid,Ref} = spawn_monitor(fun() -> do_otp_7198_test(Filler) end),
+ receive
+ {'DOWN',Ref,process,Pid,normal} ->
+ ok;
+ {'DOWN',Ref,process,Pid,Reason} ->
+ io:format("unexpected: ~p", [Reason]),
+ ?line ?t:fail()
+ end.
+
+do_otp_7198_test(_) ->
+ [{'KEYWORD',114},
+ {'KEYWORD',101},
+ {'KEYWORD',103},
+ {'KEYWORD',105},
+ {'KEYWORD',111},
+ {'FIELD',110},
+ {'KEYWORD',119},
+ {'KEYWORD',104},
+ {'KEYWORD',97},
+ {'KEYWORD',116},
+ {'KEYWORD',101},
+ {'KEYWORD',118},
+ {'KEYWORD',101},
+ {'KEYWORD',114},
+ '$thats_all_folks$'] = otp_7198_scan(<<"region:whatever">>, []).
+
+
+otp_7198_scan(<<>>, TokAcc) ->
+ lists:reverse(['$thats_all_folks$' | TokAcc]);
+
+otp_7198_scan(<<D, Z, Rest/binary>>, TokAcc) when
+ (D =:= $D orelse D =:= $d) and
+ ((Z =:= $\s) or (Z =:= $() or (Z =:= $))) ->
+ otp_7198_scan(<<Z, Rest/binary>>, ['AND' | TokAcc]);
+
+otp_7198_scan(<<D>>, TokAcc) when
+ (D =:= $D) or (D =:= $d) ->
+ otp_7198_scan(<<>>, ['AND' | TokAcc]);
+
+otp_7198_scan(<<N, Z, Rest/binary>>, TokAcc) when
+ (N =:= $N orelse N =:= $n) and
+ ((Z =:= $\s) or (Z =:= $() or (Z =:= $))) ->
+ otp_7198_scan(<<Z, Rest/binary>>, ['NOT' | TokAcc]);
+
+otp_7198_scan(<<C, Rest/binary>>, TokAcc) when
+ (C >= $A) and (C =< $Z);
+ (C >= $a) and (C =< $z);
+ (C >= $0) and (C =< $9) ->
+ case Rest of
+ <<$:, R/binary>> ->
+ otp_7198_scan(R, [{'FIELD', C} | TokAcc]);
+ _ ->
+ otp_7198_scan(Rest, [{'KEYWORD', C} | TokAcc])
+ end.
+
+unordered_bindings(Config) when is_list(Config) ->
+ {<<1,2,3,4>>,<<42,42>>,<<3,3,3>>} =
+ unordered_bindings(4, 2, 3, <<1,2,3,4, 42,42, 3,3,3, 3>>),
+ ok.
+
+unordered_bindings(CompressedLength, HashSize, PadLength, T) ->
+ <<Content:CompressedLength/binary,Mac:HashSize/binary,
+ Padding:PadLength/binary,PadLength>> = T,
+ {Content,Mac,Padding}.
+
+
+id(I) -> I.
diff --git a/lib/debugger/test/bs_match_tail_SUITE.erl b/lib/debugger/test/bs_match_tail_SUITE.erl
index 961ccbb599..9f7519cf3a 100644
--- a/lib/debugger/test/bs_match_tail_SUITE.erl
+++ b/lib/debugger/test/bs_match_tail_SUITE.erl
@@ -64,7 +64,7 @@ end_per_suite(Config) when is_list(Config) ->
ok.
aligned(doc) -> "Test aligned tails.";
-aligned(Config) when list(Config) ->
+aligned(Config) when is_list(Config) ->
?line Tail1 = mkbin([]),
?line {258,Tail1} = al_get_tail_used(mkbin([1,2])),
?line Tail2 = mkbin(lists:seq(1, 127)),
@@ -84,10 +84,10 @@ aligned(Config) when list(Config) ->
ok.
al_get_tail_used(<<A:16,T/binary>>) -> {A,T}.
-al_get_tail_unused(<<A:16,_T/binary>>) -> A.
+al_get_tail_unused(<<A:16,_/binary>>) -> A.
unaligned(doc) -> "Test that an non-aligned tail cannot be matched out.";
-unaligned(Config) when list(Config) ->
+unaligned(Config) when is_list(Config) ->
?line {'EXIT',{function_clause,_}} = (catch get_tail_used(mkbin([42]))),
?line {'EXIT',{{badmatch,_},_}} = (catch get_dyn_tail_used(mkbin([137]), 3)),
?line {'EXIT',{function_clause,_}} = (catch get_tail_unused(mkbin([42,33]))),
@@ -103,11 +103,11 @@ get_dyn_tail_used(Bin, Sz) ->
{A,T}.
get_dyn_tail_unused(Bin, Sz) ->
- <<A:Sz,_T/binary>> = Bin,
+ <<A:Sz,_/binary>> = Bin,
A.
zero_tail(doc) -> "Test that zero tails are tested correctly.";
-zero_tail(Config) when list(Config) ->
+zero_tail(Config) when is_list(Config) ->
?line 7 = (catch test_zero_tail(mkbin([7]))),
?line {'EXIT',{function_clause,_}} = (catch test_zero_tail(mkbin([1,2]))),
?line {'EXIT',{function_clause,_}} = (catch test_zero_tail2(mkbin([1,2,3]))),
@@ -117,4 +117,4 @@ test_zero_tail(<<A:8>>) -> A.
test_zero_tail2(<<_A:4,_B:4>>) -> ok.
-mkbin(L) when list(L) -> list_to_binary(L).
+mkbin(L) when is_list(L) -> list_to_binary(L).
diff --git a/lib/debugger/test/bug_SUITE.erl b/lib/debugger/test/bug_SUITE.erl
index a831897dfb..1a7e876329 100644
--- a/lib/debugger/test/bug_SUITE.erl
+++ b/lib/debugger/test/bug_SUITE.erl
@@ -51,7 +51,7 @@ end_per_group(_GroupName, Config) ->
otp2163(doc) -> ["BIF exit reason"];
otp2163(suite) -> [];
-otp2163(Config) when list(Config) ->
+otp2163(Config) when is_list(Config) ->
?line DataDir = ?config(data_dir, Config),
%% First compile and get the expected results:
@@ -74,7 +74,7 @@ otp2163(Config) when list(Config) ->
otp4845(doc) -> ["BIF not loading and not bug compatible, OTP-4845 OTP-4859"];
otp4845(suite) -> [];
-otp4845(Config) when list(Config) ->
+otp4845(Config) when is_list(Config) ->
?line DataDir = ?config(data_dir, Config),
%% First compile and get the expected results:
diff --git a/lib/debugger/test/exception_SUITE.erl b/lib/debugger/test/exception_SUITE.erl
index 8c864e4b5f..86554ab2d4 100644
--- a/lib/debugger/test/exception_SUITE.erl
+++ b/lib/debugger/test/exception_SUITE.erl
@@ -23,7 +23,8 @@
-export([all/0, suite/0,groups/0,init_per_group/2,end_per_group/2,
init_per_testcase/2,end_per_testcase/2,
init_per_suite/1,end_per_suite/1,
- badmatch/1,pending_errors/1,nil_arith/1]).
+ badmatch/1,pending_errors/1,nil_arith/1,
+ stacktrace/1,nested_stacktrace/1,raise/1,gunilla/1,per/1]).
-export([bad_guy/2]).
@@ -31,6 +32,19 @@
suite() -> [{ct_hooks,[ts_install_cth]}].
+%% Filler.
+%%
+%%
+%%
+%%
+%% This is line 40.
+even(N) when is_integer(N), N > 1, (N rem 2) == 0 ->
+ odd(N-1)++[N].
+
+odd(N) when is_integer(N), N > 1, (N rem 2) == 1 ->
+ even(N-1)++[N].
+
+
all() ->
cases().
@@ -45,7 +59,8 @@ end_per_group(_GroupName, Config) ->
cases() ->
- [badmatch, pending_errors, nil_arith].
+ [badmatch, pending_errors, nil_arith, stacktrace,
+ nested_stacktrace, raise, gunilla, per].
-define(try_match(E),
catch ?MODULE:bar(),
@@ -69,9 +84,9 @@ init_per_suite(Config) when is_list(Config) ->
end_per_suite(Config) when is_list(Config) ->
ok.
-badmatch(doc) -> "Test that deliberately bad matches are reported correctly.";
-badmatch(suite) -> [];
-badmatch(Config) when list(Config) ->
+%% Test that deliberately bad matches are reported correctly.
+
+badmatch(Config) when is_list(Config) ->
?line ?try_match(a),
?line ?try_match(42),
?line ?try_match({a, b, c}),
@@ -79,11 +94,9 @@ badmatch(Config) when list(Config) ->
?line ?try_match(1.0),
ok.
-pending_errors(doc) ->
- ["Test various exceptions, in the presence of a previous error suppressed ",
- "in a guard."];
-pending_errors(suite) -> [];
-pending_errors(Config) when list(Config) ->
+%% Test various exceptions, in the presence of a previous error suppressed
+%% in a guard.
+pending_errors(Config) when is_list(Config) ->
?line pending(e_badmatch, {badmatch, b}),
?line pending(x, function_clause),
?line pending(e_case, {case_clause, xxx}),
@@ -100,7 +113,7 @@ bad_guy(pe_badarith, Other) when Other+1 == 0 -> % badarith (suppressed)
bad_guy(pe_badarg, Other) when length(Other) > 0 -> % badarg (suppressed)
ok;
bad_guy(_, e_case) ->
- case xxx of
+ case id(xxx) of
ok -> ok
end; % case_clause
bad_guy(_, e_if) ->
@@ -121,7 +134,7 @@ bad_guy(_, e_badarg) ->
bad_guy(_, e_badarg_spawn) ->
spawn({}, {}, {}); % badarg
bad_guy(_, e_badmatch) ->
- a = b. % badmatch
+ a = id(b). % badmatch
pending(Arg, Expected) ->
pending(pe_badarith, Arg, Expected),
@@ -155,28 +168,23 @@ pending_exit_message(Args, Expected) ->
end,
process_flag(trap_exit, false).
-pending({badarg,[{erlang,Bif,BifArgs},{?MODULE,Func,Arity}|_]}, Func, Args, _Code)
- when atom(Bif), list(BifArgs), length(Args) == Arity -> %Threaded code.
- ok;
-pending({badarg,[{erlang,Bif,BifArgs},{?MODULE,Func,Args}|_]}, Func, Args, _Code)
- when atom(Bif), list(BifArgs) -> %From interpreted code.
+pending({badarg, [{erlang,Bif,BifArgs,_},{?MODULE,Func,Arity,_}|_]},
+ Func, Args, _Code)
+ when is_atom(Bif), is_list(BifArgs), length(Args) == Arity ->
ok;
-pending({undef,[{non_existing_module,foo,[]}|_]}, _, _, _) ->
+pending({undef,[{non_existing_module,foo,[],_}|_]}, _, _, _) ->
ok;
-pending({function_clause,[{?MODULE,Func,Args}|_]}, Func, Args, _Code) ->
+pending({function_clause,[{?MODULE,Func,Args,_}|_]}, Func, Args, _Code) ->
ok;
-pending({Code,[{?MODULE,Func,Arity}|_]}, Func, Args, Code) when length(Args) == Arity -> %Threaded code
+pending({Code,[{?MODULE,Func,Arity,_}|_]}, Func, Args, Code)
+ when length(Args) == Arity ->
ok;
-pending({Code,[{?MODULE,Func,Args}|_]}, Func, Args, Code) -> %From interpreted code.
- ok;
-pending(Reason, Func, Args, Code) ->
- test_server:fail({bad_exit_reason,Reason,{Func,Args,Code}}).
-
-nil_arith(doc) ->
- "Test that doing arithmetics on [] gives a badarith EXIT and not a crash.";
-nil_arith(suite) ->
- [];
-nil_arith(Config) when list(Config) ->
+pending(Reason, _Function, _Args, _Code) ->
+ test_server:fail({bad_exit_reason,Reason}).
+
+%% Test that doing arithmetics on [] gives a badarith EXIT and not a crash.
+
+nil_arith(Config) when is_list(Config) ->
?line ba_plus_minus_times([], []),
?line ba_plus_minus_times([], 0),
@@ -268,3 +276,199 @@ ba_shift(A, B) ->
ba_bnot(A) ->
io:format("bnot ~p", [A]),
{'EXIT', {badarith, _}} = (catch bnot A).
+
+stacktrace(Conf) when is_list(Conf) ->
+ Tag = make_ref(),
+ ?line {_,Mref} = spawn_monitor(fun() -> exit({Tag,erlang:get_stacktrace()}) end),
+ ?line {Tag,[]} = receive {'DOWN',Mref,_,_,Info} -> Info end,
+ V = [make_ref()|self()],
+ ?line {value2,{caught1,badarg,[{erlang,abs,[V],_}|_]=St1}} =
+ stacktrace_1({'abs',V}, error, {value,V}),
+ ?line St1 = erase(stacktrace1),
+ ?line St1 = erase(stacktrace2),
+ ?line St1 = erlang:get_stacktrace(),
+ ?line {caught2,{error,badarith},[{?MODULE,my_add,2,_}|_]=St2} =
+ stacktrace_1({'div',{1,0}}, error, {'add',{0,a}}),
+ ?line [{?MODULE,my_div,2,_}|_] = erase(stacktrace1),
+ ?line St2 = erase(stacktrace2),
+ ?line St2 = erlang:get_stacktrace(),
+ ?line {caught2,{error,{try_clause,V}},[{?MODULE,stacktrace_1,3,_}|_]=St3} =
+ stacktrace_1({value,V}, error, {value,V}),
+ ?line St3 = erase(stacktrace1),
+ ?line St3 = erase(stacktrace2),
+ ?line St3 = erlang:get_stacktrace(),
+ ?line {caught2,{throw,V},[{?MODULE,foo,1,_}|_]=St4} =
+ stacktrace_1({value,V}, error, {throw,V}),
+ ?line [{?MODULE,stacktrace_1,3,_}|_] = erase(stacktrace1),
+ ?line St4 = erase(stacktrace2),
+ ?line St4 = erlang:get_stacktrace(),
+ ok.
+
+stacktrace_1(X, C1, Y) ->
+ erase(stacktrace1),
+ erase(stacktrace2),
+ try try foo(X) of
+ C1 -> value1
+ catch
+ C1:D1 -> {caught1,D1,erlang:get_stacktrace()}
+ after
+ put(stacktrace1, erlang:get_stacktrace()),
+ foo(Y)
+ end of
+ V2 -> {value2,V2}
+ catch
+ C2:D2 -> {caught2,{C2,D2},erlang:get_stacktrace()}
+ after
+ put(stacktrace2, erlang:get_stacktrace())
+ end.
+
+
+
+nested_stacktrace(Conf) when is_list(Conf) ->
+ V = [{make_ref()}|[self()]],
+ ?line value1 =
+ nested_stacktrace_1({{value,{V,x1}},void,{V,x1}},
+ {void,void,void}),
+ ?line {caught1,
+ [{?MODULE,my_add,2,_}|_],
+ value2,
+ [{?MODULE,my_add,2,_}|_]} =
+ nested_stacktrace_1({{'add',{V,x1}},error,badarith},
+ {{value,{V,x2}},void,{V,x2}}),
+ ?line {caught1,
+ [{?MODULE,my_add,2,_}|_],
+ {caught2,[{erlang,abs,[V],_}|_]},
+ [{erlang,abs,[V],_}|_]} =
+ nested_stacktrace_1({{'add',{V,x1}},error,badarith},
+ {{'abs',V},error,badarg}),
+ ok.
+
+nested_stacktrace_1({X1,C1,V1}, {X2,C2,V2}) ->
+ try foo(X1) of
+ V1 -> value1
+ catch
+ C1:V1 ->
+ S1 = erlang:get_stacktrace(),
+ T2 =
+ try foo(X2) of
+ V2 -> value2
+ catch
+ C2:V2 -> {caught2,erlang:get_stacktrace()}
+ end,
+ {caught1,S1,T2,erlang:get_stacktrace()}
+ end.
+
+
+
+raise(Conf) when is_list(Conf) ->
+ ?line erase(raise),
+ ?line A =
+ try
+ ?line try foo({'div',{1,0}})
+ catch
+ error:badarith ->
+ put(raise, A0 = erlang:get_stacktrace()),
+ ?line erlang:raise(error, badarith, A0)
+ end
+ catch
+ error:badarith ->
+ ?line A1 = erlang:get_stacktrace(),
+ ?line A1 = get(raise)
+ end,
+ ?line A = erlang:get_stacktrace(),
+ ?line A = get(raise),
+ ?line [{?MODULE,my_div,2,_}|_] = A,
+ %%
+ N = 8, % Must be even
+ ?line N = erlang:system_flag(backtrace_depth, N),
+ ?line try even(N)
+ catch error:function_clause -> ok
+ end,
+ ?line B = odd_even(N, []),
+ ?line B = erlang:get_stacktrace(),
+ %%
+ ?line C0 = odd_even(N+1, []),
+ ?line C = lists:sublist(C0, N),
+ ?line try odd(N+1)
+ catch error:function_clause -> ok
+ end,
+ ?line C = erlang:get_stacktrace(),
+ ?line try erlang:raise(error, function_clause, C0)
+ catch error:function_clause -> ok
+ end,
+ ?line C = erlang:get_stacktrace(),
+ ok.
+
+odd_even(N, R) when is_integer(N), N > 1 ->
+ odd_even(N-1,
+ [if (N rem 2) == 0 ->
+ {?MODULE,even,1,[{file,?MODULE_STRING++".erl"},
+ {line,42}]};
+ true ->
+ {?MODULE,odd,1,[{file,?MODULE_STRING++".erl"},
+ {line,45}]}
+ end|R]);
+odd_even(1, R) ->
+ [{?MODULE,odd,[1],[{file,?MODULE_STRING++".erl"},
+ {line,44}]}|R].
+
+foo({value,Value}) -> Value;
+foo({'div',{A,B}}) ->
+ my_div(A, B);
+foo({'add',{A,B}}) ->
+ my_add(A, B);
+foo({'abs',X}) ->
+ my_abs(X);
+foo({error,Error}) ->
+ erlang:error(Error);
+foo({throw,Throw}) ->
+ erlang:throw(Throw);
+foo({exit,Exit}) ->
+ erlang:exit(Exit);
+foo({raise,{Class,Reason,Stacktrace}}) ->
+ erlang:raise(Class, Reason, Stacktrace).
+%%foo(function_clause) -> % must not be defined!
+
+my_div(A, B) ->
+ A div B.
+
+my_add(A, B) ->
+ A + B.
+
+my_abs(X) -> abs(X).
+
+gunilla(Config) when is_list(Config) ->
+ ?line {throw,kalle} = gunilla_1(),
+ ?line [] = erlang:get_stacktrace(),
+ ok.
+
+gunilla_1() ->
+ try try arne()
+ after
+ pelle
+ end
+ catch
+ C:R ->
+ {C,R}
+ end.
+
+arne() ->
+ %% Empty stack trace used to cause change the error class to 'error'.
+ erlang:raise(throw, kalle, []).
+
+per(Config) when is_list(Config) ->
+ try
+ t1(0,pad,0),
+ t2(0,pad,0)
+ catch
+ error:badarith ->
+ ok
+ end.
+
+t1(_,X,_) ->
+ (1 bsl X) + 1.
+
+t2(_,X,_) ->
+ (X bsl 1) + 1.
+
+id(I) -> I.
diff --git a/lib/debugger/test/fun_SUITE.erl b/lib/debugger/test/fun_SUITE.erl
index 8103d9c692..a06cdc7165 100644
--- a/lib/debugger/test/fun_SUITE.erl
+++ b/lib/debugger/test/fun_SUITE.erl
@@ -24,8 +24,10 @@
init_per_testcase/2,end_per_testcase/2,
init_per_suite/1,end_per_suite/1,
good_call/1,bad_apply/1,bad_fun_call/1,badarity/1,
- ext_badarity/1,otp_6061/1]).
--export([nothing/0]).
+ ext_badarity/1,otp_6061/1,external/1]).
+
+%% Internal exports.
+-export([nothing/0,call_me/1]).
-include_lib("test_server/include/test_server.hrl").
@@ -46,7 +48,7 @@ end_per_group(_GroupName, Config) ->
cases() ->
[good_call, bad_apply, bad_fun_call, badarity,
- ext_badarity, otp_6061].
+ ext_badarity, otp_6061, external].
init_per_testcase(_Case, Config) ->
test_lib:interpret(?MODULE),
@@ -244,3 +246,47 @@ test_otp_6061(Starter) ->
fun() -> Starter ! working end,
fun() -> Starter ! not_working end],
lists:foreach(fun(P)->(lists:nth(P,PassesF))() end,Passes).
+
+-define(APPLY(M, F, A), (fun(Fun) -> {ok,{a,b}} = Fun({a,b}) end)(fun M:F/A)).
+-define(APPLY2(M, F, A),
+ (fun(Map) ->
+ Id = fun(I) -> I end,
+ List = [x,y],
+ List = Map(Id, List),
+ {type,external} = erlang:fun_info(Map, type)
+ end)(fun M:F/A)).
+
+external(Config) when is_list(Config) ->
+ Mod = id(?MODULE),
+ Func = id(call_me),
+ Arity = id(1),
+
+ ?APPLY(?MODULE, call_me, 1),
+ ?APPLY(?MODULE, call_me, Arity),
+ ?APPLY(?MODULE, Func, 1),
+ ?APPLY(?MODULE, Func, Arity),
+ ?APPLY(Mod, call_me, 1),
+ ?APPLY(Mod, call_me, Arity),
+ ?APPLY(Mod, Func, 1),
+ ?APPLY(Mod, Func, Arity),
+
+ ListsMod = id(lists),
+ ListsMap = id(map),
+ ListsArity = id(2),
+
+ ?APPLY2(lists, map, 2),
+ ?APPLY2(lists, map, ListsArity),
+ ?APPLY2(lists, ListsMap, 2),
+ ?APPLY2(lists, ListsMap, ListsArity),
+ ?APPLY2(ListsMod, map, 2),
+ ?APPLY2(ListsMod, map, ListsArity),
+ ?APPLY2(ListsMod, ListsMap, 2),
+ ?APPLY2(ListsMod, ListsMap, ListsArity),
+
+ ok.
+
+call_me(I) ->
+ {ok,I}.
+
+id(I) ->
+ I.
diff --git a/lib/debugger/test/guard_SUITE.erl b/lib/debugger/test/guard_SUITE.erl
index 611dcb4dff..bf5fa82749 100644
--- a/lib/debugger/test/guard_SUITE.erl
+++ b/lib/debugger/test/guard_SUITE.erl
@@ -35,7 +35,8 @@
t_is_boolean/1,is_function_2/1,
tricky/1,rel_ops/1,
basic_andalso_orelse/1,traverse_dcd/1,
- check_qlc_hrl/1]).
+ check_qlc_hrl/1,andalso_semi/1,t_tuple_size/1,binary_part/1,
+ bad_constants/1]).
-include_lib("test_server/include/test_server.hrl").
@@ -65,7 +66,8 @@ cases() ->
xor_guard, more_xor_guards, build_in_guard,
old_guard_tests, gbif, t_is_boolean, is_function_2,
tricky, rel_ops, basic_andalso_orelse, traverse_dcd,
- check_qlc_hrl].
+ check_qlc_hrl, andalso_semi, t_tuple_size, binary_part,
+ bad_constants].
init_per_testcase(_Case, Config) ->
test_lib:interpret(?MODULE),
@@ -294,9 +296,7 @@ try_gbif(Id, X, Y) ->
try_fail_gbif(Id, X, Y) ->
case catch guard_bif(Id, X, Y) of
- {'EXIT', {function_clause,{?MODULE,guard_bif,[Id,X,Y]}}} -> %Jam
- io:format("guard_bif(~p, ~p, ~p) -- ok", [Id,X,Y]);
- {'EXIT', {function_clause,[{?MODULE,guard_bif,[Id,X,Y]}|_]}} -> %Beam
+ {'EXIT', {function_clause,[{?MODULE,guard_bif,[Id,X,Y],_}|_]}} ->
io:format("guard_bif(~p, ~p, ~p) -- ok", [Id,X,Y]);
Other ->
?line ok = io:format("guard_bif(~p, ~p, ~p) -- bad result: ~p\n",
@@ -367,9 +367,8 @@ type_tests(Test, [Type|T], Allowed) ->
end;
false ->
case catch type_test(Test, Value) of
- {'EXIT', {function_clause, {?MODULE, type_test, [Test, Value]}}} ->
- ok;
- {'EXIT', {function_clause,[{?MODULE,type_test,[Test,Value]}|_]}} ->
+ {'EXIT',{function_clause,
+ [{?MODULE,type_test,[Test,Value],_}|_]}} ->
ok;
{'EXIT',Other} ->
?line test_server:fail({unexpected_error_reason,Other});
@@ -1477,7 +1476,207 @@ cqlc(M, F, As, St) ->
St
end.
+%% OTP-7679: Thanks to Hunter Morris.
+andalso_semi(Config) when is_list(Config) ->
+ ?line ok = andalso_semi_foo(0),
+ ?line ok = andalso_semi_foo(1),
+ ?line fc(catch andalso_semi_foo(2)),
+
+ ?line ok = andalso_semi_bar([a,b,c]),
+ ?line ok = andalso_semi_bar(1),
+ ?line fc(catch andalso_semi_bar([a,b])),
+ ok.
+
+andalso_semi_foo(Bar) when is_integer(Bar) andalso Bar =:= 0; Bar =:= 1 ->
+ ok.
+
+andalso_semi_bar(Bar) when is_list(Bar) andalso length(Bar) =:= 3; Bar =:= 1 ->
+ ok.
+
+
+t_tuple_size(Config) when is_list(Config) ->
+ ?line 10 = do_tuple_size({1,2,3,4}),
+ ?line fc(catch do_tuple_size({1,2,3})),
+ ?line fc(catch do_tuple_size(42)),
+ ?line error = ludicrous_tuple_size({a,b,c}),
+ ?line error = ludicrous_tuple_size([a,b,c]),
+
+ ok.
+
+do_tuple_size(T) when tuple_size(T) =:= 4 ->
+ {A,B,C,D} = T,
+ A+B+C+D.
+
+ludicrous_tuple_size(T)
+ when tuple_size(T) =:= 16#7777777777777777777777777777777777 -> ok;
+ludicrous_tuple_size(T)
+ when tuple_size(T) =:= 16#10000000000000000 -> ok;
+ludicrous_tuple_size(T)
+ when tuple_size(T) =:= (1 bsl 64) - 1 -> ok;
+ludicrous_tuple_size(T)
+ when tuple_size(T) =:= 16#FFFFFFFFFFFFFFFF -> ok;
+ludicrous_tuple_size(_) -> error.
+
+%%
+%% The binary_part/2,3 guard BIFs
+%%
+-define(MASK_ERROR(EXPR),mask_error((catch (EXPR)))).
+mask_error({'EXIT',{Err,_}}) ->
+ Err;
+mask_error(Else) ->
+ Else.
+
+binary_part(doc) ->
+ ["Tests the binary_part/2,3 guard (GC) bif's"];
+binary_part(Config) when is_list(Config) ->
+ %% This is more or less a copy of what the guard_SUITE in emulator
+ %% does to cover the guard bif's
+ ?line 1 = bptest(<<1,2,3>>),
+ ?line 2 = bptest(<<2,1,3>>),
+ ?line error = bptest(<<1>>),
+ ?line error = bptest(<<>>),
+ ?line error = bptest(apa),
+ ?line 3 = bptest(<<2,3,3>>),
+ % With one variable (pos)
+ ?line 1 = bptest(<<1,2,3>>,1),
+ ?line 2 = bptest(<<2,1,3>>,1),
+ ?line error = bptest(<<1>>,1),
+ ?line error = bptest(<<>>,1),
+ ?line error = bptest(apa,1),
+ ?line 3 = bptest(<<2,3,3>>,1),
+ % With one variable (length)
+ ?line 1 = bptesty(<<1,2,3>>,1),
+ ?line 2 = bptesty(<<2,1,3>>,1),
+ ?line error = bptesty(<<1>>,1),
+ ?line error = bptesty(<<>>,1),
+ ?line error = bptesty(apa,1),
+ ?line 3 = bptesty(<<2,3,3>>,2),
+ % With one variable (whole tuple)
+ ?line 1 = bptestx(<<1,2,3>>,{1,1}),
+ ?line 2 = bptestx(<<2,1,3>>,{1,1}),
+ ?line error = bptestx(<<1>>,{1,1}),
+ ?line error = bptestx(<<>>,{1,1}),
+ ?line error = bptestx(apa,{1,1}),
+ ?line 3 = bptestx(<<2,3,3>>,{1,2}),
+ % With two variables
+ ?line 1 = bptest(<<1,2,3>>,1,1),
+ ?line 2 = bptest(<<2,1,3>>,1,1),
+ ?line error = bptest(<<1>>,1,1),
+ ?line error = bptest(<<>>,1,1),
+ ?line error = bptest(apa,1,1),
+ ?line 3 = bptest(<<2,3,3>>,1,2),
+ % Direct (autoimported) call, these will be evaluated by the compiler...
+ ?line <<2>> = binary_part(<<1,2,3>>,1,1),
+ ?line <<1>> = binary_part(<<2,1,3>>,1,1),
+ % Compiler warnings due to constant evaluation expected (3)
+ ?line badarg = ?MASK_ERROR(binary_part(<<1>>,1,1)),
+ ?line badarg = ?MASK_ERROR(binary_part(<<>>,1,1)),
+ ?line badarg = ?MASK_ERROR(binary_part(apa,1,1)),
+ ?line <<3,3>> = binary_part(<<2,3,3>>,1,2),
+ % Direct call through apply
+ ?line <<2>> = apply(erlang,binary_part,[<<1,2,3>>,1,1]),
+ ?line <<1>> = apply(erlang,binary_part,[<<2,1,3>>,1,1]),
+ % Compiler warnings due to constant evaluation expected (3)
+ ?line badarg = ?MASK_ERROR(apply(erlang,binary_part,[<<1>>,1,1])),
+ ?line badarg = ?MASK_ERROR(apply(erlang,binary_part,[<<>>,1,1])),
+ ?line badarg = ?MASK_ERROR(apply(erlang,binary_part,[apa,1,1])),
+ ?line <<3,3>> = apply(erlang,binary_part,[<<2,3,3>>,1,2]),
+ % Constant propagation
+ ?line Bin = <<1,2,3>>,
+ ?line ok = if
+ binary_part(Bin,1,1) =:= <<2>> ->
+ ok;
+ %% Compiler warning, clause cannot match (expected)
+ true ->
+ error
+ end,
+ ?line ok = if
+ binary_part(Bin,{1,1}) =:= <<2>> ->
+ ok;
+ %% Compiler warning, clause cannot match (expected)
+ true ->
+ error
+ end,
+ ok.
+
+
+bptest(B) when length(B) =:= 1337 ->
+ 1;
+bptest(B) when binary_part(B,{1,1}) =:= <<2>> ->
+ 1;
+bptest(B) when erlang:binary_part(B,1,1) =:= <<1>> ->
+ 2;
+bptest(B) when erlang:binary_part(B,{1,2}) =:= <<3,3>> ->
+ 3;
+bptest(_) ->
+ error.
+
+bptest(B,A) when length(B) =:= A ->
+ 1;
+bptest(B,A) when binary_part(B,{A,1}) =:= <<2>> ->
+ 1;
+bptest(B,A) when erlang:binary_part(B,A,1) =:= <<1>> ->
+ 2;
+bptest(B,A) when erlang:binary_part(B,{A,2}) =:= <<3,3>> ->
+ 3;
+bptest(_,_) ->
+ error.
+
+bptestx(B,A) when length(B) =:= A ->
+ 1;
+bptestx(B,A) when binary_part(B,A) =:= <<2>> ->
+ 1;
+bptestx(B,A) when erlang:binary_part(B,A) =:= <<1>> ->
+ 2;
+bptestx(B,A) when erlang:binary_part(B,A) =:= <<3,3>> ->
+ 3;
+bptestx(_,_) ->
+ error.
+
+bptesty(B,A) when length(B) =:= A ->
+ 1;
+bptesty(B,A) when binary_part(B,{1,A}) =:= <<2>> ->
+ 1;
+bptesty(B,A) when erlang:binary_part(B,1,A) =:= <<1>> ->
+ 2;
+bptesty(B,A) when erlang:binary_part(B,{1,A}) =:= <<3,3>> ->
+ 3;
+bptesty(_,_) ->
+ error.
+
+bptest(B,A,_C) when length(B) =:= A ->
+ 1;
+bptest(B,A,C) when binary_part(B,{A,C}) =:= <<2>> ->
+ 1;
+bptest(B,A,C) when erlang:binary_part(B,A,C) =:= <<1>> ->
+ 2;
+bptest(B,A,C) when erlang:binary_part(B,{A,C}) =:= <<3,3>> ->
+ 3;
+bptest(_,_,_) ->
+ error.
+
+-define(FAILING(C),
+ if
+ C -> ?t:fail(should_fail);
+ true -> ok
+ end,
+ if
+ true, C -> ?t:fail(should_fail);
+ true -> ok
+ end).
+
+bad_constants(Config) when is_list(Config) ->
+ ?line ?FAILING(false),
+ ?line ?FAILING([]),
+ ?line ?FAILING([a]),
+ ?line ?FAILING([Config]),
+ ?line ?FAILING({a,b}),
+ ?line ?FAILING({a,Config}),
+ ?line ?FAILING(<<1>>),
+ ?line ?FAILING(42),
+ ?line ?FAILING(3.14),
+ ok.
%% Call this function to turn off constant propagation.
id(I) -> I.
@@ -1490,3 +1689,5 @@ check(F, Result) ->
io:format(" Got: ~p\n", [Other]),
test_server:fail()
end.
+
+fc({'EXIT',{function_clause,_}}) -> ok.
diff --git a/lib/debugger/test/int_eval_SUITE.erl b/lib/debugger/test/int_eval_SUITE.erl
index f36ed213d1..4ffcf7888e 100644
--- a/lib/debugger/test/int_eval_SUITE.erl
+++ b/lib/debugger/test/int_eval_SUITE.erl
@@ -28,7 +28,7 @@
bifs_outside_erlang/1, spawning/1, applying/1,
catch_and_throw/1, external_call/1, test_module_info/1,
apply_interpreted_fun/1, apply_uninterpreted_fun/1,
- interpreted_exit/1, otp_8310/1]).
+ interpreted_exit/1, otp_8310/1, stacktrace/1]).
%% Helpers.
-export([applier/3]).
@@ -44,7 +44,7 @@ all() ->
[bifs_outside_erlang, spawning, applying,
catch_and_throw, external_call, test_module_info,
apply_interpreted_fun, apply_uninterpreted_fun,
- interpreted_exit, otp_8310].
+ interpreted_exit, otp_8310, stacktrace].
groups() ->
[].
@@ -191,23 +191,23 @@ apply_interpreted_fun(Config) when is_list(Config) ->
?line {ok,ATerm} = spawn_eval(fun() -> F2() end),
%% Called from uninterpreted code, badarity
- ?line {'EXIT',{{badarity,{F1,[snape]}},[{?MODULE,_,_}|_]}} =
+ ?line {'EXIT',{{badarity,{F1,[snape]}},[{?MODULE,_,_,_}|_]}} =
spawn_eval(fun() -> F1(snape) end),
%% Called from uninterpreted code, error in fun
?line F3 = spawn_eval(fun() -> ?IM:give_me_a_bad_fun() end),
- ?line {'EXIT',{snape,[{?IM,_FunName,_}|_]}} =
+ ?line {'EXIT',{snape,[{?IM,_FunName,_,_}|_]}} =
spawn_eval(fun() -> F3(snape) end),
%% Called from within interpreted code
?line perfectly_alright = spawn_eval(fun() -> ?IM:do_apply(F1) end),
%% Called from within interpreted code, badarity
- ?line {'EXIT',{{badarity,{F1,[snape]}},[{?IM,do_apply,_}|_]}} =
+ ?line {'EXIT',{{badarity,{F1,[snape]}},[{?IM,do_apply,_,_}|_]}} =
spawn_eval(fun() -> ?IM:do_apply(F1, snape) end),
%% Called from within interpreted code, error in fun
- ?line {'EXIT',{snape,[{?IM,_FunName,_}|_]}} =
+ ?line {'EXIT',{snape,[{?IM,_FunName,_,_}|_]}} =
spawn_eval(fun() -> ?IM:do_apply(F3, snape) end),
%% Try some more complex funs.
@@ -239,11 +239,11 @@ apply_uninterpreted_fun(Config) when is_list(Config) ->
spawn_eval(fun() -> ?IM:do_apply(F1, any_arg) end),
%% Badarity (evaluated in dbg_debugged, which calls erlang:apply/2)
- ?line {'EXIT',{{badarity,{F1,[]}},[{erlang,apply,_}|_]}} =
+ ?line {'EXIT',{{badarity,{F1,[]}},[{erlang,apply,_,_}|_]}} =
spawn_eval(fun() -> ?IM:do_apply(F1) end),
%% Error in fun
- ?line {'EXIT',{snape,[{?MODULE,_FunName,_}|_]}} =
+ ?line {'EXIT',{snape,[{?MODULE,_FunName,_,_}|_]}} =
spawn_eval(fun() -> ?IM:do_apply(F1, snape) end),
ok.
@@ -277,6 +277,37 @@ applier(M, F, A) ->
io:format("~p:~p(~p) => ~p\n", [M,F,A,Res]),
Res.
+stacktrace(Config) when is_list(Config) ->
+ ?line {done,Stk} = do_eval(Config, stacktrace),
+ ?line 13 = length(Stk),
+ ?line OldStackTraceFlag = int:stack_trace(),
+ ?line int:stack_trace(no_tail),
+ try
+ ?line Res = spawn_eval(fun() -> stacktrace:stacktrace() end),
+ ?line io:format("\nInterpreted (no_tail):\n~p", [Res]),
+ ?line {done,Stk} = Res
+ after
+ ?line int:stack_trace(OldStackTraceFlag)
+ end,
+ ok.
+
+
+do_eval(Config, Mod) ->
+ ?line DataDir = ?config(data_dir, Config),
+ ?line ok = file:set_cwd(DataDir),
+
+ ?line {ok,Mod} = compile:file(Mod, [report,debug_info]),
+ ?line {module,Mod} = code:load_file(Mod),
+ ?line CompiledRes = Mod:Mod(),
+ ?line ok = io:format("Compiled:\n~p", [CompiledRes]),
+ io:nl(),
+
+ ?line {module,Mod} = int:i(Mod),
+ ?line IntRes = Mod:Mod(),
+ ?line ok = io:format("Interpreted:\n~p", [IntRes]),
+
+ ?line CompiledRes = IntRes.
+
%%
%% Evaluate in another process, to prevent the test_case process to become
%% interpreted.
diff --git a/lib/debugger/test/int_eval_SUITE_data/my_int_eval_module.erl b/lib/debugger/test/int_eval_SUITE_data/my_int_eval_module.erl
index 997ee6e17d..90f83e80e8 100644
--- a/lib/debugger/test/int_eval_SUITE_data/my_int_eval_module.erl
+++ b/lib/debugger/test/int_eval_SUITE_data/my_int_eval_module.erl
@@ -117,7 +117,7 @@ more_nocatch(Fun) ->
%% External calls.
external_call_test(Data) ->
- {'EXIT',{undef,[{?MODULE,not_exported,[42,Data]}|_]}} =
+ {'EXIT',{undef,[{?MODULE,not_exported,[42,Data],_}|_]}} =
(catch ?MODULE:not_exported(42, Data)),
{yes,Data} = i_am_exported(Data),
{yes,Data} = ?MODULE:i_am_exported(Data),
@@ -127,7 +127,7 @@ external_call_test(Data) ->
{ok,Data,[a,b]} = not_exported(Data, [a,b]),
{yes,Data} = i_am_exported(Data),
{ok,Data,[a,b]} = not_exported(Data, [a,b]),
- {'EXIT',{undef,[{?MODULE,not_exported,[7,Data]}|_]}} =
+ {'EXIT',{undef,[{?MODULE,not_exported,[7,Data],_}|_]}} =
(catch ?MODULE:not_exported(7, Data)),
{yes,Data} = ?MODULE:i_am_exported(Data),
ok.
diff --git a/lib/debugger/test/int_eval_SUITE_data/stacktrace.erl b/lib/debugger/test/int_eval_SUITE_data/stacktrace.erl
new file mode 100644
index 0000000000..3380178fdc
--- /dev/null
+++ b/lib/debugger/test/int_eval_SUITE_data/stacktrace.erl
@@ -0,0 +1,130 @@
+-module(stacktrace).
+-export([?MODULE/0]).
+
+?MODULE() ->
+ OldDepth = erlang:system_flag(backtrace_depth, 32),
+ done = (catch do_try()),
+ Stk = trim(erlang:get_stacktrace()),
+ erlang:system_flag(backtrace_depth, OldDepth),
+ {done,Stk}.
+
+trim([{int_eval_SUITE,_,_,_}|_]) ->
+ [];
+trim([H|T]) ->
+ [H|trim(T)];
+trim([]) -> [].
+
+do_try() ->
+ try
+ 0 = id(42)
+ catch
+ error:{badmatch,42} ->
+ do_try2() %Tail-recursive
+ end.
+
+do_try2() ->
+ try
+ 0 = id(42)
+ catch
+ error:{badmatch,42} ->
+ do_try3() %Not tail-recursive
+ end,
+ ?LINE.
+
+do_try3() ->
+ try id(42) of
+ 42 -> do_try4() %Tail-recursive
+ catch
+ error:ignore -> %Should never catch
+ ?LINE
+ end.
+
+do_try4() ->
+ try
+ do_recv() %Not tail-recursive
+ catch
+ error:ignore -> %Should never catch
+ ?LINE
+ end.
+
+do_recv() ->
+ self() ! x,
+ receive
+ x -> do_recv2() %Not tail-recursive
+ end,
+ ?LINE.
+
+do_recv2() ->
+ self() ! y,
+ receive
+ y -> do_recv3() %Tail-recursive
+ end.
+
+do_recv3() ->
+ receive
+ after 0 -> do_recv4() %Tail-recursive
+ end.
+
+do_recv4() ->
+ receive
+ after 0 -> do_if(true) %Not tail-recursive
+ end,
+ ?LINE.
+
+do_if(Bool) ->
+ if
+ Bool -> do_if2(Bool) %Tail-recursive
+ end.
+
+do_if2(Bool) ->
+ if
+ Bool -> do_case(Bool) %Not tail-recursive
+ end,
+ ?LINE.
+
+
+do_case(Bool) ->
+ case Bool of
+ true -> do_case2(Bool) %Tail-recursive
+ end.
+
+do_case2(Bool) ->
+ case Bool of
+ true -> do_fun(Bool) %Not tail-recursive
+ end,
+ ?LINE.
+
+do_fun(Bool) ->
+ F = fun(true) ->
+ do_fun2(Bool) %Tail-recursive
+ end,
+ F(Bool). %Tail-recursive
+
+do_fun2(Bool) ->
+ F = fun(true) ->
+ cons(Bool) %Tail-recursive
+ end,
+ F(Bool), %Not tail-recursive
+ ?LINE.
+
+cons(Bool) ->
+ [Bool|tuple()].
+
+tuple() ->
+ {ok,op()}.
+
+op() ->
+ 1 + lc().
+
+lc() ->
+ [done() || true].
+
+done() ->
+ tail(100),
+ throw(done).
+
+tail(0) -> ok;
+tail(N) -> tail(N-1).
+
+id(I) ->
+ I.
diff --git a/lib/debugger/test/lc_SUITE.erl b/lib/debugger/test/lc_SUITE.erl
index 92a03ef58e..2f05eb7fca 100644
--- a/lib/debugger/test/lc_SUITE.erl
+++ b/lib/debugger/test/lc_SUITE.erl
@@ -17,21 +17,22 @@
%% %CopyrightEnd%
%%
-%%
-module(lc_SUITE).
--author('[email protected]').
+%% Copied from lc_SUITE in the compiler application.
+
-export([all/0, suite/0,groups/0,init_per_group/2,end_per_group/2,
init_per_testcase/2,end_per_testcase/2,
init_per_suite/1,end_per_suite/1,
- basic/1]).
+ basic/1,deeply_nested/1,no_generator/1,
+ empty_generator/1]).
-include_lib("test_server/include/test_server.hrl").
suite() -> [{ct_hooks,[ts_install_cth]}].
all() ->
- cases().
+ [basic, deeply_nested, no_generator, empty_generator].
groups() ->
[].
@@ -42,10 +43,6 @@ init_per_group(_GroupName, Config) ->
end_per_group(_GroupName, Config) ->
Config.
-
-cases() ->
- [basic].
-
init_per_testcase(_Case, Config) ->
test_lib:interpret(?MODULE),
Dog = test_server:timetrap(?t:minutes(1)),
@@ -64,7 +61,7 @@ init_per_suite(Config) when is_list(Config) ->
end_per_suite(Config) when is_list(Config) ->
ok.
-basic(Config) when list(Config) ->
+basic(Config) when is_list(Config) ->
?line L0 = lists:seq(1, 10),
?line L1 = my_map(fun(X) -> {x,X} end, L0),
?line L1 = [{x,X} || X <- L0],
@@ -73,16 +70,116 @@ basic(Config) when list(Config) ->
?line [4,5,6] = [X || X <- L0, X > 3, X < 7],
?line [] = [X || X <- L0, X > 32, X < 7],
?line [1,3,5,7,9] = [X || X <- L0, odd(X)],
+ ?line [2,4,6,8,10] = [X || X <- L0, not odd(X)],
+ ?line [1,3,5,9] = [X || X <- L0, odd(X), X =/= 7],
+ ?line [2,4,8,10] = [X || X <- L0, not odd(X), X =/= 6],
+
+ %% Append is specially handled.
+ ?line [1,3,5,9,2,4,8,10] = [X || X <- L0, odd(X), X =/= 7] ++
+ [X || X <- L0, not odd(X), X =/= 6],
+
+ %% Guards BIFs are evaluated in guard context. Weird, but true.
+ ?line [{a,b,true},{x,y,true,true}] = [X || X <- tuple_list(), element(3, X)],
+
+ %% Filter expressions with andalso/orelse.
+ ?line "abc123" = alphanum("?abc123.;"),
%% Error cases.
- ?line [] = [X || X <- L1, X+1 < 2],
?line [] = [{xx,X} || X <- L0, element(2, X) == no_no_no],
- ?line {'EXIT',_} = (catch [X || X <- L1, odd(X)]),
+ ?line {'EXIT',_} = (catch [X || X <- L1, list_to_atom(X) == dum]),
+ ?line [] = [X || X <- L1, X+1 < 2],
+ ?line {'EXIT',_} = (catch [X || X <- L1, odd(X)]),
+ %% A bad generator has a different exception compared to BEAM.
+ ?line {'EXIT',{{bad_generator,x},_}} = (catch [E || E <- id(x)]),
ok.
+tuple_list() ->
+ [{a,b,true},[a,b,c],glurf,{a,b,false,xx},{a,b},{x,y,true,true},{a,b,d,ddd}].
+
my_map(F, L) ->
[F(X) || X <- L].
odd(X) ->
X rem 2 == 1.
+
+alphanum(Str) ->
+ [C || C <- Str, ((C >= $0) andalso (C =< $9))
+ orelse ((C >= $a) andalso (C =< $z))
+ orelse ((C >= $A) andalso (C =< $Z))].
+
+deeply_nested(Config) when is_list(Config) ->
+ [[99,98,97,96,42,17,1764,12,11,10,9,8,7,6,5,4,3,7,2,1]] = deeply_nested_1(),
+ ok.
+
+deeply_nested_1() ->
+ %% This used to compile really, really SLOW before R11B-1...
+ [[X1,X2,X3,X4,X5,X6,X7(),X8,X9,X10,X11,X12,X13,X14,X15,X16,X17,X18(),X19,X20] ||
+ X1 <- [99],X2 <- [98],X3 <- [97],X4 <- [96],X5 <- [42],X6 <- [17],
+ X7 <- [fun() -> X5*X5 end],X8 <- [12],X9 <- [11],X10 <- [10],
+ X11 <- [9],X12 <- [8],X13 <- [7],X14 <- [6],X15 <- [5],
+ X16 <- [4],X17 <- [3],X18 <- [fun() -> X16+X17 end],X19 <- [2],X20 <- [1]].
+
+no_generator(Config) when is_list(Config) ->
+ ?line Seq = lists:seq(-10, 17),
+ ?line [no_gen_verify(no_gen(A, B), A, B) || A <- Seq, B <- Seq],
+
+ %% Literal expression, for coverage.
+ ?line [a] = [a || true],
+ ?line [a,b,c] = [a || true] ++ [b,c],
+ ok.
+
+no_gen(A, B) ->
+ [{A,B} || A+B =:= 0] ++
+ [{A,B} || A*B =:= 0] ++
+ [{A,B} || A rem B =:= 3] ++
+ [{A,B} || A =:= B] ++
+ [{one_more,A,B} || no_gen_one_more(A, B)] ++
+ [A || A =:= 1] ++
+ [A || A =:= 2] ++
+ [A || A =:= 3] ++
+ [A || A =:= 4] ++
+ [A || A =:= 5] ++
+ [A || A =:= 6] ++
+ [A || A =:= 7] ++
+ [A || A =:= 8] ++
+ [A || A =:= 9] ++
+ [B || B =:= 1] ++
+ [B || B =:= 2] ++
+ [B || B =:= 3] ++
+ [B || B =:= 4] ++
+ [B || B =:= 5] ++
+ [B || B =:= 6] ++
+ [B || B =:= 7] ++
+ [B || B =:= 8] ++
+ [B || B =:= 9].
+
+no_gen_verify(Res, A, B) ->
+ Pair = {A,B},
+ ShouldBe = no_gen_eval(fun() -> A+B =:= 0 end, Pair) ++
+ no_gen_eval(fun() -> A*B =:= 0 end, Pair) ++
+ no_gen_eval(fun() -> B =/= 0 andalso A rem B =:= 3 end, Pair) ++
+ no_gen_eval(fun() -> A =:= B end, Pair) ++
+ no_gen_eval(fun() -> A + 1 =:= B end, {one_more,A,B}) ++
+ no_gen_eval(fun() -> 1 =< A andalso A =< 9 end, A) ++
+ no_gen_eval(fun() -> 1 =< B andalso B =< 9 end, B),
+ case Res of
+ ShouldBe -> ok;
+ _ ->
+ io:format("A = ~p; B = ~p; Expected = ~p, actual = ~p", [A,B,ShouldBe,Res]),
+ ?t:fail()
+ end.
+
+no_gen_eval(Fun, Res) ->
+ case Fun() of
+ true -> [Res];
+ false -> []
+ end.
+
+no_gen_one_more(A, B) -> A + 1 =:= B.
+
+empty_generator(Config) when is_list(Config) ->
+ ?line [] = [X || {X} <- [], (false or (X/0 > 3))],
+ ok.
+
+id(I) -> I.
diff --git a/lib/debugger/test/line_number_SUITE.erl b/lib/debugger/test/line_number_SUITE.erl
new file mode 100644
index 0000000000..d1f56d3493
--- /dev/null
+++ b/lib/debugger/test/line_number_SUITE.erl
@@ -0,0 +1,220 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 1999-2011. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+-module(line_number_SUITE).
+
+-export([all/0, suite/0,groups/0,init_per_group/2,end_per_group/2,
+ init_per_testcase/2,end_per_testcase/2,
+ init_per_suite/1,end_per_suite/1,
+ line_numbers/1]).
+-export([crash/1]).
+
+-include_lib("test_server/include/test_server.hrl").
+
+suite() -> [{ct_hooks,[ts_install_cth]}].
+
+all() ->
+ cases().
+
+groups() ->
+ [].
+
+init_per_group(_GroupName, Config) ->
+ Config.
+
+end_per_group(_GroupName, Config) ->
+ Config.
+
+cases() ->
+ [line_numbers].
+
+init_per_testcase(_Case, Config) ->
+ test_lib:interpret(?MODULE),
+ Dog = test_server:timetrap(?t:minutes(1)),
+ [{watchdog,Dog}|Config].
+
+end_per_testcase(_Case, Config) ->
+ Dog = ?config(watchdog, Config),
+ ?t:timetrap_cancel(Dog),
+ ok.
+
+init_per_suite(Config) when is_list(Config) ->
+ ?line test_lib:interpret(?MODULE),
+ ?line true = lists:member(?MODULE, int:interpreted()),
+ Config.
+
+end_per_suite(Config) when is_list(Config) ->
+ ok.
+
+
+
+
+
+%%
+%% === Make sure that this is always line 70 ===
+%%
+line1(Tag, X) -> %Line 72
+ case Tag of %Line 73
+ a ->
+ Y = X + 1, %Line 75
+ Res = id({ok,Y}), %Line 76
+ ?MODULE:crash({ok,42} = Res); %Line 77
+ b ->
+ x = id(x), %Line 79
+ ok %Line 80
+ end. %Line 81
+
+crash(_) -> %Line 83
+ erlang:error(crash). %Line 84
+
+close_calls(Where) -> %Line 86
+ put(where_to_crash, Where), %Line 87
+ try
+ call1(), %Line 89
+ call2(), %Line 90
+ call3(), %Line 91
+ no_crash %Line 92
+ catch error:crash ->
+ erlang:get_stacktrace() %Line 94
+ end. %Line 95
+
+call1() -> %Line 97
+ maybe_crash(call1), %Line 98
+ ok. %Line 99
+
+call2() -> %Line 101
+ maybe_crash(call2), %Line 102
+ ok. %Line 103
+
+call3() -> %Line 105
+ maybe_crash(call3), %Line 106
+ ok. %Line 107
+
+maybe_crash(Name) -> %Line 109
+ case get(where_to_crash) of %Line 110
+ Name ->
+ erlang:error(crash); %Line 112
+ _ ->
+ ok %Line 114
+ end. %Line 115
+
+build_binary1(Size) -> %Line 117
+ id(42), %Line 118
+ <<0:Size>>. %Line 119
+
+build_binary2(Size, Bin) -> %Line 121
+ id(0), %Line 122
+ <<7:Size,Bin/binary>>. %Line 123
+
+do_call_abs(x, Arg) -> %Line 125
+ abs(Arg). %Line 126
+
+do_call_unsafe_bif(x, Arg) -> %Line 128
+ link(Arg). %Line 129
+
+
+line_numbers(Config) when is_list(Config) ->
+ File = ?MODULE_STRING ++ ".erl",
+ {'EXIT',{{case_clause,bad_tag},
+ [{?MODULE,line1,2,
+ [{file,File},{line,73}]},
+ {?MODULE,line_numbers,1,_}|_]}} =
+ (catch line1(bad_tag, 0)),
+ {'EXIT',{badarith,
+ [{?MODULE,line1,2,
+ [{file,File},{line,75}]},
+ {?MODULE,line_numbers,1,_}|_]}} =
+ (catch line1(a, not_an_integer)),
+ {'EXIT',{{badmatch,{ok,1}},
+ [{?MODULE,line1,2,
+ [{file,File},{line,77}]},
+ {?MODULE,line_numbers,1,_}|_]}} =
+ (catch line1(a, 0)),
+ {'EXIT',{crash,
+ [{?MODULE,crash,1,
+ [{file,File},{line,84}]},
+ {?MODULE,line_numbers,1,_}|_]}} =
+ (catch line1(a, 41)),
+
+ [{?MODULE,maybe_crash,1,[{file,File},{line,112}]},
+ {?MODULE,call1,0,[{file,File},{line,98}]},
+ {?MODULE,close_calls,1,[{file,File},{line,89}]},
+ {?MODULE,line_numbers,1,[{file,File},{line,_}]}|_] =
+ close_calls(call1),
+ [{?MODULE,maybe_crash,1,[{file,File},{line,112}]},
+ {?MODULE,call2,0,[{file,File},{line,102}]},
+ {?MODULE,close_calls,1,[{file,File},{line,90}]},
+ {?MODULE,line_numbers,1,[{file,File},{line,_}]}|_] =
+ close_calls(call2),
+ [{?MODULE,maybe_crash,1,[{file,File},{line,112}]},
+ {?MODULE,call3,0,[{file,File},{line,106}]},
+ {?MODULE,close_calls,1,[{file,File},{line,91}]},
+ {?MODULE,line_numbers,1,[{file,File},{line,_}]}|_] =
+ close_calls(call3),
+ no_crash = close_calls(other),
+
+ <<0,0>> = build_binary1(16),
+ {'EXIT',{badarg,
+ [{?MODULE,build_binary1,1,
+ [{file,File},{line,119}]},
+ {?MODULE,line_numbers,1,
+ [{file,ModFile},{line,_}]}|_]}} =
+ (catch build_binary1(bad_size)),
+
+ <<7,1,2,3>> = build_binary2(8, <<1,2,3>>),
+ {'EXIT',{badarg,
+ [{?MODULE,build_binary2,2,
+ [{file,File},{line,123}]},
+ {?MODULE,line_numbers,1,
+ [{file,ModFile},{line,_}]}|_]}} =
+ (catch build_binary2(bad_size, <<>>)),
+ {'EXIT',{badarg,
+ [%% Beam has an extra here:
+ %% {erlang,bit_size,[bad_binary],[]}
+ %% Since this is an artifact of the implementation,
+ %% we don't attempt to mimic it in the debugger.
+ {?MODULE,build_binary2,2,
+ [{file,File},{line,123}]},
+ {?MODULE,line_numbers,1,
+ [{file,ModFile},{line,_}]}|_]}} =
+ (catch build_binary2(8, bad_binary)),
+
+ {'EXIT',{function_clause,
+ [{?MODULE,do_call_abs,[y,y],
+ [{file,File},{line,125}]},
+ {?MODULE,line_numbers,1,_}|_]}} =
+ (catch do_call_abs(y, y)),
+ {'EXIT',{badarg,
+ [{erlang,abs,[[]],[]},
+ {?MODULE,do_call_abs,2,
+ [{file,File},{line,126}]},
+ {?MODULE,line_numbers,1,_}|_]}} =
+ (catch do_call_abs(x, [])),
+
+ {'EXIT',{badarg,
+ [{erlang,link,[[]],[]},
+ {?MODULE,do_call_unsafe_bif,2,
+ [{file,File},{line,129}]},
+ {?MODULE,line_numbers,1,_}|_]}} =
+ (catch do_call_unsafe_bif(x, [])),
+
+ ok.
+
+id(I) ->
+ I.
diff --git a/lib/debugger/test/test_lib.erl b/lib/debugger/test/test_lib.erl
index 541375e64a..5e4ac7f164 100644
--- a/lib/debugger/test/test_lib.erl
+++ b/lib/debugger/test/test_lib.erl
@@ -22,7 +22,7 @@
-export([interpret/1]).
-interpret(Mod) when atom(Mod) ->
+interpret(Mod) when is_atom(Mod) ->
case lists:member(Mod, int:interpreted()) of
true -> ok;
false -> {module,Mod} = i:ii(Mod)
diff --git a/lib/debugger/test/trycatch_SUITE.erl b/lib/debugger/test/trycatch_SUITE.erl
index a87c5db138..470d46d915 100644
--- a/lib/debugger/test/trycatch_SUITE.erl
+++ b/lib/debugger/test/trycatch_SUITE.erl
@@ -318,17 +318,18 @@ eclectic(Conf) when is_list(Conf) ->
V = {make_ref(),3.1415926535,[[]|{}]},
?line {{value,{value,V},V},V} =
eclectic_1({foo,{value,{value,V}}}, undefined, {value,V}),
- ?line {{'EXIT',{V,[{?MODULE,foo,_}|_]}},V} =
+ ?line {{'EXIT',{V,[{?MODULE,foo,_,_}|_]}},V} =
eclectic_1({catch_foo,{error,V}}, undefined, {value,V}),
?line {{error,{exit,V},{'EXIT',V}},V} =
eclectic_1({foo,{error,{exit,V}}}, error, {value,V}),
- ?line {{value,{value,V},V},{'EXIT',{badarith,[{?MODULE,my_add,_}|_]}}} =
+ ?line {{value,{value,V},V},{'EXIT',{badarith,[{?MODULE,my_add,_,_}|_]}}} =
eclectic_1({foo,{value,{value,V}}}, undefined, {'add',{0,a}}),
?line {{'EXIT',V},V} =
eclectic_1({catch_foo,{exit,V}}, undefined, {throw,V}),
- ?line {{error,{'div',{1,0}},{'EXIT',{badarith,[{?MODULE,my_div,_}|_]}}}, {'EXIT',V}} =
+ ?line {{error,{'div',{1,0}},{'EXIT',{badarith,[{?MODULE,my_div,_,_}|_]}}},
+ {'EXIT',V}} =
eclectic_1({foo,{error,{'div',{1,0}}}}, error, {exit,V}),
- ?line {{{error,V},{'EXIT',{V,[{?MODULE,foo,_}|_]}}},{'EXIT',V}} =
+ ?line {{{error,V},{'EXIT',{V,[{?MODULE,foo,_,_}|_]}}},{'EXIT',V}} =
eclectic_1({catch_foo,{throw,{error,V}}}, undefined, {exit,V}),
%%
?line {{value,{value,{value,V},V}},V} =
@@ -337,15 +338,15 @@ eclectic(Conf) when is_list(Conf) ->
eclectic_2({throw,{value,V}}, throw, {value,V}),
?line {{caught,{'EXIT',V}},undefined} =
eclectic_2({value,{value,V}}, undefined, {exit,V}),
- ?line {{caught,{'EXIT',{V,[{?MODULE,foo,_}|_]}}},undefined} =
+ ?line {{caught,{'EXIT',{V,[{?MODULE,foo,_,_}|_]}}},undefined} =
eclectic_2({error,{value,V}}, throw, {error,V}),
- ?line {{caught,{'EXIT',{badarg,[{erlang,abs,[V]}|_]}}},V} =
+ ?line {{caught,{'EXIT',{badarg,[{erlang,abs,[V],_}|_]}}},V} =
eclectic_2({value,{'abs',V}}, undefined, {value,V}),
- ?line {{caught,{'EXIT',{badarith,[{?MODULE,my_add,_}|_]}}},V} =
+ ?line {{caught,{'EXIT',{badarith,[{?MODULE,my_add,_,_}|_]}}},V} =
eclectic_2({exit,{'add',{0,a}}}, exit, {value,V}),
?line {{caught,{'EXIT',V}},undefined} =
eclectic_2({value,{error,V}}, undefined, {exit,V}),
- ?line {{caught,{'EXIT',{V,[{?MODULE,foo,_}|_]}}},undefined} =
+ ?line {{caught,{'EXIT',{V,[{?MODULE,foo,_,_}|_]}}},undefined} =
eclectic_2({throw,{'div',{1,0}}}, throw, {error,V}),
ok.
diff --git a/lib/dialyzer/doc/src/Makefile b/lib/dialyzer/doc/src/Makefile
index 45b0ffa5ff..45b0ffa5ff 100755..100644
--- a/lib/dialyzer/doc/src/Makefile
+++ b/lib/dialyzer/doc/src/Makefile
diff --git a/lib/dialyzer/doc/src/book.xml b/lib/dialyzer/doc/src/book.xml
index 0b4e1cb617..0b4e1cb617 100755..100644
--- a/lib/dialyzer/doc/src/book.xml
+++ b/lib/dialyzer/doc/src/book.xml
diff --git a/lib/dialyzer/doc/src/fascicules.xml b/lib/dialyzer/doc/src/fascicules.xml
index 0678195e07..0678195e07 100755..100644
--- a/lib/dialyzer/doc/src/fascicules.xml
+++ b/lib/dialyzer/doc/src/fascicules.xml
diff --git a/lib/dialyzer/doc/src/make.dep b/lib/dialyzer/doc/src/make.dep
deleted file mode 100755
index f8177cd419..0000000000
--- a/lib/dialyzer/doc/src/make.dep
+++ /dev/null
@@ -1,20 +0,0 @@
-# ----------------------------------------------------
-# >>>> Do not edit this file <<<<
-# This file was automaticly generated by
-# /home/otp/bin/docdepend
-# ----------------------------------------------------
-
-
-# ----------------------------------------------------
-# TeX files that the DVI file depend on
-# ----------------------------------------------------
-
-book.dvi: book.tex dialyzer.tex dialyzer_chapter.tex \
- part.tex ref_man.tex
-
-# ----------------------------------------------------
-# Source inlined when transforming from source to LaTeX
-# ----------------------------------------------------
-
-book.tex: ref_man.xml
-
diff --git a/lib/dialyzer/doc/src/notes.xml b/lib/dialyzer/doc/src/notes.xml
index 17291b24f7..17291b24f7 100755..100644
--- a/lib/dialyzer/doc/src/notes.xml
+++ b/lib/dialyzer/doc/src/notes.xml
diff --git a/lib/dialyzer/doc/src/part.xml b/lib/dialyzer/doc/src/part.xml
index 4410840660..4410840660 100755..100644
--- a/lib/dialyzer/doc/src/part.xml
+++ b/lib/dialyzer/doc/src/part.xml
diff --git a/lib/dialyzer/doc/src/part_notes.xml b/lib/dialyzer/doc/src/part_notes.xml
index cb048d55dd..cb048d55dd 100755..100644
--- a/lib/dialyzer/doc/src/part_notes.xml
+++ b/lib/dialyzer/doc/src/part_notes.xml
diff --git a/lib/dialyzer/doc/src/ref_man.xml b/lib/dialyzer/doc/src/ref_man.xml
index ca5410f6b8..ca5410f6b8 100755..100644
--- a/lib/dialyzer/doc/src/ref_man.xml
+++ b/lib/dialyzer/doc/src/ref_man.xml
diff --git a/lib/dialyzer/info b/lib/dialyzer/info
index 9fba4b54ad..9fba4b54ad 100755..100644
--- a/lib/dialyzer/info
+++ b/lib/dialyzer/info
diff --git a/lib/dialyzer/src/dialyzer.erl b/lib/dialyzer/src/dialyzer.erl
index 5014a4244c..3e3c12405f 100644
--- a/lib/dialyzer/src/dialyzer.erl
+++ b/lib/dialyzer/src/dialyzer.erl
@@ -442,23 +442,29 @@ message_to_string({opaque_type_test, [Fun, Opaque]}) ->
message_to_string({race_condition, [M, F, Args, Reason]}) ->
io_lib:format("The call ~w:~w~s ~s\n", [M, F, Args, Reason]);
%%----- Warnings for behaviour errors --------------------
-message_to_string({callback_type_mismatch, [B, F, A, O]}) ->
- io_lib:format("The inferred return type of the ~w/~w callback includes the"
- " type ~s which is not a valid return for the ~w behaviour\n",
- [F, A, erl_types:t_to_string(O), B]);
-message_to_string({callback_arg_type_mismatch, [B, F, A, N, O]}) ->
- io_lib:format("The inferred type of the ~s argument of ~w/~w callback"
- " includes the type ~s which is not valid for the ~w behaviour"
- "\n", [ordinal(N), F, A, erl_types:t_to_string(O), B]);
+message_to_string({callback_type_mismatch, [B, F, A, ST, CT]}) ->
+ io_lib:format("The inferred return type of ~w/~w (~s) has nothing in common"
+ " with ~s, which is the expected return type for the callback of"
+ " ~w behaviour\n", [F, A, ST, CT, B]);
+message_to_string({callback_arg_type_mismatch, [B, F, A, N, ST, CT]}) ->
+ io_lib:format("The inferred type for the ~s argument of ~w/~w (~s) is"
+ " not a supertype of ~s, which is expected type for this"
+ " argument in the callback of the ~w behaviour\n",
+ [ordinal(N), F, A, ST, CT, B]);
+message_to_string({callback_spec_type_mismatch, [B, F, A, ST, CT]}) ->
+ io_lib:format("The return type ~s in the specification of ~w/~w is not a"
+ " subtype of ~s, which is the expected return type for the"
+ " callback of ~w behaviour\n", [ST, F, A, CT, B]);
+message_to_string({callback_spec_arg_type_mismatch, [B, F, A, N, ST, CT]}) ->
+ io_lib:format("The specified type for the ~s argument of ~w/~w (~s) is"
+ " not a supertype of ~s, which is expected type for this"
+ " argument in the callback of the ~w behaviour\n",
+ [ordinal(N), F, A, ST, CT, B]);
message_to_string({callback_missing, [B, F, A]}) ->
io_lib:format("Undefined callback function ~w/~w (behaviour '~w')\n",
[F, A, B]);
-message_to_string({invalid_spec, [B, F, A, R]}) ->
- io_lib:format("The spec for the ~w:~w/~w callback is not correct: ~s\n",
- [B, F, A, R]);
-message_to_string({spec_missing, [B, F, A]}) ->
- io_lib:format("Type info about ~w:~w/~w callback is not available\n",
- [B, F, A]).
+message_to_string({callback_info_missing, [B]}) ->
+ io_lib:format("Callback info about the ~w behaviour is not available\n", [B]).
%%-----------------------------------------------------------------------------
%% Auxiliary functions below
diff --git a/lib/dialyzer/src/dialyzer.hrl b/lib/dialyzer/src/dialyzer.hrl
index 9d2e554981..5e089d1773 100644
--- a/lib/dialyzer/src/dialyzer.hrl
+++ b/lib/dialyzer/src/dialyzer.hrl
@@ -57,6 +57,7 @@
-define(WARN_UNMATCHED_RETURN, warn_umatched_return).
-define(WARN_RACE_CONDITION, warn_race_condition).
-define(WARN_BEHAVIOUR, warn_behaviour).
+-define(WARN_UNDEFINED_CALLBACK, warn_undefined_callbacks).
%%
%% The following type has double role:
@@ -71,7 +72,8 @@
| ?WARN_CONTRACT_NOT_EQUAL | ?WARN_CONTRACT_SUBTYPE
| ?WARN_CONTRACT_SUPERTYPE | ?WARN_CALLGRAPH
| ?WARN_UNMATCHED_RETURN | ?WARN_RACE_CONDITION
- | ?WARN_BEHAVIOUR | ?WARN_CONTRACT_RANGE.
+ | ?WARN_BEHAVIOUR | ?WARN_CONTRACT_RANGE
+ | ?WARN_UNDEFINED_CALLBACK.
%%
%% This is the representation of each warning as they will be returned
diff --git a/lib/dialyzer/src/dialyzer_analysis_callgraph.erl b/lib/dialyzer/src/dialyzer_analysis_callgraph.erl
index abad1f3a75..62153fa176 100644
--- a/lib/dialyzer/src/dialyzer_analysis_callgraph.erl
+++ b/lib/dialyzer/src/dialyzer_analysis_callgraph.erl
@@ -43,8 +43,7 @@
parent :: pid(),
plt :: dialyzer_plt:plt(),
start_from = byte_code :: start_from(),
- use_contracts = true :: boolean(),
- behaviours = {false,[]} :: {boolean(),[atom()]}
+ use_contracts = true :: boolean()
}).
-record(server_state, {parent :: pid(), legal_warnings :: [dial_warn_tag()]}).
@@ -57,9 +56,7 @@
start(Parent, LegalWarnings, Analysis) ->
RacesOn = ordsets:is_element(?WARN_RACE_CONDITION, LegalWarnings),
- BehavOn = ordsets:is_element(?WARN_BEHAVIOUR, LegalWarnings),
- Analysis0 = Analysis#analysis{race_detection = RacesOn,
- behaviours_chk = BehavOn},
+ Analysis0 = Analysis#analysis{race_detection = RacesOn},
Analysis1 = expand_files(Analysis0),
Analysis2 = run_analysis(Analysis1),
State = #server_state{parent = Parent, legal_warnings = LegalWarnings},
@@ -125,8 +122,7 @@ analysis_start(Parent, Analysis) ->
plt = Plt,
parent = Parent,
start_from = Analysis#analysis.start_from,
- use_contracts = Analysis#analysis.use_contracts,
- behaviours = {Analysis#analysis.behaviours_chk, []}
+ use_contracts = Analysis#analysis.use_contracts
},
Files = ordsets:from_list(Analysis#analysis.files),
{Callgraph, NoWarn, TmpCServer0} = compile_and_store(Files, State),
@@ -180,8 +176,8 @@ analysis_start(Parent, Analysis) ->
send_analysis_done(Parent, Plt4, State3#analysis_state.doc_plt).
analyze_callgraph(Callgraph, State) ->
- Plt = State#analysis_state.plt,
Codeserver = State#analysis_state.codeserver,
+ Plt = dialyzer_plt:insert_callbacks(State#analysis_state.plt, Codeserver),
Parent = State#analysis_state.parent,
case State#analysis_state.analysis_type of
plt_build ->
@@ -192,13 +188,11 @@ analyze_callgraph(Callgraph, State) ->
State#analysis_state{plt = NewPlt};
succ_typings ->
NoWarn = State#analysis_state.no_warn_unused,
- {BehavioursChk, _Known} = State#analysis_state.behaviours,
DocPlt = State#analysis_state.doc_plt,
Callgraph1 = dialyzer_callgraph:finalize(Callgraph),
{Warnings, NewPlt, NewDocPlt} =
dialyzer_succ_typings:get_warnings(Callgraph1, Plt, DocPlt,
- Codeserver, NoWarn, Parent,
- BehavioursChk),
+ Codeserver, NoWarn, Parent),
dialyzer_callgraph:delete(Callgraph1),
send_warnings(State#analysis_state.parent, Warnings),
State#analysis_state{plt = NewPlt, doc_plt = NewDocPlt}
@@ -213,8 +207,7 @@ compile_and_store(Files, #analysis_state{codeserver = CServer,
include_dirs = Dirs,
parent = Parent,
use_contracts = UseContracts,
- start_from = StartFrom,
- behaviours = {BehChk, _}
+ start_from = StartFrom
} = State) ->
send_log(Parent, "Reading files and computing callgraph... "),
{T1, _} = statistics(runtime),
@@ -263,37 +256,26 @@ compile_and_store(Files, #analysis_state{codeserver = CServer,
{T2, _} = statistics(runtime),
Msg1 = io_lib:format("done in ~.2f secs\nRemoving edges... ", [(T2-T1)/1000]),
send_log(Parent, Msg1),
- {KnownBehaviours, UnknownBehaviours} =
- dialyzer_behaviours:get_behaviours(Modules, NewCServer),
- if UnknownBehaviours =:= [] -> ok;
- true -> send_unknown_behaviours(Parent, UnknownBehaviours)
- end,
- State1 = State#analysis_state{behaviours = {BehChk, KnownBehaviours}},
- NewCallgraph2 = cleanup_callgraph(State1, NewCServer, NewCallgraph1, Modules),
+ NewCallgraph2 = cleanup_callgraph(State, NewCServer, NewCallgraph1, Modules),
{T3, _} = statistics(runtime),
Msg2 = io_lib:format("done in ~.2f secs\n", [(T3-T2)/1000]),
send_log(Parent, Msg2),
{NewCallgraph2, sets:from_list(NoWarn), NewCServer}.
cleanup_callgraph(#analysis_state{plt = InitPlt, parent = Parent,
- codeserver = CodeServer,
- behaviours = {BehChk, KnownBehaviours}
+ codeserver = CodeServer
},
CServer, Callgraph, Modules) ->
ModuleDeps = dialyzer_callgraph:module_deps(Callgraph),
send_mod_deps(Parent, ModuleDeps),
{Callgraph1, ExtCalls} = dialyzer_callgraph:remove_external(Callgraph),
- if BehChk ->
- RelevantAPICalls =
- dialyzer_behaviours:get_behaviour_apis(KnownBehaviours),
- BehaviourAPICalls = [Call || {_From, To} = Call <- ExtCalls,
- lists:member(To, RelevantAPICalls)],
- Callgraph2 =
- dialyzer_callgraph:put_behaviour_api_calls(BehaviourAPICalls,
- Callgraph1);
- true ->
- Callgraph2 = Callgraph1
- end,
+ RelevantAPICalls =
+ dialyzer_behaviours:get_behaviour_apis([gen_server]),
+ BehaviourAPICalls = [Call || {_From, To} = Call <- ExtCalls,
+ lists:member(To, RelevantAPICalls)],
+ Callgraph2 =
+ dialyzer_callgraph:put_behaviour_api_calls(BehaviourAPICalls,
+ Callgraph1),
ExtCalls1 = [Call || Call = {_From, To} <- ExtCalls,
not dialyzer_plt:contains_mfa(InitPlt, To)],
{BadCalls1, RealExtCalls} =
@@ -325,63 +307,42 @@ compile_src(File, Includes, Defines, Callgraph, CServer, UseContracts) ->
case dialyzer_utils:get_abstract_code_from_src(File, CompOpts) of
{error, _Msg} = Error -> Error;
{ok, AbstrCode} ->
- case dialyzer_utils:get_core_from_abstract_code(AbstrCode, CompOpts) of
- error -> {error, " Could not find abstract code for: " ++ File};
- {ok, Core} ->
- Mod = cerl:concrete(cerl:module_name(Core)),
- NoWarn = abs_get_nowarn(AbstrCode, Mod),
- case dialyzer_utils:get_record_and_type_info(AbstrCode) of
- {error, _} = Error -> Error;
- {ok, RecInfo} ->
- CServer2 =
- dialyzer_codeserver:store_temp_records(Mod, RecInfo, CServer),
- case UseContracts of
- true ->
- case dialyzer_utils:get_spec_info(Mod, AbstrCode, RecInfo) of
- {error, _} = Error -> Error;
- {ok, SpecInfo} ->
- CServer3 =
- dialyzer_codeserver:store_temp_contracts(Mod,
- SpecInfo,
- CServer2),
- store_core(Mod, Core, NoWarn, Callgraph, CServer3)
- end;
- false ->
- store_core(Mod, Core, NoWarn, Callgraph, CServer2)
- end
- end
- end
+ compile_common(File, AbstrCode, CompOpts, Callgraph, CServer, UseContracts)
end.
compile_byte(File, Callgraph, CServer, UseContracts) ->
case dialyzer_utils:get_abstract_code_from_beam(File) of
error ->
{error, " Could not get abstract code for: " ++ File ++ "\n" ++
- " Recompile with +debug_info or analyze starting from source code"};
+ " Recompile with +debug_info or analyze starting from source code"};
{ok, AbstrCode} ->
- case dialyzer_utils:get_core_from_abstract_code(AbstrCode) of
- error -> {error, " Could not get core for: "++File};
- {ok, Core} ->
- Mod = cerl:concrete(cerl:module_name(Core)),
- NoWarn = abs_get_nowarn(AbstrCode, Mod),
- case dialyzer_utils:get_record_and_type_info(AbstrCode) of
- {error, _} = Error -> Error;
- {ok, RecInfo} ->
- CServer1 =
- dialyzer_codeserver:store_temp_records(Mod, RecInfo, CServer),
- case UseContracts of
- true ->
- case dialyzer_utils:get_spec_info(Mod, AbstrCode, RecInfo) of
- {error, _} = Error -> Error;
- {ok, SpecInfo} ->
- CServer2 =
- dialyzer_codeserver:store_temp_contracts(Mod, SpecInfo,
- CServer1),
- store_core(Mod, Core, NoWarn, Callgraph, CServer2)
- end;
- false ->
- store_core(Mod, Core, NoWarn, Callgraph, CServer1)
- end
+ compile_common(File, AbstrCode, [], Callgraph, CServer, UseContracts)
+ end.
+
+compile_common(File, AbstrCode, CompOpts, Callgraph, CServer, UseContracts) ->
+ case dialyzer_utils:get_core_from_abstract_code(AbstrCode, CompOpts) of
+ error -> {error, " Could not get core Erlang code for: " ++ File};
+ {ok, Core} ->
+ Mod = cerl:concrete(cerl:module_name(Core)),
+ NoWarn = abs_get_nowarn(AbstrCode, Mod),
+ case dialyzer_utils:get_record_and_type_info(AbstrCode) of
+ {error, _} = Error -> Error;
+ {ok, RecInfo} ->
+ CServer1 =
+ dialyzer_codeserver:store_temp_records(Mod, RecInfo, CServer),
+ case UseContracts of
+ true ->
+ case dialyzer_utils:get_spec_info(Mod, AbstrCode, RecInfo) of
+ {error, _} = Error -> Error;
+ {ok, SpecInfo, CallbackInfo} ->
+ CServer2 =
+ dialyzer_codeserver:store_temp_contracts(Mod, SpecInfo,
+ CallbackInfo,
+ CServer1),
+ store_core(Mod, Core, NoWarn, Callgraph, CServer2)
+ end;
+ false ->
+ store_core(Mod, Core, NoWarn, Callgraph, CServer1)
end
end
end.
diff --git a/lib/dialyzer/src/dialyzer_behaviours.erl b/lib/dialyzer/src/dialyzer_behaviours.erl
index 47ce9ba6eb..56eb46d78a 100644
--- a/lib/dialyzer/src/dialyzer_behaviours.erl
+++ b/lib/dialyzer/src/dialyzer_behaviours.erl
@@ -30,7 +30,7 @@
-module(dialyzer_behaviours).
--export([check_callbacks/4, get_behaviours/2, get_behaviour_apis/1,
+-export([check_callbacks/4, get_behaviour_apis/1,
translate_behaviour_api_call/5, translatable_behaviours/1,
translate_callgraph/3]).
@@ -51,12 +51,6 @@
%%--------------------------------------------------------------------
--spec get_behaviours([module()], dialyzer_codeserver:codeserver()) ->
- {[behaviour()], [behaviour()]}.
-
-get_behaviours(Modules, Codeserver) ->
- get_behaviours(Modules, Codeserver, [], []).
-
-spec check_callbacks(module(), [{cerl:cerl(), cerl:cerl()}],
dialyzer_plt:plt(),
dialyzer_codeserver:codeserver()) -> [dial_warning()].
@@ -69,12 +63,165 @@ check_callbacks(Module, Attrs, Plt, Codeserver) ->
MFA = {Module,module_info,0},
{_Var,Code} = dialyzer_codeserver:lookup_mfa_code(MFA, Codeserver),
File = get_file(cerl:get_ann(Code)),
- State = #state{plt = Plt, codeserver = Codeserver, filename = File,
- behlines = BehLines},
+ State = #state{plt = Plt, filename = File, behlines = BehLines,
+ codeserver = Codeserver},
Warnings = get_warnings(Module, Behaviours, State),
[add_tag_file_line(Module, W, State) || W <- Warnings]
end.
+%%--------------------------------------------------------------------
+
+get_behaviours(Attrs) ->
+ BehaviourListsAndLine = [{cerl:concrete(L2), hd(cerl:get_ann(L2))} ||
+ {L1, L2} <- Attrs, cerl:is_literal(L1),
+ cerl:is_literal(L2), cerl:concrete(L1) =:= 'behaviour'],
+ Behaviours = lists:append([Behs || {Behs,_} <- BehaviourListsAndLine]),
+ BehLines = [{B,L} || {L1,L} <- BehaviourListsAndLine, B <- L1],
+ {Behaviours, BehLines}.
+
+get_warnings(Module, Behaviours, State) ->
+ get_warnings(Module, Behaviours, State, []).
+
+get_warnings(_, [], _, Acc) ->
+ Acc;
+get_warnings(Module, [Behaviour|Rest], State, Acc) ->
+ NewAcc = check_behaviour(Module, Behaviour, State, Acc),
+ get_warnings(Module, Rest, State, NewAcc).
+
+check_behaviour(Module, Behaviour, #state{plt = Plt} = State, Acc) ->
+ case dialyzer_plt:lookup_callbacks(Plt, Behaviour) of
+ [] -> [{callback_info_missing, [Behaviour]}|Acc];
+ Callbacks -> check_all_callbacks(Module, Behaviour, Callbacks, State, Acc)
+ end.
+
+check_all_callbacks(_Module, _Behaviour, [], _State, Acc) ->
+ Acc;
+check_all_callbacks(Module, Behaviour, [Cb|Rest],
+ #state{plt = Plt, codeserver = Codeserver} = State, Acc) ->
+ {{Behaviour, Function, Arity},
+ {{_BehFile, _BehLine}, Callback}} = Cb,
+ CbMFA = {Module, Function, Arity},
+ CbReturnType = dialyzer_contracts:get_contract_return(Callback),
+ CbArgTypes = dialyzer_contracts:get_contract_args(Callback),
+ Records =
+ case dict:find(Module, dialyzer_codeserver:get_records(Codeserver)) of
+ {ok, V} -> V;
+ error -> dict:new()
+ end,
+ Acc0 = Acc,
+ Acc1 =
+ case dialyzer_plt:lookup(Plt, CbMFA) of
+ 'none' -> [{callback_missing, [Behaviour, Function, Arity]}|Acc0];
+ {'value', RetArgTypes} ->
+ Acc00 = Acc0,
+ {ReturnType, ArgTypes} = RetArgTypes,
+ Acc01 =
+ case erl_types:t_is_subtype(ReturnType, CbReturnType) of
+ true -> Acc00;
+ false ->
+ case erl_types:t_is_none(
+ erl_types:t_inf(ReturnType, CbReturnType)) of
+ false -> Acc00;
+ true ->
+ [{callback_type_mismatch,
+ [Behaviour, Function, Arity,
+ erl_types:t_to_string(ReturnType, Records),
+ erl_types:t_to_string(CbReturnType, Records)]}|Acc00]
+ end
+ end,
+ Acc02 =
+ case erl_types:any_none(
+ erl_types:t_inf_lists(ArgTypes, CbArgTypes)) of
+ false -> Acc01;
+ true ->
+ find_mismatching_args(type, ArgTypes, CbArgTypes, Behaviour,
+ Function, Arity, Records, 1, Acc01)
+ end,
+ Acc02
+ end,
+ Acc2 =
+ case dialyzer_codeserver:lookup_mfa_contract(CbMFA, Codeserver) of
+ 'error' -> Acc1;
+ {ok, {{File, Line}, Contract}} ->
+ Acc10 = Acc1,
+ SpecReturnType = dialyzer_contracts:get_contract_return(Contract),
+ SpecArgTypes = dialyzer_contracts:get_contract_args(Contract),
+ Acc11 =
+ case erl_types:t_is_subtype(SpecReturnType, CbReturnType) of
+ true -> Acc10;
+ false -> [{callback_spec_type_mismatch,
+ [File, Line, Behaviour, Function, Arity,
+ erl_types:t_to_string(SpecReturnType, Records),
+ erl_types:t_to_string(CbReturnType, Records)]}|Acc10]
+ end,
+ Acc12 =
+ case erl_types:any_none(
+ erl_types:t_inf_lists(SpecArgTypes, CbArgTypes)) of
+ false -> Acc11;
+ true ->
+ find_mismatching_args({spec, File, Line}, SpecArgTypes,
+ CbArgTypes, Behaviour, Function,
+ Arity, Records, 1, Acc11)
+ end,
+ Acc12
+ end,
+ NewAcc = Acc2,
+ check_all_callbacks(Module, Behaviour, Rest, State, NewAcc).
+
+find_mismatching_args(_, [], [], _Beh, _Function, _Arity, _Records, _N, Acc) ->
+ Acc;
+find_mismatching_args(Kind, [Type|Rest], [CbType|CbRest], Behaviour,
+ Function, Arity, Records, N, Acc) ->
+ case erl_types:t_is_none(erl_types:t_inf(Type, CbType)) of
+ false ->
+ find_mismatching_args(Kind, Rest, CbRest, Behaviour, Function,
+ Arity, Records, N+1, Acc);
+ true ->
+ Info =
+ [Behaviour, Function, Arity, N,
+ erl_types:t_to_string(Type, Records),
+ erl_types:t_to_string(CbType, Records)],
+ NewAcc =
+ [case Kind of
+ type -> {callback_arg_type_mismatch, Info};
+ {spec, File, Line} ->
+ {callback_spec_arg_type_mismatch, [File, Line | Info]}
+ end | Acc],
+ find_mismatching_args(Kind, Rest, CbRest, Behaviour, Function,
+ Arity, Records, N+1, NewAcc)
+ end.
+
+add_tag_file_line(_Module, {Tag, [B|_R]} = Warn, State)
+ when Tag =:= callback_missing;
+ Tag =:= callback_info_missing ->
+ {B, Line} = lists:keyfind(B, 1, State#state.behlines),
+ Category =
+ case Tag of
+ callback_missing -> ?WARN_BEHAVIOUR;
+ callback_info_missing -> ?WARN_UNDEFINED_CALLBACK
+ end,
+ {Category, {State#state.filename, Line}, Warn};
+add_tag_file_line(_Module, {Tag, [File, Line|R]}, _State)
+ when Tag =:= callback_spec_type_mismatch;
+ Tag =:= callback_spec_arg_type_mismatch ->
+ {?WARN_BEHAVIOUR, {File, Line}, {Tag, R}};
+add_tag_file_line(Module, {_Tag, [_B, Fun, Arity|_R]} = Warn, State) ->
+ {_A, FunCode} =
+ dialyzer_codeserver:lookup_mfa_code({Module, Fun, Arity},
+ State#state.codeserver),
+ Anns = cerl:get_ann(FunCode),
+ FileLine = {get_file(Anns), get_line(Anns)},
+ {?WARN_BEHAVIOUR, FileLine, Warn}.
+
+get_line([Line|_]) when is_integer(Line) -> Line;
+get_line([_|Tail]) -> get_line(Tail);
+get_line([]) -> -1.
+
+get_file([{file, File}|_]) -> File;
+get_file([_|Tail]) -> get_file(Tail).
+
+%%-----------------------------------------------------------------------------
+
-spec translatable_behaviours(cerl:c_module()) -> behaviour_api_dict().
translatable_behaviours(Tree) ->
@@ -133,182 +280,6 @@ translate_callgraph([{Behaviour,_}|Behaviours], Module, Callgraph) ->
translate_callgraph([], _Module, Callgraph) ->
Callgraph.
-%%--------------------------------------------------------------------
-
-get_behaviours(Attrs) ->
- BehaviourListsAndLine = [{cerl:concrete(L2), hd(cerl:get_ann(L2))} ||
- {L1, L2} <- Attrs, cerl:is_literal(L1),
- cerl:is_literal(L2), cerl:concrete(L1) =:= 'behaviour'],
- Behaviours = lists:append([Behs || {Behs,_} <- BehaviourListsAndLine]),
- BehLines = [{B,L} || {L1,L} <- BehaviourListsAndLine, B <- L1],
- {Behaviours, BehLines}.
-
-get_warnings(Module, Behaviours, State) ->
- get_warnings(Module, Behaviours, State, []).
-
-get_warnings(_, [], _, Acc) ->
- Acc;
-get_warnings(Module, [Behaviour|Rest], State, Acc) ->
- Warnings = check_behaviour(Module, Behaviour, State),
- get_warnings(Module, Rest, State, Warnings ++ Acc).
-
-check_behaviour(Module, Behaviour, State) ->
- try
- Callbacks = Behaviour:behaviour_info(callbacks),
- Fun = fun({_,_,_}) -> true;
- (_) -> false
- end,
- case lists:any(Fun, Callbacks) of
- true -> check_all_callbacks(Module, Behaviour, Callbacks, State);
- false -> []
- end
- catch
- _:_ -> []
- end.
-
-check_all_callbacks(Module, Behaviour, Callbacks, State) ->
- check_all_callbacks(Module, Behaviour, Callbacks, State, []).
-
-check_all_callbacks(_Module, _Behaviour, [], _State, Acc) ->
- Acc;
-check_all_callbacks(Module, Behaviour, [{Fun, Arity, Spec}|Rest],
- #state{codeserver = CServer} = State, Acc) ->
- Records = dialyzer_codeserver:get_records(CServer),
- ExpTypes = dialyzer_codeserver:get_exported_types(CServer),
- case parse_spec(Spec, ExpTypes, Records) of
- {ok, Fun, Type} ->
- RetType = erl_types:t_fun_range(Type),
- ArgTypes = erl_types:t_fun_args(Type),
- Warns = check_callback(Module, Behaviour, Fun, Arity, RetType,
- ArgTypes, State#state.plt);
- Else ->
- Warns = [{invalid_spec, [Behaviour, Fun, Arity, reason_spec_error(Else)]}]
- end,
- check_all_callbacks(Module, Behaviour, Rest, State, Warns ++ Acc);
-check_all_callbacks(Module, Behaviour, [{Fun, Arity}|Rest], State, Acc) ->
- Warns = {spec_missing, [Behaviour, Fun, Arity]},
- check_all_callbacks(Module, Behaviour, Rest, State, [Warns|Acc]).
-
-parse_spec(String, ExpTypes, Records) ->
- case erl_scan:string(String) of
- {ok, Tokens, _} ->
- case erl_parse:parse(Tokens) of
- {ok, Form} ->
- case Form of
- {attribute, _, 'spec', {{Fun, _}, [TypeForm|_Constraint]}} ->
- MaybeRemoteType = erl_types:t_from_form(TypeForm),
- try
- Type = erl_types:t_solve_remote(MaybeRemoteType, ExpTypes,
- Records),
- {ok, Fun, Type}
- catch
- throw:{error,Msg} -> {spec_remote_error, Msg}
- end;
- _Other -> not_a_spec
- end;
- {error, {Line, _, Msg}} -> {spec_parser_error, Line, Msg}
- end;
- _Other ->
- lexer_error
- end.
-
-reason_spec_error({spec_remote_error, Msg}) ->
- io_lib:format("Remote type solver error: ~s. Make sure the behaviour source is included in the analysis or the plt",[Msg]);
-reason_spec_error(not_a_spec) ->
- "This is not a spec";
-reason_spec_error({spec_parser_error, Line, Msg}) ->
- io_lib:format("~s line of the spec: ~s", [ordinal(Line),Msg]);
-reason_spec_error(lexer_error) ->
- "Lexical error".
-
-ordinal(1) -> "1st";
-ordinal(2) -> "2nd";
-ordinal(3) -> "3rd";
-ordinal(N) when is_integer(N) -> io_lib:format("~wth",[N]).
-
-check_callback(Module, Behaviour, Fun, Arity, XRetType, XArgTypes, Plt) ->
- LookupType = dialyzer_plt:lookup(Plt, {Module, Fun, Arity}),
- case LookupType of
- {value, {Type,Args}} ->
- Warn1 = case unifiable(Type, XRetType) of
- [] -> [];
- Offenders ->
- [{callback_type_mismatch,
- [Behaviour, Fun, Arity, erl_types:t_sup(Offenders)]}]
- end,
- ZipArgs = lists:zip3(lists:seq(1, Arity), Args, XArgTypes),
- Warn2 = [{callback_arg_type_mismatch,
- [Behaviour, Fun, Arity, N,
- erl_types:t_sup(Offenders)]} ||
- {Offenders, N} <- [check_callback_1(V) || V <- ZipArgs],
- Offenders =/= []],
- Warn1 ++ Warn2;
- _ -> [{callback_missing, [Behaviour, Fun, Arity]}]
- end.
-
-check_callback_1({N, T1, T2}) ->
- {unifiable(T1, T2), N}.
-
-unifiable(Type1, Type2) ->
- List1 = erl_types:t_elements(Type1),
- List2 = erl_types:t_elements(Type2),
- [T || T <- List1,
- lists:all(fun(T1) ->
- erl_types:t_is_none(erl_types:t_inf(T, T1, opaque))
- end, List2)].
-
-add_tag_file_line(_Module, {Tag, [B|_R]} = Warn, State)
- when Tag =:= spec_missing;
- Tag =:= invalid_spec;
- Tag =:= callback_missing ->
- {B, Line} = lists:keyfind(B, 1, State#state.behlines),
- {?WARN_BEHAVIOUR, {State#state.filename, Line}, Warn};
-add_tag_file_line(Module, {_Tag, [_B, Fun, Arity|_R]} = Warn, State) ->
- {_A, FunCode} =
- dialyzer_codeserver:lookup_mfa_code({Module, Fun, Arity},
- State#state.codeserver),
- Anns = cerl:get_ann(FunCode),
- FileLine = {get_file(Anns), get_line(Anns)},
- {?WARN_BEHAVIOUR, FileLine, Warn}.
-
-get_line([Line|_]) when is_integer(Line) -> Line;
-get_line([_|Tail]) -> get_line(Tail);
-get_line([]) -> -1.
-
-get_file([{file, File}|_]) -> File;
-get_file([_|Tail]) -> get_file(Tail).
-
-%%-----------------------------------------------------------------------------
-
-get_behaviours([], _Codeserver, KnownAcc, UnknownAcc) ->
- {KnownAcc, UnknownAcc};
-get_behaviours([M|Rest], Codeserver, KnownAcc, UnknownAcc) ->
- Tree = dialyzer_codeserver:lookup_mod_code(M, Codeserver),
- Attrs = cerl:module_attrs(Tree),
- {Behaviours, _BehLines} = get_behaviours(Attrs),
- {Known, Unknown} = call_behaviours(Behaviours),
- get_behaviours(Rest, Codeserver, Known ++ KnownAcc, Unknown ++ UnknownAcc).
-
-call_behaviours(Behaviours) ->
- call_behaviours(Behaviours, [], []).
-call_behaviours([], KnownAcc, UnknownAcc) ->
- {lists:reverse(KnownAcc), lists:reverse(UnknownAcc)};
-call_behaviours([Behaviour|Rest], KnownAcc, UnknownAcc) ->
- try
- Callbacks = Behaviour:behaviour_info(callbacks),
- Fun = fun({_,_,_}) -> true;
- (_) -> false
- end,
- case lists:any(Fun, Callbacks) of
- false -> call_behaviours(Rest, KnownAcc, [Behaviour | UnknownAcc]);
- true -> call_behaviours(Rest, [Behaviour | KnownAcc], UnknownAcc)
- end
- catch
- _:_ -> call_behaviours(Rest, KnownAcc, [Behaviour | UnknownAcc])
- end.
-
-%------------------------------------------------------------------------------
-
get_behaviour_apis([], Acc) ->
Acc;
get_behaviour_apis([Behaviour | Rest], Acc) ->
diff --git a/lib/dialyzer/src/dialyzer_cl.erl b/lib/dialyzer/src/dialyzer_cl.erl
index 8d61216b7a..732bd4ac84 100644
--- a/lib/dialyzer/src/dialyzer_cl.erl
+++ b/lib/dialyzer/src/dialyzer_cl.erl
@@ -525,10 +525,7 @@ native_compile(Mods) ->
end.
hc(Mod) ->
- case code:ensure_loaded(Mod) of
- {module, Mod} -> ok;
- {error, sticky_directory} -> ok
- end,
+ {module, Mod} = code:ensure_loaded(Mod),
case code:is_module_native(Mod) of
true -> ok;
false ->
@@ -611,7 +608,7 @@ cl_loop(State, LogCache) ->
-spec failed_anal_msg(string(), [_]) -> nonempty_string().
failed_anal_msg(Reason, LogCache) ->
- Msg = "Analysis failed with error: " ++ Reason ++ "\n",
+ Msg = "Analysis failed with error:\n" ++ Reason ++ "\n",
case LogCache =:= [] of
true -> Msg;
false ->
@@ -754,15 +751,13 @@ print_unknown_behaviours(#cl_state{output = Output,
true -> io:nl(Output); %% Need to do a newline first
false -> ok
end,
- case Format of
- formatted ->
- io:put_chars(Output, "Unknown behaviours (behaviour_info(callbacks)"
- " does not return any specs):\n"),
- do_print_unknown_behaviours(Output, Behaviours, " ");
- raw ->
- io:put_chars(Output, "%% Unknown behaviours:\n"),
- do_print_unknown_behaviours(Output, Behaviours, "%% ")
- end
+ {Prompt, Prefix} =
+ case Format of
+ formatted -> {"Unknown behaviours:\n"," "};
+ raw -> {"%% Unknown behaviours:\n","%% "}
+ end,
+ io:put_chars(Output, Prompt),
+ do_print_unknown_behaviours(Output, Behaviours, Prefix)
end.
do_print_unknown_behaviours(Output, [B|T], Before) ->
diff --git a/lib/dialyzer/src/dialyzer_cl_parse.erl b/lib/dialyzer/src/dialyzer_cl_parse.erl
index f80eb81ac6..ff8fc39a5e 100644
--- a/lib/dialyzer/src/dialyzer_cl_parse.erl
+++ b/lib/dialyzer/src/dialyzer_cl_parse.erl
@@ -491,6 +491,12 @@ warning_options_msg() ->
Suppress warnings for patterns that are unused or cannot match.
-Wno_opaque
Suppress warnings for violations of opaqueness of data types.
+ -Wno_behaviours
+ Suppress warnings about behaviour callbacks which drift from the published
+ recommended interfaces.
+ -Wno_undefined_callbacks
+ Suppress warnings about behaviours that have no -callback attributes for
+ their callbacks.
-Wunmatched_returns ***
Include warnings for function calls which ignore a structured return
value or do not match against one of many possible return value(s).
@@ -498,9 +504,6 @@ warning_options_msg() ->
Include warnings for functions that only return by means of an exception.
-Wrace_conditions ***
Include warnings for possible race conditions.
- -Wbehaviours ***
- Include warnings about behaviour callbacks which drift from the published
- recommended interfaces.
-Wunderspecs ***
Warn about underspecified functions
(those whose -spec is strictly more allowing than the success typing).
diff --git a/lib/dialyzer/src/dialyzer_codeserver.erl b/lib/dialyzer/src/dialyzer_codeserver.erl
index b2097f7e53..c34a9f0b7d 100644
--- a/lib/dialyzer/src/dialyzer_codeserver.erl
+++ b/lib/dialyzer/src/dialyzer_codeserver.erl
@@ -28,10 +28,11 @@
-module(dialyzer_codeserver).
-export([delete/1,
- finalize_contracts/2,
+ finalize_contracts/3,
finalize_exported_types/2,
finalize_records/2,
get_contracts/1,
+ get_callbacks/1,
get_exported_types/1,
get_exports/1,
get_records/1,
@@ -54,7 +55,7 @@
store_records/3,
store_temp_records/3,
store_contracts/3,
- store_temp_contracts/3]).
+ store_temp_contracts/4]).
-export_type([codeserver/0]).
@@ -70,7 +71,10 @@
records = dict:new() :: dict(),
temp_records = dict:new() :: dict(),
contracts = dict:new() :: dict(),
- temp_contracts = dict:new() :: dict()}).
+ callbacks = dict:new() :: dict(),
+ temp_contracts = dict:new() :: dict(),
+ temp_callbacks = dict:new() :: dict()
+ }).
-opaque codeserver() :: #codeserver{}.
@@ -227,24 +231,42 @@ lookup_mfa_contract({M,_F,_A} = MFA, #codeserver{contracts = ContDict}) ->
get_contracts(#codeserver{contracts = ContDict}) ->
ContDict.
--spec store_temp_contracts(atom(), dict(), codeserver()) -> codeserver().
+-spec get_callbacks(codeserver()) -> dict().
-store_temp_contracts(Mod, Dict, #codeserver{temp_contracts = C} = CS)
+get_callbacks(#codeserver{callbacks = CallbDict}) ->
+ CallbDict.
+
+-spec store_temp_contracts(atom(), dict(), dict(), codeserver()) ->
+ codeserver().
+
+store_temp_contracts(Mod, SpecDict, CallbackDict,
+ #codeserver{temp_contracts = Cn,
+ temp_callbacks = Cb} = CS)
when is_atom(Mod) ->
- case dict:size(Dict) =:= 0 of
- true -> CS;
- false -> CS#codeserver{temp_contracts = dict:store(Mod, Dict, C)}
+ CS1 =
+ case dict:size(SpecDict) =:= 0 of
+ true -> CS;
+ false -> CS#codeserver{temp_contracts = dict:store(Mod, SpecDict, Cn)}
+ end,
+ case dict:size(CallbackDict) =:= 0 of
+ true -> CS1;
+ false -> CS1#codeserver{temp_callbacks = dict:store(Mod, CallbackDict, Cb)}
end.
--spec get_temp_contracts(codeserver()) -> dict().
+-spec get_temp_contracts(codeserver()) -> {dict(), dict()}.
-get_temp_contracts(#codeserver{temp_contracts = TempContDict}) ->
- TempContDict.
+get_temp_contracts(#codeserver{temp_contracts = TempContDict,
+ temp_callbacks = TempCallDict}) ->
+ {TempContDict, TempCallDict}.
--spec finalize_contracts(dict(), codeserver()) -> codeserver().
+-spec finalize_contracts(dict(), dict(), codeserver()) -> codeserver().
-finalize_contracts(Dict, CS) ->
- CS#codeserver{contracts = Dict, temp_contracts = dict:new()}.
+finalize_contracts(CnDict, CbDict, CS) ->
+ CS#codeserver{contracts = CnDict,
+ callbacks = CbDict,
+ temp_contracts = dict:new(),
+ temp_callbacks = dict:new()
+ }.
table__new() ->
spawn_link(fun() -> table__loop(none, dict:new()) end).
diff --git a/lib/dialyzer/src/dialyzer_contracts.erl b/lib/dialyzer/src/dialyzer_contracts.erl
index bcdcf2685d..8b43740e34 100644
--- a/lib/dialyzer/src/dialyzer_contracts.erl
+++ b/lib/dialyzer/src/dialyzer_contracts.erl
@@ -141,7 +141,8 @@ sequence([H|T], Delimiter) -> H ++ Delimiter ++ sequence(T, Delimiter).
dialyzer_codeserver:codeserver().
process_contract_remote_types(CodeServer) ->
- TmpContractDict = dialyzer_codeserver:get_temp_contracts(CodeServer),
+ {TmpContractDict, TmpCallbackDict} =
+ dialyzer_codeserver:get_temp_contracts(CodeServer),
ExpTypes = dialyzer_codeserver:get_exported_types(CodeServer),
RecordDict = dialyzer_codeserver:get_records(CodeServer),
ContractFun =
@@ -155,7 +156,9 @@ process_contract_remote_types(CodeServer) ->
dict:map(ContractFun, ContractDict)
end,
NewContractDict = dict:map(ModuleFun, TmpContractDict),
- dialyzer_codeserver:finalize_contracts(NewContractDict, CodeServer).
+ NewCallbackDict = dict:map(ModuleFun, TmpCallbackDict),
+ dialyzer_codeserver:finalize_contracts(NewContractDict, NewCallbackDict,
+ CodeServer).
-spec check_contracts([{mfa(), file_contract()}],
dialyzer_callgraph:callgraph(), dict()) -> plt_contracts().
@@ -253,7 +256,7 @@ check_extraneous([C|Cs], SuccType) ->
check_extraneous_1(Contract, SuccType) ->
CRngs = erl_types:t_elements(erl_types:t_fun_range(Contract)),
STRng = erl_types:t_fun_range(SuccType),
- %% io:format("CR = ~p\nSR = ~p\n", [CRngs, STRng]),
+ ?debug("CR = ~p\nSR = ~p\n", [CRngs, STRng]),
case [CR || CR <- CRngs, erl_types:t_is_none(erl_types:t_inf(CR, STRng, opaque))] of
[] -> ok;
CRs -> {error, {extra_range, erl_types:t_sup(CRs), STRng}}
@@ -349,28 +352,37 @@ insert_constraints([], Dict) -> Dict.
store_tmp_contract(MFA, FileLine, TypeSpec, SpecDict, RecordsDict) ->
%% io:format("contract from form: ~p\n", [TypeSpec]),
- TmpContract = contract_from_form(TypeSpec, RecordsDict),
+ TmpContract = contract_from_form(TypeSpec, RecordsDict, FileLine),
%% io:format("contract: ~p\n", [Contract]),
dict:store(MFA, {FileLine, TmpContract}, SpecDict).
-contract_from_form(Forms, RecDict) ->
- {CFuns, Forms1} = contract_from_form(Forms, RecDict, [], []),
+contract_from_form(Forms, RecDict, FileLine) ->
+ {CFuns, Forms1} = contract_from_form(Forms, RecDict, FileLine, [], []),
#tmp_contract{contract_funs = CFuns, forms = Forms1}.
contract_from_form([{type, _, 'fun', [_, _]} = Form | Left], RecDict,
- TypeAcc, FormAcc) ->
+ FileLine, TypeAcc, FormAcc) ->
TypeFun =
fun(ExpTypes, AllRecords) ->
- Type = erl_types:t_from_form(Form, RecDict),
+ Type =
+ try
+ erl_types:t_from_form(Form, RecDict)
+ catch
+ throw:{error, Msg} ->
+ {File, Line} = FileLine,
+ NewMsg = io_lib:format("~s:~p: ~s", [filename:basename(File),
+ Line, Msg]),
+ throw({error, NewMsg})
+ end,
NewType = erl_types:t_solve_remote(Type, ExpTypes, AllRecords),
{NewType, []}
end,
NewTypeAcc = [TypeFun | TypeAcc],
NewFormAcc = [{Form, []} | FormAcc],
- contract_from_form(Left, RecDict, NewTypeAcc, NewFormAcc);
+ contract_from_form(Left, RecDict, FileLine, NewTypeAcc, NewFormAcc);
contract_from_form([{type, _L1, bounded_fun,
[{type, _L2, 'fun', [_, _]} = Form, Constr]}| Left],
- RecDict, TypeAcc, FormAcc) ->
+ RecDict, FileLine, TypeAcc, FormAcc) ->
TypeFun =
fun(ExpTypes, AllRecords) ->
Constr1 = [constraint_from_form(C, RecDict, ExpTypes, AllRecords)
@@ -382,8 +394,8 @@ contract_from_form([{type, _L1, bounded_fun,
end,
NewTypeAcc = [TypeFun | TypeAcc],
NewFormAcc = [{Form, Constr} | FormAcc],
- contract_from_form(Left, RecDict, NewTypeAcc, NewFormAcc);
-contract_from_form([], _RecDict, TypeAcc, FormAcc) ->
+ contract_from_form(Left, RecDict, FileLine, NewTypeAcc, NewFormAcc);
+contract_from_form([], _RecDict, _FileLine, TypeAcc, FormAcc) ->
{lists:reverse(TypeAcc), lists:reverse(FormAcc)}.
constraint_from_form({type, _, constraint, [{atom, _, is_subtype},
@@ -441,7 +453,21 @@ get_invalid_contract_warnings_funs([{MFA, {FileLine, Contract}}|Left],
{error, invalid_contract} ->
[invalid_contract_warning(MFA, FileLine, Sig, RecDict)|Acc];
{error, {extra_range, ExtraRanges, STRange}} ->
- [extra_range_warning(MFA, FileLine, ExtraRanges, STRange)|Acc];
+ Warn =
+ case t_from_forms_without_remote(Contract#contract.forms,
+ RecDict) of
+ {ok, NoRemoteType} ->
+ CRet = erl_types:t_fun_range(NoRemoteType),
+ erl_types:t_is_subtype(ExtraRanges, CRet);
+ unsupported ->
+ true
+ end,
+ case Warn of
+ true ->
+ [extra_range_warning(MFA, FileLine, ExtraRanges, STRange)|Acc];
+ false ->
+ Acc
+ end;
{error, Msg} ->
[{?WARN_CONTRACT_SYNTAX, FileLine, Msg}|Acc];
ok ->
@@ -480,7 +506,7 @@ invalid_contract_warning({M, F, A}, FileLine, SuccType, RecDict) ->
extra_range_warning({M, F, A}, FileLine, ExtraRanges, STRange) ->
ERangesStr = erl_types:t_to_string(ExtraRanges),
STRangeStr = erl_types:t_to_string(STRange),
- {?WARN_CONTRACT_TYPES, FileLine,
+ {?WARN_CONTRACT_SUPERTYPE, FileLine,
{extra_range, [M, F, A, ERangesStr, STRangeStr]}}.
picky_contract_check(CSig0, Sig0, MFA, FileLine, Contract, RecDict, Acc) ->
@@ -504,26 +530,92 @@ picky_contract_check(CSig0, Sig0, MFA, FileLine, Contract, RecDict, Acc) ->
extra_contract_warning({M, F, A}, FileLine, Contract, CSig, Sig, RecDict) ->
SigString = lists:flatten(dialyzer_utils:format_sig(Sig, RecDict)),
ContractString0 = lists:flatten(dialyzer_utils:format_sig(CSig, RecDict)),
- case SigString =:= ContractString0 of
+ %% The only difference is in record fields containing 'undefined' or not.
+ IsUndefRecordFieldsRelated = SigString =:= ContractString0,
+ {IsRemoteTypesRelated, SubtypeRelation} =
+ is_remote_types_related(Contract, CSig, Sig, RecDict),
+ case IsUndefRecordFieldsRelated orelse IsRemoteTypesRelated of
true ->
- %% The only difference is in record fields containing 'undefined' or not.
no_warning;
false ->
ContractString = contract_to_string(Contract),
{Tag, Msg} =
- case erl_types:t_is_subtype(CSig, Sig) of
- true ->
+ case SubtypeRelation of
+ contract_is_subtype ->
{?WARN_CONTRACT_SUBTYPE,
{contract_subtype, [M, F, A, ContractString, SigString]}};
- false ->
- case erl_types:t_is_subtype(Sig, CSig) of
- true ->
- {?WARN_CONTRACT_SUPERTYPE,
- {contract_supertype, [M, F, A, ContractString, SigString]}};
- false ->
- {?WARN_CONTRACT_NOT_EQUAL,
- {contract_diff, [M, F, A, ContractString, SigString]}}
- end
+ contract_is_supertype ->
+ {?WARN_CONTRACT_SUPERTYPE,
+ {contract_supertype, [M, F, A, ContractString, SigString]}};
+ neither ->
+ {?WARN_CONTRACT_NOT_EQUAL,
+ {contract_diff, [M, F, A, ContractString, SigString]}}
end,
{warning, {Tag, FileLine, Msg}}
end.
+
+is_remote_types_related(Contract, CSig, Sig, RecDict) ->
+ case erl_types:t_is_subtype(CSig, Sig) of
+ true ->
+ {false, contract_is_subtype};
+ false ->
+ case erl_types:t_is_subtype(Sig, CSig) of
+ true ->
+ case t_from_forms_without_remote(Contract#contract.forms, RecDict) of
+ {ok, NoRemoteTypeSig} ->
+ case blame_remote(CSig, NoRemoteTypeSig, Sig) of
+ true ->
+ {true, neither};
+ false ->
+ {false, contract_is_supertype}
+ end;
+ unsupported ->
+ {false, contract_is_supertype}
+ end;
+ false ->
+ {false, neither}
+ end
+ end.
+
+t_from_forms_without_remote([{FType, []}], RecDict) ->
+ Type0 = erl_types:t_from_form(FType, RecDict),
+ Map =
+ fun(Type) ->
+ case erl_types:t_is_remote(Type) of
+ true -> erl_types:t_none();
+ false -> Type
+ end
+ end,
+ {ok, erl_types:t_map(Map, Type0)};
+t_from_forms_without_remote([{_FType, _Constrs}], _RecDict) ->
+ %% 'When' constraints
+ unsupported;
+t_from_forms_without_remote(_Forms, _RecDict) ->
+ %% Lots of forms
+ unsupported.
+
+blame_remote(ContractSig, NoRemoteContractSig, Sig) ->
+ CArgs = erl_types:t_fun_args(ContractSig),
+ CRange = erl_types:t_fun_range(ContractSig),
+ NRArgs = erl_types:t_fun_args(NoRemoteContractSig),
+ NRRange = erl_types:t_fun_range(NoRemoteContractSig),
+ SArgs = erl_types:t_fun_args(Sig),
+ SRange = erl_types:t_fun_range(Sig),
+ blame_remote_list([CRange|CArgs], [NRRange|NRArgs], [SRange|SArgs]).
+
+blame_remote_list([], [], []) ->
+ true;
+blame_remote_list([CArg|CArgs], [NRArg|NRArgs], [SArg|SArgs]) ->
+ case erl_types:t_is_equal(CArg, NRArg) of
+ true ->
+ case not erl_types:t_is_equal(CArg, SArg) of
+ true -> false;
+ false -> blame_remote_list(CArgs, NRArgs, SArgs)
+ end;
+ false ->
+ case erl_types:t_is_subtype(SArg, NRArg)
+ andalso not erl_types:t_is_subtype(NRArg, SArg) of
+ true -> false;
+ false -> blame_remote_list(CArgs, NRArgs, SArgs)
+ end
+ end.
diff --git a/lib/dialyzer/src/dialyzer_options.erl b/lib/dialyzer/src/dialyzer_options.erl
index b2a67de8bd..866650a0b2 100644
--- a/lib/dialyzer/src/dialyzer_options.erl
+++ b/lib/dialyzer/src/dialyzer_options.erl
@@ -49,7 +49,9 @@ build(Opts) ->
?WARN_CALLGRAPH,
?WARN_CONTRACT_RANGE,
?WARN_CONTRACT_TYPES,
- ?WARN_CONTRACT_SYNTAX],
+ ?WARN_CONTRACT_SYNTAX,
+ ?WARN_BEHAVIOUR,
+ ?WARN_UNDEFINED_CALLBACK],
DefaultWarns1 = ordsets:from_list(DefaultWarns),
InitPlt = dialyzer_plt:get_default_plt(),
DefaultOpts = #options{},
@@ -275,14 +277,16 @@ build_warnings([Opt|Opts], Warnings) ->
no_contracts ->
Warnings1 = ordsets:del_element(?WARN_CONTRACT_SYNTAX, Warnings),
ordsets:del_element(?WARN_CONTRACT_TYPES, Warnings1);
+ no_behaviours ->
+ ordsets:del_element(?WARN_BEHAVIOUR, Warnings);
+ no_undefined_callbacks ->
+ ordsets:del_element(?WARN_UNDEFINED_CALLBACK, Warnings);
unmatched_returns ->
ordsets:add_element(?WARN_UNMATCHED_RETURN, Warnings);
error_handling ->
ordsets:add_element(?WARN_RETURN_ONLY_EXIT, Warnings);
race_conditions ->
ordsets:add_element(?WARN_RACE_CONDITION, Warnings);
- behaviours ->
- ordsets:add_element(?WARN_BEHAVIOUR, Warnings);
specdiffs ->
S = ordsets:from_list([?WARN_CONTRACT_SUBTYPE,
?WARN_CONTRACT_SUPERTYPE,
diff --git a/lib/dialyzer/src/dialyzer_plt.erl b/lib/dialyzer/src/dialyzer_plt.erl
index 6033d7f17c..206c43e4e2 100644
--- a/lib/dialyzer/src/dialyzer_plt.erl
+++ b/lib/dialyzer/src/dialyzer_plt.erl
@@ -43,10 +43,12 @@
%% insert/3,
insert_list/2,
insert_contract_list/2,
+ insert_callbacks/2,
insert_types/2,
insert_exported_types/2,
lookup/2,
lookup_contract/2,
+ lookup_callbacks/2,
lookup_module/2,
merge_plts/1,
merge_plts_or_report_conflicts/2,
@@ -79,6 +81,7 @@
-record(plt, {info = table_new() :: dict(),
types = table_new() :: dict(),
contracts = table_new() :: dict(),
+ callbacks = table_new() :: dict(),
exported_types = sets:new() :: set()}).
-opaque plt() :: #plt{}.
@@ -91,6 +94,7 @@
file_md5_list = [] :: [file_md5()],
info = dict:new() :: dict(),
contracts = dict:new() :: dict(),
+ callbacks = dict:new() :: dict(),
types = dict:new() :: dict(),
exported_types = sets:new() :: set(),
mod_deps :: mod_deps(),
@@ -105,20 +109,26 @@ new() ->
-spec delete_module(plt(), atom()) -> plt().
-delete_module(#plt{info = Info, types = Types, contracts = Contracts,
+delete_module(#plt{info = Info, types = Types,
+ contracts = Contracts,
+ callbacks = Callbacks,
exported_types = ExpTypes}, Mod) ->
#plt{info = table_delete_module(Info, Mod),
types = table_delete_module2(Types, Mod),
contracts = table_delete_module(Contracts, Mod),
+ callbacks = table_delete_module(Callbacks, Mod),
exported_types = table_delete_module1(ExpTypes, Mod)}.
-spec delete_list(plt(), [mfa() | integer()]) -> plt().
-delete_list(#plt{info = Info, types = Types, contracts = Contracts,
+delete_list(#plt{info = Info, types = Types,
+ contracts = Contracts,
+ callbacks = Callbacks,
exported_types = ExpTypes}, List) ->
#plt{info = table_delete_list(Info, List),
types = Types,
contracts = table_delete_list(Contracts, List),
+ callbacks = table_delete_list(Callbacks, List),
exported_types = ExpTypes}.
-spec insert_contract_list(plt(), dialyzer_contracts:plt_contracts()) -> plt().
@@ -126,16 +136,42 @@ delete_list(#plt{info = Info, types = Types, contracts = Contracts,
insert_contract_list(#plt{contracts = Contracts} = PLT, List) ->
PLT#plt{contracts = table_insert_list(Contracts, List)}.
+-spec insert_callbacks(plt(), dialyzer_codeserver:codeserver()) -> plt().
+
+insert_callbacks(#plt{callbacks = Callbacks} = Plt, Codeserver) ->
+ FunPreferNew = fun(_Key, _Val1, Val2) -> Val2 end,
+ FunDictMerger =
+ fun(_Key, Value, AccIn) -> dict:merge(FunPreferNew, Value, AccIn) end,
+ MergedCallbacks = dict:fold(FunDictMerger, dict:new(),
+ dialyzer_codeserver:get_callbacks(Codeserver)),
+ List = dict:to_list(MergedCallbacks),
+ Plt#plt{callbacks = table_insert_list(Callbacks, List)}.
+
-spec lookup_contract(plt(), mfa_patt()) -> 'none' | {'value', #contract{}}.
lookup_contract(#plt{contracts = Contracts},
{M, F, _} = MFA) when is_atom(M), is_atom(F) ->
table_lookup(Contracts, MFA).
+-spec lookup_callbacks(plt(), module()) -> [{mfa(),
+ {{Filename::string(),
+ Line::pos_integer()},
+ #contract{}}}].
+
+lookup_callbacks(#plt{callbacks = Callbacks}, Mod) when is_atom(Mod) ->
+ FunModFilter =
+ fun({M, _F, _A}, _Val) -> M =:= Mod;
+ ( _Key, _Val) -> false
+ end,
+ ModCallbacks = dict:filter(FunModFilter, Callbacks),
+ dict:to_list(ModCallbacks).
+
-spec delete_contract_list(plt(), [mfa()]) -> plt().
-delete_contract_list(#plt{contracts = Contracts} = PLT, List) ->
- PLT#plt{contracts = table_delete_list(Contracts, List)}.
+delete_contract_list(#plt{contracts = Contracts,
+ callbacks = Callbacks} = PLT, List) ->
+ PLT#plt{contracts = table_delete_list(Contracts, List),
+ callbacks = table_delete_list(Callbacks, List)}.
%% -spec insert(plt(), mfa() | integer(), {_, _}) -> plt().
%%
@@ -230,6 +266,7 @@ from_file(FileName, ReturnInfo) ->
Plt = #plt{info = Rec#file_plt.info,
types = Rec#file_plt.types,
contracts = Rec#file_plt.contracts,
+ callbacks = Rec#file_plt.callbacks,
exported_types = Rec#file_plt.exported_types},
case ReturnInfo of
false -> Plt;
@@ -284,26 +321,34 @@ get_record_from_file(FileName) ->
-spec merge_plts([plt()]) -> plt().
merge_plts(List) ->
- InfoList = [Info || #plt{info = Info} <- List],
- TypesList = [Types || #plt{types = Types} <- List],
- ExpTypesList = [ExpTypes || #plt{exported_types = ExpTypes} <- List],
- ContractsList = [Contracts || #plt{contracts = Contracts} <- List],
+ {InfoList, TypesList, ExpTypesList, ContractsList, CallbacksList} =
+ group_fields(List),
#plt{info = table_merge(InfoList),
types = table_merge(TypesList),
exported_types = sets_merge(ExpTypesList),
- contracts = table_merge(ContractsList)}.
+ contracts = table_merge(ContractsList),
+ callbacks = table_merge(CallbacksList)
+ }.
-spec merge_disj_plts([plt()]) -> plt().
merge_disj_plts(List) ->
+ {InfoList, TypesList, ExpTypesList, ContractsList, CallbacksList} =
+ group_fields(List),
+ #plt{info = table_disj_merge(InfoList),
+ types = table_disj_merge(TypesList),
+ exported_types = sets_disj_merge(ExpTypesList),
+ contracts = table_disj_merge(ContractsList),
+ callbacks = table_disj_merge(CallbacksList)
+ }.
+
+group_fields(List) ->
InfoList = [Info || #plt{info = Info} <- List],
TypesList = [Types || #plt{types = Types} <- List],
ExpTypesList = [ExpTypes || #plt{exported_types = ExpTypes} <- List],
ContractsList = [Contracts || #plt{contracts = Contracts} <- List],
- #plt{info = table_disj_merge(InfoList),
- types = table_disj_merge(TypesList),
- exported_types = sets_disj_merge(ExpTypesList),
- contracts = table_disj_merge(ContractsList)}.
+ CallbacksList = [Callbacks || #plt{callbacks = Callbacks} <- List],
+ {InfoList, TypesList, ExpTypesList, ContractsList, CallbacksList}.
-spec merge_plts_or_report_conflicts([file:filename()], [plt()]) -> plt().
@@ -329,7 +374,7 @@ find_duplicates(List) ->
to_file(FileName,
#plt{info = Info, types = Types, contracts = Contracts,
- exported_types = ExpTypes},
+ callbacks = Callbacks, exported_types = ExpTypes},
ModDeps, {MD5, OldModDeps}) ->
NewModDeps = dict:merge(fun(_Key, OldVal, NewVal) ->
ordsets:union(OldVal, NewVal)
@@ -340,6 +385,7 @@ to_file(FileName,
file_md5_list = MD5,
info = Info,
contracts = Contracts,
+ callbacks = Callbacks,
types = Types,
exported_types = ExpTypes,
mod_deps = NewModDeps,
diff --git a/lib/dialyzer/src/dialyzer_succ_typings.erl b/lib/dialyzer/src/dialyzer_succ_typings.erl
index dc5a3fed37..4d86bb34a7 100644
--- a/lib/dialyzer/src/dialyzer_succ_typings.erl
+++ b/lib/dialyzer/src/dialyzer_succ_typings.erl
@@ -29,7 +29,7 @@
-export([analyze_callgraph/3,
analyze_callgraph/4,
- get_warnings/7]).
+ get_warnings/6]).
%% These are only intended as debug functions.
-export([doit/1,
@@ -106,21 +106,19 @@ get_refined_success_typings(State) ->
-type doc_plt() :: 'undefined' | dialyzer_plt:plt().
-spec get_warnings(dialyzer_callgraph:callgraph(), dialyzer_plt:plt(),
doc_plt(), dialyzer_codeserver:codeserver(), set(),
- pid(), boolean()) ->
+ pid()) ->
{[dial_warning()], dialyzer_plt:plt(), doc_plt()}.
-get_warnings(Callgraph, Plt, DocPlt, Codeserver,
- NoWarnUnused, Parent, BehavioursChk) ->
+get_warnings(Callgraph, Plt, DocPlt, Codeserver, NoWarnUnused, Parent) ->
InitState = #st{callgraph = Callgraph, codeserver = Codeserver,
no_warn_unused = NoWarnUnused, parent = Parent, plt = Plt},
NewState = get_refined_success_typings(InitState),
Mods = dialyzer_callgraph:modules(NewState#st.callgraph),
CWarns = dialyzer_contracts:get_invalid_contract_warnings(Mods, Codeserver,
NewState#st.plt),
- get_warnings_from_modules(Mods, NewState, DocPlt, BehavioursChk, CWarns).
+ get_warnings_from_modules(Mods, NewState, DocPlt, CWarns).
-get_warnings_from_modules([M|Ms], State, DocPlt,
- BehavioursChk, Acc) when is_atom(M) ->
+get_warnings_from_modules([M|Ms], State, DocPlt, Acc) when is_atom(M) ->
send_log(State#st.parent, io_lib:format("Getting warnings for ~w\n", [M])),
#st{callgraph = Callgraph, codeserver = Codeserver,
no_warn_unused = NoWarnUnused, plt = Plt} = State,
@@ -135,19 +133,15 @@ get_warnings_from_modules([M|Ms], State, DocPlt,
dialyzer_dataflow:get_warnings(ModCode, Plt, Callgraph, Records, NoWarnUnused),
{NewAcc, Warnings2} = postprocess_dataflow_warns(RawWarnings2, State, Acc),
Attrs = cerl:module_attrs(ModCode),
- Warnings3 = if BehavioursChk ->
- dialyzer_behaviours:check_callbacks(M, Attrs,
- Plt, Codeserver);
- true -> []
- end,
+ Warnings3 = dialyzer_behaviours:check_callbacks(M, Attrs, Plt, Codeserver),
NewDocPlt = insert_into_doc_plt(FunTypes, Callgraph, DocPlt),
NewCallgraph =
dialyzer_callgraph:renew_race_info(Callgraph, RaceCode, PublicTables,
NamedTables),
State1 = st__renew_state_calls(NewCallgraph, State),
- get_warnings_from_modules(Ms, State1, NewDocPlt, BehavioursChk,
+ get_warnings_from_modules(Ms, State1, NewDocPlt,
[Warnings1, Warnings2, Warnings3|NewAcc]);
-get_warnings_from_modules([], #st{plt = Plt}, DocPlt, _, Acc) ->
+get_warnings_from_modules([], #st{plt = Plt}, DocPlt, Acc) ->
{lists:flatten(Acc), Plt, DocPlt}.
postprocess_dataflow_warns(RawWarnings, State, WarnAcc) ->
@@ -476,7 +470,7 @@ doit(Module) ->
{ok, Code} = dialyzer_utils:get_core_from_abstract_code(AbstrCode),
{ok, Records} = dialyzer_utils:get_record_and_type_info(AbstrCode),
%% contract typing info in dictionary format
- {ok, Contracts} =
+ {ok, Contracts, _Callbacks} =
dialyzer_utils:get_spec_info(cerl:concrete(cerl:module_name(Code)),
AbstrCode, Records),
Sigs0 = get_top_level_signatures(Code, Records, Contracts),
diff --git a/lib/dialyzer/src/dialyzer_typesig.erl b/lib/dialyzer/src/dialyzer_typesig.erl
index 30aec59d22..92868b6878 100644
--- a/lib/dialyzer/src/dialyzer_typesig.erl
+++ b/lib/dialyzer/src/dialyzer_typesig.erl
@@ -2161,13 +2161,21 @@ get_apply_constr(FunLabels, Dst, ArgTypes, #state{callgraph = CG} = State) ->
case lists:member(error, MFAs) of
true -> error;
false ->
- Constrs = [begin
- State1 = state__new_constraint_context(State),
- State2 = get_plt_constr(MFA, Dst, ArgTypes, State1),
- state__cs(State2)
- end || {ok, MFA} <- MFAs],
- ApplyConstr = mk_disj_constraint_list(Constrs),
- {ok, state__store_conj(ApplyConstr, State)}
+ Constrs0 =
+ [begin
+ State1 = state__new_constraint_context(State),
+ try get_plt_constr(MFA, Dst, ArgTypes, State1) of
+ State2 -> state__cs(State2)
+ catch
+ throw:error -> error
+ end
+ end || {ok, MFA} <- MFAs],
+ case [C || C <- Constrs0, C =/= error] of
+ [] -> throw(error);
+ Constrs ->
+ ApplyConstr = mk_disj_constraint_list(Constrs),
+ {ok, state__store_conj(ApplyConstr, State)}
+ end
end.
state__scc(#state{scc = SCC}) ->
diff --git a/lib/dialyzer/src/dialyzer_utils.erl b/lib/dialyzer/src/dialyzer_utils.erl
index 12f8dec67e..2a248fb028 100644
--- a/lib/dialyzer/src/dialyzer_utils.erl
+++ b/lib/dialyzer/src/dialyzer_utils.erl
@@ -311,11 +311,15 @@ merge_records(NewRecords, OldRecords) ->
%%
%% ============================================================================
+-type spec_dict() :: dict().
+-type callback_dict() :: dict().
+
-spec get_spec_info(atom(), abstract_code(), dict()) ->
- {'ok', dict()} | {'error', string()}.
+ {'ok', spec_dict(), callback_dict()} | {'error', string()}.
get_spec_info(ModName, AbstractCode, RecordsDict) ->
- get_spec_info(AbstractCode, dict:new(), RecordsDict, ModName, "nofile").
+ get_spec_info(AbstractCode, dict:new(), dict:new(),
+ RecordsDict, ModName, "nofile").
%% TypeSpec is a list of conditional contracts for a function.
%% Each contract is of the form {[Argument], Range, [Constraint]} where
@@ -323,21 +327,34 @@ get_spec_info(ModName, AbstractCode, RecordsDict) ->
%% - Constraint is of the form {subtype, T1, T2} where T1 and T2
%% are erl_types:erl_type()
-get_spec_info([{attribute, Ln, spec, {Id, TypeSpec}}|Left],
- SpecDict, RecordsDict, ModName, File) when is_list(TypeSpec) ->
+get_spec_info([{attribute, Ln, Contract, {Id, TypeSpec}}|Left],
+ SpecDict, CallbackDict, RecordsDict, ModName, File)
+ when ((Contract =:= 'spec') or (Contract =:= 'callback')),
+ is_list(TypeSpec) ->
MFA = case Id of
{_, _, _} = T -> T;
{F, A} -> {ModName, F, A}
end,
- try dict:find(MFA, SpecDict) of
+ ActiveDict =
+ case Contract of
+ spec -> SpecDict;
+ callback -> CallbackDict
+ end,
+ try dict:find(MFA, ActiveDict) of
error ->
- NewSpecDict =
+ NewActiveDict =
dialyzer_contracts:store_tmp_contract(MFA, {File, Ln}, TypeSpec,
- SpecDict, RecordsDict),
- get_spec_info(Left, NewSpecDict, RecordsDict, ModName, File);
+ ActiveDict, RecordsDict),
+ {NewSpecDict, NewCallbackDict} =
+ case Contract of
+ spec -> {NewActiveDict, CallbackDict};
+ callback -> {SpecDict, NewActiveDict}
+ end,
+ get_spec_info(Left, NewSpecDict, NewCallbackDict,
+ RecordsDict, ModName,File);
{ok, {{OtherFile, L},_C}} ->
{Mod, Fun, Arity} = MFA,
- Msg = flat_format(" Contract for function ~w:~w/~w "
+ Msg = flat_format(" Contract/callback for function ~w:~w/~w "
"already defined in ~s:~w\n",
[Mod, Fun, Arity, OtherFile, L]),
throw({error, Msg})
@@ -347,12 +364,14 @@ get_spec_info([{attribute, Ln, spec, {Id, TypeSpec}}|Left],
[Ln, Error])}
end;
get_spec_info([{attribute, _, file, {IncludeFile, _}}|Left],
- SpecDict, RecordsDict, ModName, _File) ->
- get_spec_info(Left, SpecDict, RecordsDict, ModName, IncludeFile);
-get_spec_info([_Other|Left], SpecDict, RecordsDict, ModName, File) ->
- get_spec_info(Left, SpecDict, RecordsDict, ModName, File);
-get_spec_info([], SpecDict, _RecordsDict, _ModName, _File) ->
- {ok, SpecDict}.
+ SpecDict, CallbackDict, RecordsDict, ModName, _File) ->
+ get_spec_info(Left, SpecDict, CallbackDict,
+ RecordsDict, ModName, IncludeFile);
+get_spec_info([_Other|Left], SpecDict, CallbackDict,
+ RecordsDict, ModName, File) ->
+ get_spec_info(Left, SpecDict, CallbackDict, RecordsDict, ModName, File);
+get_spec_info([], SpecDict, CallbackDict, _RecordsDict, _ModName, _File) ->
+ {ok, SpecDict, CallbackDict}.
%% ============================================================================
%%
diff --git a/lib/dialyzer/test/behaviour_SUITE_data/dialyzer_options b/lib/dialyzer/test/behaviour_SUITE_data/dialyzer_options
new file mode 100644
index 0000000000..50991c9bc5
--- /dev/null
+++ b/lib/dialyzer/test/behaviour_SUITE_data/dialyzer_options
@@ -0,0 +1 @@
+{dialyzer_options, []}.
diff --git a/lib/dialyzer/test/behaviour_SUITE_data/results/callbacks_and_specs b/lib/dialyzer/test/behaviour_SUITE_data/results/callbacks_and_specs
new file mode 100644
index 0000000000..da498c225d
--- /dev/null
+++ b/lib/dialyzer/test/behaviour_SUITE_data/results/callbacks_and_specs
@@ -0,0 +1,5 @@
+
+my_callbacks_wrong.erl:26: The return type #state{parent::'undefined' | pid(),status::'closed' | 'init' | 'open',subscribe::[{pid(),integer()}],counter::integer()} in the specification of callback_init/1 is not a subtype of {'ok',_}, which is the expected return type for the callback of my_behaviour behaviour
+my_callbacks_wrong.erl:28: The inferred return type of callback_init/1 (#state{parent::'undefined' | pid(),status::'init',subscribe::[],counter::1}) has nothing in common with {'ok',_}, which is the expected return type for the callback of my_behaviour behaviour
+my_callbacks_wrong.erl:30: The return type {'noreply',#state{parent::'undefined' | pid(),status::'closed' | 'init' | 'open',subscribe::[{pid(),integer()}],counter::integer()}} | {'reply',#state{parent::'undefined' | pid(),status::'closed' | 'init' | 'open',subscribe::[{pid(),integer()}],counter::integer()}} in the specification of callback_cast/3 is not a subtype of {'noreply',_}, which is the expected return type for the callback of my_behaviour behaviour
+my_callbacks_wrong.erl:39: The specified type for the 2nd argument of callback_call/3 (atom()) is not a supertype of pid(), which is expected type for this argument in the callback of the my_behaviour behaviour
diff --git a/lib/dialyzer/test/behaviour_SUITE_data/results/gen_event_incorrect_return b/lib/dialyzer/test/behaviour_SUITE_data/results/gen_event_incorrect_return
new file mode 100644
index 0000000000..e646eea383
--- /dev/null
+++ b/lib/dialyzer/test/behaviour_SUITE_data/results/gen_event_incorrect_return
@@ -0,0 +1,2 @@
+
+gen_event_incorrect_return.erl:16: The inferred return type of init/1 ('error') has nothing in common with {'error',_} | {'ok',_} | {'ok',_,'hibernate'}, which is the expected return type for the callback of gen_event behaviour
diff --git a/lib/dialyzer/test/behaviour_SUITE_data/results/gen_server_incorrect_args b/lib/dialyzer/test/behaviour_SUITE_data/results/gen_server_incorrect_args
new file mode 100644
index 0000000000..3e98da785f
--- /dev/null
+++ b/lib/dialyzer/test/behaviour_SUITE_data/results/gen_server_incorrect_args
@@ -0,0 +1,8 @@
+
+gen_server_incorrect_args.erl:3: Undefined callback function code_change/3 (behaviour 'gen_server')
+gen_server_incorrect_args.erl:3: Undefined callback function handle_cast/2 (behaviour 'gen_server')
+gen_server_incorrect_args.erl:3: Undefined callback function handle_info/2 (behaviour 'gen_server')
+gen_server_incorrect_args.erl:3: Undefined callback function init/1 (behaviour 'gen_server')
+gen_server_incorrect_args.erl:3: Undefined callback function terminate/2 (behaviour 'gen_server')
+gen_server_incorrect_args.erl:7: The inferred return type of handle_call/3 ({'no'} | {'ok'}) has nothing in common with {'noreply',_} | {'noreply',_,'hibernate' | 'infinity' | non_neg_integer()} | {'reply',_,_} | {'stop',_,_} | {'reply',_,_,'hibernate' | 'infinity' | non_neg_integer()} | {'stop',_,_,_}, which is the expected return type for the callback of gen_server behaviour
+gen_server_incorrect_args.erl:7: The inferred type for the 2nd argument of handle_call/3 ('boo' | 'foo') is not a supertype of {pid(),_}, which is expected type for this argument in the callback of the gen_server behaviour
diff --git a/lib/dialyzer/test/behaviour_SUITE_data/results/gen_server_missing_callbacks b/lib/dialyzer/test/behaviour_SUITE_data/results/gen_server_missing_callbacks
new file mode 100644
index 0000000000..5e0ed5fd27
--- /dev/null
+++ b/lib/dialyzer/test/behaviour_SUITE_data/results/gen_server_missing_callbacks
@@ -0,0 +1,3 @@
+
+gen_server_missing_callbacks.erl:3: Undefined callback function handle_cast/2 (behaviour 'gen_server')
+gen_server_missing_callbacks.erl:3: Undefined callback function handle_info/2 (behaviour 'gen_server')
diff --git a/lib/dialyzer/test/behaviour_SUITE_data/results/sample_behaviour b/lib/dialyzer/test/behaviour_SUITE_data/results/sample_behaviour
new file mode 100644
index 0000000000..a38e662ccf
--- /dev/null
+++ b/lib/dialyzer/test/behaviour_SUITE_data/results/sample_behaviour
@@ -0,0 +1,9 @@
+
+sample_callback_wrong.erl:15: The inferred return type of sample_callback_2/0 (42) has nothing in common with atom(), which is the expected return type for the callback of sample_behaviour behaviour
+sample_callback_wrong.erl:16: The inferred return type of sample_callback_3/0 ('fair') has nothing in common with 'fail' | {'ok',1..255}, which is the expected return type for the callback of sample_behaviour behaviour
+sample_callback_wrong.erl:17: The inferred return type of sample_callback_4/1 ('fail') has nothing in common with 'ok', which is the expected return type for the callback of sample_behaviour behaviour
+sample_callback_wrong.erl:19: The inferred return type of sample_callback_5/1 (string()) has nothing in common with 'fail' | 'ok', which is the expected return type for the callback of sample_behaviour behaviour
+sample_callback_wrong.erl:19: The inferred type for the 1st argument of sample_callback_5/1 (atom()) is not a supertype of 1..255, which is expected type for this argument in the callback of the sample_behaviour behaviour
+sample_callback_wrong.erl:21: The inferred return type of sample_callback_6/3 ({'okk',number()}) has nothing in common with 'fail' | {'ok',1..255}, which is the expected return type for the callback of sample_behaviour behaviour
+sample_callback_wrong.erl:21: The inferred type for the 3rd argument of sample_callback_6/3 (atom()) is not a supertype of string(), which is expected type for this argument in the callback of the sample_behaviour behaviour
+sample_callback_wrong.erl:3: Undefined callback function sample_callback_1/0 (behaviour 'sample_behaviour')
diff --git a/lib/dialyzer/test/behaviour_SUITE_data/results/sample_behaviour_old b/lib/dialyzer/test/behaviour_SUITE_data/results/sample_behaviour_old
new file mode 100644
index 0000000000..f0181bb59c
--- /dev/null
+++ b/lib/dialyzer/test/behaviour_SUITE_data/results/sample_behaviour_old
@@ -0,0 +1,4 @@
+
+incorrect_args_callback.erl:12: The inferred type for the 2nd argument of bar/2 ('yes') is not a supertype of [any()], which is expected type for this argument in the callback of the correct_behaviour behaviour
+incorrect_return_callback.erl:9: The inferred return type of foo/0 ('error') has nothing in common with 'no' | 'yes', which is the expected return type for the callback of correct_behaviour behaviour
+missing_callback.erl:5: Undefined callback function foo/0 (behaviour 'correct_behaviour')
diff --git a/lib/dialyzer/test/behaviour_SUITE_data/results/supervisor_incorrect_return b/lib/dialyzer/test/behaviour_SUITE_data/results/supervisor_incorrect_return
new file mode 100644
index 0000000000..e89caf3cf7
--- /dev/null
+++ b/lib/dialyzer/test/behaviour_SUITE_data/results/supervisor_incorrect_return
@@ -0,0 +1,2 @@
+
+supervisor_incorrect_return.erl:14: The inferred return type of init/1 ({'ok',{{'one_against_one',0,1},[{_,_,_,_,_,_},...]}}) has nothing in common with 'ignore' | {'ok',{{'one_for_all',non_neg_integer(),non_neg_integer()} | {'one_for_one',non_neg_integer(),non_neg_integer()} | {'rest_for_one',non_neg_integer(),non_neg_integer()} | {'simple_one_for_one',non_neg_integer(),non_neg_integer()},[{_,{atom() | tuple(),atom(),'undefined' | [any()]},'permanent' | 'temporary' | 'transient','brutal_kill' | 'infinity' | non_neg_integer(),'supervisor' | 'worker','dynamic' | [atom() | tuple()]}]}}, which is the expected return type for the callback of supervisor behaviour
diff --git a/lib/dialyzer/test/behaviour_SUITE_data/results/undefined_callbacks b/lib/dialyzer/test/behaviour_SUITE_data/results/undefined_callbacks
new file mode 100644
index 0000000000..7147ffc750
--- /dev/null
+++ b/lib/dialyzer/test/behaviour_SUITE_data/results/undefined_callbacks
@@ -0,0 +1,2 @@
+
+undefined_beh_callback.erl:5: Callback info about the undefined_behaviour behaviour is not available
diff --git a/lib/dialyzer/test/behaviour_SUITE_data/src/callbacks_and_specs/my_behaviour.erl b/lib/dialyzer/test/behaviour_SUITE_data/src/callbacks_and_specs/my_behaviour.erl
new file mode 100644
index 0000000000..c4e5203448
--- /dev/null
+++ b/lib/dialyzer/test/behaviour_SUITE_data/src/callbacks_and_specs/my_behaviour.erl
@@ -0,0 +1,11 @@
+-module(my_behaviour).
+
+-callback callback_init(Parent :: pid()) -> {'ok', State::term()}.
+
+-callback callback_cast(State::term(), From::pid(), Msg::term()) ->
+ {'noreply', NewState::term()}.
+
+-callback callback_call(State::term(), From::pid(), Msg::term()) ->
+ {'reply', NewState::term(), Reply::term()}.
+
+-callback callback_exit(State::term()) -> 'ok'.
diff --git a/lib/dialyzer/test/behaviour_SUITE_data/src/callbacks_and_specs/my_callbacks_correct.erl b/lib/dialyzer/test/behaviour_SUITE_data/src/callbacks_and_specs/my_callbacks_correct.erl
new file mode 100644
index 0000000000..041b4ac56c
--- /dev/null
+++ b/lib/dialyzer/test/behaviour_SUITE_data/src/callbacks_and_specs/my_callbacks_correct.erl
@@ -0,0 +1,59 @@
+-module(my_callbacks_correct).
+
+-export([
+ callback_init/1
+ , callback_call/3
+ , callback_cast/3
+ , callback_exit/1
+ ]).
+
+-record(state, {
+ parent :: pid(),
+ status = init :: 'init' | 'open' | 'closed',
+ subscribe = [] :: list({pid(), integer()}),
+ counter = 1 :: integer()
+ }).
+
+-type state() :: #state{}.
+
+-type cast_message() :: 'open' | 'closed'.
+
+-type call_message() :: 'subscribe' | 'unsubscribe'.
+-type call_reply() :: 'accepted' | 'rejected'.
+
+-spec callback_init(Parent::pid()) -> {'ok', state()}.
+
+callback_init(Parent) ->
+ {ok, #state{parent = Parent}}.
+
+-spec callback_cast(state(), pid(), cast_message()) -> {'noreply', state()}.
+
+callback_cast(#state{parent = Pid} = State, Pid, Message)
+ when Message =:= 'open'; Message =:= 'close' ->
+ {noreply, State#state{status = Message}};
+callback_cast(State, _Pid, _Message) ->
+ {noreply, State}.
+
+-spec callback_call(state(), pid(), call_message()) ->
+ {'reply', state(), call_reply()}.
+
+callback_call(#state{status = open, subscribe = Subscribers} = State,
+ Pid, Message)
+ when Message =:= 'subscribe';
+ Message =:= 'unsubscribe' ->
+ NewState =
+ case Message of
+ subscribe ->
+ N = State#state.counter,
+ State#state{subscribe = [{Pid, N}|Subscribers], counter = N+1};
+ unsubscribe ->
+ State#state{subscribe = lists:keydelete(Pid, 1, Subscribers)}
+ end,
+ {reply, NewState, accepted};
+callback_call(State, _Pid, _Message) ->
+ {reply, State, rejected}.
+
+-spec callback_exit(state()) -> 'ok'.
+
+callback_exit(_State) ->
+ ok.
diff --git a/lib/dialyzer/test/behaviour_SUITE_data/src/callbacks_and_specs/my_callbacks_wrong.erl b/lib/dialyzer/test/behaviour_SUITE_data/src/callbacks_and_specs/my_callbacks_wrong.erl
new file mode 100644
index 0000000000..0459622dc1
--- /dev/null
+++ b/lib/dialyzer/test/behaviour_SUITE_data/src/callbacks_and_specs/my_callbacks_wrong.erl
@@ -0,0 +1,61 @@
+-module(my_callbacks_wrong).
+
+-export([
+ callback_init/1
+ , callback_call/3
+ , callback_cast/3
+ , callback_exit/1
+ ]).
+
+-behaviour(my_behaviour).
+
+-record(state, {
+ parent :: pid(),
+ status = init :: 'init' | 'open' | 'closed',
+ subscribe = [] :: list({pid(), integer()}),
+ counter = 1 :: integer()
+ }).
+
+-type state() :: #state{}.
+
+-type cast_message() :: 'open' | 'closed'.
+
+-type call_message() :: 'subscribe' | 'unsubscribe'.
+-type call_reply() :: 'accepted' | 'rejected'.
+
+-spec callback_init(Parent::pid()) -> state(). %% Wrong return spec
+
+callback_init(Parent) -> #state{parent = Parent}. %% Wrong return
+
+-spec callback_cast(state(), pid() | atom(), cast_message()) ->
+ {'noreply' | 'reply', state()}. %% More generic spec
+
+callback_cast(#state{parent = Pid} = State, Pid, Message)
+ when Message =:= 'open'; Message =:= 'close' ->
+ {noreply, State#state{status = Message}};
+callback_cast(State, _Pid, _Message) ->
+ {noreply, State}.
+
+-spec callback_call(state(), atom(), call_message()) -> %% Wrong arg spec
+ {'reply', state(), call_reply()}.
+
+callback_call(#state{status = open, subscribe = Subscribers} = State,
+ Pid, Message)
+ when Message =:= 'subscribe';
+ Message =:= 'unsubscribe' ->
+ NewState =
+ case Message of
+ subscribe ->
+ N = State#state.counter,
+ State#state{subscribe = [{Pid, N}|Subscribers], counter = N+1};
+ unsubscribe ->
+ State#state{subscribe = lists:keydelete(Pid, 1, Subscribers)}
+ end,
+ {reply, NewState, accepted};
+callback_call(State, _Pid, _Message) ->
+ {reply, State, rejected}.
+
+-spec callback_exit(state()) -> ok.
+
+callback_exit(_State) ->
+ ok.
diff --git a/lib/dialyzer/test/behaviour_SUITE_data/src/gen_event_incorrect_return.erl b/lib/dialyzer/test/behaviour_SUITE_data/src/gen_event_incorrect_return.erl
new file mode 100644
index 0000000000..f5ccf7f8c4
--- /dev/null
+++ b/lib/dialyzer/test/behaviour_SUITE_data/src/gen_event_incorrect_return.erl
@@ -0,0 +1,33 @@
+-module(gen_event_incorrect_return).
+
+-behaviour(gen_event).
+
+-export([start_link/0, add_handler/0]).
+
+-export([init/1, handle_event/2, handle_call/2,
+ handle_info/2, terminate/2, code_change/3]).
+
+start_link() ->
+ gen_event:start_link({local, myserver}).
+
+add_handler() ->
+ gen_event:add_handler(myserver, ?MODULE, []).
+
+init([]) ->
+ error.
+
+handle_event(_Event, State) ->
+ {ok, State}.
+
+handle_call(_Request, State) ->
+ Reply = ok,
+ {ok, Reply, State}.
+
+handle_info(_Info, State) ->
+ {ok, State}.
+
+terminate(_Reason, _State) ->
+ ok.
+
+code_change(_OldVsn, State, _Extra) ->
+ {ok, State}.
diff --git a/lib/dialyzer/test/behaviour_SUITE_data/src/gen_server_incorrect_args.erl b/lib/dialyzer/test/behaviour_SUITE_data/src/gen_server_incorrect_args.erl
new file mode 100644
index 0000000000..df04dff80d
--- /dev/null
+++ b/lib/dialyzer/test/behaviour_SUITE_data/src/gen_server_incorrect_args.erl
@@ -0,0 +1,11 @@
+-module(gen_server_incorrect_args).
+
+-behaviour(gen_server).
+
+-export([handle_call/3]).
+
+handle_call(_Request, From, _State) ->
+ case From of
+ 'boo' -> {'ok'};
+ 'foo' -> {'no'}
+ end.
diff --git a/lib/dialyzer/test/behaviour_SUITE_data/src/gen_server_missing_callbacks.erl b/lib/dialyzer/test/behaviour_SUITE_data/src/gen_server_missing_callbacks.erl
new file mode 100644
index 0000000000..760466fdac
--- /dev/null
+++ b/lib/dialyzer/test/behaviour_SUITE_data/src/gen_server_missing_callbacks.erl
@@ -0,0 +1,23 @@
+-module(gen_server_missing_callbacks).
+
+-behaviour(gen_server).
+
+-export([start_link/0]).
+
+-export([init/1, handle_call/3, terminate/2, code_change/3]).
+
+start_link() ->
+ gen_server:start_link({local, myserver}, ?MODULE, [], []).
+
+init([]) ->
+ ignore.
+
+handle_call(_Request, _From, State) ->
+ Reply = ok,
+ {reply, Reply, State}.
+
+terminate(_Reason, _State) ->
+ ok.
+
+code_change(_OldVsn, State, _Extra) ->
+ {ok, State}.
diff --git a/lib/dialyzer/test/behaviour_SUITE_data/src/sample_behaviour/sample_behaviour.erl b/lib/dialyzer/test/behaviour_SUITE_data/src/sample_behaviour/sample_behaviour.erl
new file mode 100644
index 0000000000..116980986b
--- /dev/null
+++ b/lib/dialyzer/test/behaviour_SUITE_data/src/sample_behaviour/sample_behaviour.erl
@@ -0,0 +1,13 @@
+-module(sample_behaviour).
+
+-type custom() :: 1..42.
+
+-callback sample_callback_1() -> term().
+-callback sample_callback_2() -> atom().
+-callback sample_callback_3() -> {'ok', custom()} | 'fail'.
+
+-callback sample_callback_4(term()) -> 'ok'.
+-callback sample_callback_5(custom()) -> 'ok' | 'fail'.
+
+-callback sample_callback_6(custom(), custom(), string()) ->
+ {'ok', custom()} | 'fail'.
diff --git a/lib/dialyzer/test/behaviour_SUITE_data/src/sample_behaviour/sample_callback_correct.erl b/lib/dialyzer/test/behaviour_SUITE_data/src/sample_behaviour/sample_callback_correct.erl
new file mode 100644
index 0000000000..ab0378e6f0
--- /dev/null
+++ b/lib/dialyzer/test/behaviour_SUITE_data/src/sample_behaviour/sample_callback_correct.erl
@@ -0,0 +1,32 @@
+-module(sample_callback_correct).
+
+-behaviour(sample_behaviour).
+
+-export([
+ sample_callback_1/0,
+ sample_callback_2/0,
+ sample_callback_3/0,
+ sample_callback_4/1,
+ sample_callback_5/1,
+ sample_callback_6/3
+ ]).
+
+sample_callback_1() -> 42. % This is a valid return.
+sample_callback_2() -> foo. % This is a valid return.
+sample_callback_3() -> {ok, 17}. % This is a valid return.
+sample_callback_4(Input) ->
+ put(mine, Input+1), % This is valid handling of the input
+ ok. % This is a valid return.
+sample_callback_5(Input) ->
+ case Input - 1 < 22 of % This is valid handling of the input
+ true -> ok; % This is a valid return.
+ false -> fail % This is a valid return.
+ end.
+sample_callback_6(OldNr, NewNr, Reason) ->
+ Diff = NewNr - OldNr, % This is valid handling of the input
+ Msg = string:join(["Reason: ", Reason], ","), % This is valid handling of the input
+ case Diff > 0 of
+ true -> put(mine, {NewNr, Msg}),
+ {ok, NewNr}; % This is a valid return.
+ false -> fail % This is a valid return.
+ end.
diff --git a/lib/dialyzer/test/behaviour_SUITE_data/src/sample_behaviour/sample_callback_correct_2.erl b/lib/dialyzer/test/behaviour_SUITE_data/src/sample_behaviour/sample_callback_correct_2.erl
new file mode 100644
index 0000000000..c218174e58
--- /dev/null
+++ b/lib/dialyzer/test/behaviour_SUITE_data/src/sample_behaviour/sample_callback_correct_2.erl
@@ -0,0 +1,38 @@
+-module(sample_callback_correct_2).
+
+-behaviour(sample_behaviour).
+
+-export([
+ sample_callback_1/0,
+ sample_callback_2/0,
+ sample_callback_3/0,
+ sample_callback_4/1,
+ sample_callback_5/1,
+ sample_callback_6/3,
+ common_infrastructure/1
+ ]).
+
+sample_callback_1() -> 42. % This is a valid return.
+sample_callback_2() -> halt(). % Crashes are also allowed.
+sample_callback_3() -> {ok, 17}. % This is a valid return.
+sample_callback_4(Input) ->
+ case Input of
+ 1 -> common_infrastructure(Input); % This is 'correct' input for
+ _ -> ok % common_infrastructure.
+ end.
+sample_callback_5(Input) ->
+ case get(Input) of % This is valid handling of a more generic input
+ true -> ok; % This is a valid return.
+ false -> fail % This is a valid return.
+ end.
+sample_callback_6(OldNr, NewNr, Reason) ->
+ Diff = NewNr - OldNr, % This is valid handling of the input
+ Msg = string:join(["Reason: ", Reason], ","), % This is valid handling of the input
+ case Diff > 0 of
+ true -> put(mine, {NewNr, Msg}),
+ {ok, NewNr}; % This is a valid return.
+ false -> fail % This is a valid return.
+ end.
+
+common_infrastructure( 1) -> 'ok';
+common_infrastructure(42) -> 'fail'.
diff --git a/lib/dialyzer/test/behaviour_SUITE_data/src/sample_behaviour/sample_callback_wrong.erl b/lib/dialyzer/test/behaviour_SUITE_data/src/sample_behaviour/sample_callback_wrong.erl
new file mode 100644
index 0000000000..02a063fab7
--- /dev/null
+++ b/lib/dialyzer/test/behaviour_SUITE_data/src/sample_behaviour/sample_callback_wrong.erl
@@ -0,0 +1,25 @@
+-module(sample_callback_wrong).
+
+-behaviour(sample_behaviour).
+
+-export([
+% sample_callback_1/0,
+ sample_callback_2/0,
+ sample_callback_3/0,
+ sample_callback_4/1,
+ sample_callback_5/1,
+ sample_callback_6/3
+ ]).
+
+% sample_callback_1() -> 41. % We can't really break this contract so: missing!
+sample_callback_2() -> 42. % This is not an atom().
+sample_callback_3() -> fair. % This is probably a typo.
+sample_callback_4(_) -> % We cannot break the input.
+ fail. % We can definitely return a wrong value however. :)
+sample_callback_5(Input) -> % Input is treated as an atom, result is a list.
+ atom_to_list(Input). % Both violate the contract.
+sample_callback_6(OldNr, NewNr, Reason) ->
+ Diff = NewNr - OldNr, % This is valid handling of the input
+ %% Reason should have been treated as a string.
+ Msg = string:join(["Reason: ", atom_to_list(Reason)], ","),
+ {okk, NewNr}. %% This, too, is a typo.
diff --git a/lib/dialyzer/test/behaviour_SUITE_data/src/sample_behaviour_old/correct_behaviour.erl b/lib/dialyzer/test/behaviour_SUITE_data/src/sample_behaviour_old/correct_behaviour.erl
new file mode 100644
index 0000000000..90ce590997
--- /dev/null
+++ b/lib/dialyzer/test/behaviour_SUITE_data/src/sample_behaviour_old/correct_behaviour.erl
@@ -0,0 +1,6 @@
+%%% This is a behaviour with info about its calllbacks.
+
+-module(correct_behaviour).
+
+-callback foo() -> yes | no.
+-callback bar({atom(),_},[_]) -> term().
diff --git a/lib/dialyzer/test/behaviour_SUITE_data/src/sample_behaviour_old/correct_callback.erl b/lib/dialyzer/test/behaviour_SUITE_data/src/sample_behaviour_old/correct_callback.erl
new file mode 100644
index 0000000000..8f254520ab
--- /dev/null
+++ b/lib/dialyzer/test/behaviour_SUITE_data/src/sample_behaviour_old/correct_callback.erl
@@ -0,0 +1,15 @@
+%%% This is a correct callback module for the correct_behaviour.
+
+-module(correct_callback).
+
+-behaviour(correct_behaviour).
+
+-export([foo/0, bar/2]).
+
+foo() ->
+ yes.
+
+bar({'query', 'boo'}, _Any) ->
+ no;
+bar({'reply', [_R]}, [1,2,3]) ->
+ yes.
diff --git a/lib/dialyzer/test/behaviour_SUITE_data/src/sample_behaviour_old/incorrect_args_callback.erl b/lib/dialyzer/test/behaviour_SUITE_data/src/sample_behaviour_old/incorrect_args_callback.erl
new file mode 100644
index 0000000000..68fc60d418
--- /dev/null
+++ b/lib/dialyzer/test/behaviour_SUITE_data/src/sample_behaviour_old/incorrect_args_callback.erl
@@ -0,0 +1,13 @@
+%%% This is a correct callback module for the correct_behaviour.
+
+-module(incorrect_args_callback).
+
+-behaviour(correct_behaviour).
+
+-export([foo/0, bar/2]).
+
+foo() ->
+ yes.
+
+bar({'reply', _Any}, yes) -> %% Should be a tuple and a list.
+ yes.
diff --git a/lib/dialyzer/test/behaviour_SUITE_data/src/sample_behaviour_old/incorrect_return_callback.erl b/lib/dialyzer/test/behaviour_SUITE_data/src/sample_behaviour_old/incorrect_return_callback.erl
new file mode 100644
index 0000000000..9ff920cdd0
--- /dev/null
+++ b/lib/dialyzer/test/behaviour_SUITE_data/src/sample_behaviour_old/incorrect_return_callback.erl
@@ -0,0 +1,15 @@
+%%% This is a correct callback module for the correct_behaviour.
+
+-module(incorrect_return_callback).
+
+-behaviour(correct_behaviour).
+
+-export([foo/0, bar/2]).
+
+foo() ->
+ error. %% Should be 'yes' or 'no'.
+
+bar({'query', 'boo'}, _Any) ->
+ no;
+bar({'reply', [_R]}, [1,2,3]) ->
+ yes.
diff --git a/lib/dialyzer/test/behaviour_SUITE_data/src/sample_behaviour_old/missing_callback.erl b/lib/dialyzer/test/behaviour_SUITE_data/src/sample_behaviour_old/missing_callback.erl
new file mode 100644
index 0000000000..e6c5306839
--- /dev/null
+++ b/lib/dialyzer/test/behaviour_SUITE_data/src/sample_behaviour_old/missing_callback.erl
@@ -0,0 +1,10 @@
+%%% This is a correct callback module for the correct_behaviour.
+
+-module(missing_callback).
+
+-behaviour(correct_behaviour).
+
+-export([bar/2]).
+
+bar({'reply', _Any}, []) ->
+ yes.
diff --git a/lib/dialyzer/test/behaviour_SUITE_data/src/supervisor_incorrect_return.erl b/lib/dialyzer/test/behaviour_SUITE_data/src/supervisor_incorrect_return.erl
new file mode 100644
index 0000000000..616a9073ae
--- /dev/null
+++ b/lib/dialyzer/test/behaviour_SUITE_data/src/supervisor_incorrect_return.erl
@@ -0,0 +1,17 @@
+-module(supervisor_incorrect_return).
+
+-behaviour(supervisor).
+
+-export([start_link/0]).
+
+-export([init/1]).
+
+-define(SERVER, ?MODULE).
+
+start_link() ->
+ supervisor:start_link({local, ?SERVER}, ?MODULE, []).
+
+init([]) ->
+ AChild = {'AName',{'AModule',start_link,[]},
+ permanent,2000,worker,['AModule']},
+ {ok,{{one_against_one,0,1}, [AChild]}}.
diff --git a/lib/dialyzer/test/behaviour_SUITE_data/src/undefined_callbacks/undefined_beh_callback.erl b/lib/dialyzer/test/behaviour_SUITE_data/src/undefined_callbacks/undefined_beh_callback.erl
new file mode 100644
index 0000000000..8223225b4b
--- /dev/null
+++ b/lib/dialyzer/test/behaviour_SUITE_data/src/undefined_callbacks/undefined_beh_callback.erl
@@ -0,0 +1,13 @@
+%%% This is a correct callback module for the correct_behaviour.
+
+-module(undefined_beh_callback).
+
+-behaviour(undefined_behaviour).
+
+-export([foo/0, bar/2]).
+
+foo() ->
+ yes.
+
+bar({'reply', _Any}, yes) ->
+ yes.
diff --git a/lib/dialyzer/test/behaviour_SUITE_data/src/undefined_callbacks/undefined_behaviour.erl b/lib/dialyzer/test/behaviour_SUITE_data/src/undefined_callbacks/undefined_behaviour.erl
new file mode 100644
index 0000000000..fb3d4c5e03
--- /dev/null
+++ b/lib/dialyzer/test/behaviour_SUITE_data/src/undefined_callbacks/undefined_behaviour.erl
@@ -0,0 +1,10 @@
+%%% This is a behaviour with undefined info about its calllbacks.
+
+-module(undefined_behaviour).
+
+-export([behaviour_info/1]).
+
+behaviour_info(callbacks) ->
+ [{foo, 0}, {bar, 2}];
+behaviour_info(_Other) ->
+ undefined.
diff --git a/lib/dialyzer/test/opaque_SUITE_data/results/crash b/lib/dialyzer/test/opaque_SUITE_data/results/crash
index 6bdd934169..1ddae5149f 100644
--- a/lib/dialyzer/test/opaque_SUITE_data/results/crash
+++ b/lib/dialyzer/test/opaque_SUITE_data/results/crash
@@ -1,5 +1,4 @@
-crash_1.erl:42: The specification for crash_1:empty/0 states that the function might also return crash_1:targetlist() but the inferred return is none()
crash_1.erl:45: Record construction #targetlist{list::[]} violates the declared type of field list::'undefined' | crash_1:target()
crash_1.erl:48: The call crash_1:get_using_branch2(Branch::maybe_improper_list(),L::'undefined' | crash_1:target()) contains an opaque term as 2nd argument when terms of different types are expected in these positions
crash_1.erl:50: The pattern <_Branch, []> can never match the type <maybe_improper_list(),'undefined' | crash_1:target()>
diff --git a/lib/dialyzer/test/r9c_SUITE_data/results/inets b/lib/dialyzer/test/r9c_SUITE_data/results/inets
index 0177dcc88c..24cb39e52b 100644
--- a/lib/dialyzer/test/r9c_SUITE_data/results/inets
+++ b/lib/dialyzer/test/r9c_SUITE_data/results/inets
@@ -3,21 +3,15 @@ ftp.erl:1243: The pattern {'ok', {N, Bytes}} can never match the type 'eof' | {'
ftp.erl:640: The pattern {'closed', _Why} can never match the type 'perm_fname_not_allowed' | 'perm_neg_compl' | 'perm_no_space' | 'pos_compl' | 'pos_interm' | 'pos_interm_acct' | 'trans_neg_compl' | 'trans_no_space' | {'error' | 'perm_fname_not_allowed' | 'perm_neg_compl' | 'perm_no_space' | 'pos_compl' | 'pos_interm' | 'pos_interm_acct' | 'pos_prel' | 'trans_neg_compl' | 'trans_no_space',atom() | [any()] | {'invalid_server_response',[any(),...]}}
http.erl:117: The pattern {'error', Reason} can never match the type #req_headers{connection::[45 | 97 | 101 | 105 | 107 | 108 | 112 | 118,...],content_length::[48,...],other::[{_,_}]}
http.erl:138: Function close_session/2 will never be called
-http_lib.erl:286: The call http_lib:close('ip_comm' | {'ssl',_},port() | {'sslsocket',_,_}) will never return since it differs in the 1st argument from the success typing arguments: ('http' | 'https',port() | {'sslsocket',_,pid() | {_,{'config',_,_,_,_,{_,_,_,_}}} | {'sslsocket',_,pid() | {'sslsocket',_,pid() | {_,_,_}}}})
-http_lib.erl:415: The pattern 61 can never match the type 'http_eoh' | binary() | maybe_improper_list(any(),binary() | []) | {'http_error',binary() | string()} | #http_request{method::'DELETE' | 'GET' | 'HEAD' | 'OPTIONS' | 'POST' | 'PUT' | 'TRACE' | binary() | string(),path::'*' | binary() | string() | {'abs_path',binary() | string()} | {'scheme',binary() | string(),binary() | string()} | {'absoluteURI','http' | 'https',binary() | string(),'undefined' | non_neg_integer(),binary() | string()},version::{non_neg_integer(),non_neg_integer()}} | #http_response{version::{non_neg_integer(),non_neg_integer()},status::integer(),phrase::binary() | string()} | {'http_header',integer(),atom() | binary() | string(),_,binary() | string()}
-http_lib.erl:417: The pattern 59 can never match the type 'http_eoh' | binary() | maybe_improper_list(any(),binary() | []) | {'http_error',binary() | string()} | #http_request{method::'DELETE' | 'GET' | 'HEAD' | 'OPTIONS' | 'POST' | 'PUT' | 'TRACE' | binary() | string(),path::'*' | binary() | string() | {'abs_path',binary() | string()} | {'scheme',binary() | string(),binary() | string()} | {'absoluteURI','http' | 'https',binary() | string(),'undefined' | non_neg_integer(),binary() | string()},version::{non_neg_integer(),non_neg_integer()}} | #http_response{version::{non_neg_integer(),non_neg_integer()},status::integer(),phrase::binary() | string()} | {'http_header',integer(),atom() | binary() | string(),_,binary() | string()}
-http_lib.erl:420: The pattern 13 can never match the type 'http_eoh' | binary() | maybe_improper_list(any(),binary() | []) | {'http_error',binary() | string()} | #http_request{method::'DELETE' | 'GET' | 'HEAD' | 'OPTIONS' | 'POST' | 'PUT' | 'TRACE' | binary() | string(),path::'*' | binary() | string() | {'abs_path',binary() | string()} | {'scheme',binary() | string(),binary() | string()} | {'absoluteURI','http' | 'https',binary() | string(),'undefined' | non_neg_integer(),binary() | string()},version::{non_neg_integer(),non_neg_integer()}} | #http_response{version::{non_neg_integer(),non_neg_integer()},status::integer(),phrase::binary() | string()} | {'http_header',integer(),atom() | binary() | string(),_,binary() | string()}
-http_lib.erl:424: The variable _ can never match since previous clauses completely covered the type 'http_eoh' | binary() | maybe_improper_list(any(),binary() | []) | {'http_error',binary() | string()} | #http_request{method::'DELETE' | 'GET' | 'HEAD' | 'OPTIONS' | 'POST' | 'PUT' | 'TRACE' | binary() | string(),path::'*' | binary() | string() | {'abs_path',binary() | string()} | {'scheme',binary() | string(),binary() | string()} | {'absoluteURI','http' | 'https',binary() | string(),'undefined' | non_neg_integer(),binary() | string()},version::{non_neg_integer(),non_neg_integer()}} | #http_response{version::{non_neg_integer(),non_neg_integer()},status::integer(),phrase::binary() | string()} | {'http_header',integer(),atom() | binary() | string(),_,binary() | string()}
-http_lib.erl:428: Function read_chunk_ext_val/6 will never be called
-http_lib.erl:444: The pattern 10 can never match the type 'http_eoh' | binary() | maybe_improper_list(any(),binary() | []) | {'http_error',binary() | string()} | #http_request{method::'DELETE' | 'GET' | 'HEAD' | 'OPTIONS' | 'POST' | 'PUT' | 'TRACE' | binary() | string(),path::'*' | binary() | string() | {'abs_path',binary() | string()} | {'scheme',binary() | string(),binary() | string()} | {'absoluteURI','http' | 'https',binary() | string(),'undefined' | non_neg_integer(),binary() | string()},version::{non_neg_integer(),non_neg_integer()}} | #http_response{version::{non_neg_integer(),non_neg_integer()},status::integer(),phrase::binary() | string()} | {'http_header',integer(),atom() | binary() | string(),_,binary() | string()}
-http_lib.erl:552: Call to missing or unexported function ssl:accept/2
+http_lib.erl:286: The call http_lib:close('ip_comm' | {'ssl',_},any()) will never return since it differs in the 1st argument from the success typing arguments: ('http' | 'https',any())
+http_lib.erl:424: The variable _ can never match since previous clauses completely covered the type any()
+http_lib.erl:438: The variable _ can never match since previous clauses completely covered the type any()
http_lib.erl:99: Function getHeaderValue/2 will never be called
httpc_handler.erl:660: Function exit_session_ok/2 has no local return
httpc_manager.erl:145: The pattern {ErrorReply, State2} can never match the type {{'ok',number()},number(),#state{reqid::number()}}
httpc_manager.erl:160: The pattern {ErrorReply, State2} can never match the type {{'ok',number()},number(),#state{reqid::number()}}
httpc_manager.erl:478: The pattern {'error', Reason} can never match the type 'ok' | {number(),#session{clientclose::boolean(),pipeline::[],quelength::1}}
httpc_manager.erl:490: The pattern {'error', Reason} can never match the type 'ok' | {number(),#session{clientclose::boolean(),pipeline::[],quelength::1}}
-httpd.erl:583: The pattern <{'error', Reason}, _Fd, SoFar> can never match the type <[any()],pid(),[[any(),...]]>
httpd_acceptor.erl:105: The pattern {'error', Reason} can never match the type {'ok',pid()}
httpd_acceptor.erl:110: Function handle_connection_err/4 will never be called
httpd_acceptor.erl:168: Function report_error/2 will never be called
@@ -26,14 +20,10 @@ httpd_manager.erl:885: The pattern {'EXIT', Reason} can never match since previo
httpd_manager.erl:919: Function auth_status/1 will never be called
httpd_manager.erl:926: Function sec_status/1 will never be called
httpd_manager.erl:933: Function acceptor_status/1 will never be called
-httpd_request_handler.erl:374: The call httpd_response:send_status(Info::#mod{parsed_header::maybe_improper_list()},417,[32 | 66 | 98 | 100 | 103 | 105 | 111 | 116 | 121,...]) will never return since it differs in the 2nd argument from the success typing arguments: (#mod{socket_type::'ip_comm' | {'ssl',_},socket::port() | {'sslsocket',_,_}},100 | 301 | 304 | 400 | 401 | 403 | 404 | 412 | 414 | 416 | 500 | 501 | 503,any())
-httpd_request_handler.erl:378: The call httpd_response:send_status(Info::#mod{parsed_header::maybe_improper_list()},417,[32 | 77 | 97 | 100 | 101 | 104 | 108 | 110 | 111 | 116 | 119,...]) will never return since it differs in the 2nd argument from the success typing arguments: (#mod{socket_type::'ip_comm' | {'ssl',_},socket::port() | {'sslsocket',_,_}},100 | 301 | 304 | 400 | 401 | 403 | 404 | 412 | 414 | 416 | 500 | 501 | 503,any())
-httpd_request_handler.erl:401: The call httpd_response:send_status(Info::#mod{parsed_header::maybe_improper_list()},417,[32 | 77 | 97 | 100 | 101 | 104 | 108 | 110 | 111 | 116 | 119,...]) will never return since it differs in the 2nd argument from the success typing arguments: (#mod{socket_type::'ip_comm' | {'ssl',_},socket::port() | {'sslsocket',_,_}},100 | 301 | 304 | 400 | 401 | 403 | 404 | 412 | 414 | 416 | 500 | 501 | 503,any())
-httpd_request_handler.erl:489: The variable Other can never match since previous clauses completely covered the type {'error',_} | {'ok','http_eoh' | binary() | maybe_improper_list(any(),binary() | []) | {'http_error',binary() | string()} | {'http_request','DELETE' | 'GET' | 'HEAD' | 'OPTIONS' | 'POST' | 'PUT' | 'TRACE' | binary() | string(),'*' | binary() | string() | {'abs_path',binary() | [any()]} | {'scheme',binary() | [any()],binary() | [any()]} | {'absoluteURI','http' | 'https',binary() | [any()],'undefined' | non_neg_integer(),binary() | [any()]},{non_neg_integer(),non_neg_integer()}} | {'http_response',{non_neg_integer(),non_neg_integer()},integer(),binary() | string()} | {'http_header',integer(),atom() | binary() | string(),_,binary() | string()}}
-httpd_request_handler.erl:644: The call lists:reverse(Fields0::{'error',_} | {'ok',_}) will never return since it differs in the 1st argument from the success typing arguments: ([any()])
-httpd_request_handler.erl:645: Function will never be called
-httpd_socket.erl:129: Call to missing or unexported function ssl:accept/2
-httpd_socket.erl:49: The pattern {'ok', _} can never match the type {'error',_}
+httpd_request_handler.erl:374: The call httpd_response:send_status(Info::#mod{parsed_header::maybe_improper_list()},417,[32 | 66 | 98 | 100 | 103 | 105 | 111 | 116 | 121,...]) will never return since it differs in the 2nd argument from the success typing arguments: (#mod{socket_type::'ip_comm' | {'ssl',_}},100 | 301 | 304 | 400 | 401 | 403 | 404 | 412 | 414 | 416 | 500 | 501 | 503,any())
+httpd_request_handler.erl:378: The call httpd_response:send_status(Info::#mod{parsed_header::maybe_improper_list()},417,[32 | 77 | 97 | 100 | 101 | 104 | 108 | 110 | 111 | 116 | 119,...]) will never return since it differs in the 2nd argument from the success typing arguments: (#mod{socket_type::'ip_comm' | {'ssl',_}},100 | 301 | 304 | 400 | 401 | 403 | 404 | 412 | 414 | 416 | 500 | 501 | 503,any())
+httpd_request_handler.erl:401: The call httpd_response:send_status(Info::#mod{parsed_header::maybe_improper_list()},417,[32 | 77 | 97 | 100 | 101 | 104 | 108 | 110 | 111 | 116 | 119,...]) will never return since it differs in the 2nd argument from the success typing arguments: (#mod{socket_type::'ip_comm' | {'ssl',_}},100 | 301 | 304 | 400 | 401 | 403 | 404 | 412 | 414 | 416 | 500 | 501 | 503,any())
+httpd_request_handler.erl:649: Guard test [{_,_}] =:= Trailers::nonempty_string() can never succeed
httpd_sup.erl:63: The variable Else can never match since previous clauses completely covered the type {'error',_} | {'ok',[any()],_,_}
httpd_sup.erl:88: The pattern {'error', Reason} can never match the type {'ok',_,_}
httpd_sup.erl:92: The variable Else can never match since previous clauses completely covered the type {'ok',_,_}
@@ -48,10 +38,10 @@ mod_dir.erl:72: The pattern {'error', Reason} can never match the type {'ok',[[[
mod_get.erl:135: The pattern <{'enfile', _}, _Info, Path> can never match the type <atom(),#mod{},atom() | binary() | [atom() | [any()] | char()]>
mod_head.erl:80: The pattern <{'enfile', _}, _Info, Path> can never match the type <atom(),#mod{},atom() | binary() | [atom() | [any()] | char()]>
mod_htaccess.erl:460: The pattern {'error', BadData} can never match the type {'ok',_}
-mod_include.erl:193: The pattern {_, Name, {[], []}} can never match the type {[any()],[any()],string()}
-mod_include.erl:195: The pattern {_, Name, {PathInfo, []}} can never match the type {[any()],[any()],string()}
-mod_include.erl:197: The pattern {_, Name, {PathInfo, QueryString}} can never match the type {[any()],[any()],string()}
-mod_include.erl:201: The variable Gurka can never match since previous clauses completely covered the type {[any()],[any()],string()}
+mod_include.erl:193: The pattern {_, Name, {[], []}} can never match the type {[any()],[any()],maybe_improper_list()}
+mod_include.erl:195: The pattern {_, Name, {PathInfo, []}} can never match the type {[any()],[any()],maybe_improper_list()}
+mod_include.erl:197: The pattern {_, Name, {PathInfo, QueryString}} can never match the type {[any()],[any()],maybe_improper_list()}
+mod_include.erl:201: The variable Gurka can never match since previous clauses completely covered the type {[any()],[any()],maybe_improper_list()}
mod_include.erl:692: The pattern <{'read', Reason}, Info, Path> can never match the type <{'open',atom()},#mod{},atom() | binary() | [atom() | [any()] | char()]>
mod_include.erl:706: The pattern <{'enfile', _}, _Info, Path> can never match the type <atom(),#mod{},atom() | binary() | [atom() | [any()] | char()]>
mod_include.erl:716: Function read_error/3 will never be called
diff --git a/lib/dialyzer/test/r9c_SUITE_data/results/mnesia b/lib/dialyzer/test/r9c_SUITE_data/results/mnesia
index 2be71ac7d7..b397d37523 100644
--- a/lib/dialyzer/test/r9c_SUITE_data/results/mnesia
+++ b/lib/dialyzer/test/r9c_SUITE_data/results/mnesia
@@ -2,6 +2,7 @@
mnesia.erl:1319: Guard test size(Spec::[{_,_,_},...]) can never succeed
mnesia.erl:1498: The call mnesia:bad_info_reply(Tab::atom(),Item::'type') will never return since it differs in the 2nd argument from the success typing arguments: (atom(),'memory' | 'size')
mnesia.erl:331: Function mod2abs/1 has no local return
+mnesia_backup.erl:49: Callback info about the mnesia_backup behaviour is not available
mnesia_bup.erl:111: The created fun has no local return
mnesia_bup.erl:574: Function fallback_receiver/2 has no local return
mnesia_bup.erl:967: Function uninstall_fallback_master/2 has no local return
@@ -12,9 +13,12 @@ mnesia_controller.erl:1679: The pattern {'stop', Reason, Reply, State2} can neve
mnesia_controller.erl:1685: The pattern {'noreply', State2, _Timeout} can never match the type {'reply',_,_}
mnesia_event.erl:77: The pattern 'remove_handler' can never match the type {'ok',_}
mnesia_event.erl:79: The pattern {'swap_handler', Args1, State1, Mod2, Args2} can never match the type {'ok',_}
+mnesia_frag.erl:26: Callback info about the mnesia_access behaviour is not available
mnesia_frag.erl:294: The call mnesia_frag:remote_collect(Ref::reference(),{'error',_},[],OldSelectFun::fun(() -> [any()])) will never return since it differs in the 2nd argument from the success typing arguments: (reference(),'ok',[any()],fun(() -> [any()]))
mnesia_frag.erl:304: The call mnesia_frag:remote_collect(Ref::reference(),{'error',{'node_not_running',_}},[],OldSelectFun::fun(() -> [any()])) will never return since it differs in the 2nd argument from the success typing arguments: (reference(),'ok',[any()],fun(() -> [any()]))
mnesia_frag.erl:312: The call mnesia_frag:remote_collect(Ref::reference(),LocalRes::{'error',_},[],OldSelectFun::fun(() -> [any()])) will never return since it differs in the 2nd argument from the success typing arguments: (reference(),'ok',[any()],fun(() -> [any()]))
+mnesia_frag_hash.erl:24: Callback info about the mnesia_frag_hash behaviour is not available
+mnesia_frag_old_hash.erl:23: Callback info about the mnesia_frag_hash behaviour is not available
mnesia_index.erl:52: The call mnesia_lib:other_val(Var::{_,'commit_work' | 'index' | 'setorbag' | 'storage_type' | {'index',_}},_ReASoN_::any()) will never return since it differs in the 1st argument from the success typing arguments: ({_,'active_replicas' | 'where_to_read' | 'where_to_write'},any())
mnesia_lib.erl:1028: The pattern {'EXIT', Reason} can never match the type [any()] | {'error',_}
mnesia_lib.erl:957: The pattern {'ok', {0, _}} can never match the type 'eof' | {'error',atom()} | {'ok',binary() | string()}
diff --git a/lib/dialyzer/test/small_SUITE_data/results/higher_order_discrepancy b/lib/dialyzer/test/small_SUITE_data/results/higher_order_discrepancy
new file mode 100644
index 0000000000..7ce440a60d
--- /dev/null
+++ b/lib/dialyzer/test/small_SUITE_data/results/higher_order_discrepancy
@@ -0,0 +1,4 @@
+
+higher_order_discrepancy.erl:11: The call higher_order_discrepancy:g('foo') will never return since it differs in the 1st argument from the success typing arguments: ('bar')
+higher_order_discrepancy.erl:14: Function g/1 has no local return
+higher_order_discrepancy.erl:14: The pattern 'bar' can never match the type 'foo'
diff --git a/lib/dialyzer/test/small_SUITE_data/results/higher_order_discrepancy_2 b/lib/dialyzer/test/small_SUITE_data/results/higher_order_discrepancy_2
new file mode 100644
index 0000000000..c1c7dbbfcc
--- /dev/null
+++ b/lib/dialyzer/test/small_SUITE_data/results/higher_order_discrepancy_2
@@ -0,0 +1,8 @@
+
+higher_order_discrepancy_2.erl:11: The call higher_order_discrepancy_2:f('foo') will never return since it differs in the 1st argument from the success typing arguments: ('bar')
+higher_order_discrepancy_2.erl:11: The call higher_order_discrepancy_2:g('foo') will never return since it differs in the 1st argument from the success typing arguments: ('baz')
+higher_order_discrepancy_2.erl:13: Function f/1 has no local return
+higher_order_discrepancy_2.erl:13: The pattern 'bar' can never match the type 'foo'
+higher_order_discrepancy_2.erl:14: Function g/1 has no local return
+higher_order_discrepancy_2.erl:14: The pattern 'baz' can never match the type 'foo'
+higher_order_discrepancy_2.erl:5: Function test/1 has no local return
diff --git a/lib/dialyzer/test/small_SUITE_data/results/tuple_set_crash b/lib/dialyzer/test/small_SUITE_data/results/tuple_set_crash
index 191d3d4173..8c9df56a4b 100644
--- a/lib/dialyzer/test/small_SUITE_data/results/tuple_set_crash
+++ b/lib/dialyzer/test/small_SUITE_data/results/tuple_set_crash
@@ -12,4 +12,3 @@ tuple_set_crash.erl:179: The pattern <<AudioVolume:16/integer-little-unit:1,Rest
tuple_set_crash.erl:182: The pattern <<Delay:16/integer-little-unit:1,_Padding/binary-unit:8>> can never match the type <<_:8>>
tuple_set_crash.erl:62: The pattern {'play_list', _Playlist} can never match the type 'ok' | {'device_properties',[{atom(),_}]} | {'error',[{atom(),_}]}
tuple_set_crash.erl:64: The pattern {'error', 17} can never match the type 'ok' | {'device_properties',[{atom(),_}]} | {'error',[{atom(),_}]}
-tuple_set_crash.erl:83: The specification for tuple_set_crash:parse_message/1 states that the function might also return {'media_item_url_reply',integer(),binary()} but the inferred return is 'ok' | {'audio_device_info' | 'audio_output_info' | 'audio_target_info' | 'device_properties' | 'error' | 'video_device_info' | 'video_output_info' | 'video_target_info',[{'address' | 'audio_volume' | 'controller_description' | 'controller_name' | 'controller_status' | 'device_id' | 'display_type' | 'fw_version' | 'master_volume' | 'model' | 'output_id' | 'status' | 'target_id',binary() | non_neg_integer()}] | 1..255}
diff --git a/lib/dialyzer/test/small_SUITE_data/src/higher_order_discrepancy.erl b/lib/dialyzer/test/small_SUITE_data/src/higher_order_discrepancy.erl
new file mode 100644
index 0000000000..ff5ee6bac4
--- /dev/null
+++ b/lib/dialyzer/test/small_SUITE_data/src/higher_order_discrepancy.erl
@@ -0,0 +1,14 @@
+-module(higher_order_discrepancy).
+
+-export([test/1]).
+
+test(X) ->
+ F =
+ case X of
+ 1 -> fun f/1;
+ 2 -> fun g/1
+ end,
+ F(foo).
+
+f(foo) -> ok.
+g(bar) -> ok.
diff --git a/lib/dialyzer/test/small_SUITE_data/src/higher_order_discrepancy_2.erl b/lib/dialyzer/test/small_SUITE_data/src/higher_order_discrepancy_2.erl
new file mode 100644
index 0000000000..4b0d4f6b45
--- /dev/null
+++ b/lib/dialyzer/test/small_SUITE_data/src/higher_order_discrepancy_2.erl
@@ -0,0 +1,14 @@
+-module(higher_order_discrepancy_2).
+
+-export([test/1]).
+
+test(X) ->
+ F =
+ case X of
+ 1 -> fun f/1;
+ 2 -> fun g/1
+ end,
+ F(foo).
+
+f(bar) -> ok.
+g(baz) -> ok.
diff --git a/lib/dialyzer/test/underspecs_SUITE_data/dialyzer_options b/lib/dialyzer/test/underspecs_SUITE_data/dialyzer_options
new file mode 100644
index 0000000000..f7197ac30f
--- /dev/null
+++ b/lib/dialyzer/test/underspecs_SUITE_data/dialyzer_options
@@ -0,0 +1 @@
+{dialyzer_options, [{warnings, [underspecs]}]}.
diff --git a/lib/dialyzer/test/underspecs_SUITE_data/results/remote b/lib/dialyzer/test/underspecs_SUITE_data/results/remote
new file mode 100644
index 0000000000..1e0cda3bde
--- /dev/null
+++ b/lib/dialyzer/test/underspecs_SUITE_data/results/remote
@@ -0,0 +1,9 @@
+
+remotes1.erl:17: The specification for remotes1:foo5/1 states that the function might also return 'ko' but the inferred return is 'ok'
+remotes1.erl:20: Type specification remotes1:foo6('ok' | 'ko') -> 'ok' is a supertype of the success typing: remotes1:foo6('ok') -> 'ok'
+remotes1.erl:25: The specification for remotes1:foo7/1 states that the function might also return 'ko' but the inferred return is 'ok'
+remotes1.erl:28: Type specification remotes1:foo8(local_type_42()) -> 'ok' is a supertype of the success typing: remotes1:foo8('ok') -> 'ok'
+remotes1.erl:33: The specification for remotes1:foo9/1 states that the function might also return 'ko' but the inferred return is 'ok'
+remotes1.erl:36: Type specification remotes1:foo10(local_and_known_remote_type_42()) -> 'ok' is a supertype of the success typing: remotes1:foo10('ok') -> 'ok'
+remotes1.erl:49: Type specification remotes1:foo13('ok') -> local_and_unknown_remote_type_42() is a supertype of the success typing: remotes1:foo13('ok') -> 'ok'
+remotes1.erl:52: Type specification remotes1:foo14(local_and_unknown_remote_type_42()) -> 'ok' is a supertype of the success typing: remotes1:foo14('ok') -> 'ok'
diff --git a/lib/dialyzer/test/underspecs_SUITE_data/src/remote/remotes1.erl b/lib/dialyzer/test/underspecs_SUITE_data/src/remote/remotes1.erl
new file mode 100644
index 0000000000..b722495095
--- /dev/null
+++ b/lib/dialyzer/test/underspecs_SUITE_data/src/remote/remotes1.erl
@@ -0,0 +1,61 @@
+-module(remotes1).
+
+-compile(export_all).
+
+-spec foo1(some_unknown_remote:type42()) -> ok.
+foo1(ok) -> ok.
+
+-spec foo2(ok) -> some_unknown_remote:type42().
+foo2(ok) -> ok.
+
+-spec foo3(some_known_remote:type42()) -> ok.
+foo3(ok) -> ok.
+
+-spec foo4(ok) -> some_known_remote:type42().
+foo4(ok) -> ok.
+
+-spec foo5(ok|ko) -> ok|ko.
+foo5(ok) -> ok.
+
+-spec foo6(ok|ko) -> ok.
+foo6(ok) -> ok.
+
+-type local_type_42() :: ok | ko.
+
+-spec foo7(ok) -> local_type_42().
+foo7(ok) -> ok.
+
+-spec foo8(local_type_42()) -> ok.
+foo8(ok) -> ok.
+
+-type local_and_known_remote_type_42() :: some_known_remote:type42() | ok | ko.
+
+-spec foo9(ok) -> local_and_known_remote_type_42().
+foo9(ok) -> ok.
+
+-spec foo10(local_and_known_remote_type_42()) -> ok.
+foo10(ok) -> ok.
+
+-type local_and_ok_known_remote_type_42() :: some_known_remote:type42() | ok.
+
+-spec foo11(ok) -> local_and_ok_known_remote_type_42().
+foo11(ok) -> ok.
+
+-spec foo12(local_and_ok_known_remote_type_42()) -> ok.
+foo12(ok) -> ok.
+
+-type local_and_unknown_remote_type_42() :: some_unknown_remote:type42() | ok | ko.
+
+-spec foo13(ok) -> local_and_unknown_remote_type_42().
+foo13(ok) -> ok.
+
+-spec foo14(local_and_unknown_remote_type_42()) -> ok.
+foo14(ok) -> ok.
+
+-type local_and_ok_unknown_remote_type_42() :: some_unknown_remote:type42() | ok.
+
+-spec foo15(ok) -> local_and_ok_unknown_remote_type_42().
+foo15(ok) -> ok.
+
+-spec foo16(local_and_ok_unknown_remote_type_42()) -> ok.
+foo16(ok) -> ok.
diff --git a/lib/dialyzer/test/underspecs_SUITE_data/src/remote/some_known_remote.erl b/lib/dialyzer/test/underspecs_SUITE_data/src/remote/some_known_remote.erl
new file mode 100644
index 0000000000..437f1e7826
--- /dev/null
+++ b/lib/dialyzer/test/underspecs_SUITE_data/src/remote/some_known_remote.erl
@@ -0,0 +1,5 @@
+-module(some_known_remote).
+
+-export_type([type42/0]).
+
+-type type42() :: ok | ko.
diff --git a/lib/diameter/bin/diameterc b/lib/diameter/bin/diameterc
index f5cf3ebc10..c0e83ea1a4 100755
--- a/lib/diameter/bin/diameterc
+++ b/lib/diameter/bin/diameterc
@@ -33,19 +33,24 @@
usage() ->
io:format(
- "~w [options] file~n"
+ "~w [options] dict~n"
"~n"
" Compile a diameter dictionary file (.dia) to Erlang source (.erl)~n"
" and/or header (.hrl) files.~n"
"~n"
" options:~n"
- " -h = print this message~n"
- " -v = verbose output~n"
- " -o dir = set the output directory (default .)~n"
- " -i dir = set an include directory for inherited beams~n"
- " -E = no .erl output~n"
- " -H = no .hrl output~n"
- " -d = write intermediate files (.spec and .forms)~n",
+ "~n"
+ " --name name = set @name~n"
+ " --prefix prefix = set @prefix~n"
+ " --inherits dict|- = set/clear @inherits~n"
+ "~n"
+ " -h = print this message~n"
+ " -v = verbose output~n"
+ " -o dir = set the output directory (default .)~n"
+ " -i dir = set an include directory for inherited beams~n"
+ " -E = no .erl output~n"
+ " -H = no .hrl output~n"
+ " -d = write intermediate files (.spec and .forms)~n",
[?MODULE]).
main(Args) ->
@@ -109,9 +114,17 @@ arg(["-o", Dir | Args], #argv{options = Opts} = A) ->
arg(Args, A#argv{options = [{outdir, Dir} | Opts]});
arg(["-i", Dir | Args], #argv{options = Opts} = A) ->
- true = dir_exists(Dir),
arg(Args, A#argv{options = Opts ++ [{include, Dir}]});
+arg(["--name", Name | Args], #argv{options = Opts} = A) ->
+ arg(Args, A#argv{options = [{name, Name} | Opts]});
+
+arg(["--prefix", Name | Args], #argv{options = Opts} = A) ->
+ arg(Args, A#argv{options = [{prefix, Name} | Opts]});
+
+arg(["--inherits", Dict | Args], #argv{options = Opts} = A) ->
+ arg(Args, A#argv{options = Opts ++ [{inherits, Dict}]});
+
arg(["-E" | Args], #argv{output = Output} = A) ->
arg(Args, A#argv{output = lists:delete(erl, Output)});
@@ -120,10 +133,10 @@ arg(["-H" | Args], #argv{output = Output} = A) ->
arg(["-d" | Args], #argv{options = Opts, output = Output} = A) ->
arg(Args, A#argv{options = [debug | Opts],
- output = [spec | Output]});
+ output = [spec | Output]});
arg([[$- = M, C, H | T] | Args], A) %% clustered options
- when C /= $i, C /= $o ->
+ when C /= $i, C /= $o, C /= $- ->
arg([[M,C], [M,H|T] | Args], A);
arg([File], A) ->
diff --git a/lib/diameter/configure.in b/lib/diameter/configure.in
index 9aca3859c5..8acfb28fed 100644
--- a/lib/diameter/configure.in
+++ b/lib/diameter/configure.in
@@ -132,7 +132,6 @@ dnl </STANDALONE DIAMETER>
AC_OUTPUT(
Makefile:Makefile.in
- src/app/diameter.mk:src/app/diameter.mk.in
make/$host/rules.mk:make/rules.mk.in
)
diff --git a/lib/diameter/doc/src/Makefile b/lib/diameter/doc/src/Makefile
index 1453138cb6..bc3e649e6b 100644
--- a/lib/diameter/doc/src/Makefile
+++ b/lib/diameter/doc/src/Makefile
@@ -126,8 +126,6 @@ debug opt:
info:
@echo "->Makefile<-"
@echo ""
- @echo "DOCSUPPORT = $(DOCSUPPORT)"
- @echo ""
@echo "INDEX_FILE = $(INDEX_FILE)"
@echo "INDEX_SRC = $(INDEX_SRC)"
@echo "INDEX_TARGET = $(INDEX_TARGET)"
@@ -141,10 +139,6 @@ info:
@echo ""
@echo "GIF_FILES = $(GIF_FILES)"
@echo ""
- @echo "TEX_FILES_USERS_GUIDE = $(TEX_FILES_USERS_GUIDE)"
- @echo "TEX_FILES_REF_MAN = $(TEX_FILES_REF_MAN)"
- @echo "TEX_FILES_BOOK = $(TEX_FILES_BOOK)"
- @echo ""
@echo "MAN1_FILES = $(MAN1_FILES)"
@echo "MAN3_FILES = $(MAN3_FILES)"
@echo "MAN4_FILES = $(MAN4_FILES)"
diff --git a/lib/diameter/doc/src/depend.sed b/lib/diameter/doc/src/depend.sed
index 5973c4586e..42de597f15 100644
--- a/lib/diameter/doc/src/depend.sed
+++ b/lib/diameter/doc/src/depend.sed
@@ -21,14 +21,18 @@
# massaged in Makefile.
#
-/^<com>\([^<]*\)<\/com>/b rf
-/^<module>\([^<]*\)<\/module>/b rf
+/^<com>/b c
+/^<module>/b c
/^<chapter>/!d
+# Chapter: html basename is same as xml.
s@@$(HTMLDIR)/%FILE%.html: %FILE%.xml@
q
-:rf
-s@@$(HTMLDIR)/\1.html: %FILE%.xml@
+# Reference: html basename is from contents of com/module element.
+:c
+s@^[^>]*>@@
+s@<.*@@
+s@.*@$(HTMLDIR)/&.html: %FILE%.xml@
q
diff --git a/lib/diameter/doc/src/diameter.xml b/lib/diameter/doc/src/diameter.xml
index 2cad70e3bc..2d8edb1301 100644
--- a/lib/diameter/doc/src/diameter.xml
+++ b/lib/diameter/doc/src/diameter.xml
@@ -367,6 +367,19 @@ capabilities exchange message.
Optional, defaults to the empty list.</p>
</item>
+<tag><c>{'Inband-Security-Id', [Unsigned32()]}</c></tag>
+<item>
+<p>
+Values of Inband-Security-Id AVPs sent in an outgoing
+capabilities exchange message.
+Optional, defaults to the empty list, which is equivalent to a
+list containing only 0 (= NO_INBAND_SECURITY).</p>
+
+<p>
+If 1 (= TLS) is specified then TLS is selected if the CER/CEA received
+from the peer offers it.</p>
+</item>
+
<tag><c>{'Acct-Application-Id', [Unsigned32()]}</c></tag>
<item>
<p>
@@ -418,7 +431,7 @@ eval(F) ->
</code>
<p>
-Evaluating an evaluable() <c>E</c> on an argument list <c>A</c>
+Applying an evaluable() <c>E</c> to an argument list <c>A</c>
is meant in the sense of <c>eval([E|A])</c>.</p>
<p>
@@ -552,7 +565,7 @@ Pkt = #diameter_packet{}
</code>
<p>
-Reports that the RFC 3539 watchdog state machine has
+The RFC 3539 watchdog state machine has
transitioned into (<c>up</c>) or out of (<c>down</c>) the open
state.
If a <c>diameter_packet</c> record is present in an <c>up</c> tuple
@@ -563,9 +576,9 @@ connectivity.</p>
<p>
Note that a single up/down event for a given peer corresponds to
-as many peer_up/down callbacks as there are Diameter
-applications shared by the peer, as determined during capablilities
-exchange.
+as many <seealso marker="diameter_app#peer_up">peer_up/peer_down</seealso>
+callbacks as there are Diameter applications shared by the peer,
+as determined during capablilities exchange.
That is, the event communicates connectivity with the
peer as a whole while the callbacks communicate connectivity with
respect to individual Diameter applications.</p>
@@ -584,12 +597,96 @@ transport connection with a peer following <c>reconnect_timer</c> or
<c>watchdog_timer</c> expiry.</p>
</item>
+<tag><c>{closed, Ref, Reason, Config}</c></tag>
+<item>
+<code>
+Ref = transport_ref()
+Config = {connect|listen, [transport_opt()]}
+</code>
+
+<p>
+Capabilities exchange has failed. <c>Reason</c> can be one of
+the following.</p>
+
+<taglist>
+
+<tag><c>{'CER', Result, Caps, Pkt}</c></tag>
+<item>
+<code>
+Result = ResultCode | {capabilities_cb, CB, ResultCode|discard}
+Caps = #diameter_caps{}
+Pkt = #diameter_packet{}
+ResultCode = integer()
+CB = evaluable()
+</code>
+
+<p>
+An incoming CER has been answered with the indicated result code or
+discarded.
+The capabilities record contains pairs of values for the the local
+node and remote peer.
+The packet record contains the CER in question.
+In the case of rejection by a capabilities callback, the tuple
+indicates the rejecting callback.</p>
+</item>
+
+<tag><c>{'CER', Caps, {ResultCode, Pkt}}</c></tag>
+<item>
+<code>
+ResultCode = integer()
+Caps = #diameter_caps{}
+Pkt = #diameter_packet{}
+</code>
+
+<p>
+An incoming CER contained errors and has been answered with the
+indicated result code.
+The capabilities record contains only values for the the local
+node.
+The packet record contains the CER in question.</p>
+</item>
+
+<tag><c>{'CEA', Result, Caps, Pkt}</c></tag>
+<item>
+<code>
+Result = integer() | atom() | {capabilities_cb, CB, ResultCode|discard}
+Caps = #diameter_caps{}
+Pkt = #diameter_packet{}
+ResultCode = integer()
+</code>
+
+<p>
+An incoming CEA has been rejected for the indicated reason.
+An integer-valued <c>Result</c> indicates the result code sent
+by the peer.
+The capabilities record contains pairs of values for the the local
+node and remote peer.
+The packet record contains the CEA in question.
+In the case of rejection by a capabilities callback, the tuple
+indicates the rejecting callback.</p>
+</item>
+
+<tag><c>{'CEA', Caps, Pkt}</c></tag>
+<item>
+<code>
+Caps = #diameter_caps{}
+Pkt = #diameter_packet{}
+</code>
+
+<p>
+An incoming CER contained errors and has been rejected.
+The capabilities record contains only values for the the local node.
+The packet record contains the CEA in question.</p>
+</item>
+
+</taglist>
+</item>
+
</taglist>
<p>
For forward compatibility, a subscriber should be prepared to receive
-<c>diameter_event.info</c> of forms other than those documented
-above.</p>
+info fields of forms other than the above.</p>
<marker id="service_name"/>
</item>
@@ -683,6 +780,39 @@ in question.</p>
AVP's used to construct outgoing CER/CEA messages.
Any AVP specified takes precedence over a corresponding value specified
for the service in question.</p>
+
+<p>
+Specifying a capability as a transport option
+may be particularly appropriate for Inband-Security-Id in case
+TLS is desired over TCP as implemented by
+<seealso marker="diameter_tcp">diameter_tcp(3)</seealso> but
+not over SCTP as implemented by
+<seealso marker="diameter_sctp">diameter_sctp(3)</seealso>.</p>
+</item>
+
+<tag><c>{capabilities_cb, evaluable()}</c></tag>
+<item>
+<p>
+A callback invoked upon reception of CER/CEA during capabilities
+exchange in order to ask whether or not the connection should
+be accepted.
+Applied to the transport reference (as returned by <seealso
+marker="#add_transport">add_transport/2</seealso>) and
+<c>diameter_caps</c> record of the connection.
+Returning <c>ok</c> accepts the connection.
+Returning <c>integer()</c> causes an incoming
+CER to be answered with the specified Result-Code.
+Returning <c>discard</c> causes an incoming CER to
+be discarded.
+Returning <c>unknown</c> is equivalent to returning <c>3010</c>,
+DIAMETER_UNKNOWN_PEER.
+Returning anything but <c>ok</c> or a 2xxx series result
+code causes the transport connection to be broken.</p>
+
+<p>
+Multiple <c>capabilities_cb</c> options can be specified, in which
+case the corresponding callbacks are applied until either all return
+<c>ok</c> or one does not.</p>
</item>
<tag><c>{watchdog_timer, TwInit}</c></tag>
diff --git a/lib/diameter/doc/src/diameter_compile.xml b/lib/diameter/doc/src/diameter_compile.xml
index 72bac30709..60e08d41da 100644
--- a/lib/diameter/doc/src/diameter_compile.xml
+++ b/lib/diameter/doc/src/diameter_compile.xml
@@ -64,9 +64,10 @@ Defaults to the current working directory.</p>
<item>
<p>
Specifies a directory to add to the code path.
-Typically used to point at beam files corresponding to dictionaries
-included by the one being compiled (using the <c>@includes</c> directive):
-inclusion is a beam dependency, not an erl/hrl dependency.</p>
+Use to point at beam files corresponding to dictionaries
+inherited by the one being compiled using <c>@inherits</c> or
+<c>--inherits</c>.
+Inheritance is a beam dependency, not an erl/hrl dependency.</p>
<p>
Multiple <c>-i</c> options can be specified.</p>
@@ -84,6 +85,31 @@ Supresses erl generation.</p>
Supresses hrl generation.</p>
</item>
+<tag><![CDATA[--name <name>]]></tag>
+<item>
+<p>
+Set <c>@name</c> in the dictionary file.
+Overrides any setting in the file itself.</p>
+</item>
+
+<tag><![CDATA[--prefix <prefix>]]></tag>
+<item>
+<p>
+Set <c>@prefix</c> in the dictionary file.
+Overrides any setting in the file itself.</p>
+</item>
+
+<tag><![CDATA[--inherits <dict>]]></tag>
+<item>
+<p>
+Append an <c>@inherits</c> to the dictionary file.
+Specifying <c>'-'</c> as the dictionary has the effect of clearing
+any previous inherits, effectively ignoring previous inherits.</p>
+
+<p>
+Multiple <c>--inherits</c> options can be specified.</p>
+</item>
+
</taglist>
</item>
diff --git a/lib/diameter/doc/src/diameter_soc.xml b/lib/diameter/doc/src/diameter_soc.xml
index 4f8581a904..6b9ef9f756 100644
--- a/lib/diameter/doc/src/diameter_soc.xml
+++ b/lib/diameter/doc/src/diameter_soc.xml
@@ -57,9 +57,13 @@ including the P Flag in the AVP header.</p>
<item>
<p>
-There is no TLS support.
-It's unclear (aka uninvestigated) how TLS would impact
-diameter but IPsec can be used without it needing to know.</p>
+There is no TLS support over SCTP.
+RFC 3588 requires that a Diameter server support TLS but in
+practise this seems to mean TLS over SCTP since there are limitations
+with running over SCTP: see RFC 6083 (DTLS over SCTP), which is a
+response to RFC 3436 (TLS over SCTP).
+The current RFC 3588 draft acknowledges this by equating
+TLS with TLS/TCP and DTLS/SCTP but we do not yet support DTLS.</p>
</item>
<item>
diff --git a/lib/diameter/doc/src/diameter_tcp.xml b/lib/diameter/doc/src/diameter_tcp.xml
index a502e53972..e6b53383c0 100644
--- a/lib/diameter/doc/src/diameter_tcp.xml
+++ b/lib/diameter/doc/src/diameter_tcp.xml
@@ -43,7 +43,14 @@ It can be specified as the value of a transport_module option to
<seealso
marker="diameter#add_transport">diameter:add_transport/2</seealso>
and implements the behaviour documented in
-<seealso marker="diameter_transport">diameter_transport(3)</seealso>.</p>
+<seealso marker="diameter_transport">diameter_transport(3)</seealso>.
+TLS security is supported, both as an upgrade following
+capabilities exchange as specified by RFC 3588 and
+at connection establishment as in the current draft standard.</p>
+
+<p>
+Note that the ssl application is required for TLS and must be started
+before configuring TLS capability on diameter transports.</p>
<marker id="start"/>
</description>
@@ -60,10 +67,15 @@ and implements the behaviour documented in
<v>Type = connect | accept</v>
<v>Ref = reference()</v>
<v>Svc = #diameter_service{}</v>
-<v>Opt = {raddr, ip_address()} | {rport, integer()} | term()</v>
+<v>Opt = OwnOpt | SslOpt | OtherOpt</v>
<v>Pid = pid()</v>
<v>LAddr = ip_address()</v>
<v>Reason = term()</v>
+<v>OwnOpt = {raddr, ip_address()}
+ | {rport, integer()}
+ | {port, integer()}</v>
+<v>SslOpt = {ssl_options, true | list()}</v>
+<v>OtherOpt = term()</v>
</type>
<desc>
@@ -74,17 +86,42 @@ marker="diameter_transport#start">diameter_transport(3)</seealso>.</p>
<p>
The only diameter_tcp-specific argument is the options list.
Options <c>raddr</c> and <c>rport</c> specify the remote address
-and port for a connecting transport and not valid for a listening
+and port for a connecting transport and are not valid for a listening
transport.
-Remaining options are any accepted by gen_tcp:connect/3 for
-a connecting transport, or gen_tcp:listen/2 for a listening transport,
-with the exception of <c>binary</c>, <c>packet</c> and <c>active</c>.
+Option <c>ssl_options</c> must be specified for a transport
+that must be able to support TLS: a value of <c>true</c> results in a
+TLS handshake immediately upon connection establishment while
+list() specifies options to be passed to ssl:connect/2 of ssl:ssl_accept/2
+after capabilities exchange if TLS is negotiated.
+Remaining options are any accepted by ssl:connect/3 or gen_tcp:connect/3 for
+a connecting transport, or ssl:listen/3 or gen_tcp:listen/2 for
+a listening transport, depending on whether or not <c>{ssl_options, true}</c>
+has been specified.
+Options <c>binary</c>, <c>packet</c> and <c>active</c> cannot be specified.
Also, option <c>port</c> can be specified for a listening transport
to specify the local listening port, the default being the standardized
3868 if unspecified.
Note that option <c>ip</c> specifies the local address.</p>
<p>
+An <c>ssl_options</c> list must be specified if and only if
+the transport in question has specified an Inband-Security-Id
+AVP with value TLS on the relevant call to
+<seealso
+marker="diameter#start_service">start_service/2</seealso> or
+<seealso
+marker="diameter#add_transport">add_transport/2</seealso>,
+so that the transport process will receive notification of
+whether or not to commence with a TLS handshake following capabilities
+exchange.
+Failing to specify an options list on a TLS-capable transport
+for which TLS is negotiated will cause TLS handshake to fail.
+Failing to specify TLS capability when <c>ssl_options</c> has been
+specified will cause the transport process to wait for a notification
+that will not be forthcoming, which will eventually cause the RFC 3539
+watchdog to take down the connection.</p>
+
+<p>
If the service specifies more than one Host-IP-Address and
option <c>ip</c> is unspecified then then the
first of the service's addresses is used as the local address.</p>
@@ -104,6 +141,7 @@ The returned local address list has length one.</p>
<title>SEE ALSO</title>
<p>
+<seealso marker="diameter">diameter(3)</seealso>,
<seealso marker="diameter_transport">diameter_transport(3)</seealso></p>
</section>
diff --git a/lib/diameter/doc/src/diameter_transport.xml b/lib/diameter/doc/src/diameter_transport.xml
index 37cc871e75..087a90b099 100644
--- a/lib/diameter/doc/src/diameter_transport.xml
+++ b/lib/diameter/doc/src/diameter_transport.xml
@@ -143,6 +143,34 @@ connection.
Pid is the pid() of the parent process.</p>
</item>
+<tag><c>{diameter, {tls, Ref, Type, Bool}}</c></tag>
+<item>
+<p>
+Indication of whether or not capabilities exchange has selected
+inband security using TLS.
+Ref is a reference() that must be included in the
+<c>{diameter, {tls, Ref}}</c> reply message to the transport's
+parent process (see below).
+Type is either <c>connect</c> or <c>accept</c> depending on
+whether the process has been started for a connecting or listening
+transport respectively.
+Bool is a boolean() indicating whether or not the transport connection
+should be upgraded to TLS.</p>
+
+<p>
+If TLS is requested (Bool = true) then a connecting process should
+initiate a TLS handshake with the peer and an accepting process should
+prepare to accept a handshake.
+A successful handshake should be followed by a <c>{diameter, {tls, Ref}}</c>
+message to the parent process.
+A failed handshake should cause the process to exit.</p>
+
+<p>
+This message is only sent to a transport process over whose
+<c>Inband-Security-Id</c> configuration has indicated support for
+TLS.</p>
+</item>
+
</taglist>
<p>
@@ -184,6 +212,16 @@ How the <c>transport_data</c> is used/interpreted is up to the
transport module.</p>
</item>
+<tag><c>{diameter, {tls, Ref}}</c></tag>
+<item>
+<p>
+Acknowledgment of a successful TLS handshake.
+Ref is the reference() received in the
+<c>{diameter, {tls, Ref, Type, Bool}}</c> message in response
+to which the reply is sent.
+A transport must exit if a handshake is not successful.</p>
+</item>
+
</taglist>
</section>
diff --git a/lib/diameter/include/diameter_gen.hrl b/lib/diameter/include/diameter_gen.hrl
index d037e1044a..13a6c462af 100644
--- a/lib/diameter/include/diameter_gen.hrl
+++ b/lib/diameter/include/diameter_gen.hrl
@@ -40,14 +40,14 @@ encode_avps(Name, Rec) ->
list_to_binary(encode(Name, Rec))
catch
throw: {?MODULE, Reason} ->
- diameter_dbg:log({encode, error},
+ diameter_lib:log({encode, error},
?MODULE,
?LINE,
{Reason, Name, Rec}),
erlang:error(list_to_tuple(Reason ++ [Name]));
error: Reason ->
Stack = erlang:get_stacktrace(),
- diameter_dbg:log({encode, failure},
+ diameter_lib:log({encode, failure},
?MODULE,
?LINE,
{Reason, Name, Rec, Stack}),
@@ -159,7 +159,7 @@ d_rc(Name, {Avps, {Rec, [] = Failed}}) ->
{Rec, Avps, Failed}
catch
throw: {?MODULE, {AvpName, Reason}} ->
- diameter_dbg:log({decode, error},
+ diameter_lib:log({decode, error},
?MODULE,
?LINE,
{AvpName, Reason, Rec}),
@@ -260,7 +260,7 @@ d(Name, Avp, {Avps, Acc}) ->
%% respond sensibly to. Log the occurence for traceability,
%% but the peer will also receive info in the resulting
%% answer-message.
- diameter_dbg:log({decode, failure},
+ diameter_lib:log({decode, failure},
?MODULE,
?LINE,
{Reason, Avp, erlang:get_stacktrace()}),
diff --git a/lib/diameter/make/rules.mk.in b/lib/diameter/make/rules.mk.in
index 6318f2bc9c..cd3c297d75 100644
--- a/lib/diameter/make/rules.mk.in
+++ b/lib/diameter/make/rules.mk.in
@@ -112,8 +112,6 @@ $(EBIN)/%.beam: $(ESRC)/%.erl
# ----------------------------------------------------
# export VSN
-# DOCSUPPORT = 1
-
# TOPDOCDIR=../../../../doc
DOCDIR = ..
diff --git a/lib/diameter/src/compiler/.gitignore b/lib/diameter/src/.gitignore
index d9f072e262..feeb378fd8 100644
--- a/lib/diameter/src/compiler/.gitignore
+++ b/lib/diameter/src/.gitignore
@@ -1,3 +1,2 @@
/depend.mk
-
diff --git a/lib/diameter/src/Makefile b/lib/diameter/src/Makefile
index 6935eb053e..eea2aa894d 100644
--- a/lib/diameter/src/Makefile
+++ b/lib/diameter/src/Makefile
@@ -16,28 +16,225 @@
#
# %CopyrightEnd%
-ifneq ($(ERL_TOP),)
-include $(ERL_TOP)/make/target.mk
-include $(ERL_TOP)/make/$(TARGET)/otp.mk
-else
+ifeq ($(ERL_TOP),)
include $(DIAMETER_TOP)/make/target.mk
include $(DIAMETER_TOP)/make/$(TARGET)/rules.mk
+else
+include $(ERL_TOP)/make/target.mk
+include $(ERL_TOP)/make/$(TARGET)/otp.mk
endif
# ----------------------------------------------------
-# Common Macros
+# Application version
# ----------------------------------------------------
-include subdirs.mk
+include ../vsn.mk
-SPECIAL_TARGETS =
+VSN = $(DIAMETER_VSN)
# ----------------------------------------------------
-# Default Subdir Targets
+# Release directory specification
# ----------------------------------------------------
-ifneq ($(ERL_TOP),)
-include $(ERL_TOP)/make/otp_subdir.mk
+
+RELSYSDIR = $(RELEASE_PATH)/lib/diameter-$(VSN)
+
+# Where to put/find things.
+EBIN = ../ebin
+INCDIR = ../include
+
+# Dumbed down to make 3.80. In 3.81 and later it's just $(realpath $(EBIN)).
+ABS_EBIN := $(shell cd $(EBIN) && pwd)
+
+# Where make should look for dependencies.
+VPATH = .:base:compiler:transport:gen
+
+# ----------------------------------------------------
+# Target specs
+# ----------------------------------------------------
+
+include modules.mk
+
+DICT_MODULES = $(DICTS:%=gen/diameter_gen_%)
+DICT_ERLS = $(DICT_MODULES:%=%.erl)
+DICT_HRLS = $(DICT_MODULES:%=%.hrl)
+
+# Modules to build before compiling dictionaries.
+COMPILER_MODULES = $(filter compiler/%, $(CT_MODULES))
+
+# All handwritten modules.
+MODULES = \
+ $(RT_MODULES) \
+ $(CT_MODULES)
+
+# Modules whose names are inserted into the app file.
+APP_MODULES = \
+ $(RT_MODULES) \
+ $(DICT_MODULES)
+
+# Modules for which to build beams.
+TARGET_MODULES = \
+ $(APP_MODULES) \
+ $(CT_MODULES)
+
+# What to build for the 'opt' target.
+TARGET_FILES = \
+ $(patsubst %,$(EBIN)/%.$(EMULATOR),$(notdir $(TARGET_MODULES))) \
+ $(APP_TARGET) \
+ $(APPUP_TARGET)
+
+# Subdirectories of src to release modules into.
+TARGET_DIRS = $(sort $(dir $(TARGET_MODULES)))
+
+APP_FILE = diameter.app
+APP_SRC = $(APP_FILE).src
+APP_TARGET = $(EBIN)/$(APP_FILE)
+
+APPUP_FILE = diameter.appup
+APPUP_SRC = $(APPUP_FILE).src
+APPUP_TARGET = $(EBIN)/$(APPUP_FILE)
+
+# ----------------------------------------------------
+# Flags
+# ----------------------------------------------------
+
+ifeq ($(TYPE),debug)
+ERL_COMPILE_FLAGS += -Ddebug
+endif
+
+ERL_COMPILE_FLAGS += \
+ +'{parse_transform,sys_pre_attributes}' \
+ +'{attribute,insert,app_vsn,$(APP_VSN)}' \
+ +warn_export_vars \
+ +warn_unused_vars \
+ -pa $(ABS_EBIN) \
+ -I $(INCDIR) \
+ -I gen
+# -pa is to be able to include_lib from the include directory: the
+# path must contain the application name.
+
+# ----------------------------------------------------
+# Targets
+# ----------------------------------------------------
+
+# erl/hrl from dictionary file.
+gen/diameter_gen_%.erl gen/diameter_gen_%.hrl: dict/%.dia
+ ../bin/diameterc -o gen -i $(EBIN) $<
+
+opt: $(TARGET_FILES)
+
+debug:
+ @$(MAKE) TYPE=debug opt
+
+# Generate the app file.
+$(APP_TARGET): $(APP_SRC) ../vsn.mk modules.mk
+ M=`echo $(notdir $(APP_MODULES)) | tr ' ' ,`; \
+ sed -e 's;%VSN%;$(VSN);' \
+ -e "s;%MODULES%;$$M;" \
+ $< > $@
+
+$(APPUP_TARGET): $(APPUP_SRC) ../vsn.mk
+ sed -e 's;%VSN%;$(VSN);' $< > $@
+
+app: $(APP_TARGET) $(APPUP_TARGET)
+dict: $(DICT_ERLS)
+
+docs:
+
+list = echo $(1):; echo $($(1)) | tr ' ' '\n' | sort | sed 's@^@ @'
+
+info:
+ @echo ========================================
+ @$(call list,DICTS)
+ @echo
+ @$(call list,RT_MODULES)
+ @echo
+ @$(call list,CT_MODULES)
+ @echo
+ @$(call list,TARGET_MODULES)
+ @echo
+ @$(call list,TARGET_DIRS)
+ @echo
+ @$(call list,EXTERNAL_HRLS)
+ @echo
+ @$(call list,INTERNAL_HRLS)
+ @echo
+ @$(call list,EXAMPLES)
+ @echo
+ @$(call list,BINS)
+ @echo ========================================
+
+clean:
+ rm -f $(TARGET_FILES) $(DICT_ERLS) $(DICT_HRLS)
+ rm -f depend.mk
+
+# ----------------------------------------------------
+# Release targets
+# ----------------------------------------------------
+
+ifeq ($(ERL_TOP),)
+include $(DIAMETER_TOP)/make/release_targets.mk
else
-include $(DIAMETER_TOP)/make/subdir.mk
+include $(ERL_TOP)/make/otp_release_targets.mk
endif
-#include ../make/subdir.mk
+
+# Can't $(INSTALL_DIR) more than one directory at a time on Solaris.
+
+release_spec: opt
+ for d in bin ebin examples include src/dict $(TARGET_DIRS:%/=src/%); do \
+ $(INSTALL_DIR) $(RELSYSDIR)/$$d; \
+ done
+ $(INSTALL_SCRIPT) $(BINS:%=../bin/%) $(RELSYSDIR)/bin
+ $(INSTALL_DATA) $(TARGET_FILES) $(RELSYSDIR)/ebin
+ $(INSTALL_DATA) $(EXAMPLES:%=../examples/%) $(RELSYSDIR)/examples
+ $(INSTALL_DATA) $(EXTERNAL_HRLS:%=../include/%) $(DICT_HRLS) \
+ $(RELSYSDIR)/include
+ $(INSTALL_DATA) $(DICTS:%=dict/%.dia) $(RELSYSDIR)/src/dict
+ $(MAKE) $(TARGET_DIRS:%/=release_src_%)
+
+$(TARGET_DIRS:%/=release_src_%): release_src_%:
+ $(INSTALL_DATA) $(filter $*/%,$(TARGET_MODULES:%=%.erl) \
+ $(INTERNAL_HRLS)) \
+ $(RELSYSDIR)/src/$*
+
+release_docs_spec:
+
+# ----------------------------------------------------
+# Dependencies
+# ----------------------------------------------------
+
+gen/diameter_gen_base_accounting.erl gen/diameter_gen_relay.erl \
+gen/diameter_gen_base_accounting.hrl gen/diameter_gen_relay.hrl: \
+ $(EBIN)/diameter_gen_base_rfc3588.$(EMULATOR)
+
+gen/diameter_gen_base_rfc3588.erl gen/diameter_gen_base_rfc3588.hrl: \
+ $(COMPILER_MODULES:compiler/%=$(EBIN)/%.$(EMULATOR))
+
+$(DICT_MODULES:gen/%=$(EBIN)/%.$(EMULATOR)): \
+ $(INCDIR)/diameter.hrl \
+ $(INCDIR)/diameter_gen.hrl
+
+depend: depend.mk
+
+# Generate dependencies makefile.
+depend.mk: depend.sed $(MODULES:%=%.erl) Makefile
+ (for f in $(MODULES); do \
+ (echo $$f; cat $$f.erl) | sed -f $<; \
+ done) \
+ > $@
+
+-include depend.mk
+
+.PRECIOUS: $(DICT_ERLS) $(DICT_HRLS)
+.PHONY: app clean depend dict info release_subdir
+.PHONY: debug opt release_docs_spec release_spec
+.PHONY: $(TARGET_DIRS:%/=%) $(TARGET_DIRS:%/=release_src_%)
+
+# ----------------------------------------------------
+# Targets using secondary expansion (make >= 3.81)
+# ----------------------------------------------------
+
+.SECONDEXPANSION:
+
+# Make beams from a subdirectory.
+$(TARGET_DIRS:%/=%): \
+ $$(patsubst $$@/%,$(EBIN)/%.$(EMULATOR),$$(filter $$@/%,$(TARGET_MODULES)))
diff --git a/lib/diameter/src/app/.gitignore b/lib/diameter/src/app/.gitignore
deleted file mode 100644
index d388e61877..0000000000
--- a/lib/diameter/src/app/.gitignore
+++ /dev/null
@@ -1,6 +0,0 @@
-
-/diameter_gen_*.erl
-/diameter_gen_*.hrl
-/depend.mk
-/diameter.mk
-
diff --git a/lib/diameter/src/app/Makefile b/lib/diameter/src/app/Makefile
deleted file mode 100644
index a75c70d71c..0000000000
--- a/lib/diameter/src/app/Makefile
+++ /dev/null
@@ -1,212 +0,0 @@
-#
-# %CopyrightBegin%
-#
-# Copyright Ericsson AB 2010-2011. All Rights Reserved.
-#
-# The contents of this file are subject to the Erlang Public License,
-# Version 1.1, (the "License"); you may not use this file except in
-# compliance with the License. You should have received a copy of the
-# Erlang Public License along with this software. If not, it can be
-# retrieved online at http://www.erlang.org/.
-#
-# Software distributed under the License is distributed on an "AS IS"
-# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
-# the License for the specific language governing rights and limitations
-# under the License.
-#
-# %CopyrightEnd%
-#
-#
-
-ifneq ($(ERL_TOP),)
-include $(ERL_TOP)/make/target.mk
-EBIN = ../../ebin
-include $(ERL_TOP)/make/$(TARGET)/otp.mk
-else
-include $(DIAMETER_TOP)/make/target.mk
-EBIN = ../../ebin
-include $(DIAMETER_TOP)/make/$(TARGET)/rules.mk
-endif
-
-
-
-# ----------------------------------------------------
-# Application version
-# ----------------------------------------------------
-
-include ../../vsn.mk
-
-VSN=$(DIAMETER_VSN)
-
-# ----------------------------------------------------
-# Release directory specification
-# ----------------------------------------------------
-
-RELSYSDIR = $(RELEASE_PATH)/lib/diameter-$(VSN)
-
-INCDIR = ../../include
-
-# ----------------------------------------------------
-# Target Specs
-# ----------------------------------------------------
-
-include modules.mk
-
-SPEC_MODULES = \
- $(SPEC_FILES:%.dia=%)
-
-SPEC_ERL_FILES = \
- $(SPEC_FILES:%.dia=%.erl)
-
-SPEC_HRL_FILES = \
- $(SPEC_FILES:%.dia=%.hrl)
-
-MODULES = \
- $(RUNTIME_MODULES) \
- $(HELP_MODULES)
-
-APP_MODULES = \
- $(RUNTIME_MODULES) \
- $(SPEC_MODULES)
-
-TARGET_MODULES = \
- $(APP_MODULES) \
- $(HELP_MODULES)
-
-TARGET_FILES = \
- $(TARGET_MODULES:%=$(EBIN)/%.$(EMULATOR)) \
- $(APP_TARGET) \
- $(APPUP_TARGET)
-
-ESCRIPT_FILES = \
- ../../bin/diameterc
-
-APP_FILE = diameter.app
-APP_SRC = $(APP_FILE).src
-APP_TARGET = $(EBIN)/$(APP_FILE)
-
-APPUP_FILE = diameter.appup
-APPUP_SRC = $(APPUP_FILE).src
-APPUP_TARGET = $(EBIN)/$(APPUP_FILE)
-
-# ----------------------------------------------------
-# FLAGS
-# ----------------------------------------------------
-
-ifeq ($(TYPE),debug)
-ERL_COMPILE_FLAGS += -Ddebug
-endif
-
-include diameter.mk
-
-ERL_COMPILE_FLAGS += \
- $(DIAMETER_ERL_COMPILE_FLAGS) \
- -I$(INCDIR)
-
-# ----------------------------------------------------
-# Targets
-# ----------------------------------------------------
-
-debug:
- @$(MAKE) TYPE=debug opt
-
-opt: $(TARGET_FILES)
-
-clean:
- rm -f $(TARGET_FILES) $(SPEC_ERL_FILES) $(SPEC_HRL_FILES)
- rm -f $(APP_TARGET) $(APPUP_TARGET)
- rm -f errs core *~ diameter_gen_*.forms diameter_gen_*.spec
- rm -f depend.mk
-
-docs:
-
-info:
- @echo ""
- @echo "SPEC_FILES = $(FILES)"
- @echo "MODULES = $(MODULES)"
- @echo ""
- @echo "EXTERNAL_HRL_FILES = $(EXTERNAL_HRL_FILES)"
- @echo "INTERNAL_HRL_FILES = $(INTERNAL_HRL_FILES)"
- @echo ""
- @echo "EXAMPLE_FILES = $(EXAMPLE_FILES)"
- @echo ""
-
-# ----------------------------------------------------
-# Special Build Targets
-# ----------------------------------------------------
-
-# Generate the app file and then modules into in. This shouldn't know
-# about ../transport but good enough for now.
-$(APP_TARGET): $(APP_SRC) \
- ../../vsn.mk \
- modules.mk \
- ../transport/modules.mk
- sed -e 's;%VSN%;$(VSN);' $< > $@
- M=`echo $(APP_MODULES) | sed -e 's/^ *//' -e 's/ *$$//' -e 'y/ /,/'`; \
- echo "/%APP_MODULES%/s//$$M/;w;q" | tr ';' '\n' \
- | ed -s $@
- $(MAKE) -C ../transport $(APP_TARGET) APP_TARGET=$(APP_TARGET)
-
-$(APPUP_TARGET): $(APPUP_SRC) ../../vsn.mk
- sed -e 's;%VSN%;$(VSN);' $< > $@
-
-compiler:
- $(MAKE) -C ../$@
-
-app: $(APP_TARGET) $(APPUP_TARGET)
-
-# erl/hrl from application spec
-diameter_gen_%.erl diameter_gen_%.hrl: diameter_gen_%.dia
- ../../bin/diameterc -i $(EBIN) -o $(@D) $<
-
-# ----------------------------------------------------
-# Release Target
-# ----------------------------------------------------
-
-ifneq ($(ERL_TOP),)
-include $(ERL_TOP)/make/otp_release_targets.mk
-else
-include $(DIAMETER_TOP)/make/release_targets.mk
-endif
-
-release_spec: opt
- $(INSTALL_DIR) $(RELSYSDIR)/bin
- $(INSTALL_DIR) $(RELSYSDIR)/ebin
- $(INSTALL_DIR) $(RELSYSDIR)/src/app
- $(INSTALL_DIR) $(RELSYSDIR)/include
- $(INSTALL_DIR) $(RELSYSDIR)/examples
- $(INSTALL_SCRIPT) $(ESCRIPT_FILES) $(RELSYSDIR)/bin
- $(INSTALL_DATA) $(TARGET_FILES) $(RELSYSDIR)/ebin
- $(INSTALL_DATA) $(MODULES:%=%.erl) $(SPEC_ERL_FILES) $(RELSYSDIR)/src/app
- $(INSTALL_DATA) $(SPEC_FILES) $(RELSYSDIR)/src/app
- $(INSTALL_DATA) $(INTERNAL_HRL_FILES) $(RELSYSDIR)/src/app
- $(INSTALL_DATA) $(EXTERNAL_HRL_FILES) $(SPEC_HRL_FILES) $(RELSYSDIR)/include
- $(INSTALL_DATA) $(EXAMPLE_FILES) $(RELSYSDIR)/examples
-
-release_docs_spec:
-
-# ----------------------------------------------------
-# Dependencies
-# ----------------------------------------------------
-
-$(SPEC_MODULES:%=$(EBIN)/%.$(EMULATOR)): \
- $(EBIN)/diameter_exprecs.$(EMULATOR) \
- $(DIAMETER_TOP)/include/diameter.hrl \
- $(DIAMETER_TOP)/include/diameter_gen.hrl
-
-depend: depend.mk
-
-# Generate dependencies makefile. It's assumed that the compile target
-# has already been made since it's currently not smart enough to not
-# force a rebuild of those beams dependent on generated hrls, and this
-# is a no-no at make release.
-depend.mk: depend.sed $(MODULES:%=%.erl) Makefile
- (for f in $(MODULES); do \
- sed -f $< $$f.erl | sed "s@/@/$$f@"; \
- done) \
- > $@
-
--include depend.mk
-
-.PRECIOUS: $(SPEC_ERL_FILES) $(SPEC_HRL_FILES)
-.PHONY: app clean debug depend info opt compiler release_spec release_docs_spec
diff --git a/lib/diameter/src/app/diameter.appup.src b/lib/diameter/src/app/diameter.appup.src
deleted file mode 100644
index 6d8ceadb92..0000000000
--- a/lib/diameter/src/app/diameter.appup.src
+++ /dev/null
@@ -1,47 +0,0 @@
-%% This is an -*- erlang -*- file.
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2010-2011. All Rights Reserved.
-%%
-%% The contents of this file are subject to the Erlang Public License,
-%% Version 1.1, (the "License"); you may not use this file except in
-%% compliance with the License. You should have received a copy of the
-%% Erlang Public License along with this software. If not, it can be
-%% retrieved online at http://www.erlang.org/.
-%%
-%% Software distributed under the License is distributed on an "AS IS"
-%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
-%% the License for the specific language governing rights and limitations
-%% under the License.
-%%
-%% %CopyrightEnd%
-%%
-
-{"%VSN%",
- [
- {"0.9",
- [
- {load_module, diameter, soft_purge, soft_purge, []},
- {load_module, diameter_capx, soft_purge, soft_purge, []},
- {load_module, diameter_codec, soft_purge, soft_purge, [diameter_lib]},
- {load_module, diameter_lib, soft_purge, soft_purge, []},
- {load_module, diameter_types, soft_purge, soft_purge, []},
- {load_module, diameter_gen_base_accounting, soft_purge, soft_purge, []},
- {load_module, diameter_gen_base_rfc3588, soft_purge, soft_purge, []},
- {load_module, diameter_gen_relay, soft_purge, soft_purge, []},
- {update, diameter_service, soft, soft_purge, soft_purge, [diameter_lib]},
- {update, diameter_config, soft, soft_purge, soft_purge, []},
- {update, diameter_peer, soft, soft_purge, soft_purge, []},
- {update, diameter_peer_fsm, soft, soft_purge, soft_purge, [diameter_lib]},
- {update, diameter_reg, soft, soft_purge, soft_purge, []},
- {update, diameter_sctp, soft, soft_purge, soft_purge, []},
- {update, diameter_stats, soft, soft_purge, soft_purge, []},
- {update, diameter_sync, soft, soft_purge, soft_purge, []},
- {update, diameter_watchdog, soft, soft_purge, soft_purge, [diameter_lib]}
- ]
- }
- ],
- [
- ]
-}.
diff --git a/lib/diameter/src/app/diameter.mk.in b/lib/diameter/src/app/diameter.mk.in
deleted file mode 100644
index c161064303..0000000000
--- a/lib/diameter/src/app/diameter.mk.in
+++ /dev/null
@@ -1,47 +0,0 @@
-#-*-makefile-*- ; force emacs to enter makefile-mode
-
-# %CopyrightBegin%
-#
-# Copyright Ericsson AB 2010-2011. All Rights Reserved.
-#
-# The contents of this file are subject to the Erlang Public License,
-# Version 1.1, (the "License"); you may not use this file except in
-# compliance with the License. You should have received a copy of the
-# Erlang Public License along with this software. If not, it can be
-# retrieved online at http://www.erlang.org/.
-#
-# Software distributed under the License is distributed on an "AS IS"
-# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
-# the License for the specific language governing rights and limitations
-# under the License.
-#
-# %CopyrightEnd%
-
-DIAMETER_TOP = @DIAMETER_TOP@
-
-# ifneq ($(PREFIX),)
-# ifeq ($(TESTROOT),)
-# TESTROOT = $(PREFIX)
-# endif
-# endif
-
-ifeq ($(USE_DIAMETER_TEST_CODE), true)
-ERL_COMPILE_FLAGS += -DDIAMETER_TEST_CODE=mona_lisa_spelar_doom
-endif
-
-ifeq ($(USE_DIAMETER_HIPE), true)
-ERL_COMPILE_FLAGS += +native
-endif
-
-ifeq ($(WARN_UNUSED_WARS), true)
-ERL_COMPILE_FLAGS += +warn_unused_vars
-endif
-
-DIAMETER_APP_VSN_COMPILE_FLAGS = \
- +'{parse_transform,sys_pre_attributes}' \
- +'{attribute,insert,app_vsn,$(APP_VSN)}'
-
-DIAMETER_ERL_COMPILE_FLAGS += \
- -pa $(DIAMETER_TOP)/ebin \
- $(DIAMETER_APP_VSN_COMPILE_FLAGS)
-
diff --git a/lib/diameter/src/app/diameter_gen_base_accounting.dia b/lib/diameter/src/app/diameter_gen_base_accounting.dia
deleted file mode 100644
index 64e95dddb5..0000000000
--- a/lib/diameter/src/app/diameter_gen_base_accounting.dia
+++ /dev/null
@@ -1,68 +0,0 @@
-;;
-;; %CopyrightBegin%
-;;
-;; Copyright Ericsson AB 2010-2011. All Rights Reserved.
-;;
-;; The contents of this file are subject to the Erlang Public License,
-;; Version 1.1, (the "License"); you may not use this file except in
-;; compliance with the License. You should have received a copy of the
-;; Erlang Public License along with this software. If not, it can be
-;; retrieved online at http://www.erlang.org/.
-;;
-;; Software distributed under the License is distributed on an "AS IS"
-;; basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
-;; the License for the specific language governing rights and limitations
-;; under the License.
-;;
-;; %CopyrightEnd%
-;;
-
-@id 3
-@prefix diameter_base_accounting
-@vendor 0 IETF
-
-@inherits diameter_gen_base_rfc3588
-
-@messages
-
- ACR ::= < Diameter Header: 271, REQ, PXY >
- < Session-Id >
- { Origin-Host }
- { Origin-Realm }
- { Destination-Realm }
- { Accounting-Record-Type }
- { Accounting-Record-Number }
- [ Acct-Application-Id ]
- [ Vendor-Specific-Application-Id ]
- [ User-Name ]
- [ Accounting-Sub-Session-Id ]
- [ Acct-Session-Id ]
- [ Acct-Multi-Session-Id ]
- [ Acct-Interim-Interval ]
- [ Accounting-Realtime-Required ]
- [ Origin-State-Id ]
- [ Event-Timestamp ]
- * [ Proxy-Info ]
- * [ Route-Record ]
- * [ AVP ]
-
- ACA ::= < Diameter Header: 271, PXY >
- < Session-Id >
- { Result-Code }
- { Origin-Host }
- { Origin-Realm }
- { Accounting-Record-Type }
- { Accounting-Record-Number }
- [ Acct-Application-Id ]
- [ Vendor-Specific-Application-Id ]
- [ User-Name ]
- [ Accounting-Sub-Session-Id ]
- [ Acct-Session-Id ]
- [ Acct-Multi-Session-Id ]
- [ Error-Reporting-Host ]
- [ Acct-Interim-Interval ]
- [ Accounting-Realtime-Required ]
- [ Origin-State-Id ]
- [ Event-Timestamp ]
- * [ Proxy-Info ]
- * [ AVP ]
diff --git a/lib/diameter/src/app/diameter_gen_base_rfc3588.dia b/lib/diameter/src/app/diameter_gen_base_rfc3588.dia
deleted file mode 100644
index 4a12e21acd..0000000000
--- a/lib/diameter/src/app/diameter_gen_base_rfc3588.dia
+++ /dev/null
@@ -1,413 +0,0 @@
-;;
-;; %CopyrightBegin%
-;;
-;; Copyright Ericsson AB 2010-2011. All Rights Reserved.
-;;
-;; The contents of this file are subject to the Erlang Public License,
-;; Version 1.1, (the "License"); you may not use this file except in
-;; compliance with the License. You should have received a copy of the
-;; Erlang Public License along with this software. If not, it can be
-;; retrieved online at http://www.erlang.org/.
-;;
-;; Software distributed under the License is distributed on an "AS IS"
-;; basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
-;; the License for the specific language governing rights and limitations
-;; under the License.
-;;
-;; %CopyrightEnd%
-;;
-
-@id 0
-@prefix diameter_base
-@vendor 0 IETF
-
-@avp_types
-
- Acct-Interim-Interval 85 Unsigned32 M
- Accounting-Realtime-Required 483 Enumerated M
- Acct-Multi-Session-Id 50 UTF8String M
- Accounting-Record-Number 485 Unsigned32 M
- Accounting-Record-Type 480 Enumerated M
- Acct-Session-Id 44 OctetString M
- Accounting-Sub-Session-Id 287 Unsigned64 M
- Acct-Application-Id 259 Unsigned32 M
- Auth-Application-Id 258 Unsigned32 M
- Auth-Request-Type 274 Enumerated M
- Authorization-Lifetime 291 Unsigned32 M
- Auth-Grace-Period 276 Unsigned32 M
- Auth-Session-State 277 Enumerated M
- Re-Auth-Request-Type 285 Enumerated M
- Class 25 OctetString M
- Destination-Host 293 DiamIdent M
- Destination-Realm 283 DiamIdent M
- Disconnect-Cause 273 Enumerated M
- E2E-Sequence 300 Grouped M
- Error-Message 281 UTF8String -
- Error-Reporting-Host 294 DiamIdent -
- Event-Timestamp 55 Time M
- Experimental-Result 297 Grouped M
- Experimental-Result-Code 298 Unsigned32 M
- Failed-AVP 279 Grouped M
- Firmware-Revision 267 Unsigned32 -
- Host-IP-Address 257 Address M
- Inband-Security-Id 299 Unsigned32 M
- Multi-Round-Time-Out 272 Unsigned32 M
- Origin-Host 264 DiamIdent M
- Origin-Realm 296 DiamIdent M
- Origin-State-Id 278 Unsigned32 M
- Product-Name 269 UTF8String -
- Proxy-Host 280 DiamIdent M
- Proxy-Info 284 Grouped M
- Proxy-State 33 OctetString M
- Redirect-Host 292 DiamURI M
- Redirect-Host-Usage 261 Enumerated M
- Redirect-Max-Cache-Time 262 Unsigned32 M
- Result-Code 268 Unsigned32 M
- Route-Record 282 DiamIdent M
- Session-Id 263 UTF8String M
- Session-Timeout 27 Unsigned32 M
- Session-Binding 270 Unsigned32 M
- Session-Server-Failover 271 Enumerated M
- Supported-Vendor-Id 265 Unsigned32 M
- Termination-Cause 295 Enumerated M
- User-Name 1 UTF8String M
- Vendor-Id 266 Unsigned32 M
- Vendor-Specific-Application-Id 260 Grouped M
-
-@messages
-
- CER ::= < Diameter Header: 257, REQ >
- { Origin-Host }
- { Origin-Realm }
- 1* { Host-IP-Address }
- { Vendor-Id }
- { Product-Name }
- [ Origin-State-Id ]
- * [ Supported-Vendor-Id ]
- * [ Auth-Application-Id ]
- * [ Inband-Security-Id ]
- * [ Acct-Application-Id ]
- * [ Vendor-Specific-Application-Id ]
- [ Firmware-Revision ]
- * [ AVP ]
-
- CEA ::= < Diameter Header: 257 >
- { Result-Code }
- { Origin-Host }
- { Origin-Realm }
- 1* { Host-IP-Address }
- { Vendor-Id }
- { Product-Name }
- [ Origin-State-Id ]
- [ Error-Message ]
- * [ Failed-AVP ]
- * [ Supported-Vendor-Id ]
- * [ Auth-Application-Id ]
- * [ Inband-Security-Id ]
- * [ Acct-Application-Id ]
- * [ Vendor-Specific-Application-Id ]
- [ Firmware-Revision ]
- * [ AVP ]
-
- DPR ::= < Diameter Header: 282, REQ >
- { Origin-Host }
- { Origin-Realm }
- { Disconnect-Cause }
-
- DPA ::= < Diameter Header: 282 >
- { Result-Code }
- { Origin-Host }
- { Origin-Realm }
- [ Error-Message ]
- * [ Failed-AVP ]
-
- DWR ::= < Diameter Header: 280, REQ >
- { Origin-Host }
- { Origin-Realm }
- [ Origin-State-Id ]
-
- DWA ::= < Diameter Header: 280 >
- { Result-Code }
- { Origin-Host }
- { Origin-Realm }
- [ Error-Message ]
- * [ Failed-AVP ]
- [ Origin-State-Id ]
-
- answer-message ::= < Diameter Header: code, ERR [PXY] >
- 0*1< Session-Id >
- { Origin-Host }
- { Origin-Realm }
- { Result-Code }
- [ Origin-State-Id ]
- [ Error-Reporting-Host ]
- [ Proxy-Info ]
- * [ AVP ]
-
- RAR ::= < Diameter Header: 258, REQ, PXY >
- < Session-Id >
- { Origin-Host }
- { Origin-Realm }
- { Destination-Realm }
- { Destination-Host }
- { Auth-Application-Id }
- { Re-Auth-Request-Type }
- [ User-Name ]
- [ Origin-State-Id ]
- * [ Proxy-Info ]
- * [ Route-Record ]
- * [ AVP ]
-
- RAA ::= < Diameter Header: 258, PXY >
- < Session-Id >
- { Result-Code }
- { Origin-Host }
- { Origin-Realm }
- [ User-Name ]
- [ Origin-State-Id ]
- [ Error-Message ]
- [ Error-Reporting-Host ]
- * [ Failed-AVP ]
- * [ Redirect-Host ]
- [ Redirect-Host-Usage ]
- [ Redirect-Max-Cache-Time ]
- * [ Proxy-Info ]
- * [ AVP ]
-
- STR ::= < Diameter Header: 275, REQ, PXY >
- < Session-Id >
- { Origin-Host }
- { Origin-Realm }
- { Destination-Realm }
- { Auth-Application-Id }
- { Termination-Cause }
- [ User-Name ]
- [ Destination-Host ]
- * [ Class ]
- [ Origin-State-Id ]
- * [ Proxy-Info ]
- * [ Route-Record ]
- * [ AVP ]
-
- STA ::= < Diameter Header: 275, PXY >
- < Session-Id >
- { Result-Code }
- { Origin-Host }
- { Origin-Realm }
- [ User-Name ]
- * [ Class ]
- [ Error-Message ]
- [ Error-Reporting-Host ]
- * [ Failed-AVP ]
- [ Origin-State-Id ]
- * [ Redirect-Host ]
- [ Redirect-Host-Usage ]
- [ Redirect-Max-Cache-Time ]
- * [ Proxy-Info ]
- * [ AVP ]
-
- ASR ::= < Diameter Header: 274, REQ, PXY >
- < Session-Id >
- { Origin-Host }
- { Origin-Realm }
- { Destination-Realm }
- { Destination-Host }
- { Auth-Application-Id }
- [ User-Name ]
- [ Origin-State-Id ]
- * [ Proxy-Info ]
- * [ Route-Record ]
- * [ AVP ]
-
- ASA ::= < Diameter Header: 274, PXY >
- < Session-Id >
- { Result-Code }
- { Origin-Host }
- { Origin-Realm }
- [ User-Name ]
- [ Origin-State-Id ]
- [ Error-Message ]
- [ Error-Reporting-Host ]
- * [ Failed-AVP ]
- * [ Redirect-Host ]
- [ Redirect-Host-Usage ]
- [ Redirect-Max-Cache-Time ]
- * [ Proxy-Info ]
- * [ AVP ]
-
- ACR ::= < Diameter Header: 271, REQ, PXY >
- < Session-Id >
- { Origin-Host }
- { Origin-Realm }
- { Destination-Realm }
- { Accounting-Record-Type }
- { Accounting-Record-Number }
- [ Acct-Application-Id ]
- [ Vendor-Specific-Application-Id ]
- [ User-Name ]
- [ Accounting-Sub-Session-Id ]
- [ Acct-Session-Id ]
- [ Acct-Multi-Session-Id ]
- [ Acct-Interim-Interval ]
- [ Accounting-Realtime-Required ]
- [ Origin-State-Id ]
- [ Event-Timestamp ]
- * [ Proxy-Info ]
- * [ Route-Record ]
- * [ AVP ]
-
- ACA ::= < Diameter Header: 271, PXY >
- < Session-Id >
- { Result-Code }
- { Origin-Host }
- { Origin-Realm }
- { Accounting-Record-Type }
- { Accounting-Record-Number }
- [ Acct-Application-Id ]
- [ Vendor-Specific-Application-Id ]
- [ User-Name ]
- [ Accounting-Sub-Session-Id ]
- [ Acct-Session-Id ]
- [ Acct-Multi-Session-Id ]
- [ Error-Reporting-Host ]
- [ Acct-Interim-Interval ]
- [ Accounting-Realtime-Required ]
- [ Origin-State-Id ]
- [ Event-Timestamp ]
- * [ Proxy-Info ]
- * [ AVP ]
-
-@enum Disconnect-Cause
-
- REBOOTING 0
- BUSY 1
- DO_NOT_WANT_TO_TALK_TO_YOU 2
-
-@enum Redirect-Host-Usage
-
- DONT_CACHE 0
- ALL_SESSION 1
- ALL_REALM 2
- REALM_AND_APPLICATION 3
- ALL_APPLICATION 4
- ALL_HOST 5
- ALL_USER 6
-
-@enum Auth-Request-Type
-
- AUTHENTICATE_ONLY 1
- AUTHORIZE_ONLY 2
- AUTHORIZE_AUTHENTICATE 3
-
-@enum Auth-Session-State
-
- STATE_MAINTAINED 0
- NO_STATE_MAINTAINED 1
-
-@enum Re-Auth-Request-Type
-
- AUTHORIZE_ONLY 0
- AUTHORIZE_AUTHENTICATE 1
-
-@enum Termination-Cause
-
- DIAMETER_LOGOUT 1
- DIAMETER_SERVICE_NOT_PROVIDED 2
- DIAMETER_BAD_ANSWER 3
- DIAMETER_ADMINISTRATIVE 4
- DIAMETER_LINK_BROKEN 5
- DIAMETER_AUTH_EXPIRED 6
- DIAMETER_USER_MOVED 7
- DIAMETER_SESSION_TIMEOUT 8
-
-@enum Session-Server-Failover
-
- REFUSE_SERVICE 0
- TRY_AGAIN 1
- ALLOW_SERVICE 2
- TRY_AGAIN_ALLOW_SERVICE 3
-
-@enum Accounting-Record-Type
-
- EVENT_RECORD 1
- START_RECORD 2
- INTERIM_RECORD 3
- STOP_RECORD 4
-
-@enum Accounting-Realtime-Required
-
- DELIVER_AND_GRANT 1
- GRANT_AND_STORE 2
- GRANT_AND_LOSE 3
-
-@result_code Result-Code
-
-;; 7.1.1. Informational
- DIAMETER_MULTI_ROUND_AUTH 1001
-
-;; 7.1.2. Success
- DIAMETER_SUCCESS 2001
- DIAMETER_LIMITED_SUCCESS 2002
-
-;; 7.1.3. Protocol Errors
- DIAMETER_COMMAND_UNSUPPORTED 3001
- DIAMETER_UNABLE_TO_DELIVER 3002
- DIAMETER_REALM_NOT_SERVED 3003
- DIAMETER_TOO_BUSY 3004
- DIAMETER_LOOP_DETECTED 3005
- DIAMETER_REDIRECT_INDICATION 3006
- DIAMETER_APPLICATION_UNSUPPORTED 3007
- DIAMETER_INVALID_HDR_BITS 3008
- DIAMETER_INVALID_AVP_BITS 3009
- DIAMETER_UNKNOWN_PEER 3010
-
-;; 7.1.4. Transient Failures
- DIAMETER_AUTHENTICATION_REJECTED 4001
- DIAMETER_OUT_OF_SPACE 4002
- ELECTION_LOST 4003
-
-;; 7.1.5. Permanent Failures
- DIAMETER_AVP_UNSUPPORTED 5001
- DIAMETER_UNKNOWN_SESSION_ID 5002
- DIAMETER_AUTHORIZATION_REJECTED 5003
- DIAMETER_INVALID_AVP_VALUE 5004
- DIAMETER_MISSING_AVP 5005
- DIAMETER_RESOURCES_EXCEEDED 5006
- DIAMETER_CONTRADICTING_AVPS 5007
- DIAMETER_AVP_NOT_ALLOWED 5008
- DIAMETER_AVP_OCCURS_TOO_MANY_TIMES 5009
- DIAMETER_NO_COMMON_APPLICATION 5010
- DIAMETER_UNSUPPORTED_VERSION 5011
- DIAMETER_UNABLE_TO_COMPLY 5012
- DIAMETER_INVALID_BIT_IN_HEADER 5013
- DIAMETER_INVALID_AVP_LENGTH 5014
- DIAMETER_INVALID_MESSAGE_LENGTH 5015
- DIAMETER_INVALID_AVP_BIT_COMBO 5016
- DIAMETER_NO_COMMON_SECURITY 5017
-
-@grouped
-
- Proxy-Info ::= < AVP Header: 284 >
- { Proxy-Host }
- { Proxy-State }
- * [ AVP ]
-
- Failed-AVP ::= < AVP Header: 279 >
- 1* {AVP}
-
- Experimental-Result ::= < AVP Header: 297 >
- { Vendor-Id }
- { Experimental-Result-Code }
-
- Vendor-Specific-Application-Id ::= < AVP Header: 260 >
- 1* { Vendor-Id }
- [ Auth-Application-Id ]
- [ Acct-Application-Id ]
-
-;; The E2E-Sequence AVP is defined in RFC 3588 as Grouped, but
-;; there is no definition of the group - only an informal text stating
-;; that there should be a nonce (an OctetString) and a counter
-;; (integer)
-;;
- E2E-Sequence ::= <AVP Header: 300 >
- 2* { AVP }
diff --git a/lib/diameter/src/app/modules.mk b/lib/diameter/src/app/modules.mk
deleted file mode 100644
index c133e6f64e..0000000000
--- a/lib/diameter/src/app/modules.mk
+++ /dev/null
@@ -1,70 +0,0 @@
-#-*-makefile-*- ; force emacs to enter makefile-mode
-
-# %CopyrightBegin%
-#
-# Copyright Ericsson AB 2010-2011. All Rights Reserved.
-#
-# The contents of this file are subject to the Erlang Public License,
-# Version 1.1, (the "License"); you may not use this file except in
-# compliance with the License. You should have received a copy of the
-# Erlang Public License along with this software. If not, it can be
-# retrieved online at http://www.erlang.org/.
-#
-# Software distributed under the License is distributed on an "AS IS"
-# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
-# the License for the specific language governing rights and limitations
-# under the License.
-#
-# %CopyrightEnd%
-
-SPEC_FILES = \
- diameter_gen_base_rfc3588.dia \
- diameter_gen_base_accounting.dia \
- diameter_gen_relay.dia
-
-RUNTIME_MODULES = \
- diameter \
- diameter_app \
- diameter_capx \
- diameter_config \
- diameter_codec \
- diameter_dict \
- diameter_lib \
- diameter_misc_sup \
- diameter_peer \
- diameter_peer_fsm \
- diameter_peer_fsm_sup \
- diameter_reg \
- diameter_service \
- diameter_service_sup \
- diameter_session \
- diameter_stats \
- diameter_sup \
- diameter_sync \
- diameter_types \
- diameter_watchdog \
- diameter_watchdog_sup
-
-HELP_MODULES = \
- diameter_callback \
- diameter_exprecs \
- diameter_dbg \
- diameter_info
-
-INTERNAL_HRL_FILES = \
- diameter_internal.hrl \
- diameter_types.hrl
-
-EXTERNAL_HRL_FILES = \
- ../../include/diameter.hrl \
- ../../include/diameter_gen.hrl
-
-EXAMPLE_FILES = \
- ../../examples/GNUmakefile \
- ../../examples/peer.erl \
- ../../examples/client.erl \
- ../../examples/client_cb.erl \
- ../../examples/server.erl \
- ../../examples/server_cb.erl \
- ../../examples/relay.erl \
- ../../examples/relay_cb.erl
diff --git a/lib/diameter/src/app/diameter.app.src b/lib/diameter/src/base/diameter.app.src
index a806b5c78a..c092fdb022 100644
--- a/lib/diameter/src/app/diameter.app.src
+++ b/lib/diameter/src/base/diameter.app.src
@@ -20,7 +20,7 @@
{application, diameter,
[{description, "Diameter protocol"},
{vsn, "%VSN%"},
- {modules, [%APP_MODULES%,%TRANSPORT_MODULES%]},
+ {modules, [%MODULES%]},
{registered, []},
{applications, [stdlib, kernel]},
{env, []},
diff --git a/lib/ssl/test/ssl_test_MACHINE.hrl b/lib/diameter/src/base/diameter.appup.src
index e78b33f505..b1c94d4cc8 100644
--- a/lib/ssl/test/ssl_test_MACHINE.hrl
+++ b/lib/diameter/src/base/diameter.appup.src
@@ -1,7 +1,8 @@
+%% This is an -*- erlang -*- file.
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2003-2010. All Rights Reserved.
+%% Copyright Ericsson AB 2010-2011. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -17,23 +18,13 @@
%% %CopyrightEnd%
%%
--record(st, {protomod = ssl,
- serialize_accept = false,
- parent = nil,
- type = nil,
- active = nil,
- port = 0,
- peer = nil,
- lsock = nil,
- sock = nil,
- timeout = infinity,
- sockopts = [],
- sslopts = [],
- protocols = []}).
-
-%%-define(debug(X, Y), io:format(X, Y)).
--define(debug(X, Y), ok).
--define(error(X, Y), io:format(X, Y)).
-
--define(DEFAULT_TIMEOUT, 240000).
-
+{"%VSN%",
+ [
+ {"0.9", [{restart_application, diameter}]},
+ {"0.10", [{restart_application, diameter}]}
+ ],
+ [
+ {"0.9", [{restart_application, diameter}]},
+ {"0.10", [{restart_application, diameter}]}
+ ]
+}.
diff --git a/lib/diameter/src/app/diameter.erl b/lib/diameter/src/base/diameter.erl
index 2f721421d8..2f721421d8 100644
--- a/lib/diameter/src/app/diameter.erl
+++ b/lib/diameter/src/base/diameter.erl
diff --git a/lib/diameter/src/app/diameter_app.erl b/lib/diameter/src/base/diameter_app.erl
index 600f7ff04d..600f7ff04d 100644
--- a/lib/diameter/src/app/diameter_app.erl
+++ b/lib/diameter/src/base/diameter_app.erl
diff --git a/lib/diameter/src/app/diameter_callback.erl b/lib/diameter/src/base/diameter_callback.erl
index 6d5c8cdca1..6d5c8cdca1 100644
--- a/lib/diameter/src/app/diameter_callback.erl
+++ b/lib/diameter/src/base/diameter_callback.erl
diff --git a/lib/diameter/src/app/diameter_capx.erl b/lib/diameter/src/base/diameter_capx.erl
index aa5318e79d..842a9e6103 100644
--- a/lib/diameter/src/app/diameter_capx.erl
+++ b/lib/diameter/src/base/diameter_capx.erl
@@ -57,11 +57,12 @@
-include("diameter_types.hrl").
-include("diameter_gen_base_rfc3588.hrl").
--define(SUCCESS, ?'DIAMETER_BASE_RESULT-CODE_DIAMETER_SUCCESS').
--define(NOAPP, ?'DIAMETER_BASE_RESULT-CODE_DIAMETER_NO_COMMON_APPLICATION').
--define(NOSECURITY, ?'DIAMETER_BASE_RESULT-CODE_DIAMETER_NO_COMMON_SECURITY').
+-define(SUCCESS, 2001). %% DIAMETER_SUCCESS
+-define(NOAPP, 5010). %% DIAMETER_NO_COMMON_APPLICATION
+-define(NOSECURITY, 5017). %% DIAMETER_NO_COMMON_SECURITY
-define(NO_INBAND_SECURITY, 0).
+-define(TLS, 1).
%% ===========================================================================
@@ -80,7 +81,7 @@ recv_CER(CER, Svc) ->
try_it([fun rCER/2, CER, Svc]).
-spec recv_CEA(#diameter_base_CEA{}, #diameter_service{})
- -> tried({['Unsigned32'()], #diameter_caps{}}).
+ -> tried({['Unsigned32'()], ['Unsigned32'()], #diameter_caps{}}).
recv_CEA(CEA, Svc) ->
try_it([fun rCEA/2, CEA, Svc]).
@@ -95,7 +96,7 @@ try_it([Fun | Args]) ->
try apply(Fun, Args) of
T -> {ok, T}
catch
- throw: ?FAILURE(Reason) -> {error, {Reason, Args}}
+ throw: ?FAILURE(Reason) -> {error, Reason}
end.
%% mk_caps/2
@@ -126,10 +127,11 @@ mk_caps(Caps0, Opts) ->
set_cap({Key, _}, _) ->
?THROW({duplicate, Key}).
-cap(K, V) when K == 'Origin-Host';
- K == 'Origin-Realm';
- K == 'Vendor-Id';
- K == 'Product-Name' ->
+cap(K, V)
+ when K == 'Origin-Host';
+ K == 'Origin-Realm';
+ K == 'Vendor-Id';
+ K == 'Product-Name' ->
V;
cap('Host-IP-Address', Vs)
@@ -139,11 +141,8 @@ cap('Host-IP-Address', Vs)
cap('Firmware-Revision', V) ->
[V];
-%% Not documented but accept it as long as it's what we support.
-cap('Inband-Security-Id', [0] = Vs) -> %% NO_INBAND_SECURITY
- Vs;
-
-cap(K, Vs) when K /= 'Inband-Security-Id', is_list(Vs) ->
+cap(_, Vs)
+ when is_list(Vs) ->
Vs;
cap(K, V) ->
@@ -161,28 +160,10 @@ ipaddr(A) ->
%%
%% Build a CER record to send to a remote peer.
-bCER(#diameter_caps{origin_host = Host,
- origin_realm = Realm,
- host_ip_address = Addrs,
- vendor_id = Vid,
- product_name = Name,
- origin_state_id = OSI,
- supported_vendor_id = SVid,
- auth_application_id = AuId,
- acct_application_id = AcId,
- vendor_specific_application_id = VSA,
- firmware_revision = Rev}) ->
- #diameter_base_CER{'Origin-Host' = Host,
- 'Origin-Realm' = Realm,
- 'Host-IP-Address' = Addrs,
- 'Vendor-Id' = Vid,
- 'Product-Name' = Name,
- 'Origin-State-Id' = OSI,
- 'Supported-Vendor-Id' = SVid,
- 'Auth-Application-Id' = AuId,
- 'Acct-Application-Id' = AcId,
- 'Vendor-Specific-Application-Id' = VSA,
- 'Firmware-Revision' = Rev}.
+%% Use the fact that diameter_caps has the same field names as CER.
+bCER(#diameter_caps{} = Rec) ->
+ #diameter_base_CER{}
+ = list_to_tuple([diameter_base_CER | tl(tuple_to_list(Rec))]).
%% rCER/2
%%
@@ -219,19 +200,16 @@ bCER(#diameter_caps{origin_host = Host,
%% That is, each side sends all of its capabilities and is responsible for
%% not sending commands that the peer doesn't support.
-%% TODO: Make it an option to send only common applications in CEA to
-%% allow backwards compatibility, and also because there are likely
-%% servers that expect this. Or maybe a callback.
-
%% 6.10. Inband-Security-Id AVP
%%
%% NO_INBAND_SECURITY 0
%% This peer does not support TLS. This is the default value, if the
%% AVP is omitted.
+%%
+%% TLS 1
+%% This node supports TLS security, as defined by [TLS].
rCER(CER, #diameter_service{capabilities = LCaps} = Svc) ->
- #diameter_base_CER{'Inband-Security-Id' = RIS}
- = CER,
#diameter_base_CEA{}
= CEA
= cea_from_cer(bCER(LCaps)),
@@ -241,59 +219,81 @@ rCER(CER, #diameter_service{capabilities = LCaps} = Svc) ->
{SApps,
RCaps,
- build_CEA([] == SApps,
- RIS,
- lists:member(?NO_INBAND_SECURITY, RIS),
- CEA#diameter_base_CEA{'Result-Code' = ?SUCCESS,
- 'Inband-Security-Id' = []})}.
-
-%% TODO: 5.3 of RFC3588 says we MUST return DIAMETER_NO_COMMON_APPLICATION
-%% in the CEA and SHOULD disconnect the transport. However, we have
-%% no way to guarantee the send before disconnecting.
+ build_CEA(SApps,
+ LCaps,
+ RCaps,
+ CEA#diameter_base_CEA{'Result-Code' = ?SUCCESS})}.
-build_CEA(true, _, _, CEA) ->
+build_CEA([], _, _, CEA) ->
CEA#diameter_base_CEA{'Result-Code' = ?NOAPP};
-build_CEA(false, [_|_], false, CEA) ->
- CEA#diameter_base_CEA{'Result-Code' = ?NOSECURITY};
-build_CEA(false, [_|_], true, CEA) ->
- CEA#diameter_base_CEA{'Inband-Security-Id' = [?NO_INBAND_SECURITY]};
-build_CEA(false, [], false, CEA) ->
- CEA.
+
+build_CEA(_, LCaps, RCaps, CEA) ->
+ case common_security(LCaps, RCaps) of
+ [] ->
+ CEA#diameter_base_CEA{'Result-Code' = ?NOSECURITY};
+ [_] = IS ->
+ CEA#diameter_base_CEA{'Inband-Security-Id' = IS}
+ end.
+
+%% common_security/2
+
+common_security(#diameter_caps{inband_security_id = LS},
+ #diameter_caps{inband_security_id = RS}) ->
+ cs(LS, RS).
+
+%% Unspecified is equivalent to NO_INBAND_SECURITY.
+cs([], RS) ->
+ cs([?NO_INBAND_SECURITY], RS);
+cs(LS, []) ->
+ cs(LS, [?NO_INBAND_SECURITY]);
+
+%% Agree on TLS if both parties support it. When sending CEA, this is
+%% to ensure the peer is clear that we will be expecting a TLS
+%% handshake since there is no ssl:maybe_accept that would allow the
+%% peer to choose between TLS or not upon reception of our CEA. When
+%% receiving CEA it deals with a server that isn't explicit about its choice.
+%% TODO: Make the choice configurable.
+cs(LS, RS) ->
+ Is = ordsets:to_list(ordsets:intersection(ordsets:from_list(LS),
+ ordsets:from_list(RS))),
+ case lists:member(?TLS, Is) of
+ true ->
+ [?TLS];
+ false when [] == Is ->
+ Is;
+ false ->
+ [hd(Is)] %% probably NO_INBAND_SECURITY
+ end.
+%% The only two values defined by RFC 3588 are NO_INBAND_SECURITY and
+%% TLS but don't enforce this. In theory this allows some other
+%% security mechanism we don't have to know about, although in
+%% practice something there may be a need for more synchronization
+%% than notification by way of an event subscription offers.
%% cea_from_cer/1
+%% CER is a subset of CEA, the latter adding Result-Code and a few
+%% more AVP's.
cea_from_cer(#diameter_base_CER{} = CER) ->
lists:foldl(fun(F,A) -> to_cea(CER, F, A) end,
#diameter_base_CEA{},
record_info(fields, diameter_base_CER)).
to_cea(CER, Field, CEA) ->
- try ?BASE:'#info-'(diameter_base_CEA, {index, Field}) of
- N ->
- setelement(N, CEA, ?BASE:'#get-'(Field, CER))
+ try ?BASE:'#get-'(Field, CER) of
+ V -> ?BASE:'#set-'({Field, V}, CEA)
catch
- error: _ ->
- CEA
+ error: _ -> CEA
end.
-
+
%% rCEA/2
-rCEA(CEA, #diameter_service{capabilities = LCaps} = Svc)
- when is_record(CEA, diameter_base_CEA) ->
- #diameter_base_CEA{'Result-Code' = RC}
- = CEA,
-
- RC == ?SUCCESS orelse ?THROW({'Result-Code', RC}),
-
+rCEA(CEA, #diameter_service{capabilities = LCaps} = Svc) ->
RCaps = capx_to_caps(CEA),
SApps = common_applications(LCaps, RCaps, Svc),
+ IS = common_security(LCaps, RCaps),
- [] == SApps andalso ?THROW({no_common_apps, LCaps, RCaps}),
-
- {SApps, RCaps};
-
-rCEA(CEA, _Svc) ->
- ?THROW({invalid, CEA}).
+ {SApps, IS, RCaps}.
%% capx_to_caps/1
diff --git a/lib/diameter/src/app/diameter_codec.erl b/lib/diameter/src/base/diameter_codec.erl
index d88f42fb7c..fe1212b7e0 100644
--- a/lib/diameter/src/app/diameter_codec.erl
+++ b/lib/diameter/src/base/diameter_codec.erl
@@ -190,26 +190,13 @@ encode_avps(Avps) ->
%% msg_header/3
-msg_header(Mod, MsgName, Header) ->
- {Code, Flags, ApplId} = h(Mod, MsgName, Header),
- {Code, p(Flags, Header), ApplId}.
-
-%% 6.2 of 3588 requires the same 'P' bit on an answer as on the
-%% request.
-
-p(Flags, #diameter_header{is_request = true,
- is_proxiable = P}) ->
- Flags band (2#10110000 bor choose(P, 2#01000000, 0));
-p(Flags, _) ->
- Flags.
-
-h(Mod, 'answer-message' = MsgName, Header) ->
+msg_header(Mod, 'answer-message' = MsgName, Header) ->
?BASE = Mod,
#diameter_header{cmd_code = Code} = Header,
{_, Flags, ApplId} = ?BASE:msg_header(MsgName),
{Code, Flags, ApplId};
-h(Mod, MsgName, _) ->
+msg_header(Mod, MsgName, _) ->
Mod:msg_header(MsgName).
%% rec2msg/2
@@ -554,8 +541,3 @@ pack_avp(Code, Flags, Vid, Sz, Bin) ->
pack_avp(Code, Flags, Sz, Bin) ->
Length = Sz + 8,
<<Code:32, Flags:8, Length:24, Bin/binary>>.
-
-%% ===========================================================================
-
-choose(true, X, _) -> X;
-choose(false, _, X) -> X.
diff --git a/lib/diameter/src/app/diameter_config.erl b/lib/diameter/src/base/diameter_config.erl
index a6b48fe65b..a6b48fe65b 100644
--- a/lib/diameter/src/app/diameter_config.erl
+++ b/lib/diameter/src/base/diameter_config.erl
diff --git a/lib/diameter/src/app/diameter_dbg.erl b/lib/diameter/src/base/diameter_dbg.erl
index 5b0ac3a3b6..5b0ac3a3b6 100644
--- a/lib/diameter/src/app/diameter_dbg.erl
+++ b/lib/diameter/src/base/diameter_dbg.erl
diff --git a/lib/diameter/src/app/diameter_dict.erl b/lib/diameter/src/base/diameter_dict.erl
index 3b9ba00a3f..3b9ba00a3f 100644
--- a/lib/diameter/src/app/diameter_dict.erl
+++ b/lib/diameter/src/base/diameter_dict.erl
diff --git a/lib/diameter/src/app/diameter_info.erl b/lib/diameter/src/base/diameter_info.erl
index 39d32d07cd..39d32d07cd 100644
--- a/lib/diameter/src/app/diameter_info.erl
+++ b/lib/diameter/src/base/diameter_info.erl
diff --git a/lib/diameter/src/app/diameter_internal.hrl b/lib/diameter/src/base/diameter_internal.hrl
index 63b35550a8..63b35550a8 100644
--- a/lib/diameter/src/app/diameter_internal.hrl
+++ b/lib/diameter/src/base/diameter_internal.hrl
diff --git a/lib/diameter/src/app/diameter_lib.erl b/lib/diameter/src/base/diameter_lib.erl
index 362d593b24..362d593b24 100644
--- a/lib/diameter/src/app/diameter_lib.erl
+++ b/lib/diameter/src/base/diameter_lib.erl
diff --git a/lib/diameter/src/app/diameter_misc_sup.erl b/lib/diameter/src/base/diameter_misc_sup.erl
index 4e40476f14..4e40476f14 100644
--- a/lib/diameter/src/app/diameter_misc_sup.erl
+++ b/lib/diameter/src/base/diameter_misc_sup.erl
diff --git a/lib/diameter/src/app/diameter_peer.erl b/lib/diameter/src/base/diameter_peer.erl
index 3e78c4caef..3e78c4caef 100644
--- a/lib/diameter/src/app/diameter_peer.erl
+++ b/lib/diameter/src/base/diameter_peer.erl
diff --git a/lib/diameter/src/app/diameter_peer_fsm.erl b/lib/diameter/src/base/diameter_peer_fsm.erl
index 0252fb3809..fae5d763dc 100644
--- a/lib/diameter/src/app/diameter_peer_fsm.erl
+++ b/lib/diameter/src/base/diameter_peer_fsm.erl
@@ -52,7 +52,11 @@
-define(GOAWAY, ?'DIAMETER_BASE_DISCONNECT-CAUSE_DO_NOT_WANT_TO_TALK_TO_YOU').
-define(REBOOT, ?'DIAMETER_BASE_DISCONNECT-CAUSE_REBOOTING').
--define(LOOP_TIMEOUT, 2000).
+-define(NO_INBAND_SECURITY, 0).
+-define(TLS, 1).
+
+%% A 2xxx series Result-Code. Not necessarily 2001.
+-define(IS_SUCCESS(N), 2 == (N) div 1000).
%% RFC 3588:
%%
@@ -139,9 +143,12 @@ init(T) ->
proc_lib:init_ack({ok, self()}),
gen_server:enter_loop(?MODULE, [], i(T)).
-i({WPid, {M, _} = T, Opts, #diameter_service{capabilities = Caps} = Svc0}) ->
+i({WPid, T, Opts, #diameter_service{capabilities = Caps} = Svc0}) ->
putr(dwa, dwa(Caps)),
- {ok, TPid, Svc} = start_transport(T, Opts, Svc0),
+ {M, Ref} = T,
+ {[Ts], Rest} = proplists:split(Opts, [capabilities_cb]),
+ putr(capabilities_cb, {Ref, [F || {_,F} <- Ts]}),
+ {ok, TPid, Svc} = start_transport(T, Rest, Svc0),
erlang:monitor(process, TPid),
erlang:monitor(process, WPid),
#state{parent = WPid,
@@ -195,12 +202,13 @@ handle_info(T, #state{} = State) ->
?LOG(stop, T),
x(T, State)
catch
- throw: {?MODULE, close = C, Reason} ->
- ?LOG(C, {Reason, T}),
- x(Reason, State);
- throw: {?MODULE, abort, Reason} ->
+ {?MODULE, Tag, Reason} ->
+ ?LOG(Tag, {Reason, T}),
{stop, {shutdown, Reason}, State}
end.
+%% The form of the exception caught here is historical. It's
+%% significant that it's not a 2-tuple, as in ?FAILURE(Reason),
+%% since these are caught elsewhere.
x(Reason, #state{} = S) ->
close_wd(Reason, S),
@@ -225,6 +233,9 @@ putr(Key, Val) ->
getr(Key) ->
get({?MODULE, Key}).
+eraser(Key) ->
+ erase({?MODULE, Key}).
+
%% transition/2
%% Connection to peer.
@@ -281,10 +292,9 @@ transition(shutdown, _) -> %% DPR already send: ensure expected timeout
%% Request to close the transport connection.
transition({close = T, Pid}, #state{parent = Pid,
- transport = TPid}
- = S) ->
+ transport = TPid}) ->
diameter_peer:close(TPid),
- close(T,S);
+ {stop, T};
%% DPA reception has timed out.
transition(dpa_timeout, _) ->
@@ -316,9 +326,10 @@ send_CER(#state{mode = {connect, Remote},
service = #diameter_service{capabilities = Caps},
transport = TPid}
= S) ->
- req_send_CER(Caps#diameter_caps.origin_host, Remote)
+ OH = Caps#diameter_caps.origin_host,
+ req_send_CER(OH, Remote)
orelse
- close(connected, S),
+ close({already_connected, Remote, Caps}, S),
CER = build_CER(S),
?LOG(send, 'CER'),
send(TPid, encode(CER)),
@@ -418,11 +429,11 @@ rcv('CER' = N, Pkt, #state{state = recv_CER} = S) ->
%% Anything but CER/CEA in a non-Open state is an error, as is
%% CER/CEA in anything but recv_CER/Wait-CEA.
-rcv(Name, _, #state{state = PS} = S)
+rcv(Name, _, #state{state = PS})
when PS /= 'Open';
Name == 'CER';
Name == 'CEA' ->
- close({Name, PS}, S);
+ {stop, {Name, PS}};
rcv(N, Pkt, S)
when N == 'DWR';
@@ -460,20 +471,20 @@ handle_request(Type, #diameter_packet{} = Pkt, S) ->
%% send_answer/3
send_answer(Type, ReqPkt, #state{transport = TPid} = S) ->
- #diameter_packet{header = #diameter_header{version = V,
- end_to_end_id = Eid,
- hop_by_hop_id = Hid,
- is_proxiable = P},
+ #diameter_packet{header = H,
transport_data = TD}
= ReqPkt,
- {Answer, PostF} = build_answer(Type, V, ReqPkt, S),
+ {Msg, PostF} = build_answer(Type, ReqPkt, S),
- Pkt = #diameter_packet{header = #diameter_header{version = V,
- end_to_end_id = Eid,
- hop_by_hop_id = Hid,
- is_proxiable = P},
- msg = Answer,
+ %% An answer message clears the R and T flags and retains the P
+ %% flag. The E flag is set at encode.
+ Pkt = #diameter_packet{header
+ = H#diameter_header{version = ?DIAMETER_VERSION,
+ is_request = false,
+ is_error = undefined,
+ is_retransmitted = false},
+ msg = Msg,
transport_data = TD},
send(TPid, diameter_codec:encode(?BASE, Pkt)),
@@ -484,51 +495,104 @@ eval([F|A], S) ->
eval(ok, S) ->
S.
-%% build_answer/4
+%% build_answer/3
build_answer('CER',
- ?DIAMETER_VERSION,
#diameter_packet{msg = CER,
- header = #diameter_header{is_error = false},
+ header = #diameter_header{version
+ = ?DIAMETER_VERSION,
+ is_error = false},
errors = []}
= Pkt,
- #state{service = Svc}
- = S) ->
- #diameter_service{capabilities = #diameter_caps{origin_host = OH}}
- = Svc,
-
- {SupportedApps, #diameter_caps{origin_host = DH} = RCaps, CEA}
+ S) ->
+ {SupportedApps, RCaps, #diameter_base_CEA{'Result-Code' = RC,
+ 'Inband-Security-Id' = IS}
+ = CEA}
= recv_CER(CER, S),
+ #diameter_caps{origin_host = {OH, DH}}
+ = Caps
+ = capz(caps(S), RCaps),
+
try
- [] == SupportedApps
- andalso ?THROW({no_common_application, 5010}),
+ 2001 == RC %% DIAMETER_SUCCESS
+ orelse ?THROW(RC),
register_everywhere({?MODULE, connection, OH, DH})
- orelse ?THROW({election_lost, 4003}),
- {CEA, [fun open/4, Pkt, SupportedApps, RCaps]}
+ orelse ?THROW(4003), %% DIAMETER_ELECTION_LOST
+ caps_cb(Caps)
+ of
+ N -> {cea(CEA, N), [fun open/5, Pkt,
+ SupportedApps,
+ Caps,
+ {accept, hd([_] = IS)}]}
catch
- ?FAILURE({Reason, RC}) ->
- {answer('CER', S) ++ [{'Result-Code', RC}],
- [fun close/2, {'CER', Reason, DH}]}
+ ?FAILURE(Reason) ->
+ rejected(Reason, {'CER', Reason, Caps, Pkt}, S)
end;
%% The error checks below are similar to those in diameter_service for
%% other messages. Should factor out the commonality.
-build_answer(Type, V, #diameter_packet{header = H, errors = Es} = Pkt, S) ->
- FailedAvp = failed_avp([A || {_,A} <- Es]),
- Ans = answer(answer(Type, S), V, H, Es),
- {set(Ans, FailedAvp), if 'CER' == Type ->
- [fun close/2, {Type, V, Pkt}];
- true ->
- ok
- end}.
+build_answer(Type,
+ #diameter_packet{header = H,
+ errors = Es}
+ = Pkt,
+ S) ->
+ RC = rc(H, Es),
+ {answer(Type, RC, Es, S), post(Type, RC, Pkt, S)}.
+
+cea(CEA, ok) ->
+ CEA;
+cea(CEA, 2001) ->
+ CEA;
+cea(CEA, RC) ->
+ CEA#diameter_base_CEA{'Result-Code' = RC}.
+
+post('CER' = T, RC, Pkt, S) ->
+ [fun close/2, {T, caps(S), {RC, Pkt}}];
+post(_, _, _, _) ->
+ ok.
+
+rejected({capabilities_cb, _F, Reason}, T, S) ->
+ rejected(Reason, T, S);
+
+rejected(discard, T, S) ->
+ close(T, S);
+rejected({N, Es}, T, S) ->
+ {answer('CER', N, Es, S), [fun close/2, T]};
+rejected(N, T, S) ->
+ rejected({N, []}, T, S).
+
+answer(Type, RC, Es, S) ->
+ set(answer(Type, RC, S), failed_avp([A || {_,A} <- Es])).
+
+answer(Type, RC, S) ->
+ answer_message(answer(Type, S), RC).
+%% answer_message/2
+
+answer_message([_ | Avps], RC)
+ when 3000 =< RC, RC < 4000 ->
+ ['answer-message', {'Result-Code', RC}
+ | lists:filter(fun is_origin/1, Avps)];
+
+answer_message(Msg, RC) ->
+ Msg ++ [{'Result-Code', RC}].
+
+is_origin({N, _}) ->
+ N == 'Origin-Host'
+ orelse N == 'Origin-Realm'
+ orelse N == 'Origin-State-Id'.
+
+%% failed_avp/1
+
failed_avp([] = No) ->
No;
failed_avp(Avps) ->
[{'Failed-AVP', [[{'AVP', Avps}]]}].
+%% set/2
+
set(Ans, []) ->
Ans;
set(['answer-message' | _] = Ans, FailedAvp) ->
@@ -536,18 +600,22 @@ set(['answer-message' | _] = Ans, FailedAvp) ->
set([_|_] = Ans, FailedAvp) ->
Ans ++ FailedAvp.
-answer([_, OH, OR | _], _, #diameter_header{is_error = true}, _) ->
- ['answer-message', OH, OR, {'Result-Code', 3008}];
+%% rc/2
+
+rc(#diameter_header{is_error = true}, _) ->
+ 3008; %% DIAMETER_INVALID_HDR_BITS
-answer([_, OH, OR | _], _, _, [Bs|_])
+rc(_, [Bs|_])
when is_bitstring(Bs) ->
- ['answer-message', OH, OR, {'Result-Code', 3009}];
+ 3009; %% DIAMETER_INVALID_HDR_BITS
-answer(Ans, ?DIAMETER_VERSION, _, Es) ->
- Ans ++ [{'Result-Code', rc(Es)}];
+rc(#diameter_header{version = ?DIAMETER_VERSION}, Es) ->
+ rc(Es);
-answer(Ans, _, _, _) ->
- Ans ++ [{'Result-Code', 5011}]. %% DIAMETER_UNSUPPORTED_VERSION
+rc(_, _) ->
+ 5011. %% DIAMETER_UNSUPPORTED_VERSION
+
+%% rc/1
rc([]) ->
2001; %% DIAMETER_SUCCESS
@@ -590,12 +658,14 @@ a('CER', #diameter_caps{vendor_id = Vid,
origin_host = Host,
origin_realm = Realm,
host_ip_address = Addrs,
- product_name = Name}) ->
+ product_name = Name,
+ origin_state_id = OSI}) ->
['CEA', {'Origin-Host', Host},
{'Origin-Realm', Realm},
{'Host-IP-Address', Addrs},
{'Vendor-Id', Vid},
- {'Product-Name', Name}];
+ {'Product-Name', Name},
+ {'Origin-State-Id', OSI}];
a('DPR', #diameter_caps{origin_host = Host,
origin_realm = Realm}) ->
@@ -610,23 +680,25 @@ recv_CER(CER, #state{service = Svc}) ->
%% handle_CEA/1
-handle_CEA(#diameter_packet{header = #diameter_header{version = V},
- bin = Bin}
+handle_CEA(#diameter_packet{bin = Bin}
= Pkt,
- #state{service = Svc}
+ #state{service = #diameter_service{capabilities = LCaps}}
= S)
when is_binary(Bin) ->
?LOG(recv, 'CEA'),
- ?DIAMETER_VERSION == V orelse close({version, V}, S),
-
- #diameter_packet{msg = CEA, errors = Errors}
+ #diameter_packet{msg = CEA}
= DPkt
= diameter_codec:decode(?BASE, Pkt),
- [] == Errors orelse close({errors, Errors}, S),
+ {SApps, IS, RCaps} = recv_CEA(DPkt, S),
+
+ #diameter_caps{origin_host = {OH, DH}}
+ = Caps
+ = capz(LCaps, RCaps),
- {SApps, #diameter_caps{origin_host = DH} = RCaps} = recv_CEA(CEA, S),
+ #diameter_base_CEA{'Result-Code' = RC}
+ = CEA,
%% Ensure that we don't already have a connection to the peer in
%% question. This isn't the peer election of 3588 except in the
@@ -634,40 +706,103 @@ handle_CEA(#diameter_packet{header = #diameter_header{version = V},
%% receive a CER/CEA, the first that arrives wins the right to a
%% connection with the peer.
- #diameter_service{capabilities = #diameter_caps{origin_host = OH}}
- = Svc,
+ try
+ ?IS_SUCCESS(RC)
+ orelse ?THROW(RC),
+ [] == SApps
+ andalso ?THROW(no_common_application),
+ [] == IS
+ andalso ?THROW(no_common_security),
+ register_everywhere({?MODULE, connection, OH, DH})
+ orelse ?THROW(election_lost),
+ caps_cb(Caps)
+ of
+ _ -> open(DPkt, SApps, Caps, {connect, hd([_] = IS)}, S)
+ catch
+ ?FAILURE(Reason) -> close({'CEA', Reason, Caps, DPkt}, S)
+ end.
+%% Check more than the result code since the peer could send success
+%% regardless. If not 2001 then a peer_up callback could do anything
+%% required. It's not unimaginable that a peer agreeing to TLS after
+%% capabilities exchange could send DIAMETER_LIMITED_SUCCESS = 2002,
+%% even if this isn't required by RFC 3588.
- register_everywhere({?MODULE, connection, OH, DH})
- orelse
- close({'CEA', DH}, S),
+%% recv_CEA/2
- open(DPkt, SApps, RCaps, S).
+recv_CEA(#diameter_packet{header = #diameter_header{version
+ = ?DIAMETER_VERSION,
+ is_error = false},
+ msg = CEA,
+ errors = []},
+ #state{service = Svc}) ->
+ {ok, T} = diameter_capx:recv_CEA(CEA, Svc),
+ T;
-%% recv_CEA/2
+recv_CEA(Pkt, S) ->
+ close({'CEA', caps(S), Pkt}, S).
-recv_CEA(CEA, #state{service = Svc} = S) ->
- case diameter_capx:recv_CEA(CEA, Svc) of
- {ok, {[], _}} ->
- close({'CEA', no_common_application}, S);
- {ok, T} ->
- T;
- {error, Reason} ->
- close({'CEA', Reason}, S)
+caps(#diameter_service{capabilities = Caps}) ->
+ Caps;
+caps(#state{service = Svc}) ->
+ caps(Svc).
+
+%% caps_cb/1
+
+caps_cb(Caps) ->
+ {Ref, Ts} = eraser(capabilities_cb),
+ ccb(Ts, [Ref, Caps]).
+
+ccb([], _) ->
+ ok;
+ccb([F | Rest], T) ->
+ case diameter_lib:eval([F|T]) of
+ ok ->
+ ccb(Rest, T);
+ N when ?IS_SUCCESS(N) -> %% 2xxx result code: accept immediately
+ N;
+ Res ->
+ ?THROW({capabilities_cb, F, rejected(Res)})
end.
+%% Note that returning 2xxx causes the capabilities exchange to be
+%% accepted directly, without further callbacks.
+
+rejected(discard = T) ->
+ T;
+rejected(unknown) ->
+ 3010; %% DIAMETER_UNKNOWN_PEER
+rejected(N)
+ when is_integer(N) ->
+ N.
+
+%% open/5
+
+open(Pkt, SupportedApps, Caps, {Type, IS}, #state{parent = Pid} = S) ->
+ #diameter_caps{origin_host = {_,_} = H,
+ inband_security_id = {LS,_}}
+ = Caps,
+
+ tls_ack(lists:member(?TLS, LS), Caps, Type, IS, S),
+ Pid ! {open, self(), H, {Caps, SupportedApps, Pkt}},
-%% open/4
-
-open(Pkt, SupportedApps, RCaps, #state{parent = Pid,
- service = Svc}
- = S) ->
- #diameter_service{capabilities = #diameter_caps{origin_host = OH}
- = LCaps}
- = Svc,
- #diameter_caps{origin_host = DH}
- = RCaps,
- Pid ! {open, self(), {OH,DH}, {capz(LCaps, RCaps), SupportedApps, Pkt}},
S#state{state = 'Open'}.
+%% We've advertised TLS support: tell the transport the result
+%% and expect a reply when the handshake is complete.
+tls_ack(true, Caps, Type, IS, #state{transport = TPid} = S) ->
+ Ref = make_ref(),
+ TPid ! {diameter, {tls, Ref, Type, IS == ?TLS}},
+ receive
+ {diameter, {tls, Ref}} ->
+ ok;
+ {'DOWN', _, process, TPid, Reason} ->
+ close({tls_ack, Reason, Caps}, S)
+ end;
+
+%% Or not. Don't send anything to the transport so that transports
+%% not supporting TLS work as before without modification.
+tls_ack(false, _, _, _, _) ->
+ ok.
+
capz(#diameter_caps{} = L, #diameter_caps{} = R) ->
#diameter_caps{}
= list_to_tuple([diameter_caps | lists:zip(tl(tuple_to_list(L)),
diff --git a/lib/diameter/src/app/diameter_peer_fsm_sup.erl b/lib/diameter/src/base/diameter_peer_fsm_sup.erl
index 995eaf74d0..995eaf74d0 100644
--- a/lib/diameter/src/app/diameter_peer_fsm_sup.erl
+++ b/lib/diameter/src/base/diameter_peer_fsm_sup.erl
diff --git a/lib/diameter/src/app/diameter_reg.erl b/lib/diameter/src/base/diameter_reg.erl
index 882b9da238..882b9da238 100644
--- a/lib/diameter/src/app/diameter_reg.erl
+++ b/lib/diameter/src/base/diameter_reg.erl
diff --git a/lib/diameter/src/app/diameter_service.erl b/lib/diameter/src/base/diameter_service.erl
index 421e36ccf5..7adcf1c265 100644
--- a/lib/diameter/src/app/diameter_service.erl
+++ b/lib/diameter/src/base/diameter_service.erl
@@ -983,7 +983,8 @@ peer_cb(MFA, Alias) ->
connection_down(Pid, #state{peerT = PeerT,
connT = ConnT}
= S) ->
- #peer{conn = TPid}
+ #peer{op_state = ?STATE_UP, %% assert
+ conn = TPid}
= P
= fetch(PeerT, Pid),
@@ -993,6 +994,9 @@ connection_down(Pid, #state{peerT = PeerT,
%% connection_down/3
+connection_down(#peer{op_state = ?STATE_DOWN}, _, S) ->
+ S;
+
connection_down(#peer{conn = TPid,
op_state = ?STATE_UP}
= P,
@@ -1034,13 +1038,23 @@ down_conn(Id, Alias, TC, {SvcName, Apps}) ->
%% Peer process has died.
-peer_down(Pid, _Reason, #state{peerT = PeerT} = S) ->
+peer_down(Pid, Reason, #state{peerT = PeerT} = S) ->
P = fetch(PeerT, Pid),
ets:delete_object(PeerT, P),
+ closed(Reason, P, S),
restart(P,S),
peer_down(P,S).
-%% peer_down/2
+%% Send an event at connection establishment failure.
+closed({shutdown, {close, _TPid, Reason}},
+ #peer{op_state = ?STATE_DOWN,
+ ref = Ref,
+ type = Type,
+ options = Opts},
+ #state{service_name = SvcName}) ->
+ send_event(SvcName, {closed, Ref, Reason, {type(Type), Opts}});
+closed(_, _, _) ->
+ ok.
%% The peer has never come up ...
peer_down(#peer{conn = B}, S)
@@ -1048,27 +1062,9 @@ peer_down(#peer{conn = B}, S)
S;
%% ... or it has.
-peer_down(#peer{ref = Ref,
- conn = TPid,
- type = Type,
- options = Opts}
- = P,
- #state{service_name = SvcName,
- connT = ConnT}
- = S) ->
- #conn{caps = Caps}
- = C
- = fetch(ConnT, TPid),
+peer_down(#peer{conn = TPid} = P, #state{connT = ConnT} = S) ->
+ #conn{} = C = fetch(ConnT, TPid),
ets:delete_object(ConnT, C),
- try
- pd(P,C,S)
- after
- send_event(SvcName, {closed, Ref, {TPid, Caps}, {type(Type), Opts}})
- end.
-
-pd(#peer{op_state = ?STATE_DOWN}, _, S) ->
- S;
-pd(#peer{op_state = ?STATE_UP} = P, C, S) ->
connection_down(P,C,S).
%% restart/2
@@ -1259,11 +1255,11 @@ send_request({TPid, Caps, App}, Msg, Opts, Caller, SvcName) ->
#diameter_app{module = ModX}
= App,
- Pkt = make_packet(Msg),
+ Pkt = make_request_packet(Msg),
case cb(ModX, prepare_request, [Pkt, SvcName, {TPid, Caps}]) of
{send, P} ->
- send_request(make_packet(P, Pkt),
+ send_request(make_request_packet(P, Pkt),
TPid,
Caps,
App,
@@ -1278,70 +1274,73 @@ send_request({TPid, Caps, App}, Msg, Opts, Caller, SvcName) ->
?ERROR({invalid_return, prepare_request, App, T})
end.
-%% make_packet/1
+%% make_request_packet/1
%%
%% Turn an outgoing request as passed to call/4 into a diameter_packet
%% record in preparation for a prepare_request callback.
-make_packet(Bin)
+make_request_packet(Bin)
when is_binary(Bin) ->
#diameter_packet{header = diameter_codec:decode_header(Bin),
bin = Bin};
-make_packet(#diameter_packet{msg = [#diameter_header{} = Hdr | Avps]} = Pkt) ->
- Pkt#diameter_packet{msg = [make_header(Hdr) | Avps]};
+make_request_packet(#diameter_packet{msg = [#diameter_header{} = Hdr | Avps]}
+ = Pkt) ->
+ Pkt#diameter_packet{msg = [make_request_header(Hdr) | Avps]};
-make_packet(#diameter_packet{header = Hdr} = Pkt) ->
- Pkt#diameter_packet{header = make_header(Hdr)};
+make_request_packet(#diameter_packet{header = Hdr} = Pkt) ->
+ Pkt#diameter_packet{header = make_request_header(Hdr)};
-make_packet(Msg) ->
- make_packet(#diameter_packet{msg = Msg}).
+make_request_packet(Msg) ->
+ make_request_packet(#diameter_packet{msg = Msg}).
-%% make_header/1
+%% make_request_header/1
-make_header(undefined) ->
+make_request_header(undefined) ->
Seq = diameter_session:sequence(),
- make_header(#diameter_header{end_to_end_id = Seq,
- hop_by_hop_id = Seq});
+ make_request_header(#diameter_header{end_to_end_id = Seq,
+ hop_by_hop_id = Seq});
-make_header(#diameter_header{version = undefined} = Hdr) ->
- make_header(Hdr#diameter_header{version = ?DIAMETER_VERSION});
+make_request_header(#diameter_header{version = undefined} = Hdr) ->
+ make_request_header(Hdr#diameter_header{version = ?DIAMETER_VERSION});
-make_header(#diameter_header{end_to_end_id = undefined} = H) ->
+make_request_header(#diameter_header{end_to_end_id = undefined} = H) ->
Seq = diameter_session:sequence(),
- make_header(H#diameter_header{end_to_end_id = Seq});
+ make_request_header(H#diameter_header{end_to_end_id = Seq});
-make_header(#diameter_header{hop_by_hop_id = undefined} = H) ->
+make_request_header(#diameter_header{hop_by_hop_id = undefined} = H) ->
Seq = diameter_session:sequence(),
- make_header(H#diameter_header{hop_by_hop_id = Seq});
+ make_request_header(H#diameter_header{hop_by_hop_id = Seq});
-make_header(#diameter_header{} = Hdr) ->
+make_request_header(#diameter_header{} = Hdr) ->
Hdr;
-make_header(T) ->
+make_request_header(T) ->
?ERROR({invalid_header, T}).
-%% make_packet/2
+%% make_request_packet/2
%%
%% Reconstruct a diameter_packet from the return value of
%% prepare_request or prepare_retransmit callback.
-make_packet(Bin, _)
+make_request_packet(Bin, _)
when is_binary(Bin) ->
- make_packet(Bin);
+ make_request_packet(Bin);
-make_packet(#diameter_packet{msg = [#diameter_header{} | _]} = Pkt, _) ->
+make_request_packet(#diameter_packet{msg = [#diameter_header{} | _]}
+ = Pkt,
+ _) ->
Pkt;
%% Returning a diameter_packet with no header from a prepare_request
%% or prepare_retransmit callback retains the header passed into it.
%% This is primarily so that the end to end and hop by hop identifiers
%% are retained.
-make_packet(#diameter_packet{header = Hdr} = Pkt,
+make_request_packet(#diameter_packet{header = Hdr} = Pkt,
#diameter_packet{header = Hdr0}) ->
Pkt#diameter_packet{header = fold_record(Hdr0, Hdr)};
-make_packet(Msg, Pkt) ->
+make_request_packet(Msg, Pkt) ->
Pkt#diameter_packet{msg = Msg}.
%% fold_record/2
@@ -1533,7 +1532,7 @@ retransmit({TPid, Caps, #diameter_app{alias = Alias} = App},
case cb(App, prepare_retransmit, [Pkt, SvcName, {TPid, Caps}]) of
{send, P} ->
- retransmit(make_packet(P, Pkt), TPid, Caps, Req, Timeout);
+ retransmit(make_request_packet(P, Pkt), TPid, Caps, Req, Timeout);
{discard, Reason} ->
?THROW(Reason);
discard ->
@@ -1946,7 +1945,7 @@ reply(Msg, Dict, TPid, #diameter_packet{errors = Es,
= ReqPkt)
when [] == Es;
is_record(hd(Msg), diameter_header) ->
- Pkt = diameter_codec:encode(Dict, make_reply_packet(Msg, ReqPkt)),
+ Pkt = diameter_codec:encode(Dict, make_answer_packet(Msg, ReqPkt)),
incr(send, Pkt, Dict, TPid), %% count result codes in sent answers
send(TPid, Pkt#diameter_packet{transport_data = TD});
@@ -1957,18 +1956,19 @@ reply(Msg, Dict, TPid, #diameter_packet{errors = [H|_] = Es} = Pkt) ->
TPid,
Pkt#diameter_packet{errors = []}).
-%% make_reply_packet/2
+%% make_answer_packet/2
%% Binaries and header/avp lists are sent as-is.
-make_reply_packet(Bin, _)
+make_answer_packet(Bin, _)
when is_binary(Bin) ->
#diameter_packet{bin = Bin};
-make_reply_packet([#diameter_header{} | _] = Msg, _) ->
+make_answer_packet([#diameter_header{} | _] = Msg, _) ->
#diameter_packet{msg = Msg};
%% Otherwise a reply message clears the R and T flags and retains the
-%% P flag. The E flag will be set at encode.
-make_reply_packet(Msg, #diameter_packet{header = ReqHdr}) ->
+%% P flag. The E flag will be set at encode. 6.2 of 3588 requires the
+%% same P flag on an answer as on the request.
+make_answer_packet(Msg, #diameter_packet{header = ReqHdr}) ->
Hdr = ReqHdr#diameter_header{version = ?DIAMETER_VERSION,
is_request = false,
is_error = undefined,
diff --git a/lib/diameter/src/app/diameter_service_sup.erl b/lib/diameter/src/base/diameter_service_sup.erl
index 153fff902f..153fff902f 100644
--- a/lib/diameter/src/app/diameter_service_sup.erl
+++ b/lib/diameter/src/base/diameter_service_sup.erl
diff --git a/lib/diameter/src/app/diameter_session.erl b/lib/diameter/src/base/diameter_session.erl
index bb91e97f39..bb91e97f39 100644
--- a/lib/diameter/src/app/diameter_session.erl
+++ b/lib/diameter/src/base/diameter_session.erl
diff --git a/lib/diameter/src/app/diameter_stats.erl b/lib/diameter/src/base/diameter_stats.erl
index 71479afa95..71479afa95 100644
--- a/lib/diameter/src/app/diameter_stats.erl
+++ b/lib/diameter/src/base/diameter_stats.erl
diff --git a/lib/diameter/src/app/diameter_sup.erl b/lib/diameter/src/base/diameter_sup.erl
index e5afd23dcd..e5afd23dcd 100644
--- a/lib/diameter/src/app/diameter_sup.erl
+++ b/lib/diameter/src/base/diameter_sup.erl
diff --git a/lib/diameter/src/app/diameter_sync.erl b/lib/diameter/src/base/diameter_sync.erl
index ce2db4b3a2..ce2db4b3a2 100644
--- a/lib/diameter/src/app/diameter_sync.erl
+++ b/lib/diameter/src/base/diameter_sync.erl
diff --git a/lib/diameter/src/app/diameter_types.erl b/lib/diameter/src/base/diameter_types.erl
index 6b1b1b8d39..6b1b1b8d39 100644
--- a/lib/diameter/src/app/diameter_types.erl
+++ b/lib/diameter/src/base/diameter_types.erl
diff --git a/lib/diameter/src/app/diameter_types.hrl b/lib/diameter/src/base/diameter_types.hrl
index 02bf8a74dd..02bf8a74dd 100644
--- a/lib/diameter/src/app/diameter_types.hrl
+++ b/lib/diameter/src/base/diameter_types.hrl
diff --git a/lib/diameter/src/app/diameter_watchdog.erl b/lib/diameter/src/base/diameter_watchdog.erl
index b7c1491f4b..6dc53d9f31 100644
--- a/lib/diameter/src/app/diameter_watchdog.erl
+++ b/lib/diameter/src/base/diameter_watchdog.erl
@@ -179,11 +179,11 @@ transition({close, TPid, _Reason}, #watchdog{transport = TPid}) ->
%% state okay as the result of the Peer State Machine reaching the
%% Open state.
%%
-%% If we're an acceptor then we may be resuming a connection that went
-%% down in another acceptor process, in which case this is the
-%% transition below, from down into reopen. That is, it's not until
-%% we know the identity of the peer (ie. now) that we know that we're
-%% in state down rather than initial.
+%% If we're accepting then we may be resuming a connection that went
+%% down in another watchdog process, in which case this is the
+%% transition below, from down to reopen. That is, it's not until we
+%% know the identity of the peer (ie. now) that we know that we're in
+%% state down rather than initial.
transition({open, TPid, Hosts, T} = Open,
#watchdog{transport = TPid,
diff --git a/lib/diameter/src/app/diameter_watchdog_sup.erl b/lib/diameter/src/base/diameter_watchdog_sup.erl
index fc837fe4ef..fc837fe4ef 100644
--- a/lib/diameter/src/app/diameter_watchdog_sup.erl
+++ b/lib/diameter/src/base/diameter_watchdog_sup.erl
diff --git a/lib/diameter/src/compiler/Makefile b/lib/diameter/src/compiler/Makefile
deleted file mode 100644
index 779013bfbc..0000000000
--- a/lib/diameter/src/compiler/Makefile
+++ /dev/null
@@ -1,131 +0,0 @@
-#
-# %CopyrightBegin%
-#
-# Copyright Ericsson AB 2010-2011. All Rights Reserved.
-#
-# The contents of this file are subject to the Erlang Public License,
-# Version 1.1, (the "License"); you may not use this file except in
-# compliance with the License. You should have received a copy of the
-# Erlang Public License along with this software. If not, it can be
-# retrieved online at http://www.erlang.org/.
-#
-# Software distributed under the License is distributed on an "AS IS"
-# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
-# the License for the specific language governing rights and limitations
-# under the License.
-#
-# %CopyrightEnd%
-#
-#
-
-ifneq ($(ERL_TOP),)
-include $(ERL_TOP)/make/target.mk
-EBIN = ../../ebin
-include $(ERL_TOP)/make/$(TARGET)/otp.mk
-else
-include $(DIAMETER_TOP)/make/target.mk
-EBIN = ../../ebin
-include $(DIAMETER_TOP)/make/$(TARGET)/rules.mk
-endif
-
-
-# ----------------------------------------------------
-# Application version
-# ----------------------------------------------------
-include ../../vsn.mk
-VSN=$(DIAMETER_VSN)
-
-# ----------------------------------------------------
-# Release directory specification
-# ----------------------------------------------------
-
-RELSYSDIR = $(RELEASE_PATH)/lib/diameter-$(VSN)
-
-INCDIR = ../../include
-
-# ----------------------------------------------------
-# Target Specs
-# ----------------------------------------------------
-
-include modules.mk
-
-ERL_FILES = \
- $(MODULES:%=%.erl)
-
-TARGET_FILES = \
- $(MODULES:%=$(EBIN)/%.$(EMULATOR))
-
-# ----------------------------------------------------
-# FLAGS
-# ----------------------------------------------------
-
-ifeq ($(TYPE),debug)
-ERL_COMPILE_FLAGS += -Ddebug
-endif
-
-include ../app/diameter.mk
-
-ERL_COMPILE_FLAGS += \
- $(DIAMETER_ERL_COMPILE_FLAGS) \
- -I$(INCDIR)
-
-# ----------------------------------------------------
-# Targets
-# ----------------------------------------------------
-
-debug:
- @${MAKE} TYPE=debug opt
-
-opt: $(TARGET_FILES)
-
-clean:
- rm -f $(TARGET_FILES)
- rm -f errs core *~
- rm -f depend.mk
-
-docs:
-
-info:
- @echo ""
- @echo "ERL_FILES = $(ERL_FILES)"
- @echo "HRL_FILES = $(HRL_FILES)"
- @echo ""
- @echo "TARGET_FILES = $(TARGET_FILES)"
- @echo ""
-
-# ----------------------------------------------------
-# Release Target
-# ----------------------------------------------------
-ifneq ($(ERL_TOP),)
-include $(ERL_TOP)/make/otp_release_targets.mk
-else
-include $(DIAMETER_TOP)/make/release_targets.mk
-endif
-
-release_spec: opt
- $(INSTALL_DIR) $(RELSYSDIR)/ebin
- $(INSTALL_DATA) $(TARGET_FILES) $(RELSYSDIR)/ebin
- $(INSTALL_DIR) $(RELSYSDIR)/src
- $(INSTALL_DIR) $(RELSYSDIR)/src/compiler
- $(INSTALL_DATA) $(ERL_FILES) $(HRL_FILES) $(RELSYSDIR)/src/compiler
-
-release_docs_spec:
-
-force:
-
-# ----------------------------------------------------
-# Dependencies
-# ----------------------------------------------------
-
-depend: depend.mk
-
-# Generate dependencies makefile.
-depend.mk: ../app/depend.sed $(ERL_FILES) Makefile
- for f in $(MODULES); do \
- sed -f $< $$f.erl | sed "s@/@/$$f@"; \
- done \
- > $@
-
--include depend.mk
-
-.PHONY: clean debug depend docs force info opt release_docs_spec release_spec
diff --git a/lib/diameter/src/compiler/diameter_codegen.erl b/lib/diameter/src/compiler/diameter_codegen.erl
index a33b07a3d3..0fd4a0b301 100644
--- a/lib/diameter/src/compiler/diameter_codegen.erl
+++ b/lib/diameter/src/compiler/diameter_codegen.erl
@@ -707,9 +707,9 @@ gen_hrl(Path, Mod, Spec) ->
write("ENUM Macros",
Fd,
m_enums(PREFIX, false, get_value(enums, Spec))),
- write("RESULT CODE Macros",
+ write("DEFINE Macros",
Fd,
- m_enums(PREFIX, false, get_value(result_codes, Spec))),
+ m_enums(PREFIX, false, get_value(defines, Spec))),
lists:foreach(fun({M,Es}) ->
write("ENUM Macros from " ++ atom_to_list(M),
diff --git a/lib/diameter/src/app/diameter_exprecs.erl b/lib/diameter/src/compiler/diameter_exprecs.erl
index 5e120d6f44..5e120d6f44 100644
--- a/lib/diameter/src/app/diameter_exprecs.erl
+++ b/lib/diameter/src/compiler/diameter_exprecs.erl
diff --git a/lib/diameter/src/compiler/diameter_make.erl b/lib/diameter/src/compiler/diameter_make.erl
index 4431b88c4d..5380ee56ca 100644
--- a/lib/diameter/src/compiler/diameter_make.erl
+++ b/lib/diameter/src/compiler/diameter_make.erl
@@ -18,103 +18,61 @@
%%
%%
-%% Driver for the encoder generator utility.
+%% Module alternative to diameterc for dictionary compilation.
+%%
+%% Eg. 1> diameter_make:dict("mydict.dia").
+%%
+%% $ erl -noshell \
+%% -boot start_clean \
+%% -s diameter_make dict mydict.dia \
+%% -s init stop
%%
-module(diameter_make).
--export([spec/0,
- hrl/0,
- erl/0]).
+-export([dict/1,
+ dict/2,
+ spec/1,
+ spec/2]).
--spec spec() -> no_return().
--spec hrl() -> no_return().
--spec erl() -> no_return().
+-type opt() :: {outdir|include|name|prefix|inherits, string()}
+ | verbose
+ | debug.
-spec() ->
- make(spec).
+%% dict/1-2
-hrl() ->
- make(hrl).
+-spec dict(string(), [opt()])
+ -> ok.
-erl() ->
- make(erl).
+dict(File, Opts) ->
+ make(File,
+ Opts,
+ spec(File, Opts),
+ [spec || _ <- [1], lists:member(debug, Opts)] ++ [erl, hrl]).
-%% make/1
+dict(File) ->
+ dict(File, []).
-make(Mode) ->
- Args = init:get_plain_arguments(),
- Opts = try options(Args) catch throw: help -> help(Mode) end,
- Files = proplists:get_value(files, Opts, []),
- lists:foreach(fun(F) -> from_file(F, Mode, Opts) end, Files),
- halt(0).
+%% spec/2
-%% from_file/3
-
-from_file(F, Mode, Opts) ->
- try to_spec(F, Mode, Opts) of
- Spec ->
- from_spec(F, Spec, Mode, Opts)
- catch
- error: Reason ->
- io:format("==> ~p parse failure:~n~p~n",
- [F, {Reason, erlang:get_stacktrace()}]),
- halt(1)
- end.
+-spec spec(string(), [opt()])
+ -> orddict:orddict().
-%% to_spec/2
+spec(File, Opts) ->
+ diameter_spec_util:parse(File, Opts).
-%% Try to read the input as an already parsed file or else parse it.
-to_spec(F, spec, Opts) ->
- diameter_spec_util:parse(F, Opts);
-to_spec(F, _, _) ->
- {ok, [Spec]} = file:consult(F),
- Spec.
+spec(File) ->
+ spec(File, []).
-%% from_spec/4
+%% ===========================================================================
-from_spec(File, Spec, Mode, Opts) ->
- try
- diameter_codegen:from_spec(File, Spec, Opts, Mode)
+make(_, _, _, []) ->
+ ok;
+make(File, Opts, Spec, [Mode | Rest]) ->
+ try diameter_codegen:from_spec(File, Spec, Opts, Mode) of
+ ok ->
+ make(File, Opts, Spec, Rest)
catch
error: Reason ->
- io:format("==> ~p codegen failure:~n~p~n~p~n",
- [Mode, File, {Reason, erlang:get_stacktrace()}]),
- halt(1)
+ {error, {Reason, Mode, erlang:get_stacktrace()}}
end.
-
-%% options/1
-
-options(["-v" | Rest]) ->
- [verbose | options(Rest)];
-
-options(["-o", Outdir | Rest]) ->
- [{outdir, Outdir} | options(Rest)];
-
-options(["-i", Incdir | Rest]) ->
- [{include, Incdir} | options(Rest)];
-
-options(["-h" | _]) ->
- throw(help);
-
-options(["--" | Fs]) ->
- [{files, Fs}];
-
-options(["-" ++ _ = Opt | _]) ->
- io:fwrite("==> unknown option: ~s~n", [Opt]),
- throw(help);
-
-options(Fs) -> %% trailing arguments
- options(["--" | Fs]).
-
-%% help/1
-
-help(M) ->
- io:fwrite("Usage: ~p ~p [Options] [--] File ...~n"
- "Options:~n"
- " -v verbose output~n"
- " -h shows this help message~n"
- " -o OutDir where to put the output files~n"
- " -i IncludeDir where to search for beams to import~n",
- [?MODULE, M]),
- halt(1).
diff --git a/lib/diameter/src/compiler/diameter_spec_util.erl b/lib/diameter/src/compiler/diameter_spec_util.erl
index b60886b678..62536bf06d 100644
--- a/lib/diameter/src/compiler/diameter_spec_util.erl
+++ b/lib/diameter/src/compiler/diameter_spec_util.erl
@@ -34,19 +34,38 @@
%%
%% Output: orddict()
-parse(Path, Options) ->
- put({?MODULE, verbose}, lists:member(verbose, Options)),
+parse(Path, Opts) ->
+ put({?MODULE, verbose}, lists:member(verbose, Opts)),
{ok, B} = file:read_file(Path),
Chunks = chunk(B),
- Spec = make_spec(Chunks),
+ Spec = reset(make_spec(Chunks), Opts, [name, prefix, inherits]),
true = groups_defined(Spec), %% sanity checks
true = customs_defined(Spec), %%
- Full = import_enums(import_groups(import_avps(insert_codes(Spec),
- Options))),
+ Full = import_enums(import_groups(import_avps(insert_codes(Spec), Opts))),
true = enums_defined(Full), %% sanity checks
true = v_flags_set(Spec),
Full.
+reset(Spec, Opts, Keys) ->
+ lists:foldl(fun(K,S) ->
+ reset([{A,?ATOM(V)} || {A,V} <- Opts, A == K], S)
+ end,
+ Spec,
+ Keys).
+
+reset(L, Spec)
+ when is_list(L) ->
+ lists:foldl(fun reset/2, Spec, L);
+
+reset({inherits = Key, '-'}, Spec) ->
+ orddict:erase(Key, Spec);
+reset({inherits = Key, Dict}, Spec) ->
+ orddict:append(Key, Dict, Spec);
+reset({Key, Atom}, Spec) ->
+ orddict:store(Key, Atom, Spec);
+reset(_, Spec) ->
+ Spec.
+
%% Optional reports when running verbosely.
report(What, Data) ->
report(get({?MODULE, verbose}), What, Data).
@@ -204,9 +223,11 @@ chunk({avp_vendor_id = T, [{number, I}], Body}, Dict) ->
chunk({enum, [N], Str}, Dict) ->
append(enums, {atomize(N), parse_enums(Str)}, Dict);
-%% result_codes -> [{ResultName, [{Value, Name}, ...]}, ...]
-chunk({result_code, [N], Str}, Dict) ->
- append(result_codes, {atomize(N), parse_enums(Str)}, Dict);
+%% defines -> [{DefineName, [{Value, Name}, ...]}, ...]
+chunk({define, [N], Str}, Dict) ->
+ append(defines, {atomize(N), parse_enums(Str)}, Dict);
+chunk({result_code, [_] = N, Str}, Dict) -> %% backwards compatibility
+ chunk({define, N, Str}, Dict);
%% commands -> [{Name, Abbrev}, ...]
chunk({commands = T, [], Body}, Dict) ->
diff --git a/lib/diameter/src/compiler/modules.mk b/lib/diameter/src/compiler/modules.mk
deleted file mode 100644
index 17a311dacf..0000000000
--- a/lib/diameter/src/compiler/modules.mk
+++ /dev/null
@@ -1,27 +0,0 @@
-#-*-makefile-*- ; force emacs to enter makefile-mode
-
-# %CopyrightBegin%
-#
-# Copyright Ericsson AB 2010-2011. All Rights Reserved.
-#
-# The contents of this file are subject to the Erlang Public License,
-# Version 1.1, (the "License"); you may not use this file except in
-# compliance with the License. You should have received a copy of the
-# Erlang Public License along with this software. If not, it can be
-# retrieved online at http://www.erlang.org/.
-#
-# Software distributed under the License is distributed on an "AS IS"
-# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
-# the License for the specific language governing rights and limitations
-# under the License.
-#
-# %CopyrightEnd%
-
-MODULES = \
- diameter_codegen \
- diameter_spec_scan \
- diameter_spec_util
-
-HRL_FILES = \
- diameter_forms.hrl
-
diff --git a/lib/diameter/src/depend.sed b/lib/diameter/src/depend.sed
new file mode 100644
index 0000000000..8f999f646f
--- /dev/null
+++ b/lib/diameter/src/depend.sed
@@ -0,0 +1,51 @@
+#
+# %CopyrightBegin%
+#
+# Copyright Ericsson AB 2010-2011. All Rights Reserved.
+#
+# The contents of this file are subject to the Erlang Public License,
+# Version 1.1, (the "License"); you may not use this file except in
+# compliance with the License. You should have received a copy of the
+# Erlang Public License along with this software. If not, it can be
+# retrieved online at http://www.erlang.org/.
+#
+# Software distributed under the License is distributed on an "AS IS"
+# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+# the License for the specific language governing rights and limitations
+# under the License.
+#
+# %CopyrightEnd%
+#
+
+#
+# Extract include dependencies from .erl files. First line of input
+# is the path to the module in question (minus the .erl extension),
+# the rest is the contents of the module.
+#
+
+1{
+ s@^[^/]*/@@
+ h
+ d
+}
+
+# Only interested in includes of diameter hrls.
+/^-include/!d
+/"diameter/!d
+
+# Extract the name of the included files in one of two forms:
+#
+# $(INCDIR)/diameter.hrl
+# diameter_internal.hrl
+
+s@^-include_lib(".*/@$(INCDIR)/@
+s@^-include("@@
+s@".*@@
+
+# Retrieve the path to our module from the hold space, morph it
+# into a beam path and turn it into a dependency like this:
+#
+# $(EBIN)/diameter_service.$(EMULATOR): $(INCDIR)/diameter.hrl
+
+G
+s@^\(.*\)\n\(.*\)@$(EBIN)/\2.$(EMULATOR): \1@
diff --git a/lib/diameter/src/dict/base_accounting.dia b/lib/diameter/src/dict/base_accounting.dia
new file mode 100644
index 0000000000..ced324078c
--- /dev/null
+++ b/lib/diameter/src/dict/base_accounting.dia
@@ -0,0 +1,69 @@
+;;
+;; %CopyrightBegin%
+;;
+;; Copyright Ericsson AB 2010-2011. All Rights Reserved.
+;;
+;; The contents of this file are subject to the Erlang Public License,
+;; Version 1.1, (the "License"); you may not use this file except in
+;; compliance with the License. You should have received a copy of the
+;; Erlang Public License along with this software. If not, it can be
+;; retrieved online at http://www.erlang.org/.
+;;
+;; Software distributed under the License is distributed on an "AS IS"
+;; basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+;; the License for the specific language governing rights and limitations
+;; under the License.
+;;
+;; %CopyrightEnd%
+;;
+
+@id 3
+@name diameter_gen_base_accounting
+@prefix diameter_base_accounting
+@vendor 0 IETF
+
+@inherits diameter_gen_base_rfc3588
+
+@messages
+
+ ACR ::= < Diameter Header: 271, REQ, PXY >
+ < Session-Id >
+ { Origin-Host }
+ { Origin-Realm }
+ { Destination-Realm }
+ { Accounting-Record-Type }
+ { Accounting-Record-Number }
+ [ Acct-Application-Id ]
+ [ Vendor-Specific-Application-Id ]
+ [ User-Name ]
+ [ Accounting-Sub-Session-Id ]
+ [ Acct-Session-Id ]
+ [ Acct-Multi-Session-Id ]
+ [ Acct-Interim-Interval ]
+ [ Accounting-Realtime-Required ]
+ [ Origin-State-Id ]
+ [ Event-Timestamp ]
+ * [ Proxy-Info ]
+ * [ Route-Record ]
+ * [ AVP ]
+
+ ACA ::= < Diameter Header: 271, PXY >
+ < Session-Id >
+ { Result-Code }
+ { Origin-Host }
+ { Origin-Realm }
+ { Accounting-Record-Type }
+ { Accounting-Record-Number }
+ [ Acct-Application-Id ]
+ [ Vendor-Specific-Application-Id ]
+ [ User-Name ]
+ [ Accounting-Sub-Session-Id ]
+ [ Acct-Session-Id ]
+ [ Acct-Multi-Session-Id ]
+ [ Error-Reporting-Host ]
+ [ Acct-Interim-Interval ]
+ [ Accounting-Realtime-Required ]
+ [ Origin-State-Id ]
+ [ Event-Timestamp ]
+ * [ Proxy-Info ]
+ * [ AVP ]
diff --git a/lib/diameter/src/dict/base_rfc3588.dia b/lib/diameter/src/dict/base_rfc3588.dia
new file mode 100644
index 0000000000..f7a0b717cd
--- /dev/null
+++ b/lib/diameter/src/dict/base_rfc3588.dia
@@ -0,0 +1,414 @@
+;;
+;; %CopyrightBegin%
+;;
+;; Copyright Ericsson AB 2010-2011. All Rights Reserved.
+;;
+;; The contents of this file are subject to the Erlang Public License,
+;; Version 1.1, (the "License"); you may not use this file except in
+;; compliance with the License. You should have received a copy of the
+;; Erlang Public License along with this software. If not, it can be
+;; retrieved online at http://www.erlang.org/.
+;;
+;; Software distributed under the License is distributed on an "AS IS"
+;; basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+;; the License for the specific language governing rights and limitations
+;; under the License.
+;;
+;; %CopyrightEnd%
+;;
+
+@id 0
+@name diameter_gen_base_rfc3588
+@prefix diameter_base
+@vendor 0 IETF
+
+@avp_types
+
+ Acct-Interim-Interval 85 Unsigned32 M
+ Accounting-Realtime-Required 483 Enumerated M
+ Acct-Multi-Session-Id 50 UTF8String M
+ Accounting-Record-Number 485 Unsigned32 M
+ Accounting-Record-Type 480 Enumerated M
+ Acct-Session-Id 44 OctetString M
+ Accounting-Sub-Session-Id 287 Unsigned64 M
+ Acct-Application-Id 259 Unsigned32 M
+ Auth-Application-Id 258 Unsigned32 M
+ Auth-Request-Type 274 Enumerated M
+ Authorization-Lifetime 291 Unsigned32 M
+ Auth-Grace-Period 276 Unsigned32 M
+ Auth-Session-State 277 Enumerated M
+ Re-Auth-Request-Type 285 Enumerated M
+ Class 25 OctetString M
+ Destination-Host 293 DiamIdent M
+ Destination-Realm 283 DiamIdent M
+ Disconnect-Cause 273 Enumerated M
+ E2E-Sequence 300 Grouped M
+ Error-Message 281 UTF8String -
+ Error-Reporting-Host 294 DiamIdent -
+ Event-Timestamp 55 Time M
+ Experimental-Result 297 Grouped M
+ Experimental-Result-Code 298 Unsigned32 M
+ Failed-AVP 279 Grouped M
+ Firmware-Revision 267 Unsigned32 -
+ Host-IP-Address 257 Address M
+ Inband-Security-Id 299 Unsigned32 M
+ Multi-Round-Time-Out 272 Unsigned32 M
+ Origin-Host 264 DiamIdent M
+ Origin-Realm 296 DiamIdent M
+ Origin-State-Id 278 Unsigned32 M
+ Product-Name 269 UTF8String -
+ Proxy-Host 280 DiamIdent M
+ Proxy-Info 284 Grouped M
+ Proxy-State 33 OctetString M
+ Redirect-Host 292 DiamURI M
+ Redirect-Host-Usage 261 Enumerated M
+ Redirect-Max-Cache-Time 262 Unsigned32 M
+ Result-Code 268 Unsigned32 M
+ Route-Record 282 DiamIdent M
+ Session-Id 263 UTF8String M
+ Session-Timeout 27 Unsigned32 M
+ Session-Binding 270 Unsigned32 M
+ Session-Server-Failover 271 Enumerated M
+ Supported-Vendor-Id 265 Unsigned32 M
+ Termination-Cause 295 Enumerated M
+ User-Name 1 UTF8String M
+ Vendor-Id 266 Unsigned32 M
+ Vendor-Specific-Application-Id 260 Grouped M
+
+@messages
+
+ CER ::= < Diameter Header: 257, REQ >
+ { Origin-Host }
+ { Origin-Realm }
+ 1* { Host-IP-Address }
+ { Vendor-Id }
+ { Product-Name }
+ [ Origin-State-Id ]
+ * [ Supported-Vendor-Id ]
+ * [ Auth-Application-Id ]
+ * [ Inband-Security-Id ]
+ * [ Acct-Application-Id ]
+ * [ Vendor-Specific-Application-Id ]
+ [ Firmware-Revision ]
+ * [ AVP ]
+
+ CEA ::= < Diameter Header: 257 >
+ { Result-Code }
+ { Origin-Host }
+ { Origin-Realm }
+ 1* { Host-IP-Address }
+ { Vendor-Id }
+ { Product-Name }
+ [ Origin-State-Id ]
+ [ Error-Message ]
+ * [ Failed-AVP ]
+ * [ Supported-Vendor-Id ]
+ * [ Auth-Application-Id ]
+ * [ Inband-Security-Id ]
+ * [ Acct-Application-Id ]
+ * [ Vendor-Specific-Application-Id ]
+ [ Firmware-Revision ]
+ * [ AVP ]
+
+ DPR ::= < Diameter Header: 282, REQ >
+ { Origin-Host }
+ { Origin-Realm }
+ { Disconnect-Cause }
+
+ DPA ::= < Diameter Header: 282 >
+ { Result-Code }
+ { Origin-Host }
+ { Origin-Realm }
+ [ Error-Message ]
+ * [ Failed-AVP ]
+
+ DWR ::= < Diameter Header: 280, REQ >
+ { Origin-Host }
+ { Origin-Realm }
+ [ Origin-State-Id ]
+
+ DWA ::= < Diameter Header: 280 >
+ { Result-Code }
+ { Origin-Host }
+ { Origin-Realm }
+ [ Error-Message ]
+ * [ Failed-AVP ]
+ [ Origin-State-Id ]
+
+ answer-message ::= < Diameter Header: code, ERR [PXY] >
+ 0*1 < Session-Id >
+ { Origin-Host }
+ { Origin-Realm }
+ { Result-Code }
+ [ Origin-State-Id ]
+ [ Error-Reporting-Host ]
+ [ Proxy-Info ]
+ * [ AVP ]
+
+ RAR ::= < Diameter Header: 258, REQ, PXY >
+ < Session-Id >
+ { Origin-Host }
+ { Origin-Realm }
+ { Destination-Realm }
+ { Destination-Host }
+ { Auth-Application-Id }
+ { Re-Auth-Request-Type }
+ [ User-Name ]
+ [ Origin-State-Id ]
+ * [ Proxy-Info ]
+ * [ Route-Record ]
+ * [ AVP ]
+
+ RAA ::= < Diameter Header: 258, PXY >
+ < Session-Id >
+ { Result-Code }
+ { Origin-Host }
+ { Origin-Realm }
+ [ User-Name ]
+ [ Origin-State-Id ]
+ [ Error-Message ]
+ [ Error-Reporting-Host ]
+ * [ Failed-AVP ]
+ * [ Redirect-Host ]
+ [ Redirect-Host-Usage ]
+ [ Redirect-Max-Cache-Time ]
+ * [ Proxy-Info ]
+ * [ AVP ]
+
+ STR ::= < Diameter Header: 275, REQ, PXY >
+ < Session-Id >
+ { Origin-Host }
+ { Origin-Realm }
+ { Destination-Realm }
+ { Auth-Application-Id }
+ { Termination-Cause }
+ [ User-Name ]
+ [ Destination-Host ]
+ * [ Class ]
+ [ Origin-State-Id ]
+ * [ Proxy-Info ]
+ * [ Route-Record ]
+ * [ AVP ]
+
+ STA ::= < Diameter Header: 275, PXY >
+ < Session-Id >
+ { Result-Code }
+ { Origin-Host }
+ { Origin-Realm }
+ [ User-Name ]
+ * [ Class ]
+ [ Error-Message ]
+ [ Error-Reporting-Host ]
+ * [ Failed-AVP ]
+ [ Origin-State-Id ]
+ * [ Redirect-Host ]
+ [ Redirect-Host-Usage ]
+ [ Redirect-Max-Cache-Time ]
+ * [ Proxy-Info ]
+ * [ AVP ]
+
+ ASR ::= < Diameter Header: 274, REQ, PXY >
+ < Session-Id >
+ { Origin-Host }
+ { Origin-Realm }
+ { Destination-Realm }
+ { Destination-Host }
+ { Auth-Application-Id }
+ [ User-Name ]
+ [ Origin-State-Id ]
+ * [ Proxy-Info ]
+ * [ Route-Record ]
+ * [ AVP ]
+
+ ASA ::= < Diameter Header: 274, PXY >
+ < Session-Id >
+ { Result-Code }
+ { Origin-Host }
+ { Origin-Realm }
+ [ User-Name ]
+ [ Origin-State-Id ]
+ [ Error-Message ]
+ [ Error-Reporting-Host ]
+ * [ Failed-AVP ]
+ * [ Redirect-Host ]
+ [ Redirect-Host-Usage ]
+ [ Redirect-Max-Cache-Time ]
+ * [ Proxy-Info ]
+ * [ AVP ]
+
+ ACR ::= < Diameter Header: 271, REQ, PXY >
+ < Session-Id >
+ { Origin-Host }
+ { Origin-Realm }
+ { Destination-Realm }
+ { Accounting-Record-Type }
+ { Accounting-Record-Number }
+ [ Acct-Application-Id ]
+ [ Vendor-Specific-Application-Id ]
+ [ User-Name ]
+ [ Accounting-Sub-Session-Id ]
+ [ Acct-Session-Id ]
+ [ Acct-Multi-Session-Id ]
+ [ Acct-Interim-Interval ]
+ [ Accounting-Realtime-Required ]
+ [ Origin-State-Id ]
+ [ Event-Timestamp ]
+ * [ Proxy-Info ]
+ * [ Route-Record ]
+ * [ AVP ]
+
+ ACA ::= < Diameter Header: 271, PXY >
+ < Session-Id >
+ { Result-Code }
+ { Origin-Host }
+ { Origin-Realm }
+ { Accounting-Record-Type }
+ { Accounting-Record-Number }
+ [ Acct-Application-Id ]
+ [ Vendor-Specific-Application-Id ]
+ [ User-Name ]
+ [ Accounting-Sub-Session-Id ]
+ [ Acct-Session-Id ]
+ [ Acct-Multi-Session-Id ]
+ [ Error-Reporting-Host ]
+ [ Acct-Interim-Interval ]
+ [ Accounting-Realtime-Required ]
+ [ Origin-State-Id ]
+ [ Event-Timestamp ]
+ * [ Proxy-Info ]
+ * [ AVP ]
+
+@enum Disconnect-Cause
+
+ REBOOTING 0
+ BUSY 1
+ DO_NOT_WANT_TO_TALK_TO_YOU 2
+
+@enum Redirect-Host-Usage
+
+ DONT_CACHE 0
+ ALL_SESSION 1
+ ALL_REALM 2
+ REALM_AND_APPLICATION 3
+ ALL_APPLICATION 4
+ ALL_HOST 5
+ ALL_USER 6
+
+@enum Auth-Request-Type
+
+ AUTHENTICATE_ONLY 1
+ AUTHORIZE_ONLY 2
+ AUTHORIZE_AUTHENTICATE 3
+
+@enum Auth-Session-State
+
+ STATE_MAINTAINED 0
+ NO_STATE_MAINTAINED 1
+
+@enum Re-Auth-Request-Type
+
+ AUTHORIZE_ONLY 0
+ AUTHORIZE_AUTHENTICATE 1
+
+@enum Termination-Cause
+
+ DIAMETER_LOGOUT 1
+ DIAMETER_SERVICE_NOT_PROVIDED 2
+ DIAMETER_BAD_ANSWER 3
+ DIAMETER_ADMINISTRATIVE 4
+ DIAMETER_LINK_BROKEN 5
+ DIAMETER_AUTH_EXPIRED 6
+ DIAMETER_USER_MOVED 7
+ DIAMETER_SESSION_TIMEOUT 8
+
+@enum Session-Server-Failover
+
+ REFUSE_SERVICE 0
+ TRY_AGAIN 1
+ ALLOW_SERVICE 2
+ TRY_AGAIN_ALLOW_SERVICE 3
+
+@enum Accounting-Record-Type
+
+ EVENT_RECORD 1
+ START_RECORD 2
+ INTERIM_RECORD 3
+ STOP_RECORD 4
+
+@enum Accounting-Realtime-Required
+
+ DELIVER_AND_GRANT 1
+ GRANT_AND_STORE 2
+ GRANT_AND_LOSE 3
+
+@define Result-Code
+
+;; 7.1.1. Informational
+ DIAMETER_MULTI_ROUND_AUTH 1001
+
+;; 7.1.2. Success
+ DIAMETER_SUCCESS 2001
+ DIAMETER_LIMITED_SUCCESS 2002
+
+;; 7.1.3. Protocol Errors
+ DIAMETER_COMMAND_UNSUPPORTED 3001
+ DIAMETER_UNABLE_TO_DELIVER 3002
+ DIAMETER_REALM_NOT_SERVED 3003
+ DIAMETER_TOO_BUSY 3004
+ DIAMETER_LOOP_DETECTED 3005
+ DIAMETER_REDIRECT_INDICATION 3006
+ DIAMETER_APPLICATION_UNSUPPORTED 3007
+ DIAMETER_INVALID_HDR_BITS 3008
+ DIAMETER_INVALID_AVP_BITS 3009
+ DIAMETER_UNKNOWN_PEER 3010
+
+;; 7.1.4. Transient Failures
+ DIAMETER_AUTHENTICATION_REJECTED 4001
+ DIAMETER_OUT_OF_SPACE 4002
+ ELECTION_LOST 4003
+
+;; 7.1.5. Permanent Failures
+ DIAMETER_AVP_UNSUPPORTED 5001
+ DIAMETER_UNKNOWN_SESSION_ID 5002
+ DIAMETER_AUTHORIZATION_REJECTED 5003
+ DIAMETER_INVALID_AVP_VALUE 5004
+ DIAMETER_MISSING_AVP 5005
+ DIAMETER_RESOURCES_EXCEEDED 5006
+ DIAMETER_CONTRADICTING_AVPS 5007
+ DIAMETER_AVP_NOT_ALLOWED 5008
+ DIAMETER_AVP_OCCURS_TOO_MANY_TIMES 5009
+ DIAMETER_NO_COMMON_APPLICATION 5010
+ DIAMETER_UNSUPPORTED_VERSION 5011
+ DIAMETER_UNABLE_TO_COMPLY 5012
+ DIAMETER_INVALID_BIT_IN_HEADER 5013
+ DIAMETER_INVALID_AVP_LENGTH 5014
+ DIAMETER_INVALID_MESSAGE_LENGTH 5015
+ DIAMETER_INVALID_AVP_BIT_COMBO 5016
+ DIAMETER_NO_COMMON_SECURITY 5017
+
+@grouped
+
+ Proxy-Info ::= < AVP Header: 284 >
+ { Proxy-Host }
+ { Proxy-State }
+ * [ AVP ]
+
+ Failed-AVP ::= < AVP Header: 279 >
+ 1* {AVP}
+
+ Experimental-Result ::= < AVP Header: 297 >
+ { Vendor-Id }
+ { Experimental-Result-Code }
+
+ Vendor-Specific-Application-Id ::= < AVP Header: 260 >
+ 1* { Vendor-Id }
+ [ Auth-Application-Id ]
+ [ Acct-Application-Id ]
+
+;; The E2E-Sequence AVP is defined in RFC 3588 as Grouped, but
+;; there is no definition of the group - only an informal text stating
+;; that there should be a nonce (an OctetString) and a counter
+;; (integer)
+;;
+ E2E-Sequence ::= <AVP Header: 300 >
+ 2* { AVP }
diff --git a/lib/diameter/src/app/diameter_gen_relay.dia b/lib/diameter/src/dict/relay.dia
index d86446e368..c22293209b 100644
--- a/lib/diameter/src/app/diameter_gen_relay.dia
+++ b/lib/diameter/src/dict/relay.dia
@@ -18,6 +18,7 @@
;;
@id 0xFFFFFFFF
+@name diameter_gen_relay
@prefix diameter_relay
@vendor 0 IETF
diff --git a/lib/diameter/src/gen/.gitignore b/lib/diameter/src/gen/.gitignore
new file mode 100644
index 0000000000..d490642eb7
--- /dev/null
+++ b/lib/diameter/src/gen/.gitignore
@@ -0,0 +1,2 @@
+
+/diameter_gen*rl
diff --git a/lib/diameter/src/modules.mk b/lib/diameter/src/modules.mk
new file mode 100644
index 0000000000..c7cbe598af
--- /dev/null
+++ b/lib/diameter/src/modules.mk
@@ -0,0 +1,93 @@
+#-*-makefile-*- ; force emacs to enter makefile-mode
+
+# %CopyrightBegin%
+#
+# Copyright Ericsson AB 2010-2011. All Rights Reserved.
+#
+# The contents of this file are subject to the Erlang Public License,
+# Version 1.1, (the "License"); you may not use this file except in
+# compliance with the License. You should have received a copy of the
+# Erlang Public License along with this software. If not, it can be
+# retrieved online at http://www.erlang.org/.
+#
+# Software distributed under the License is distributed on an "AS IS"
+# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+# the License for the specific language governing rights and limitations
+# under the License.
+#
+# %CopyrightEnd%
+
+# Runtime dictionary files in ./dict. Modules will be generated from
+# these are included in the app file.
+DICTS = \
+ base_rfc3588 \
+ base_accounting \
+ relay
+
+# Handwritten (runtime) modules included in the app file.
+RT_MODULES = \
+ base/diameter \
+ base/diameter_app \
+ base/diameter_capx \
+ base/diameter_config \
+ base/diameter_codec \
+ base/diameter_dict \
+ base/diameter_lib \
+ base/diameter_misc_sup \
+ base/diameter_peer \
+ base/diameter_peer_fsm \
+ base/diameter_peer_fsm_sup \
+ base/diameter_reg \
+ base/diameter_service \
+ base/diameter_service_sup \
+ base/diameter_session \
+ base/diameter_stats \
+ base/diameter_sup \
+ base/diameter_sync \
+ base/diameter_types \
+ base/diameter_watchdog \
+ base/diameter_watchdog_sup \
+ transport/diameter_etcp \
+ transport/diameter_etcp_sup \
+ transport/diameter_tcp \
+ transport/diameter_tcp_sup \
+ transport/diameter_sctp \
+ transport/diameter_sctp_sup \
+ transport/diameter_transport_sup
+
+# Handwritten (compile time) modules not included in the app file.
+CT_MODULES = \
+ base/diameter_callback \
+ base/diameter_dbg \
+ base/diameter_info \
+ compiler/diameter_codegen \
+ compiler/diameter_exprecs \
+ compiler/diameter_spec_scan \
+ compiler/diameter_spec_util \
+ compiler/diameter_make
+
+# Released hrl files in ../include intended for public consumption.
+EXTERNAL_HRLS = \
+ diameter.hrl \
+ diameter_gen.hrl
+
+# Released hrl files intended for private use.
+INTERNAL_HRLS = \
+ base/diameter_internal.hrl \
+ base/diameter_types.hrl \
+ compiler/diameter_forms.hrl
+
+# Released files relative to ../bin.
+BINS = \
+ diameterc
+
+# Released files relative to ../examples.
+EXAMPLES = \
+ GNUmakefile \
+ peer.erl \
+ client.erl \
+ client_cb.erl \
+ server.erl \
+ server_cb.erl \
+ relay.erl \
+ relay_cb.erl
diff --git a/lib/diameter/src/subdirs.mk b/lib/diameter/src/subdirs.mk
deleted file mode 100644
index 3e12d935bc..0000000000
--- a/lib/diameter/src/subdirs.mk
+++ /dev/null
@@ -1,21 +0,0 @@
-#-*-makefile-*- ; force emacs to enter makefile-mode
-
-# %CopyrightBegin%
-#
-# Copyright Ericsson AB 2010-2011. All Rights Reserved.
-#
-# The contents of this file are subject to the Erlang Public License,
-# Version 1.1, (the "License"); you may not use this file except in
-# compliance with the License. You should have received a copy of the
-# Erlang Public License along with this software. If not, it can be
-# retrieved online at http://www.erlang.org/.
-#
-# Software distributed under the License is distributed on an "AS IS"
-# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
-# the License for the specific language governing rights and limitations
-# under the License.
-#
-# %CopyrightEnd%
-
-SUB_DIRS = compiler app transport
-SUB_DIRECTORIES = $(SUB_DIRS) \ No newline at end of file
diff --git a/lib/diameter/src/transport/.gitignore b/lib/diameter/src/transport/.gitignore
deleted file mode 100644
index d9f072e262..0000000000
--- a/lib/diameter/src/transport/.gitignore
+++ /dev/null
@@ -1,3 +0,0 @@
-
-/depend.mk
-
diff --git a/lib/diameter/src/transport/Makefile b/lib/diameter/src/transport/Makefile
deleted file mode 100644
index 4b53100fd2..0000000000
--- a/lib/diameter/src/transport/Makefile
+++ /dev/null
@@ -1,141 +0,0 @@
-#
-# %CopyrightBegin%
-#
-# Copyright Ericsson AB 2010-2011. All Rights Reserved.
-#
-# The contents of this file are subject to the Erlang Public License,
-# Version 1.1, (the "License"); you may not use this file except in
-# compliance with the License. You should have received a copy of the
-# Erlang Public License along with this software. If not, it can be
-# retrieved online at http://www.erlang.org/.
-#
-# Software distributed under the License is distributed on an "AS IS"
-# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
-# the License for the specific language governing rights and limitations
-# under the License.
-#
-# %CopyrightEnd%
-#
-#
-
-ifneq ($(ERL_TOP),)
-include $(ERL_TOP)/make/target.mk
-EBIN = ../../ebin
-include $(ERL_TOP)/make/$(TARGET)/otp.mk
-else
-include $(DIAMETER_TOP)/make/target.mk
-EBIN = ../../ebin
-include $(DIAMETER_TOP)/make/$(TARGET)/rules.mk
-endif
-
-
-# ----------------------------------------------------
-# Application version
-# ----------------------------------------------------
-
-include ../../vsn.mk
-VSN=$(DIAMETER_VSN)
-
-# ----------------------------------------------------
-# Release directory specification
-# ----------------------------------------------------
-
-RELSYSDIR = $(RELEASE_PATH)/lib/diameter-$(VSN)
-
-INCDIR = ../../include
-
-# ----------------------------------------------------
-# Target Specs
-# ----------------------------------------------------
-
-include modules.mk
-
-ERL_FILES = \
- $(MODULES:%=%.erl)
-
-TARGET_FILES = \
- $(MODULES:%=$(EBIN)/%.$(EMULATOR))
-
-# ----------------------------------------------------
-# FLAGS
-# ----------------------------------------------------
-
-ifeq ($(TYPE),debug)
-ERL_COMPILE_FLAGS += -Ddebug
-endif
-
-include ../app/diameter.mk
-
-ERL_COMPILE_FLAGS += \
- $(DIAMETER_ERL_COMPILE_FLAGS) \
- -I$(INCDIR)
-
-# ----------------------------------------------------
-# Targets
-# ----------------------------------------------------
-
-debug:
- @${MAKE} TYPE=debug opt
-
-opt: $(TARGET_FILES)
-
-clean:
- rm -f $(TARGET_FILES)
- rm -f errs core *~
- rm -f depend.mk
-
-docs:
-
-info:
- @echo ""
- @echo "ERL_FILES = $(ERL_FILES)"
- @echo "HRL_FILES = $(HRL_FILES)"
- @echo ""
- @echo "TARGET_FILES = $(TARGET_FILES)"
- @echo ""
-
-# ----------------------------------------------------
-# Special Build Targets
-# ----------------------------------------------------
-
-# Invoked from ../app to add modules to the app file.
-$(APP_TARGET): force
- M=`echo $(MODULES) | sed -e 's/^ *//' -e 's/ *$$//' -e 'y/ /,/'`; \
- echo "/%TRANSPORT_MODULES%/s//$$M/;w;q" | tr ';' '\n' \
- | ed -s $@
-
-# ----------------------------------------------------
-# Release Target
-# ----------------------------------------------------
-ifneq ($(ERL_TOP),)
-include $(ERL_TOP)/make/otp_release_targets.mk
-else
-include $(DIAMETER_TOP)/make/release_targets.mk
-endif
-
-release_spec: opt
- $(INSTALL_DIR) $(RELSYSDIR)/ebin
- $(INSTALL_DATA) $(TARGET_FILES) $(RELSYSDIR)/ebin
- $(INSTALL_DIR) $(RELSYSDIR)/src/transport
- $(INSTALL_DATA) $(ERL_FILES) $(HRL_FILES) $(RELSYSDIR)/src/transport
-
-release_docs_spec:
-
-force:
-
-# ----------------------------------------------------
-# Dependencies
-# ----------------------------------------------------
-
-depend: depend.mk
-
-# Generate dependencies makefile.
-depend.mk: ../app/depend.sed $(ERL_FILES) Makefile
- for f in $(MODULES); do \
- sed -f $< $$f.erl | sed "s@/@/$$f@"; \
- done \
- > $@
-
--include depend.mk
-
-.PHONY: clean debug depend docs force info opt release_docs_spec release_spec
diff --git a/lib/diameter/src/transport/diameter_sctp.erl b/lib/diameter/src/transport/diameter_sctp.erl
index 46473e7bf1..209f8c01c1 100644
--- a/lib/diameter/src/transport/diameter_sctp.erl
+++ b/lib/diameter/src/transport/diameter_sctp.erl
@@ -37,6 +37,9 @@
code_change/3,
terminate/2]).
+-export([ports/0,
+ ports/1]).
+
-include_lib("kernel/include/inet_sctp.hrl").
-include_lib("diameter/include/diameter.hrl").
@@ -118,8 +121,8 @@ s({accept, Ref} = A, Addrs, Opts) ->
%% gen_sctp in order to be able to accept a new association only
%% *after* an accepting transport has been spawned.
-s({connect = C, _}, Addrs, Opts) ->
- diameter_sctp_sup:start_child({C, self(), Opts, Addrs}).
+s({connect = C, Ref}, Addrs, Opts) ->
+ diameter_sctp_sup:start_child({C, self(), Opts, Addrs, Ref}).
%% start_link/1
@@ -149,28 +152,36 @@ i({listen, Ref, {Opts, Addrs}}) ->
socket = Sock});
%% A connecting transport.
-i({connect, Pid, Opts, Addrs}) ->
+i({connect, Pid, Opts, Addrs, Ref}) ->
{[As, Ps], Rest} = proplists:split(Opts, [raddr, rport]),
RAs = [diameter_lib:ipaddr(A) || {raddr, A} <- As],
[RP] = [P || {rport, P} <- Ps] ++ [P || P <- [?DEFAULT_PORT], [] == Ps],
{LAs, Sock} = open(Addrs, Rest, 0),
+ putr(ref, Ref),
proc_lib:init_ack({ok, self(), LAs}),
erlang:monitor(process, Pid),
#transport{parent = Pid,
mode = {connect, connect(Sock, RAs, RP, [])},
socket = Sock};
+i({connect, _, _, _} = T) -> %% from old code
+ x(T);
%% An accepting transport spawned by diameter.
-i({accept, Pid, LPid, Sock}) ->
+i({accept, Pid, LPid, Sock, Ref})
+ when is_pid(Pid) ->
+ putr(ref, Ref),
proc_lib:init_ack({ok, self()}),
erlang:monitor(process, Pid),
erlang:monitor(process, LPid),
#transport{parent = Pid,
mode = {accept, LPid},
socket = Sock};
+i({accept, _, _, _} = T) -> %% from old code
+ x(T);
%% An accepting transport spawned at association establishment.
i({accept, Ref, LPid, Sock, Id}) ->
+ putr(ref, Ref),
proc_lib:init_ack({ok, self()}),
MRef = erlang:monitor(process, LPid),
%% Wait for a signal that the transport has been started before
@@ -250,13 +261,33 @@ gen_opts(Opts) ->
[binary, {active, once} | Opts].
%% ---------------------------------------------------------------------------
+%% # ports/0-1
+%% ---------------------------------------------------------------------------
+
+ports() ->
+ Ts = diameter_reg:match({?MODULE, '_', '_'}),
+ [{type(T), N, Pid} || {{?MODULE, T, {_, {_, S}}}, Pid} <- Ts,
+ {ok, N} <- [inet:port(S)]].
+
+ports(Ref) ->
+ Ts = diameter_reg:match({?MODULE, '_', {Ref, '_'}}),
+ [{type(T), N, Pid} || {{?MODULE, T, {R, {_, S}}}, Pid} <- Ts,
+ R == Ref,
+ {ok, N} <- [inet:port(S)]].
+
+type(listener) ->
+ listen;
+type(T) ->
+ T.
+
+%% ---------------------------------------------------------------------------
%% # handle_call/3
%% ---------------------------------------------------------------------------
handle_call({{accept, Ref}, Pid}, _, #listener{ref = Ref,
count = N}
= S) ->
- {TPid, NewS} = accept(Pid, S),
+ {TPid, NewS} = accept(Ref, Pid, S),
{reply, {ok, TPid}, NewS#listener{count = N+1}};
handle_call(_, _, State) ->
@@ -306,6 +337,12 @@ terminate(_, #listener{socket = Sock}) ->
%% ---------------------------------------------------------------------------
+putr(Key, Val) ->
+ put({?MODULE, Key}, Val).
+
+getr(Key) ->
+ get({?MODULE, Key}).
+
%% start_timer/1
start_timer(#listener{count = 0} = S) ->
@@ -411,27 +448,41 @@ transition({diameter, {send, Msg}}, S) ->
transition({diameter, {close, Pid}}, #transport{parent = Pid}) ->
stop;
+%% TLS over SCTP is described in RFC 3436 but has limitations as
+%% described in RFC 6083. The latter describes DTLS over SCTP, which
+%% addresses these limitations, DTLS itself being described in RFC
+%% 4347. TLS is primarily used over TCP, which the current RFC 3588
+%% draft acknowledges by equating TLS with TLS/TCP and DTLS/SCTP.
+transition({diameter, {tls, _Ref, _Type, _Bool}}, _) ->
+ stop;
+
%% Listener process has died.
transition({'DOWN', _, process, Pid, _}, #transport{mode = {accept, Pid}}) ->
stop;
%% Parent process has died.
transition({'DOWN', _, process, Pid, _}, #transport{parent = Pid}) ->
- stop.
+ stop;
+
+%% Request for the local port number.
+transition({resolve_port, Pid}, #transport{socket = Sock})
+ when is_pid(Pid) ->
+ Pid ! inet:port(Sock),
+ ok.
%% Crash on anything unexpected.
-%% accept/2
+%% accept/3
%%
%% Start a new transport process or use one that's already been
%% started as a consequence of association establishment.
%% No pending associations: spawn a new transport.
-accept(Pid, #listener{socket = Sock,
- tmap = T,
- pending = {0,_} = Q}
- = S) ->
- Arg = {accept, Pid, self(), Sock},
+accept(Ref, Pid, #listener{socket = Sock,
+ tmap = T,
+ pending = {0,_} = Q}
+ = S) ->
+ Arg = {accept, Pid, self(), Sock, Ref},
{ok, TPid} = diameter_sctp_sup:start_child(Arg),
MRef = erlang:monitor(process, TPid),
ets:insert(T, [{MRef, TPid}, {TPid, MRef}]),
@@ -442,12 +493,12 @@ accept(Pid, #listener{socket = Sock,
%% Accepting transport has died. This can happen if a new transport is
%% started before the DOWN has arrived.
-accept(Pid, #listener{pending = [TPid | {0,_} = Q]} = S) ->
+accept(Ref, Pid, #listener{pending = [TPid | {0,_} = Q]} = S) ->
false = is_process_alive(TPid), %% assert
- accept(Pid, S#listener{pending = Q});
+ accept(Ref, Pid, S#listener{pending = Q});
%% Pending associations: attach to the first in the queue.
-accept(Pid, #listener{ref = Ref, pending = {N,Q}} = S) ->
+accept(_, Pid, #listener{ref = Ref, pending = {N,Q}} = S) ->
TPid = ets:first(Q),
TPid ! {Ref, Pid},
ets:delete(Q, TPid),
@@ -499,8 +550,14 @@ recv({[], #sctp_assoc_change{state = comm_up,
outbound_streams = OS,
inbound_streams = IS,
assoc_id = Id}},
- #transport{assoc_id = undefined}
+ #transport{assoc_id = undefined,
+ mode = {T, _},
+ socket = Sock}
= S) ->
+ Ref = getr(ref),
+ is_reference(Ref) %% started in new code
+ andalso
+ (true = diameter_reg:add_new({?MODULE, T, {Ref, {Id, Sock}}})),
up(S#transport{assoc_id = Id,
streams = {IS, OS}});
diff --git a/lib/diameter/src/transport/diameter_tcp.erl b/lib/diameter/src/transport/diameter_tcp.erl
index 653c114471..78dbda6888 100644
--- a/lib/diameter/src/transport/diameter_tcp.erl
+++ b/lib/diameter/src/transport/diameter_tcp.erl
@@ -37,6 +37,9 @@
code_change/3,
terminate/2]).
+-export([ports/0,
+ ports/1]).
+
-include_lib("diameter/include/diameter.hrl").
-define(ERROR(T), erlang:error({T, ?MODULE, ?LINE})).
@@ -45,6 +48,9 @@
-define(LISTENER_TIMEOUT, 30000).
-define(FRAGMENT_TIMEOUT, 1000).
+%% cb_info passed to ssl.
+-define(TCP_CB(Mod), {Mod, tcp, tcp_closed, tcp_error}).
+
%% The same gen_server implementation supports three different kinds
%% of processes: an actual transport process, one that will club it to
%% death should the parent die before a connection is established, and
@@ -71,8 +77,8 @@
{socket :: inet:socket(), %% accept or connect socket
parent :: pid(), %% of process that started us
module :: module(), %% gen_tcp-like module
- frag = <<>> :: binary() | {tref(), frag()}}). %% message fragment
-
+ frag = <<>> :: binary() | {tref(), frag()}, %% message fragment
+ ssl :: boolean() | [term()]}). %% ssl options
%% The usual transport using gen_tcp can be replaced by anything
%% sufficiently gen_tcp-like by passing a 'module' option as the first
%% (for simplicity) transport option. The transport_module diameter_etcp
@@ -122,12 +128,18 @@ i({T, Ref, Mod, Pid, Opts, Addrs})
%% that does nothing but kill us with the parent until call
%% returns.
{ok, MPid} = diameter_tcp_sup:start_child(#monitor{parent = Pid}),
- Sock = i(T, Ref, Mod, Pid, Opts, Addrs),
+ {SslOpts, Rest} = ssl(Opts),
+ Sock = i(T, Ref, Mod, Pid, SslOpts, Rest, Addrs),
MPid ! {stop, self()}, %% tell the monitor to die
- setopts(Mod, Sock),
+ M = if SslOpts -> ssl; true -> Mod end,
+ setopts(M, Sock),
+ putr(ref, Ref),
#transport{parent = Pid,
- module = Mod,
- socket = Sock};
+ module = M,
+ socket = Sock,
+ ssl = SslOpts};
+%% Put the reference in the process dictionary since we now use it
+%% advertise the ssl socket after TLS upgrade.
%% A monitor process to kill the transport if the parent dies.
i(#monitor{parent = Pid, transport = TPid} = S) ->
@@ -146,27 +158,51 @@ i({listen, LRef, APid, {Mod, Opts, Addrs}}) ->
LAddr = get_addr(LA, Addrs),
LPort = get_port(LP),
{ok, LSock} = Mod:listen(LPort, gen_opts(LAddr, Rest)),
+ true = diameter_reg:add_new({?MODULE, listener, {LRef, {LAddr, LSock}}}),
proc_lib:init_ack({ok, self(), {LAddr, LSock}}),
erlang:monitor(process, APid),
- true = diameter_reg:add_new({?MODULE, listener, {LRef, {LAddr, LSock}}}),
start_timer(#listener{socket = LSock}).
-%% i/6
+ssl(Opts) ->
+ {[SslOpts], Rest} = proplists:split(Opts, [ssl_options]),
+ {ssl_opts(SslOpts), Rest}.
+
+ssl_opts([]) ->
+ false;
+ssl_opts([{ssl_options, true}]) ->
+ true;
+ssl_opts([{ssl_options, Opts}])
+ when is_list(Opts) ->
+ Opts;
+ssl_opts(L) ->
+ ?ERROR({ssl_options, L}).
+
+%% i/7
+
+%% Establish a TLS connection before capabilities exchange ...
+i(Type, Ref, Mod, Pid, true, Opts, Addrs) ->
+ i(Type, Ref, ssl, Pid, [{cb_info, ?TCP_CB(Mod)} | Opts], Addrs);
+
+%% ... or not.
+i(Type, Ref, Mod, Pid, _, Opts, Addrs) ->
+ i(Type, Ref, Mod, Pid, Opts, Addrs).
-i(accept, Ref, Mod, Pid, Opts, Addrs) ->
+i(accept = T, Ref, Mod, Pid, Opts, Addrs) ->
{LAddr, LSock} = listener(Ref, {Mod, Opts, Addrs}),
proc_lib:init_ack({ok, self(), [LAddr]}),
Sock = ok(accept(Mod, LSock)),
+ true = diameter_reg:add_new({?MODULE, T, {Ref, Sock}}),
diameter_peer:up(Pid),
Sock;
-i(connect, _, Mod, Pid, Opts, Addrs) ->
+i(connect = T, Ref, Mod, Pid, Opts, Addrs) ->
{[LA, RA, RP], Rest} = proplists:split(Opts, [ip, raddr, rport]),
LAddr = get_addr(LA, Addrs),
RAddr = get_addr(RA, []),
RPort = get_port(RP),
proc_lib:init_ack({ok, self(), [LAddr]}),
Sock = ok(connect(Mod, RAddr, RPort, gen_opts(LAddr, Rest))),
+ true = diameter_reg:add_new({?MODULE, T, {Ref, Sock}}),
diameter_peer:up(Pid, {RAddr, RPort}),
Sock.
@@ -227,6 +263,43 @@ gen_opts(LAddr, Opts) ->
| Opts].
%% ---------------------------------------------------------------------------
+%% # ports/1
+%% ---------------------------------------------------------------------------
+
+ports() ->
+ Ts = diameter_reg:match({?MODULE, '_', '_'}),
+ [{type(T), resolve(T,S), Pid} || {{?MODULE, T, {_,S}}, Pid} <- Ts].
+
+ports(Ref) ->
+ Ts = diameter_reg:match({?MODULE, '_', {Ref, '_'}}),
+ [{type(T), resolve(T,S), Pid} || {{?MODULE, T, {R,S}}, Pid} <- Ts,
+ R == Ref].
+
+type(listener) ->
+ listen;
+type(T) ->
+ T.
+
+sock(listener, {_LAddr, Sock}) ->
+ Sock;
+sock(_, Sock) ->
+ Sock.
+
+resolve(Type, S) ->
+ Sock = sock(Type, S),
+ try
+ ok(portnr(Sock))
+ catch
+ _:_ -> Sock
+ end.
+
+portnr(Sock)
+ when is_port(Sock) ->
+ portnr(gen_tcp, Sock);
+portnr(Sock) ->
+ portnr(ssl, Sock).
+
+%% ---------------------------------------------------------------------------
%% # handle_call/3
%% ---------------------------------------------------------------------------
@@ -258,6 +331,8 @@ handle_info(T, #monitor{} = S) ->
%% # code_change/3
%% ---------------------------------------------------------------------------
+code_change(_, {transport, _, _, _, _} = S, _) ->
+ {ok, #transport{} = list_to_tuple(tuple_to_list(S) ++ [false])};
code_change(_, State, _) ->
{ok, State}.
@@ -270,6 +345,12 @@ terminate(_, _) ->
%% ---------------------------------------------------------------------------
+putr(Key, Val) ->
+ put({?MODULE, Key}, Val).
+
+getr(Key) ->
+ get({?MODULE, Key}).
+
%% start_timer/1
start_timer(#listener{count = 0} = S) ->
@@ -332,17 +413,56 @@ t(T,S) ->
%% transition/2
+%% Initial incoming message when we might need to upgrade to TLS:
+%% don't request another message until we know.
+transition({tcp, Sock, Bin}, #transport{socket = Sock,
+ parent = Pid,
+ frag = Head,
+ module = M,
+ ssl = Opts}
+ = S)
+ when is_list(Opts) ->
+ case recv1(Head, Bin) of
+ {Msg, B} when is_binary(Msg) ->
+ diameter_peer:recv(Pid, Msg),
+ S#transport{frag = B};
+ Frag ->
+ setopts(M, Sock),
+ S#transport{frag = Frag}
+ end;
+
%% Incoming message.
-transition({tcp, Sock, Data}, #transport{socket = Sock,
- module = M}
- = S) ->
+transition({P, Sock, Bin}, #transport{socket = Sock,
+ module = M,
+ ssl = B}
+ = S)
+ when P == tcp, not B;
+ P == ssl, B ->
+ setopts(M, Sock),
+ recv(Bin, S);
+
+%% Capabilties exchange has decided on whether or not to run over TLS.
+transition({diameter, {tls, Ref, Type, B}}, #transport{parent = Pid}
+ = S) ->
+ #transport{socket = Sock,
+ module = M}
+ = NS
+ = tls_handshake(Type, B, S),
+ Pid ! {diameter, {tls, Ref}},
setopts(M, Sock),
- recv(Data, S);
+ NS#transport{ssl = B};
-transition({tcp_closed, Sock}, #transport{socket = Sock}) ->
+transition({C, Sock}, #transport{socket = Sock,
+ ssl = B})
+ when C == tcp_closed, not B;
+ C == ssl_closed, B ->
stop;
-transition({tcp_error, Sock, _Reason} = T, #transport{socket = Sock} = S) ->
+transition({E, Sock, _Reason} = T, #transport{socket = Sock,
+ ssl = B}
+ = S)
+ when E == tcp_error, not B;
+ E == ssl_error, B ->
?ERROR({T,S});
%% Outgoing message.
@@ -367,10 +487,10 @@ transition({timeout, TRef, flush}, S) ->
flush(TRef, S);
%% Request for the local port number.
-transition({resolve_port, RPid}, #transport{socket = Sock,
- module = M})
- when is_pid(RPid) ->
- RPid ! lport(M, Sock),
+transition({resolve_port, Pid}, #transport{socket = Sock,
+ module = M})
+ when is_pid(Pid) ->
+ Pid ! portnr(M, Sock),
ok;
%% Parent process has died.
@@ -379,80 +499,122 @@ transition({'DOWN', _, process, Pid, _}, #transport{parent = Pid}) ->
%% Crash on anything unexpected.
+%% tls_handshake/3
+%%
+%% In the case that no tls message is received (eg. the service hasn't
+%% been configured to advertise TLS support) we will simply never ask
+%% for another TCP message, which will force the watchdog to
+%% eventually take us down.
+
+%% TLS has already been established with the connection.
+tls_handshake(_, _, #transport{ssl = true} = S) ->
+ S;
+
+%% Capabilities exchange negotiated TLS but transport was not
+%% configured with an options list.
+tls_handshake(_, true, #transport{ssl = false}) ->
+ ?ERROR(no_ssl_options);
+
+%% Capabilities exchange negotiated TLS: upgrade the connection.
+tls_handshake(Type, true, #transport{socket = Sock,
+ module = M,
+ ssl = Opts}
+ = S) ->
+ {ok, SSock} = tls(Type, Sock, [{cb_info, ?TCP_CB(M)} | Opts]),
+ Ref = getr(ref),
+ is_reference(Ref) %% started in new code
+ andalso
+ (true = diameter_reg:add_new({?MODULE, Type, {Ref, SSock}})),
+ S#transport{socket = SSock,
+ module = ssl};
+
+%% Capabilities exchange has not negotiated TLS.
+tls_handshake(_, false, S) ->
+ S.
+
+tls(connect, Sock, Opts) ->
+ ssl:connect(Sock, Opts);
+tls(accept, Sock, Opts) ->
+ ssl:ssl_accept(Sock, Opts).
+
%% recv/2
%%
%% Reassemble fragmented messages and extract multple message sent
%% using Nagle.
recv(Bin, #transport{parent = Pid, frag = Head} = S) ->
- S#transport{frag = recv(Pid, Head, Bin)}.
+ case recv1(Head, Bin) of
+ {Msg, B} when is_binary(Msg) ->
+ diameter_peer:recv(Pid, Msg),
+ recv(B, S#transport{frag = <<>>});
+ Frag ->
+ S#transport{frag = Frag}
+ end.
-%% recv/3
+%% recv1/2
%% No previous fragment.
-recv(Pid, <<>>, Bin) ->
- rcv(Pid, Bin);
+recv1(<<>>, Bin) ->
+ rcv(Bin);
-recv(Pid, {TRef, Head}, Bin) ->
+recv1({TRef, Head}, Bin) ->
erlang:cancel_timer(TRef),
- rcv(Pid, Head, Bin).
+ rcv(Head, Bin).
-%% rcv/3
+%% rcv/2
%% Not even the first four bytes of the header.
-rcv(Pid, Head, Bin)
+rcv(Head, Bin)
when is_binary(Head) ->
- rcv(Pid, <<Head/binary, Bin/binary>>);
+ rcv(<<Head/binary, Bin/binary>>);
%% Or enough to know how many bytes to extract.
-rcv(Pid, {Len, N, Head, Acc}, Bin) ->
- rcv(Pid, Len, N + size(Bin), Head, [Bin | Acc]).
+rcv({Len, N, Head, Acc}, Bin) ->
+ rcv(Len, N + size(Bin), Head, [Bin | Acc]).
-%% rcv/5
+%% rcv/4
%% Extract a message for which we have all bytes.
-rcv(Pid, Len, N, Head, Acc)
+rcv(Len, N, Head, Acc)
when Len =< N ->
- rcv(Pid, rcv1(Pid, Len, bin(Head, Acc)));
+ rcv1(Len, bin(Head, Acc));
%% Wait for more packets.
-rcv(_, Len, N, Head, Acc) ->
+rcv(Len, N, Head, Acc) ->
{start_timer(), {Len, N, Head, Acc}}.
%% rcv/2
%% Nothing left.
-rcv(_, <<>> = Bin) ->
+rcv(<<>> = Bin) ->
Bin;
%% Well, this isn't good. Chances are things will go south from here
%% but if we're lucky then the bytes we have extend to an intended
%% message boundary and we can recover by simply discarding them,
%% which is the result of receiving them.
-rcv(Pid, <<_:1/binary, Len:24, _/binary>> = Bin)
+rcv(<<_:1/binary, Len:24, _/binary>> = Bin)
when Len < 20 ->
- diameter_peer:recv(Pid, Bin),
- <<>>;
+ {Bin, <<>>};
%% Enough bytes to extract a message.
-rcv(Pid, <<_:1/binary, Len:24, _/binary>> = Bin)
+rcv(<<_:1/binary, Len:24, _/binary>> = Bin)
when Len =< size(Bin) ->
- rcv(Pid, rcv1(Pid, Len, Bin));
+ rcv1(Len, Bin);
%% Or not: wait for more packets.
-rcv(_, <<_:1/binary, Len:24, _/binary>> = Head) ->
+rcv(<<_:1/binary, Len:24, _/binary>> = Head) ->
{start_timer(), {Len, size(Head), Head, []}};
%% Not even 4 bytes yet.
-rcv(_, Head) ->
+rcv(Head) ->
{start_timer(), Head}.
-%% rcv1/3
+%% rcv1/2
-rcv1(Pid, Len, Bin) ->
+rcv1(Len, Bin) ->
<<Msg:Len/binary, Rest/binary>> = Bin,
- diameter_peer:recv(Pid, Msg),
- Rest.
+ {Msg, Rest}.
%% bin/[12]
@@ -489,15 +651,18 @@ flush(_, S) ->
%% accept/2
-accept(gen_tcp, LSock) ->
- gen_tcp:accept(LSock);
+accept(ssl, LSock) ->
+ case ssl:transport_accept(LSock) of
+ {ok, Sock} ->
+ {ssl:ssl_accept(Sock), Sock};
+ {error, _} = No ->
+ No
+ end;
accept(Mod, LSock) ->
Mod:accept(LSock).
%% connect/4
-connect(gen_tcp, Host, Port, Opts) ->
- gen_tcp:connect(Host, Port, Opts);
connect(Mod, Host, Port, Opts) ->
Mod:connect(Host, Port, Opts).
@@ -505,6 +670,8 @@ connect(Mod, Host, Port, Opts) ->
send(gen_tcp, Sock, Bin) ->
gen_tcp:send(Sock, Bin);
+send(ssl, Sock, Bin) ->
+ ssl:send(Sock, Bin);
send(M, Sock, Bin) ->
M:send(Sock, Bin).
@@ -512,6 +679,8 @@ send(M, Sock, Bin) ->
setopts(gen_tcp, Sock, Opts) ->
inet:setopts(Sock, Opts);
+setopts(ssl, Sock, Opts) ->
+ ssl:setopts(Sock, Opts);
setopts(M, Sock, Opts) ->
M:setopts(Sock, Opts).
@@ -523,9 +692,16 @@ setopts(M, Sock) ->
X -> x({setopts, M, Sock, X}) %% possibly on peer disconnect
end.
-%% lport/2
+%% portnr/2
-lport(gen_tcp, Sock) ->
+portnr(gen_tcp, Sock) ->
inet:port(Sock);
-lport(M, Sock) ->
+portnr(ssl, Sock) ->
+ case ssl:sockname(Sock) of
+ {ok, {_Addr, PortNr}} ->
+ {ok, PortNr};
+ {error, _} = No ->
+ No
+ end;
+portnr(M, Sock) ->
M:port(Sock).
diff --git a/lib/diameter/src/transport/modules.mk b/lib/diameter/src/transport/modules.mk
deleted file mode 100644
index a0dc3cf2c0..0000000000
--- a/lib/diameter/src/transport/modules.mk
+++ /dev/null
@@ -1,29 +0,0 @@
-#-*-makefile-*- ; force emacs to enter makefile-mode
-
-# %CopyrightBegin%
-#
-# Copyright Ericsson AB 2010-2011. All Rights Reserved.
-#
-# The contents of this file are subject to the Erlang Public License,
-# Version 1.1, (the "License"); you may not use this file except in
-# compliance with the License. You should have received a copy of the
-# Erlang Public License along with this software. If not, it can be
-# retrieved online at http://www.erlang.org/.
-#
-# Software distributed under the License is distributed on an "AS IS"
-# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
-# the License for the specific language governing rights and limitations
-# under the License.
-#
-# %CopyrightEnd%
-
-MODULES = \
- diameter_etcp \
- diameter_etcp_sup \
- diameter_tcp \
- diameter_tcp_sup \
- diameter_sctp \
- diameter_sctp_sup \
- diameter_transport_sup
-
-HRL_FILES =
diff --git a/lib/diameter/test/Makefile b/lib/diameter/test/Makefile
index dba1f126dc..97d9069f4a 100644
--- a/lib/diameter/test/Makefile
+++ b/lib/diameter/test/Makefile
@@ -17,15 +17,13 @@
# %CopyrightEnd%
ifeq ($(ERL_TOP),)
-TOP = $(DIAMETER_TOP)
+include $(DIAMETER_TOP)/make/target.mk
+include $(DIAMETER_TOP)/make/$(TARGET)/rules.mk
else
-TOP = $(ERL_TOP)
-DIAMETER_TOP = $(TOP)/lib/diameter
+include $(ERL_TOP)/make/target.mk
+include $(ERL_TOP)/make/$(TARGET)/otp.mk
endif
-include $(TOP)/make/target.mk
-include $(TOP)/make/$(TARGET)/otp.mk
-
# ----------------------------------------------------
# Application version
# ----------------------------------------------------
@@ -46,38 +44,32 @@ RELSYSDIR = $(RELEASE_PATH)/diameter_test
include modules.mk
-EBIN = .
-
-HRL_FILES = $(INTERNAL_HRL_FILES)
-ERL_FILES = $(MODULES:%=%.erl)
-
-SOURCE = $(HRL_FILES) $(ERL_FILES)
+ERL_FILES = $(MODULES:%=%.erl)
TARGET_FILES = $(MODULES:%=%.$(EMULATOR))
SUITE_MODULES = $(filter diameter_%_SUITE, $(MODULES))
-SUITES = $(SUITE_MODULES:diameter_%_SUITE=%)
-
-RELTEST_FILES = $(TEST_SPEC_FILE) $(COVER_SPEC_FILE) $(SOURCE)
+SUITES = $(SUITE_MODULES:diameter_%_SUITE=%)
# ----------------------------------------------------
# FLAGS
# ----------------------------------------------------
-include ../src/app/diameter.mk
-
# This is only used to compile suite locally when running with a
# target like 'all' below. Target release_tests only installs source.
-ERL_COMPILE_FLAGS += $(DIAMETER_ERL_COMPILE_FLAGS) \
- -DDIAMETER_CT=true \
- -I $(DIAMETER_TOP)/src/app
+ERL_COMPILE_FLAGS += +warn_export_vars \
+ +warn_unused_vars \
+ -I ../include \
+ -I ../src/gen
# ----------------------------------------------------
# Targets
# ----------------------------------------------------
-all: $(SUITES)
+all: opt
-tests debug opt: $(TARGET_FILES)
+run: $(SUITES)
+
+debug opt: $(TARGET_FILES)
clean:
rm -f $(TARGET_FILES)
@@ -85,65 +77,55 @@ clean:
realclean: clean
rm -rf log
- rm -f errs core *~
-
-.PHONY: all tests debug opt clean realclean
docs:
+list = echo $(1):; echo $($(1)) | tr ' ' '\n' | sort | sed 's@^@ @'
+
info:
- @echo "TARGET_FILES = $(TARGET_FILES)"
- @echo
- @echo "ERL_COMPILE_FLAGS = $(ERL_COMPILE_FLAGS)"
- @echo "ERL = $(ERL)"
- @echo "ERLC = $(ERLC)"
- @echo
- @echo "HRL_FILES = $(HRL_FILES)"
- @echo "ERL_FILES = $(ERL_FILES)"
- @echo "TARGET_FILES = $(TARGET_FILES)"
+ @echo ========================================
+ @$(call list,MODULES)
@echo
- @echo "SUITE_MODULES = $(SUITE_MODULES)"
- @echo "SUITES = $(SUITES)"
+ @$(call list,HRL_FILES)
@echo
+ @$(call list,SUITES)
+ @echo ========================================
help:
+ @echo ========================================
+ @echo "Useful targets:"
@echo
- @echo "Targets:"
+ @echo " all:"
+ @echo " Compile all test suites."
@echo
- @echo " all"
- @echo " Run all test suites."
+ @echo " run:"
+ @echo " Compile and run all test suites."
@echo
- @echo " $(SUITES)"
- @echo " Run a specific test suite."
+ @echo " $(SUITES):"
+ @echo " Compile and run a specific test suite."
@echo
- @echo " tests"
- @echo " Compile all test-code."
- @echo
- @echo " clean | realclean"
+ @echo " clean | realclean:"
@echo " Remove generated files."
@echo
- @echo " info"
- @echo " Prints various environment variables."
- @echo " May be useful when debugging this Makefile."
- @echo
- @echo " help"
- @echo " Print this info."
- @echo
+ @echo " info:"
+ @echo " Echo some relevant variables."
+ @echo ========================================
-.PHONY: docs info help
+.PHONY: all run clean debug docs help info opt realclean
# ----------------------------------------------------
# Special Targets
# ----------------------------------------------------
# Exit with a non-zero status if the output looks to indicate failure.
-# diameter_ct:run/1 itself can't tell (it seems).
-$(SUITES): log tests
+# diameter_ct:run/1 itself can't tell (it seems). The absolute -pa is
+# because ct will change directories.
+$(SUITES): log opt
$(ERL) -noshell \
- -pa $(DIAMETER_TOP)/ebin \
- -sname diameter_test_$@ \
- -s diameter_ct run diameter_$@_SUITE \
- -s init stop \
+ -pa $(realpath ../ebin) \
+ -sname diameter_test_$@ \
+ -s diameter_ct run diameter_$@_SUITE \
+ -s init stop \
| awk '1{rc=0} {print} / FAILED /{rc=1} END{exit rc}'
# Shorter in sed but requires a GNU extension (ie. Q).
@@ -156,7 +138,14 @@ log:
# Release Targets
# ----------------------------------------------------
-include $(TOP)/make/otp_release_targets.mk
+/%: % force
+ sed -f release.sed $< > $(RELSYSDIR)$@
+
+ifeq ($(ERL_TOP),)
+include $(DIAMETER_TOP)/make/release_targets.mk
+else
+include $(ERL_TOP)/make/otp_release_targets.mk
+endif
release_spec:
@@ -164,9 +153,19 @@ release_docs_spec:
release_tests_spec:
$(INSTALL_DIR) $(RELSYSDIR)
- $(INSTALL_DATA) $(RELTEST_FILES) $(RELSYSDIR)
+ $(INSTALL_DATA) $(TEST_SPEC_FILE) \
+ $(COVER_SPEC_FILE) \
+ $(HRL_FILES) \
+ $(RELSYSDIR)
+ $(MAKE) $(ERL_FILES:%=/%)
+
+force:
.PHONY: release_spec release_docs_spec release_test_specs
+.PHONY: force
+
+# Can't just make $(ERL_FILES:%=/%) phony since then implicit rule
+# searching is skipped.
# ----------------------------------------------------
@@ -175,7 +174,7 @@ depend: depend.mk
# Generate dependencies makefile.
depend.mk: depend.sed $(MODULES:%=%.erl) Makefile
(for f in $(MODULES); do \
- sed -f $< $$f.erl | sed "s@/@/$$f@"; \
+ (echo $$f; cat $$f.erl) | sed -f $<; \
done) \
> $@
diff --git a/lib/diameter/test/depend.sed b/lib/diameter/test/depend.sed
index a399eb45f0..95dca44984 100644
--- a/lib/diameter/test/depend.sed
+++ b/lib/diameter/test/depend.sed
@@ -18,14 +18,24 @@
#
#
-# Extract local include dependencies from .erl files. The output is massaged
-# further in Makefile.
+# Extract local include dependencies from an .erl file. The first
+# input line is the module name.
#
-/^-include/!d
+# Store the module name in the hold space.
+1{
+ h
+ d
+}
+
+# Throw away everything but local includes.
/^-include_lib/d
+/^-include/!d
/diameter_gen/d
+/diameter\./d
+# Output a dependency of the beam on the included file.
s@^-include("@@
s@".*@@
-s@^@$(EBIN)/.$(EMULATOR): @
+G
+s@^\(.*\)\n\(.*\)@$(EBIN)/\2.$(EMULATOR): \1@
diff --git a/lib/diameter/test/diameter_app_SUITE.erl b/lib/diameter/test/diameter_app_SUITE.erl
index 104785b4e6..7f53a4ddd4 100644
--- a/lib/diameter/test/diameter_app_SUITE.erl
+++ b/lib/diameter/test/diameter_app_SUITE.erl
@@ -98,6 +98,7 @@ modules(Config) ->
diameter_dbg,
diameter_exprecs,
diameter_info,
+ diameter_make,
diameter_spec_scan,
diameter_spec_util],
{[], Help} = {Mods -- Installed, lists:sort(Installed -- Mods)}.
@@ -133,13 +134,16 @@ release(Config) ->
Rel = {release,
{"diameter test release", fetch(vsn, App)},
{erts, erlang:system_info(version)},
- [{A, appvsn(A)} || A <- fetch(applications, App)]},
+ [{A, appvsn(A)} || A <- [sasl | fetch(applications, App)]]},
Dir = fetch(priv_dir, Config),
ok = write_file(filename:join([Dir, "diameter_test.rel"]), Rel),
{ok, _, []} = systools:make_script("diameter_test", [{path, [Dir]},
{outdir, Dir},
silent]).
+%% sasl need to be included to avoid a missing_sasl warning, error
+%% in the case of relup/1.
+
appvsn(Name) ->
[{application, Name, App}] = diameter_util:consult(Name, app),
fetch(vsn, App).
@@ -147,14 +151,13 @@ appvsn(Name) ->
%% ===========================================================================
%% # xref/1
%%
-%% Ensure that no function in our application calls an undefined function.
+%% Ensure that no function in our application calls an undefined function
+%% or one in an application we haven't specified as a dependency. (Almost.)
%% ===========================================================================
xref(Config) ->
App = fetch(app, Config),
- Mods = fetch(modules, App) -- [diameter_codegen, diameter_dbg],
- %% Skip modules that aren't required at runtime and that have
- %% dependencies beyond those applications listed in the app file.
+ Mods = fetch(modules, App),
{ok, XRef} = xref:start(make_name(xref_test_name)),
ok = xref:set_default(XRef, [{verbose, false}, {warnings, false}]),
@@ -164,7 +167,10 @@ xref(Config) ->
%% stop xref from complaining about calls to module erlang, which
%% was previously in kernel. Erts isn't an application however, in
%% the sense that there's no .app file, and isn't listed in
- %% applications. Seems less than ideal.
+ %% applications. Seems less than ideal. Also, diameter_tcp does
+ %% call ssl despite ssl not being listed as a dependency in the
+ %% app file since ssl is only required for TLS security: it's up
+ %% to a client who wants TLS it to start ssl.
ok = lists:foreach(fun(A) -> add_application(XRef, A) end,
[?APP, erts | fetch(applications, App)]),
@@ -173,7 +179,11 @@ xref(Config) ->
xref:stop(XRef),
%% Only care about calls from our own application.
- [] = lists:filter(fun({{M,_,_},_}) -> lists:member(M, Mods) end, Undefs).
+ [] = lists:filter(fun({{F,_,_},{T,_,_}}) ->
+ lists:member(F, Mods)
+ andalso {F,T} /= {diameter_tcp, ssl}
+ end,
+ Undefs).
add_application(XRef, App) ->
add_application(XRef, App, code:lib_dir(App)).
@@ -201,7 +211,7 @@ relup(Config) ->
App = fetch(app, Config),
Rel = [{erts, erlang:system_info(version)}
- | [{A, appvsn(A)} || A <- fetch(applications, App)]],
+ | [{A, appvsn(A)} || A <- [sasl | fetch(applications, App)]]],
Dir = fetch(priv_dir, Config),
@@ -209,12 +219,15 @@ relup(Config) ->
UpFrom = acc_rel(Dir, Rel, Up),
DownTo = acc_rel(Dir, Rel, Down),
- {[Name], [Name], UpFrom, DownTo} %% no intersections
+ {[Name], [Name], [], []} %% no current in up/down and go both ways
= {[Name] -- UpFrom,
[Name] -- DownTo,
UpFrom -- DownTo,
DownTo -- UpFrom},
+ [[], []] = [S -- sets:to_list(sets:from_list(S))
+ || S <- [UpFrom, DownTo]],
+
{ok, _, _, []} = systools:make_relup(Name, UpFrom, DownTo, [{path, [Dir]},
{outdir, Dir},
silent]).
diff --git a/lib/diameter/test/diameter_capx_SUITE.erl b/lib/diameter/test/diameter_capx_SUITE.erl
new file mode 100644
index 0000000000..e6b1558bf6
--- /dev/null
+++ b/lib/diameter/test/diameter_capx_SUITE.erl
@@ -0,0 +1,432 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2010-2011. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+%% Tests of capabilities exchange between Diameter nodes. In
+%% particular, of error and event handling.
+%%
+
+-module(diameter_capx_SUITE).
+
+-export([suite/0,
+ all/0,
+ groups/0,
+ init_per_group/2,
+ end_per_group/2,
+ init_per_testcase/2,
+ end_per_testcase/2]).
+
+%% testcases
+-export([start/1,
+ start_services/1,
+ add_listeners/1,
+ s_no_common_application/1,
+ c_no_common_application/1,
+ s_no_common_security/1,
+ c_no_common_security/1,
+ s_unknown_peer/1,
+ c_unknown_peer/1,
+ s_unable/1,
+ c_unable/1,
+ s_client_reject/1,
+ c_client_reject/1,
+ remove_listeners/1,
+ stop_services/1,
+ stop/1]).
+
+%% diameter callbacks
+-export([peer_up/4,
+ peer_down/4]).
+
+-include("diameter.hrl").
+-include("diameter_gen_base_rfc3588.hrl").
+
+%% ===========================================================================
+
+-define(util, diameter_util).
+
+-define(CLIENT, client).
+-define(SERVER, server).
+
+-define(ADDR, {127,0,0,1}).
+
+-define(REALM, "erlang.org").
+-define(HOST(Name), Name ++ "." ++ ?REALM).
+
+%% Config for diameter:start_service/2.
+-define(SERVICE(Name),
+ [{'Origin-Realm', ?REALM},
+ {'Host-IP-Address', [?ADDR]},
+ {'Vendor-Id', 12345},
+ {'Product-Name', "OTP/diameter"},
+ {'Auth-Application-Id', [?DIAMETER_APP_ID_COMMON]},
+ {'Acct-Application-Id', [?DIAMETER_APP_ID_ACCOUNTING]}
+ | [{application, [{alias, A},
+ {dictionary, D},
+ {module, [?MODULE, A]}]}
+ || {A,D} <- [{common, ?DIAMETER_DICT_COMMON},
+ {accounting, ?DIAMETER_DICT_ACCOUNTING}]]]).
+
+-define(A, list_to_atom).
+-define(L, atom_to_list).
+
+-define(event, #diameter_event).
+-define(caps, #diameter_caps).
+-define(packet, #diameter_packet).
+
+-define(cea, #diameter_base_CEA).
+-define(answer_message, #'diameter_base_answer-message').
+
+%% ===========================================================================
+
+suite() ->
+ [{timetrap, {seconds, 10}}].
+
+all() ->
+ [start, start_services, add_listeners
+ | [{group, N} || {N, _, _} <- groups()]]
+ ++ [remove_listeners, stop_services, stop].
+
+groups() ->
+ Ts = testcases(),
+ [{grp(P), P, Ts} || P <- [[], [parallel]]].
+
+grp([]) ->
+ sequential;
+grp([parallel = P]) ->
+ P.
+
+init_per_group(_Name, Config) ->
+ Config.
+
+end_per_group(_, _) ->
+ ok.
+
+%% Generate a unique hostname for each testcase so that watchdogs
+%% don't prevent a connection from being brought up immediately.
+init_per_testcase(Name, Config) ->
+ Uniq = ["." ++ integer_to_list(N) || N <- tuple_to_list(now())],
+ [{host, lists:flatten([?L(Name) | Uniq])} | Config].
+
+end_per_testcase(N, _)
+ when N == start;
+ N == start_services;
+ N == add_listeners;
+ N == remove_listeners;
+ N == stop_services;
+ N == stop ->
+ ok;
+end_per_testcase(Name, Config) ->
+ CRef = ?util:read_priv(Config, Name),
+ ok = diameter:remove_transport(?CLIENT, CRef).
+
+%% Testcases all come in two flavours, client and server.
+testcases() ->
+ lists:flatmap(fun tc/1, tc()).
+
+tc(Name) ->
+ [?A([C,$_|?L(Name)]) || C <- "cs"].
+
+tc() ->
+ [no_common_application,
+ no_common_security,
+ unknown_peer,
+ unable,
+ client_reject].
+
+%% ===========================================================================
+%% start/stop testcases
+
+start(_Config) ->
+ ok = diameter:start().
+
+start_services(_Config) ->
+ ok = diameter:start_service(?SERVER, ?SERVICE(?SERVER)),
+ ok = diameter:start_service(?CLIENT, ?SERVICE(?CLIENT)).
+
+%% One server that responds only to base accounting, one that responds
+%% to both this and the common application. Share a common service just
+%% to simplify config, and because we can.
+add_listeners(Config) ->
+ Acct = listen(?SERVER,
+ [{capabilities, [{'Origin-Host', ?HOST("acct-srv")},
+ {'Auth-Application-Id', []}]},
+ {applications, [accounting]},
+ {capabilities_cb, [fun server_capx/3, acct]}]),
+ Base = listen(?SERVER,
+ [{capabilities, [{'Origin-Host', ?HOST("base-srv")}]},
+ {capabilities_cb, [fun server_capx/3, base]}]),
+ ?util:write_priv(Config, ?MODULE, {Base, Acct}). %% lref/2 reads
+
+remove_listeners(_Config) ->
+ ok = diameter:remove_transport(?SERVER, true).
+
+stop_services(_Config) ->
+ ok = diameter:stop_service(?CLIENT),
+ ok = diameter:stop_service(?SERVER).
+
+stop(_Config) ->
+ ok = diameter:stop().
+
+%% ===========================================================================
+%% All the testcases come in pairs, one for receiving an event on the
+%% client side, one on the server side. Note that testcases will
+%% receive events resulting from other testcases when running in
+%% parallel since the events are per service. The unique client
+%% Origin-Host for each testcase plus transport references are used to
+%% ensure that only the relevant event is extracted from the mailbox.
+%% Don't bother extracting events that aren't relevant.
+
+%% ====================
+%% Ask the accounting server to speak the common application and expect
+%% DIAMETER_NO_COMMON_APPLICATION = 5010.
+
+s_no_common_application(Config) ->
+ server_closed(Config, fun no_common_application/1, 5010).
+
+c_no_common_application(Config) ->
+ client_closed(Config, "acct-srv", fun no_common_application/1, 5010).
+
+no_common_application(Config) ->
+ connect(Config, acct, [{capabilities, [{'Acct-Application-Id', []}]},
+ {applications, [common]}]).
+
+%% ====================
+%% Ask the base server to speak accounting with an unknown security
+%% method and expect DIAMETER_NO_COMMON_SECURITY = 5017.
+
+s_no_common_security(Config) ->
+ server_closed(Config, fun no_common_security/1, 5017).
+
+c_no_common_security(Config) ->
+ client_closed(Config, "base-srv", fun no_common_security/1, 5017).
+
+no_common_security(Config) ->
+ connect(Config, base, [{capabilities, [{'Acct-Application-Id', []},
+ {'Inband-Security-Id', [17, 18]}]},
+ {applications, [common]}]).
+
+%% ====================
+%% Have the base server reject a decent CER with the protocol error
+%% DIAMETER_UNKNOWN_PEER = 3010.
+
+s_unknown_peer(Config) ->
+ server_reject(Config, fun base/1, 3010).
+
+c_unknown_peer(Config) ->
+ true = diameter:subscribe(?CLIENT),
+ OH = ?HOST("base-srv"),
+
+ {CRef, _} = base(Config),
+
+ {'CEA', ?caps{},
+ ?packet{msg = ?answer_message{'Origin-Host' = OH,
+ 'Result-Code' = 3010}}}
+ = client_recv(CRef).
+
+base(Config) ->
+ connect(Config, base, []).
+
+%% ====================
+%% Have the base server reject a decent CER with the non-protocol
+%% error DIAMETER_UNABLE_TO_COMPLY = 5012.
+
+s_unable(Config) ->
+ server_reject(Config, fun base/1, 5012).
+
+c_unable(Config) ->
+ client_closed(Config, "base-srv", fun base/1, 5012).
+
+%% ====================
+%% Have the client reject a decent CEA.
+
+s_client_reject(Config) ->
+ true = diameter:subscribe(?SERVER),
+ OH = host(Config),
+
+ {_, LRef} = client_reject(Config),
+
+ receive
+ ?event{service = ?SERVER,
+ info = {up, LRef,
+ {_, ?caps{origin_host = {_, OH}}},
+ {listen, _},
+ ?packet{}}}
+ = Info ->
+ Info
+ after 2000 ->
+ fail({LRef, OH})
+ end.
+
+c_client_reject(Config) ->
+ true = diameter:subscribe(?CLIENT),
+ OH = ?HOST("acct-srv"),
+
+ {CRef, _} = client_reject(Config),
+
+ {'CEA', {capabilities_cb, _, discard},
+ ?caps{origin_host = {_, OH}},
+ ?packet{msg = ?cea{'Result-Code' = 2001}}}
+ = client_recv(CRef).
+
+client_reject(Config) ->
+ connect(Config, acct, [{capabilities_cb, fun client_capx/2}]).
+
+%% ===========================================================================
+
+%% server_closed/3
+
+server_closed(Config, F, RC) ->
+ true = diameter:subscribe(?SERVER),
+ OH = host(Config),
+
+ {_, LRef} = F(Config),
+
+ receive
+ ?event{service = ?SERVER,
+ info = {closed, LRef,
+ {'CER', RC,
+ ?caps{origin_host = {_, OH}},
+ ?packet{}}
+ = Reason,
+ {listen, _}}} ->
+ Reason
+ after 2000 ->
+ fail({LRef, OH})
+ end.
+
+%% server_reject/3
+
+server_reject(Config, F, RC) ->
+ true = diameter:subscribe(?SERVER),
+ OH = host(Config),
+
+ {_, LRef} = F(Config),
+
+ receive
+ ?event{service = ?SERVER,
+ info = {closed, LRef,
+ {'CER', {capabilities_cb, _, RC},
+ ?caps{origin_host = {_, OH}},
+ ?packet{}}
+ = Reason,
+ {listen, _}}} ->
+ Reason
+ after 2000 ->
+ fail({LRef, OH})
+ end.
+
+%% cliient_closed/4
+
+client_closed(Config, Host, F, RC) ->
+ true = diameter:subscribe(?CLIENT),
+ OH = ?HOST(Host),
+
+ {CRef, _} = F(Config),
+
+ {'CEA', RC, ?caps{origin_host = {_, OH}}, ?packet{}}
+ = client_recv(CRef).
+
+%% client_recv/1
+
+client_recv(CRef) ->
+ receive
+ ?event{service = ?CLIENT,
+ info = {closed, CRef, Reason, {connect, _}}} ->
+ Reason
+ after 2000 ->
+ fail(CRef)
+ end.
+
+%% server_capx/3
+
+server_capx(_, ?caps{origin_host = {_, [_,$_|"unknown_peer." ++ _]}}, _) ->
+ unknown;
+
+server_capx(_, ?caps{origin_host = {_, [_,$_|"unable." ++ _]}}, _) ->
+ 5012; %% DIAMETER_UNABLE_TO_COMPLY
+
+server_capx(_, ?caps{origin_host = {OH,DH}}, _) ->
+ io:format("connection: ~p -> ~p~n", [DH,OH]),
+ ok.
+
+%% client_capx/2
+
+client_capx(_, ?caps{origin_host = {[_,$_|"client_reject." ++ _], _}}) ->
+ discard.
+
+%% ===========================================================================
+
+fail(T) ->
+ erlang:error({T, process_info(self(), messages)}).
+
+host(Config) ->
+ {_, H} = lists:keyfind(host, 1, Config),
+ ?HOST(H).
+
+listen(Name, Opts) ->
+ ?util:listen(Name, tcp, Opts).
+
+connect(Config, T, Opts) ->
+ {_, H} = lists:keyfind(host, 1, Config),
+ LRef = lref(Config, T),
+ CRef = connect(LRef, [{capabilities, [{'Origin-Host', ?HOST(H)}]}
+ | Opts]),
+ Name = lists:takewhile(fun(C) -> C /= $. end, H),
+ ?util:write_priv(Config, Name, CRef), %% end_per_testcase reads
+ {CRef, LRef}.
+
+connect(LRef, Opts) ->
+ [PortNr] = ?util:lport(tcp, LRef, 20),
+ {ok, CRef} = diameter:add_transport(?CLIENT,
+ {connect, opts(PortNr, Opts)}),
+ CRef.
+
+opts(PortNr, Opts) ->
+ [{transport_module, diameter_tcp},
+ {transport_config, [{raddr, ?ADDR},
+ {rport, PortNr},
+ {ip, ?ADDR},
+ {port, 0}]}
+ | Opts].
+
+lref(Config, T) ->
+ case ?util:read_priv(Config, ?MODULE) of
+ {LRef, _} when T == base ->
+ LRef;
+ {_, LRef} when T == acct ->
+ LRef
+ end.
+
+%% ===========================================================================
+%% diameter callbacks
+
+peer_up(?SERVER,
+ {_, ?caps{origin_host = {"acct-srv." ++ _,
+ [_,$_|"client_reject." ++ _]}}},
+ State,
+ _) ->
+ State.
+
+peer_down(?SERVER,
+ {_, ?caps{origin_host = {"acct-srv." ++ _,
+ [_,$_|"client_reject." ++ _]}}},
+ State,
+ _) ->
+ State.
diff --git a/lib/diameter/test/diameter_codec_test.erl b/lib/diameter/test/diameter_codec_test.erl
index aab7ab35cc..8046ca4c04 100644
--- a/lib/diameter/test/diameter_codec_test.erl
+++ b/lib/diameter/test/diameter_codec_test.erl
@@ -25,7 +25,7 @@
%% Test encode/decode of dictionary-related modules.
%%
--include_lib("diameter/include/diameter.hrl").
+-include("diameter.hrl").
-define(BASE, diameter_gen_base_rfc3588).
-define(BOOL, [true, false]).
diff --git a/lib/diameter/test/diameter_failover_SUITE.erl b/lib/diameter/test/diameter_failover_SUITE.erl
new file mode 100644
index 0000000000..f4d62f94c6
--- /dev/null
+++ b/lib/diameter/test/diameter_failover_SUITE.erl
@@ -0,0 +1,257 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2010-2011. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+%% Tests of traffic between six Diameter nodes in three realms,
+%% connected as follows.
+%%
+%% ----- SERVER1.REALM2
+%% /
+%% / ----- SERVER2.REALM2
+%% | /
+%% CLIENT.REALM1 ------ SERVER3.REALM2
+%% | \
+%% | \
+%% \ ---- SERVER1.REALM3
+%% \
+%% ----- SERVER2.REALM3
+%%
+
+-module(diameter_failover_SUITE).
+
+-export([suite/0,
+ all/0]).
+
+%% testcases
+-export([start/1,
+ start_services/1,
+ connect/1,
+ send_ok/1,
+ send_nok/1,
+ stop_services/1,
+ stop/1]).
+
+%% diameter callbacks
+-export([peer_up/3,
+ peer_down/3,
+ pick_peer/4,
+ prepare_request/3,
+ prepare_retransmit/3,
+ handle_answer/4,
+ handle_error/4,
+ handle_request/3]).
+
+-include("diameter.hrl").
+-include("diameter_gen_base_rfc3588.hrl").
+-include("diameter_ct.hrl").
+
+%% ===========================================================================
+
+-define(util, diameter_util).
+
+-define(ADDR, {127,0,0,1}).
+
+-define(CLIENT, "CLIENT.REALM1").
+-define(SERVER1, "SERVER1.REALM2").
+-define(SERVER2, "SERVER2.REALM2").
+-define(SERVER3, "SERVER3.REALM2").
+-define(SERVER4, "SERVER1.REALM3").
+-define(SERVER5, "SERVER2.REALM3").
+
+-define(SERVICES, [?CLIENT, ?SERVER1, ?SERVER2, ?SERVER3, ?SERVER4, ?SERVER5]).
+
+-define(DICT_COMMON, ?DIAMETER_DICT_COMMON).
+
+-define(APP_ALIAS, the_app).
+-define(APP_ID, ?DICT_COMMON:id()).
+
+%% Config for diameter:start_service/2.
+-define(SERVICE(Host, Dict),
+ [{'Origin-Host', Host},
+ {'Origin-Realm', realm(Host)},
+ {'Host-IP-Address', [?ADDR]},
+ {'Vendor-Id', 12345},
+ {'Product-Name', "OTP/diameter"},
+ {'Acct-Application-Id', [Dict:id()]},
+ {application, [{alias, ?APP_ALIAS},
+ {dictionary, Dict},
+ {module, ?MODULE},
+ {answer_errors, callback}]}]).
+
+-define(SUCCESS, 2001).
+
+-define(LOGOUT, ?'DIAMETER_BASE_TERMINATION-CAUSE_DIAMETER_LOGOUT').
+
+%% ===========================================================================
+
+suite() ->
+ [{timetrap, {seconds, 10}}].
+
+all() ->
+ [start,
+ start_services,
+ connect,
+ send_ok,
+ send_nok,
+ stop_services,
+ stop].
+
+%% ===========================================================================
+%% start/stop testcases
+
+start(_Config) ->
+ ok = diameter:start().
+
+start_services(_Config) ->
+ S = [server(N, ?DICT_COMMON) || N <- tl(?SERVICES)],
+
+ ok = diameter:start_service(?CLIENT, ?SERVICE(?CLIENT, ?DICT_COMMON)),
+
+ {save_config, [{?CLIENT, S}]}.
+
+connect(Config) ->
+ {_, Conns} = proplists:get_value(saved_config, Config),
+
+ lists:foreach(fun({CN,Ss}) -> connect(CN, Ss) end, Conns).
+
+stop_services(_Config) ->
+ [] = [{H,T} || H <- ?SERVICES,
+ T <- [diameter:stop_service(H)],
+ T /= ok].
+
+stop(_Config) ->
+ ok = diameter:stop().
+
+%% ----------------------------------------
+
+server(Name, Dict) ->
+ ok = diameter:start_service(Name, ?SERVICE(Name, Dict)),
+ {Name, ?util:listen(Name, tcp)}.
+
+connect(Name, Refs) ->
+ [{{Name, ?util:connect(Name, tcp, LRef)}, T} || {_, LRef} = T <- Refs].
+
+%% ===========================================================================
+%% traffic testcases
+
+%% Send an STR and expect success after SERVER3 answers after a couple
+%% of failovers.
+send_ok(_Config) ->
+ Req = ['STR', {'Destination-Realm', realm(?SERVER1)},
+ {'Termination-Cause', ?LOGOUT},
+ {'Auth-Application-Id', ?APP_ID}],
+ #diameter_base_STA{'Result-Code' = ?SUCCESS,
+ 'Origin-Host' = ?SERVER3}
+ = call(Req, [{filter, realm}]).
+
+%% Send an STR and expect failure when both servers fail.
+send_nok(_Config) ->
+ Req = ['STR', {'Destination-Realm', realm(?SERVER4)},
+ {'Termination-Cause', ?LOGOUT},
+ {'Auth-Application-Id', ?APP_ID}],
+ {error, failover} = call(Req, [{filter, realm}]).
+
+%% ===========================================================================
+
+realm(Host) ->
+ tl(lists:dropwhile(fun(C) -> C /= $. end, Host)).
+
+call(Req, Opts) ->
+ diameter:call(?CLIENT, ?APP_ALIAS, Req, Opts).
+
+set([H|T], Vs) ->
+ [H | Vs ++ T].
+
+%% ===========================================================================
+%% diameter callbacks
+
+%% peer_up/3
+
+peer_up(_SvcName, _Peer, State) ->
+ State.
+
+%% peer_down/3
+
+peer_down(_SvcName, _Peer, State) ->
+ State.
+
+%% pick_peer/4
+
+%% Choose a server other than SERVER3 or SERVER5 if possible.
+pick_peer(Peers, _, ?CLIENT, _State) ->
+ case lists:partition(fun({_, #diameter_caps{origin_host = {_, OH}}}) ->
+ OH /= ?SERVER3 andalso OH /= ?SERVER5
+ end,
+ Peers)
+ of
+ {[], [Peer]} ->
+ {ok, Peer};
+ {[Peer | _], _} ->
+ {ok, Peer}
+ end.
+
+%% prepare_request/3
+
+prepare_request(Pkt, ?CLIENT, {_Ref, Caps}) ->
+ {send, prepare(Pkt, Caps)}.
+
+prepare(#diameter_packet{msg = Req}, Caps) ->
+ #diameter_caps{origin_host = {OH, _},
+ origin_realm = {OR, _}}
+ = Caps,
+ set(Req, [{'Session-Id', diameter:session_id(OH)},
+ {'Origin-Host', OH},
+ {'Origin-Realm', OR}]).
+
+%% prepare_retransmit/3
+
+prepare_retransmit(Pkt, ?CLIENT, _Peer) ->
+ {send, Pkt}.
+
+%% handle_answer/4
+
+handle_answer(Pkt, _Req, ?CLIENT, _Peer) ->
+ #diameter_packet{msg = Rec, errors = []} = Pkt,
+ Rec.
+
+%% handle_error/4
+
+handle_error(Reason, _Req, ?CLIENT, _Peer) ->
+ {error, Reason}.
+
+%% handle_request/3
+
+%% Only SERVER3 actually answers.
+handle_request(Pkt, ?SERVER3, {_, Caps}) ->
+ #diameter_packet{msg = #diameter_base_STR{'Session-Id' = SId,
+ 'Origin-Host' = ?CLIENT}}
+ = Pkt,
+ #diameter_caps{origin_host = {OH, _},
+ origin_realm = {OR, _}}
+ = Caps,
+
+ {reply, #diameter_base_STA{'Result-Code' = ?SUCCESS,
+ 'Session-Id' = SId,
+ 'Origin-Host' = OH,
+ 'Origin-Realm' = OR}};
+
+%% Others kill the transport to force failover.
+handle_request(_, _, {TPid, _}) ->
+ exit(TPid, kill),
+ discard.
diff --git a/lib/diameter/test/diameter_relay_SUITE.erl b/lib/diameter/test/diameter_relay_SUITE.erl
index d3d1fe690a..40cbdf805a 100644
--- a/lib/diameter/test/diameter_relay_SUITE.erl
+++ b/lib/diameter/test/diameter_relay_SUITE.erl
@@ -37,20 +37,22 @@
all/0,
groups/0,
init_per_group/2,
- end_per_group/2,
- init_per_suite/1,
- end_per_suite/1]).
+ end_per_group/2]).
%% testcases
--export([send1/1,
+-export([start/1,
+ start_services/1,
+ connect/1,
+ send1/1,
send2/1,
send3/1,
send4/1,
send_loop/1,
send_timeout_1/1,
send_timeout_2/1,
- remove_transports/1,
- stop_services/1]).
+ disconnect/1,
+ stop_services/1,
+ stop/1]).
%% diameter callbacks
-export([peer_up/3,
@@ -62,17 +64,14 @@
handle_error/4,
handle_request/3]).
--ifdef(DIAMETER_CT).
+-include("diameter.hrl").
-include("diameter_gen_base_rfc3588.hrl").
--else.
--include_lib("diameter/include/diameter_gen_base_rfc3588.hrl").
--endif.
-
--include_lib("diameter/include/diameter.hrl").
-include("diameter_ct.hrl").
%% ===========================================================================
+-define(util, diameter_util).
+
-define(ADDR, {127,0,0,1}).
-define(CLIENT, "CLIENT.REALM1").
@@ -83,6 +82,10 @@
-define(SERVER3, "SERVER1.REALM3").
-define(SERVER4, "SERVER2.REALM3").
+-define(SERVICES, [?CLIENT,
+ ?RELAY1, ?RELAY2,
+ ?SERVER1, ?SERVER2, ?SERVER3, ?SERVER4]).
+
-define(DICT_COMMON, ?DIAMETER_DICT_COMMON).
-define(DICT_RELAY, ?DIAMETER_DICT_RELAY).
@@ -102,19 +105,6 @@
{module, ?MODULE},
{answer_errors, callback}]}]).
-%% Config for diameter:add_transport/2. In the listening case, listen
-%% on a free port that we then lookup using the implementation detail
-%% that diameter_tcp registers the port with diameter_reg.
--define(CONNECT(PortNr),
- {connect, [{transport_module, diameter_tcp},
- {transport_config, [{raddr, ?ADDR},
- {rport, PortNr},
- {ip, ?ADDR},
- {port, 0}]}]}).
--define(LISTEN,
- {listen, [{transport_module, diameter_tcp},
- {transport_config, [{ip, ?ADDR}, {port, 0}]}]}).
-
-define(SUCCESS, 2001).
-define(LOOP_DETECTED, 3005).
-define(UNABLE_TO_DELIVER, 3002).
@@ -122,22 +112,21 @@
-define(LOGOUT, ?'DIAMETER_BASE_TERMINATION-CAUSE_DIAMETER_LOGOUT').
-define(AUTHORIZE_ONLY, ?'DIAMETER_BASE_RE-AUTH-REQUEST-TYPE_AUTHORIZE_ONLY').
--define(A, list_to_atom).
--define(L, atom_to_list).
-
%% ===========================================================================
suite() ->
[{timetrap, {seconds, 10}}].
all() ->
- [{group, N} || {N, _, _} <- groups()]
- ++ [remove_transports, stop_services].
+ [start, start_services, connect]
+ ++ tc()
+ ++ [{group, all},
+ disconnect,
+ stop_services,
+ stop].
groups() ->
- Ts = tc(),
- [{all, [], Ts},
- {p, [parallel], Ts}].
+ [{all, [parallel], tc()}].
init_per_group(_, Config) ->
Config.
@@ -145,32 +134,7 @@ init_per_group(_, Config) ->
end_per_group(_, _) ->
ok.
-init_per_suite(Config) ->
- ok = diameter:start(),
- [S1,S2,S3,S4] = S = [server(N, ?DICT_COMMON) || N <- [?SERVER1,
- ?SERVER2,
- ?SERVER3,
- ?SERVER4]],
- [R1,R2] = R = [server(N, ?DICT_RELAY) || N <- [?RELAY1, ?RELAY2]],
-
- ok = diameter:start_service(?CLIENT, ?SERVICE(?CLIENT, ?DICT_COMMON)),
-
- true = diameter:subscribe(?RELAY1),
- true = diameter:subscribe(?RELAY2),
- true = diameter:subscribe(?CLIENT),
-
- [C1,C2] = connect(?RELAY1, [S1,S2]),
- [C3,C4] = connect(?RELAY2, [S3,S4]),
- [C5,C6] = connect(?CLIENT, [R1,R2]),
-
- C7 = connect(?RELAY1, R2),
-
- [{transports, {S, R, [C1,C2,C3,C4,C5,C6,C7]}} | Config].
-
-end_per_suite(_Config) ->
- ok = diameter:stop().
-
-%% Testcases to run when services are started and connections
+%% Traffic cases run when services are started and connections
%% established.
tc() ->
[send1,
@@ -181,43 +145,56 @@ tc() ->
send_timeout_1,
send_timeout_2].
-server(Host, Dict) ->
- ok = diameter:start_service(Host, ?SERVICE(Host, Dict)),
- {ok, LRef} = diameter:add_transport(Host, ?LISTEN),
- {LRef, portnr(LRef)}.
-
-connect(Host, {_LRef, PortNr}) ->
- {ok, Ref} = diameter:add_transport(Host, ?CONNECT(PortNr)),
- ok = receive
- #diameter_event{service = Host,
- info = {up, Ref, _, _, #diameter_packet{}}} ->
- ok
- after 2000 ->
- false
- end,
- Ref;
-connect(Host, Ports) ->
- [connect(Host, P) || P <- Ports].
-
-portnr(LRef) ->
- portnr(LRef, 20).
-
-portnr(LRef, N)
- when 0 < N ->
- case diameter_reg:match({diameter_tcp, listener, {LRef, '_'}}) of
- [{T, _Pid}] ->
- {_, _, {LRef, {_Addr, LSock}}} = T,
- {ok, PortNr} = inet:port(LSock),
- PortNr;
- [] ->
- receive after 50 -> ok end,
- portnr(LRef, N-1)
- end.
+%% ===========================================================================
+%% start/stop testcases
-realm(Host) ->
- tl(lists:dropwhile(fun(C) -> C /= $. end, Host)).
+start(_Config) ->
+ ok = diameter:start().
+
+start_services(_Config) ->
+ [S1,S2,S3,S4] = [server(N, ?DICT_COMMON) || N <- [?SERVER1,
+ ?SERVER2,
+ ?SERVER3,
+ ?SERVER4]],
+ [R1,R2] = [server(N, ?DICT_RELAY) || N <- [?RELAY1, ?RELAY2]],
+
+ ok = diameter:start_service(?CLIENT, ?SERVICE(?CLIENT, ?DICT_COMMON)),
+
+ {save_config, [{?RELAY1, [S1,S2,R2]},
+ {?RELAY2, [S3,S4]},
+ {?CLIENT, [R1,R2]}]}.
+
+connect(Config) ->
+ {_, Conns} = proplists:get_value(saved_config, Config),
+
+ ?util:write_priv(Config,
+ "cfg",
+ lists:flatmap(fun({CN,Ss}) -> connect(CN, Ss) end,
+ Conns)).
+
+disconnect(Config) ->
+ lists:foreach(fun({{CN,CR},{SN,SR}}) -> ?util:disconnect(CN,CR,SN,SR) end,
+ ?util:read_priv(Config, "cfg")).
+
+stop_services(_Config) ->
+ [] = [{H,T} || H <- ?SERVICES,
+ T <- [diameter:stop_service(H)],
+ T /= ok].
+
+stop(_Config) ->
+ ok = diameter:stop().
+
+%% ----------------------------------------
+
+server(Name, Dict) ->
+ ok = diameter:start_service(Name, ?SERVICE(Name, Dict)),
+ {Name, ?util:listen(Name, tcp)}.
+
+connect(Name, Refs) ->
+ [{{Name, ?util:connect(Name, tcp, LRef)}, T} || {_, LRef} = T <- Refs].
%% ===========================================================================
+%% traffic testcases
%% Send an STR intended for a specific server and expect success.
send1(_Config) ->
@@ -254,40 +231,11 @@ send_timeout(Tmo) ->
{'Re-Auth-Request-Type', ?AUTHORIZE_ONLY}],
call(Req, [{filter, realm}, {timeout, Tmo}]).
-%% Remove the client transports and expect the corresponding server
-%% transport to go down.
-remove_transports(Config) ->
- {[S1,S2,S3,S4], [R1,R2], [C1,C2,C3,C4,C5,C6,C7]}
- = proplists:get_value(transports, Config),
-
- true = diameter:subscribe(?SERVER1),
- true = diameter:subscribe(?SERVER2),
- true = diameter:subscribe(?SERVER3),
- true = diameter:subscribe(?SERVER4),
- true = diameter:subscribe(?RELAY1),
- true = diameter:subscribe(?RELAY2),
-
- disconnect(S1, ?RELAY1, C1),
- disconnect(S2, ?RELAY1, C2),
- disconnect(S3, ?RELAY2, C3),
- disconnect(S4, ?RELAY2, C4),
- disconnect(R1, ?CLIENT, C5),
- disconnect(R2, ?CLIENT, C6),
- disconnect(R2, ?RELAY1, C7).
-
-disconnect({LRef, _PortNr}, Client, CRef) ->
- ok = diameter:remove_transport(Client, CRef),
- ok = receive #diameter_event{info = {down, LRef, _, _}} -> ok
- after 2000 -> false
- end.
-
-stop_services(_Config) ->
- S = [?CLIENT, ?RELAY1, ?RELAY2, ?SERVER1, ?SERVER2, ?SERVER3, ?SERVER4],
- Ok = [ok || _ <- S],
- Ok = [diameter:stop_service(H) || H <- S].
-
%% ===========================================================================
+realm(Host) ->
+ tl(lists:dropwhile(fun(C) -> C /= $. end, Host)).
+
call(Server) ->
Realm = realm(Server),
Req = ['STR', {'Destination-Realm', Realm},
@@ -323,7 +271,7 @@ peer_down(_SvcName, _Peer, State) ->
pick_peer([Peer | _], _, Svc, _State)
when Svc == ?RELAY1;
Svc == ?RELAY2;
- Svc == ?CLIENT->
+ Svc == ?CLIENT ->
{ok, Peer}.
%% prepare_request/3
diff --git a/lib/diameter/test/diameter_tls_SUITE.erl b/lib/diameter/test/diameter_tls_SUITE.erl
new file mode 100644
index 0000000000..127e3435dc
--- /dev/null
+++ b/lib/diameter/test/diameter_tls_SUITE.erl
@@ -0,0 +1,406 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2010-2011. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+%% Tests of traffic between six Diameter nodes connected as follows.
+%%
+%% ---- SERVER.REALM1 (TLS after capabilities exchange)
+%% /
+%% / ---- SERVER.REALM2 (ditto)
+%% | /
+%% CLIENT.REALM0 ----- SERVER.REALM3 (no security)
+%% | \
+%% \ ---- SERVER.REALM4 (TLS at connection establishment)
+%% \
+%% ---- SERVER.REALM5 (ditto)
+%%
+
+-module(diameter_tls_SUITE).
+
+-export([suite/0,
+ all/0,
+ groups/0,
+ init_per_group/2,
+ end_per_group/2,
+ init_per_suite/1,
+ end_per_suite/1]).
+
+%% testcases
+-export([start_ssl/1,
+ start_diameter/1,
+ make_certs/1, make_certs/0,
+ start_services/1,
+ add_transports/1,
+ send1/1,
+ send2/1,
+ send3/1,
+ send4/1,
+ send5/1,
+ remove_transports/1,
+ stop_services/1,
+ stop_diameter/1,
+ stop_ssl/1]).
+
+%% diameter callbacks
+-export([peer_up/3,
+ peer_down/3,
+ pick_peer/4,
+ prepare_request/3,
+ prepare_retransmit/3,
+ handle_answer/4,
+ handle_error/4,
+ handle_request/3]).
+
+-include("diameter.hrl").
+-include("diameter_gen_base_rfc3588.hrl").
+-include("diameter_ct.hrl").
+
+%% ===========================================================================
+
+-define(util, diameter_util).
+
+-define(ADDR, {127,0,0,1}).
+
+-define(CLIENT, "CLIENT.REALM0").
+-define(SERVER1, "SERVER.REALM1").
+-define(SERVER2, "SERVER.REALM2").
+-define(SERVER3, "SERVER.REALM3").
+-define(SERVER4, "SERVER.REALM4").
+-define(SERVER5, "SERVER.REALM5").
+
+-define(SERVERS, [?SERVER1, ?SERVER2, ?SERVER3, ?SERVER4, ?SERVER5]).
+
+-define(DICT_COMMON, ?DIAMETER_DICT_COMMON).
+
+-define(APP_ALIAS, the_app).
+-define(APP_ID, ?DICT_COMMON:id()).
+
+-define(NO_INBAND_SECURITY, 0).
+-define(TLS, 1).
+
+%% Config for diameter:start_service/2.
+-define(SERVICE(Host, Dict),
+ [{'Origin-Host', Host},
+ {'Origin-Realm', realm(Host)},
+ {'Host-IP-Address', [?ADDR]},
+ {'Vendor-Id', 12345},
+ {'Product-Name', "OTP/diameter"},
+ {'Inband-Security-Id', [?NO_INBAND_SECURITY]},
+ {'Auth-Application-Id', [Dict:id()]},
+ {application, [{alias, ?APP_ALIAS},
+ {dictionary, Dict},
+ {module, ?MODULE},
+ {answer_errors, callback}]}]).
+
+%% Config for diameter:add_transport/2. In the listening case, listen
+%% on a free port that we then lookup using the implementation detail
+%% that diameter_tcp registers the port with diameter_reg.
+-define(CONNECT(PortNr, Caps, Opts),
+ {connect, [{transport_module, diameter_tcp},
+ {transport_config, [{raddr, ?ADDR},
+ {rport, PortNr},
+ {ip, ?ADDR},
+ {port, 0}
+ | Opts]},
+ {capabilities, Caps}]}).
+-define(LISTEN(Caps, Opts),
+ {listen, [{transport_module, diameter_tcp},
+ {transport_config, [{ip, ?ADDR}, {port, 0} | Opts]},
+ {capabilities, Caps}]}).
+
+-define(SUCCESS, 2001).
+-define(LOGOUT, ?'DIAMETER_BASE_TERMINATION-CAUSE_DIAMETER_LOGOUT').
+
+%% ===========================================================================
+
+suite() ->
+ [{timetrap, {seconds, 10}}].
+
+all() ->
+ [start_ssl,
+ start_diameter,
+ make_certs,
+ start_services,
+ add_transports]
+ ++ [{group, N} || {N, _, _} <- groups()]
+ ++ [remove_transports, stop_services, stop_diameter, stop_ssl].
+
+groups() ->
+ Ts = tc(),
+ [{all, [], Ts},
+ {p, [parallel], Ts}].
+
+init_per_group(_, Config) ->
+ Config.
+
+end_per_group(_, _) ->
+ ok.
+
+init_per_suite(Config) ->
+ case os:find_executable("openssl") of
+ false ->
+ {skip, no_openssl};
+ _ ->
+ Config
+ end.
+
+end_per_suite(_Config) ->
+ ok.
+
+%% Testcases to run when services are started and connections
+%% established.
+tc() ->
+ [send1,
+ send2,
+ send3,
+ send4,
+ send5].
+
+%% ===========================================================================
+%% testcases
+
+start_ssl(_Config) ->
+ ok = ssl:start().
+
+start_diameter(_Config) ->
+ ok = diameter:start().
+
+make_certs() ->
+ [{timetrap, {seconds, 30}}].
+
+make_certs(Config) ->
+ Dir = proplists:get_value(priv_dir, Config),
+
+ [] = ?util:run([[fun make_cert/2, Dir, B] || B <- ["server1",
+ "server2",
+ "server4",
+ "server5",
+ "client"]]).
+
+start_services(Config) ->
+ Dir = proplists:get_value(priv_dir, Config),
+ Servers = [server(S, sopts(S, Dir)) || S <- ?SERVERS],
+
+ ok = diameter:start_service(?CLIENT, ?SERVICE(?CLIENT, ?DICT_COMMON)),
+
+ {save_config, [Dir | Servers]}.
+
+add_transports(Config) ->
+ {_, [Dir | Servers]} = proplists:get_value(saved_config, Config),
+
+ true = diameter:subscribe(?CLIENT),
+
+ Opts = ssl_options(Dir, "client"),
+ Connections = [connect(?CLIENT, S, copts(N, Opts))
+ || {S,N} <- lists:zip(Servers, ?SERVERS)],
+
+ ?util:write_priv(Config, "cfg", lists:zip(Servers, Connections)).
+
+
+%% Remove the client transports and expect the corresponding server
+%% transport to go down.
+remove_transports(Config) ->
+ Ts = ?util:read_priv(Config, "cfg"),
+ [] = [T || S <- ?SERVERS, T <- [diameter:subscribe(S)], T /= true],
+ lists:map(fun disconnect/1, Ts).
+
+stop_services(_Config) ->
+ [] = [{H,T} || H <- [?CLIENT | ?SERVERS],
+ T <- [diameter:stop_service(H)],
+ T /= ok].
+
+stop_diameter(_Config) ->
+ ok = diameter:stop().
+
+stop_ssl(_Config) ->
+ ok = ssl:stop().
+
+%% Send an STR intended for a specific server and expect success.
+send1(_Config) ->
+ call(?SERVER1).
+send2(_Config) ->
+ call(?SERVER2).
+send3(_Config) ->
+ call(?SERVER3).
+send4(_Config) ->
+ call(?SERVER4).
+send5(_Config) ->
+ call(?SERVER5).
+
+%% ===========================================================================
+%% diameter callbacks
+
+%% peer_up/3
+
+peer_up(_SvcName, _Peer, State) ->
+ State.
+
+%% peer_down/3
+
+peer_down(_SvcName, _Peer, State) ->
+ State.
+
+%% pick_peer/4
+
+pick_peer([Peer], _, ?CLIENT, _State) ->
+ {ok, Peer}.
+
+%% prepare_request/3
+
+prepare_request(#diameter_packet{msg = Req},
+ ?CLIENT,
+ {_Ref, Caps}) ->
+ #diameter_caps{origin_host = {OH, _},
+ origin_realm = {OR, _}}
+ = Caps,
+
+ {send, set(Req, [{'Session-Id', diameter:session_id(OH)},
+ {'Origin-Host', OH},
+ {'Origin-Realm', OR}])}.
+
+%% prepare_retransmit/3
+
+prepare_retransmit(_Pkt, false, _Peer) ->
+ discard.
+
+%% handle_answer/4
+
+handle_answer(Pkt, _Req, ?CLIENT, _Peer) ->
+ #diameter_packet{msg = Rec, errors = []} = Pkt,
+ Rec.
+
+%% handle_error/4
+
+handle_error(Reason, _Req, ?CLIENT, _Peer) ->
+ {error, Reason}.
+
+%% handle_request/3
+
+handle_request(#diameter_packet{msg = #diameter_base_STR{'Session-Id' = SId}},
+ OH,
+ {_Ref, #diameter_caps{origin_host = {OH,_},
+ origin_realm = {OR, _}}})
+ when OH /= ?CLIENT ->
+ {reply, #diameter_base_STA{'Result-Code' = ?SUCCESS,
+ 'Session-Id' = SId,
+ 'Origin-Host' = OH,
+ 'Origin-Realm' = OR}}.
+
+%% ===========================================================================
+%% support functions
+
+call(Server) ->
+ Realm = realm(Server),
+ Req = ['STR', {'Destination-Realm', Realm},
+ {'Termination-Cause', ?LOGOUT},
+ {'Auth-Application-Id', ?APP_ID}],
+ #diameter_base_STA{'Result-Code' = ?SUCCESS,
+ 'Origin-Host' = Server,
+ 'Origin-Realm' = Realm}
+ = call(Req, [{filter, realm}]).
+
+call(Req, Opts) ->
+ diameter:call(?CLIENT, ?APP_ALIAS, Req, Opts).
+
+set([H|T], Vs) ->
+ [H | Vs ++ T].
+
+disconnect({{LRef, _PortNr}, CRef}) ->
+ ok = diameter:remove_transport(?CLIENT, CRef),
+ ok = receive #diameter_event{info = {down, LRef, _, _}} -> ok
+ after 2000 -> false
+ end.
+
+realm(Host) ->
+ tl(lists:dropwhile(fun(C) -> C /= $. end, Host)).
+
+inband_security(Ids) ->
+ [{'Inband-Security-Id', Ids}].
+
+ssl_options(Dir, Base) ->
+ Root = filename:join([Dir, Base]),
+ [{ssl_options, [{certfile, Root ++ "_ca.pem"},
+ {keyfile, Root ++ "_key.pem"}]}].
+
+make_cert(Dir, Base) ->
+ make_cert(Dir, Base ++ "_key.pem", Base ++ "_ca.pem").
+
+make_cert(Dir, Keyfile, Certfile) ->
+ [K,C] = Paths = [filename:join([Dir, F]) || F <- [Keyfile, Certfile]],
+
+ KCmd = join(["openssl genrsa -out", K, "2048"]),
+ CCmd = join(["openssl req -new -x509 -key", K, "-out", C, "-days 7",
+ "-subj /C=SE/ST=./L=Stockholm/CN=www.erlang.org"]),
+
+ %% Hope for the best and only check that files are written.
+ os:cmd(KCmd),
+ os:cmd(CCmd),
+
+ [_,_] = [T || P <- Paths, {ok, T} <- [file:read_file_info(P)]],
+
+ {K,C}.
+
+join(Strs) ->
+ string:join(Strs, " ").
+
+%% server/2
+
+server(Host, {Caps, Opts}) ->
+ ok = diameter:start_service(Host, ?SERVICE(Host, ?DICT_COMMON)),
+ {ok, LRef} = diameter:add_transport(Host, ?LISTEN(Caps, Opts)),
+ {LRef, hd([_] = ?util:lport(tcp, LRef, 20))}.
+
+sopts(?SERVER1, Dir) ->
+ {inband_security([?TLS]),
+ ssl_options(Dir, "server1")};
+sopts(?SERVER2, Dir) ->
+ {inband_security([?NO_INBAND_SECURITY, ?TLS]),
+ ssl_options(Dir, "server2")};
+sopts(?SERVER3, _) ->
+ {[], []};
+sopts(?SERVER4, Dir) ->
+ {[], ssl(ssl_options(Dir, "server4"))};
+sopts(?SERVER5, Dir) ->
+ {[], ssl(ssl_options(Dir, "server5"))}.
+
+ssl([{ssl_options = T, Opts}]) ->
+ [{T, true} | Opts].
+
+%% connect/3
+
+connect(Host, {_LRef, PortNr}, {Caps, Opts}) ->
+ {ok, Ref} = diameter:add_transport(Host, ?CONNECT(PortNr, Caps, Opts)),
+ ok = receive
+ #diameter_event{service = Host,
+ info = {up, Ref, _, _, #diameter_packet{}}} ->
+ ok
+ after 2000 ->
+ false
+ end,
+ Ref.
+
+copts(S, Opts)
+ when S == ?SERVER1;
+ S == ?SERVER2;
+ S == ?SERVER3 ->
+ {inband_security([?NO_INBAND_SECURITY, ?TLS]), Opts};
+copts(S, Opts)
+ when S == ?SERVER4;
+ S == ?SERVER5 ->
+ {[], ssl(Opts)}.
diff --git a/lib/ssl/c_src/Makefile b/lib/diameter/test/diameter_tls_SUITE_data/Makefile.ca
index 52d9140153..3f2645add0 100644
--- a/lib/ssl/c_src/Makefile
+++ b/lib/diameter/test/diameter_tls_SUITE_data/Makefile.ca
@@ -1,26 +1,43 @@
-#
+# -*- makefile -*-
# %CopyrightBegin%
-#
-# Copyright Ericsson AB 1999-2009. All Rights Reserved.
-#
+#
+# Copyright Ericsson AB 2011. All Rights Reserved.
+#
# The contents of this file are subject to the Erlang Public License,
# Version 1.1, (the "License"); you may not use this file except in
# compliance with the License. You should have received a copy of the
# Erlang Public License along with this software. If not, it can be
# retrieved online at http://www.erlang.org/.
-#
+#
# Software distributed under the License is distributed on an "AS IS"
# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
# the License for the specific language governing rights and limitations
# under the License.
-#
-# %CopyrightEnd%
-#
-
#
+# %CopyrightEnd%
#
-# Invoke with GNU make or clearmake -C gnu.
+# Certificates are now generated from the suite itself but the
+# makefile itself is still useful.
#
-include $(ERL_TOP)/make/run_make.mk
+KEYS = $(HOSTS:%=%_key.pem)
+CERTS = $(HOSTS:%=%_ca.pem)
+
+all: $(CERTS)
+
+%_ca.pem: %_key.pem
+ openssl req -new -x509 -key $< -out $@ -days 1095 \
+ -subj '/C=SE/ST=./L=Stockholm/CN=www.erlang.org'
+
+%_key.pem:
+ openssl genrsa -out $@ 2048
+
+clean:
+ rm -f $(CERTS)
+
+realclean: clean
+ rm -f $(KEYS)
+
+.PRECIOUS: $(KEYS)
+.PHONY: all clean realclean
diff --git a/lib/diameter/test/diameter_traffic_SUITE.erl b/lib/diameter/test/diameter_traffic_SUITE.erl
index 8c85323222..55c5fc7c54 100644
--- a/lib/diameter/test/diameter_traffic_SUITE.erl
+++ b/lib/diameter/test/diameter_traffic_SUITE.erl
@@ -26,15 +26,16 @@
-export([suite/0,
all/0,
groups/0,
- init_per_suite/1,
- end_per_suite/1,
init_per_group/2,
end_per_group/2,
init_per_testcase/2,
end_per_testcase/2]).
%% testcases
--export([result_codes/1,
+-export([start/1,
+ start_services/1,
+ add_transports/1,
+ result_codes/1,
send_ok/1,
send_arbitrary/1,
send_unknown/1,
@@ -73,7 +74,8 @@
send_multiple_filters_3/1,
send_anything/1,
remove_transports/1,
- stop_services/1]).
+ stop_services/1,
+ stop/1]).
%% diameter callbacks
-export([peer_up/3,
@@ -85,17 +87,14 @@
handle_error/5,
handle_request/3]).
--ifdef(DIAMETER_CT).
+-include("diameter.hrl").
-include("diameter_gen_base_rfc3588.hrl").
--else.
--include_lib("diameter/include/diameter_gen_base_rfc3588.hrl").
--endif.
-
--include_lib("diameter/include/diameter.hrl").
-include("diameter_ct.hrl").
%% ===========================================================================
+-define(util, diameter_util).
+
-define(ADDR, {127,0,0,1}).
-define(CLIENT, "CLIENT").
@@ -123,19 +122,6 @@
{module, ?MODULE},
{answer_errors, callback}]}]).
-%% Config for diameter:add_transport/2. In the listening case, listen
-%% on a free port that we then lookup using the implementation detail
-%% that diameter_tcp registers the port with diameter_reg.
--define(CONNECT(PortNr),
- {connect, [{transport_module, diameter_tcp},
- {transport_config, [{raddr, ?ADDR},
- {rport, PortNr},
- {ip, ?ADDR},
- {port, 0}]}]}).
--define(LISTEN,
- {listen, [{transport_module, diameter_tcp},
- {transport_config, [{ip, ?ADDR}, {port, 0}]}]}).
-
-define(SUCCESS,
?'DIAMETER_BASE_RESULT-CODE_DIAMETER_SUCCESS').
-define(COMMAND_UNSUPPORTED,
@@ -177,30 +163,18 @@ suite() ->
[{timetrap, {seconds, 10}}].
all() ->
- [result_codes | [{group, N} || {N, _, _} <- groups()]]
- ++ [remove_transports, stop_services].
+ [start, start_services, add_transports, result_codes
+ | [{group, N} || {N, _, _} <- groups()]]
+ ++ [remove_transports, stop_services, stop].
groups() ->
Ts = tc(),
- [{E, [], Ts} || E <- ?ENCODINGS]
- ++ [{?P(E), [parallel], Ts} || E <- ?ENCODINGS].
+ [{grp(E,P), P, Ts} || E <- ?ENCODINGS, P <- [[], [parallel]]].
-init_per_suite(Config) ->
- ok = diameter:start(),
- ok = diameter:start_service(?SERVER, ?SERVICE(?SERVER)),
- ok = diameter:start_service(?CLIENT, ?SERVICE(?CLIENT)),
- {ok, LRef} = diameter:add_transport(?SERVER, ?LISTEN),
- true = diameter:subscribe(?CLIENT),
- {ok, CRef} = diameter:add_transport(?CLIENT, ?CONNECT(portnr())),
- {up, CRef, _Peer, _Config, #diameter_packet{}}
- = receive #diameter_event{service = ?CLIENT, info = I} -> I
- after 2000 -> false
- end,
- true = diameter:unsubscribe(?CLIENT),
- [{transports, {LRef, CRef}} | Config].
-
-end_per_suite(_Config) ->
- ok = diameter:stop().
+grp(E, []) ->
+ E;
+grp(E, [parallel]) ->
+ ?P(E).
init_per_group(Name, Config) ->
E = case ?L(Name) of
@@ -261,20 +235,35 @@ tc() ->
send_multiple_filters_3,
send_anything].
-portnr() ->
- portnr(20).
-
-portnr(N)
- when 0 < N ->
- case diameter_reg:match({diameter_tcp, listener, '_'}) of
- [{T, _Pid}] ->
- {_, _, {_LRef, {_Addr, LSock}}} = T,
- {ok, PortNr} = inet:port(LSock),
- PortNr;
- [] ->
- receive after 50 -> ok end,
- portnr(N-1)
- end.
+%% ===========================================================================
+%% start/stop testcases
+
+start(_Config) ->
+ ok = diameter:start().
+
+start_services(_Config) ->
+ ok = diameter:start_service(?SERVER, ?SERVICE(?SERVER)),
+ ok = diameter:start_service(?CLIENT, ?SERVICE(?CLIENT)).
+
+add_transports(Config) ->
+ LRef = ?util:listen(?SERVER, tcp, [{capabilities_cb, fun capx/2}]),
+ CRef = ?util:connect(?CLIENT, tcp, LRef),
+ ?util:write_priv(Config, "transport", {LRef, CRef}).
+
+remove_transports(Config) ->
+ {LRef, CRef} = ?util:read_priv(Config, "transport"),
+ ?util:disconnect(?CLIENT, CRef, ?SERVER, LRef).
+
+stop_services(_Config) ->
+ ok = diameter:stop_service(?CLIENT),
+ ok = diameter:stop_service(?SERVER).
+
+stop(_Config) ->
+ ok = diameter:stop().
+
+capx(_, #diameter_caps{origin_host = {OH,DH}}) ->
+ io:format("connection: ~p -> ~p~n", [DH,OH]),
+ ok.
%% ===========================================================================
@@ -532,21 +521,6 @@ send_anything(Config) ->
#diameter_base_STA{'Result-Code' = ?SUCCESS}
= call(Config, anything).
-%% Remove the client transport and expect the server transport to
-%% go down.
-remove_transports(Config) ->
- {LRef, CRef} = proplists:get_value(transports, Config),
- true = diameter:subscribe(?SERVER),
- ok = diameter:remove_transport(?CLIENT, CRef),
- {down, LRef, _, _}
- = receive #diameter_event{service = ?SERVER, info = I} -> I
- after 2000 -> false
- end.
-
-stop_services(_Config) ->
- {ok, ok} = {diameter:stop_service(?CLIENT),
- diameter:stop_service(?SERVER)}.
-
%% ===========================================================================
call(Config, Req) ->
diff --git a/lib/diameter/test/diameter_transport_SUITE.erl b/lib/diameter/test/diameter_transport_SUITE.erl
index d545859fe8..c22adc3334 100644
--- a/lib/diameter/test/diameter_transport_SUITE.erl
+++ b/lib/diameter/test/diameter_transport_SUITE.erl
@@ -33,17 +33,19 @@
end_per_suite/1]).
%% testcases
--export([tcp_accept/1,
+-export([start/1,
+ tcp_accept/1,
tcp_connect/1,
sctp_accept/1,
- sctp_connect/1]).
+ sctp_connect/1,
+ stop/1]).
-export([accept/1,
connect/1,
init/2]).
-include_lib("kernel/include/inet_sctp.hrl").
--include_lib("diameter/include/diameter.hrl").
+-include("diameter.hrl").
-include("diameter_ct.hrl").
-define(util, diameter_util).
@@ -67,16 +69,6 @@
= #diameter_caps{host_ip_address
= Addrs}}).
-%% The term diameter_tcp/sctp registers after opening a listening
-%% socket. This is an implementation detail that should probably be
-%% replaced by some documented way of getting at the port number of
-%% the listening socket, which is what we're after since we specify
-%% port 0 to get something unused.
--define(TCP_LISTENER(Ref, Addr, LSock),
- {diameter_tcp, listener, {Ref, {Addr, LSock}}}).
--define(SCTP_LISTENER(Ref, Addr, LSock),
- {diameter_sctp, listener, {Ref, {[Addr], LSock}}}).
-
%% The term we register after open a listening port with gen_tcp.
-define(TEST_LISTENER(Ref, PortNr),
{?MODULE, listen, Ref, PortNr}).
@@ -101,7 +93,7 @@ suite() ->
[{timetrap, {minutes, 2}}].
all() ->
- [{group, all} | tc()].
+ [start | tc()] ++ [{group, all}, stop].
groups() ->
[{all, [parallel], tc()}].
@@ -119,10 +111,17 @@ end_per_group(_, _) ->
ok.
init_per_suite(Config) ->
- ok = diameter:start(),
[{sctp, have_sctp()} | Config].
end_per_suite(_Config) ->
+ ok.
+
+%% ===========================================================================
+
+start(_Config) ->
+ ok = diameter:start().
+
+stop(_Config) ->
ok = diameter:stop().
%% ===========================================================================
@@ -180,7 +179,9 @@ have_sctp() ->
try gen_sctp:open() of
{ok, Sock} ->
gen_sctp:close(Sock),
- true
+ true;
+ {error, eprotonosupport} -> %% fail on any other reason
+ false
catch
error: badarg ->
false
@@ -216,7 +217,7 @@ init(accept, {Prot, Ref}) ->
init(gen_connect, {Prot, Ref}) ->
%% Lookup the peer's listening socket.
- {ok, PortNr} = inet:port(lsock(Prot, Ref)),
+ [PortNr] = ?util:lport(Prot, Ref, 20),
%% Connect, send a message and receive it back.
{ok, Sock} = gen_connect(Prot, PortNr, Ref),
@@ -253,22 +254,16 @@ init(connect, {Prot, Ref}) ->
MRef = erlang:monitor(process, TPid),
?RECV({'DOWN', MRef, process, _, _}).
-lsock(sctp, Ref) ->
- [{?SCTP_LISTENER(_ , _, LSock), _}]
- = match(?SCTP_LISTENER(Ref, ?ADDR, '_')),
- LSock;
-lsock(tcp, Ref) ->
- [{?TCP_LISTENER(_ , _, LSock), _}]
- = match(?TCP_LISTENER(Ref, ?ADDR, '_')),
- LSock.
-
match(Pat) ->
- case diameter_reg:match(Pat) of
- [] ->
+ match(Pat, 20).
+
+match(Pat, T) ->
+ L = diameter_reg:match(Pat),
+ if [] /= L orelse 1 == T ->
+ L;
+ true ->
?WAIT(50),
- match(Pat);
- L ->
- L
+ match(Pat, T-1)
end.
bin(sctp, #diameter_packet{bin = Bin}) ->
@@ -332,7 +327,7 @@ start_accept(Prot, Ref) ->
%% Configure the same port number for transports on the same
%% reference.
- PortNr = portnr(Prot, Ref),
+ [PortNr | _] = ?util:lport(Prot, Ref) ++ [0],
{Mod, Opts} = tmod(Prot),
try
@@ -362,23 +357,6 @@ tmod(sctp) ->
tmod(tcp) ->
{diameter_tcp, []}.
-portnr(sctp, Ref) ->
- case diameter_reg:match(?SCTP_LISTENER(Ref, ?ADDR, '_')) of
- [{?SCTP_LISTENER(_, _, LSock), _}] ->
- {ok, N} = inet:port(LSock),
- N;
- [] ->
- 0
- end;
-portnr(tcp, Ref) ->
- case diameter_reg:match(?TCP_LISTENER(Ref, ?ADDR, '_')) of
- [{?TCP_LISTENER(_, _, LSock), _}] ->
- {ok, N} = inet:port(LSock),
- N;
- [] ->
- 0
- end.
-
%% ===========================================================================
%% gen_connect/3
diff --git a/lib/diameter/test/diameter_util.erl b/lib/diameter/test/diameter_util.erl
index 99f4fa1977..6b1dc1f0c9 100644
--- a/lib/diameter/test/diameter_util.erl
+++ b/lib/diameter/test/diameter_util.erl
@@ -23,15 +23,28 @@
%% Utility functions.
%%
+%% generic
-export([consult/2,
run/1,
fold/3,
foldl/3,
- scramble/1,
- ps/0]).
+ scramble/1]).
+
+%% diameter-specific
+-export([lport/2,
+ lport/3,
+ listen/2, listen/3,
+ connect/3, connect/4,
+ disconnect/4]).
+
+%% common_test-specific
+-export([write_priv/3,
+ read_priv/2,
+ map_priv/3]).
-define(L, atom_to_list).
+%% ---------------------------------------------------------------------------
%% consult/2
%%
%% Extract info from the app/appup file (presumably) of the named
@@ -56,6 +69,7 @@ consult(Path) ->
%% Name/Path in the return value distinguish the errors and allow for
%% a useful badmatch.
+%% ---------------------------------------------------------------------------
%% run/1
%%
%% Evaluate functions in parallel and return a list of those that
@@ -71,6 +85,7 @@ cons(true, _, _, Acc) ->
cons(false, F, RC, Acc) ->
[{F, RC} | Acc].
+%% ---------------------------------------------------------------------------
%% fold/3
%%
%% Parallel fold. Results are folded in the order received.
@@ -116,6 +131,7 @@ down(MRef) ->
down() ->
receive {'DOWN', MRef, process, _, Reason} -> {MRef, Reason} end.
+%% ---------------------------------------------------------------------------
%% foldl/3
%%
%% Parallel fold. Results are folded in order of the function list.
@@ -131,6 +147,7 @@ recvl([{MRef, F} | L], Ref, Fun, Acc) ->
R = down(MRef),
recvl(L, Ref, Fun, acc(R, Ref, F, Fun, Acc)).
+%% ---------------------------------------------------------------------------
%% scramble/1
%%
%% Sort a list into random order.
@@ -150,12 +167,10 @@ s(Acc, L) ->
{H, [T|Rest]} = lists:split(random:uniform(length(L)) - 1, L),
s([T|Acc], H ++ Rest).
-%% ps/0
-
-ps() ->
- [{P, process_info(P)} || P <- erlang:processes()].
-
+%% ---------------------------------------------------------------------------
%% eval/1
+%%
+%% Evaluate a function in one of a number of forms.
eval({M,[F|A]})
when is_atom(F) ->
@@ -175,3 +190,133 @@ eval(L)
eval(F)
when is_function(F,0) ->
F().
+
+%% ---------------------------------------------------------------------------
+%% write_priv/3
+%%
+%% Write an arbitrary term to a named file.
+
+write_priv(Config, Name, Term) ->
+ write(path(Config, Name), Term).
+
+write(Path, Term) ->
+ ok = file:write_file(Path, term_to_binary(Term)).
+
+%% read_priv/2
+%%
+%% Read a term from a file.
+
+read_priv(Config, Name) ->
+ read(path(Config, Name)).
+
+read(Path) ->
+ {ok, Bin} = file:read_file(Path),
+ binary_to_term(Bin).
+
+%% map_priv/3
+%%
+%% Modify a term in a file and return both old and new values.
+
+map_priv(Config, Name, Fun1) ->
+ map(path(Config, Name), Fun1).
+
+map(Path, Fun1) ->
+ T0 = read(Path),
+ T1 = Fun1(T0),
+ write(Path, T1),
+ {T0, T1}.
+
+path(Config, Name)
+ when is_atom(Name) ->
+ path(Config, ?L(Name));
+path(Config, Name) ->
+ Dir = proplists:get_value(priv_dir, Config),
+ filename:join([Dir, Name]).
+
+%% ---------------------------------------------------------------------------
+%% lport/2-3
+%%
+%% Lookup the port number of a tcp/sctp listening transport.
+
+lport(M, Ref) ->
+ lport(M, Ref, 1).
+
+lport(M, Ref, Tries) ->
+ lp(tmod(M), Ref, Tries).
+
+lp(M, Ref, T) ->
+ L = [N || {listen, N, _} <- M:ports(Ref)],
+ if [] /= L orelse T =< 1 ->
+ L;
+ true ->
+ receive after 50 -> ok end,
+ lp(M, Ref, T-1)
+ end.
+
+%% ---------------------------------------------------------------------------
+%% listen/2-3
+%%
+%% Add a listening transport on the loopback address and a free port.
+
+listen(SvcName, Prot) ->
+ listen(SvcName, Prot, []).
+
+listen(SvcName, Prot, Opts) ->
+ add_transport(SvcName, {listen, opts(Prot, listen) ++ Opts}).
+
+%% ---------------------------------------------------------------------------
+%% connect/2-3
+%%
+%% Add a connecting transport on and connect to a listening transport
+%% with the specified reference.
+
+connect(Client, Prot, LRef) ->
+ connect(Client, Prot, LRef, []).
+
+connect(Client, Prot, LRef, Opts) ->
+ [PortNr] = lport(Prot, LRef, 20),
+ Ref = add_transport(Client, {connect, opts(Prot, PortNr) ++ Opts}),
+ true = diameter:subscribe(Client),
+ ok = receive
+ {diameter_event, Client, {up, Ref, _, _, _}} -> ok
+ after 2000 ->
+ {Client, Prot, PortNr, process_info(self(), messages)}
+ end,
+ Ref.
+
+%% ---------------------------------------------------------------------------
+%% disconnect/4
+%%
+%% Remove the client transport and expect the server transport to go
+%% down.
+
+disconnect(Client, Ref, Server, LRef) ->
+ true = diameter:subscribe(Server),
+ ok = diameter:remove_transport(Client, Ref),
+ ok = receive
+ {diameter_event, Server, {down, LRef, _, _}} -> ok
+ after 2000 ->
+ {Client, Ref, Server, LRef, process_info(self(), messages)}
+ end.
+
+%% ---------------------------------------------------------------------------
+
+-define(ADDR, {127,0,0,1}).
+
+add_transport(SvcName, T) ->
+ {ok, Ref} = diameter:add_transport(SvcName, T),
+ Ref.
+
+tmod(tcp) ->
+ diameter_tcp;
+tmod(sctp) ->
+ diameter_sctp.
+
+opts(Prot, T) ->
+ [{transport_module, tmod(Prot)},
+ {transport_config, [{ip, ?ADDR}, {port, 0} | opts(T)]}].
+
+opts(listen) ->
+ [];
+opts(PortNr) ->
+ [{raddr, ?ADDR}, {rport, PortNr}].
diff --git a/lib/diameter/test/diameter_watchdog_SUITE.erl b/lib/diameter/test/diameter_watchdog_SUITE.erl
index dec307529a..b40d7c104d 100644
--- a/lib/diameter/test/diameter_watchdog_SUITE.erl
+++ b/lib/diameter/test/diameter_watchdog_SUITE.erl
@@ -36,7 +36,7 @@
id/1, %% jitter callback
run/1]).
--include_lib("diameter/include/diameter.hrl").
+-include("diameter.hrl").
-include("diameter_ct.hrl").
%% ===========================================================================
diff --git a/lib/diameter/test/modules.mk b/lib/diameter/test/modules.mk
index c6f709dc36..f88258c232 100644
--- a/lib/diameter/test/modules.mk
+++ b/lib/diameter/test/modules.mk
@@ -33,8 +33,11 @@ MODULES = \
diameter_stats_SUITE \
diameter_watchdog_SUITE \
diameter_transport_SUITE \
+ diameter_capx_SUITE \
diameter_traffic_SUITE \
- diameter_relay_SUITE
+ diameter_relay_SUITE \
+ diameter_tls_SUITE \
+ diameter_failover_SUITE
-INTERNAL_HRL_FILES = \
+HRL_FILES = \
diameter_ct.hrl
diff --git a/lib/diameter/src/app/depend.sed b/lib/diameter/test/release.sed
index 9df0133960..2720b778f2 100644
--- a/lib/diameter/src/app/depend.sed
+++ b/lib/diameter/test/release.sed
@@ -18,14 +18,18 @@
#
#
-# Extract include dependencies from .erl files. The output is massaged
-# further in Makefile.
+# This bit of gymnastics is to replace the include of diameter's
+# public hrls by include_lib when releasing testsuites, so that they
+# compile both in the development filesystem (where generated hrls
+# aren't in diameter/include) and with common_test's autocompilation
+# on an installed release. Solving the problem by installing generated
+# hrls to ../include is anathema: that directory is for handwritten
+# source.)
#
-/^-include/!d
-/"diameter/!d
+/^-include("/!b
+/"diameter_gen_/b s
+/"diameter\./!b
-s@^-include_lib("[^/]*@$(DIAMETER_TOP)@
-s@^-include("@@
-s@".*@@
-s@^@$(EBIN)/.$(EMULATOR): @
+:s
+s@("@_lib&diameter/include/@
diff --git a/lib/diameter/vsn.mk b/lib/diameter/vsn.mk
index c783450c9f..b1d3ba2241 100644
--- a/lib/diameter/vsn.mk
+++ b/lib/diameter/vsn.mk
@@ -18,7 +18,7 @@
# %CopyrightEnd%
APPLICATION = diameter
-DIAMETER_VSN = 0.10
+DIAMETER_VSN = 0.11
PRE_VSN =
APP_VSN = "$(APPLICATION)-$(DIAMETER_VSN)$(PRE_VSN)"
diff --git a/lib/docbuilder/AUTHORS b/lib/docbuilder/AUTHORS
deleted file mode 100644
index 4f2a8e9361..0000000000
--- a/lib/docbuilder/AUTHORS
+++ /dev/null
@@ -1,10 +0,0 @@
-Docbuilder is a rewrite of the Old docbuilder
-and takes XML as input instead of SGML.
-Docbuilder makes use of xmerl for parsing XML
-and produces HTML. Everything is written in Erlang
-and there are no dependencies to external tools.
-
-Original Authors:
-Gunilla Arendt
-
-Contributors:
diff --git a/lib/docbuilder/Makefile b/lib/docbuilder/Makefile
deleted file mode 100644
index 21f42421d6..0000000000
--- a/lib/docbuilder/Makefile
+++ /dev/null
@@ -1,37 +0,0 @@
-# ``The contents of this file are subject to the Erlang Public License,
-# Version 1.1, (the "License"); you may not use this file except in
-# compliance with the License. You should have received a copy of the
-# Erlang Public License along with this software. If not, it can be
-# retrieved via the world wide web at http://www.erlang.org/.
-#
-# Software distributed under the License is distributed on an "AS IS"
-# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
-# the License for the specific language governing rights and limitations
-# under the License.
-#
-# The Initial Developer of the Original Code is Ericsson Utvecklings AB.
-# Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings
-# AB. All Rights Reserved.''
-#
-# $Id$
-#
-include $(ERL_TOP)/make/target.mk
-include $(ERL_TOP)/make/$(TARGET)/otp.mk
-
-#
-# Macros
-#
-
-SUB_DIRECTORIES = src dtd etc doc/src
-
-include vsn.mk
-VSN = $(DOCB_VSN)
-
-SPECIAL_TARGETS =
-
-#
-# Default Subdir Targets
-#
-include $(ERL_TOP)/make/otp_subdir.mk
-
-
diff --git a/lib/docbuilder/doc/pdf/.gitignore b/lib/docbuilder/doc/pdf/.gitignore
deleted file mode 100644
index e69de29bb2..0000000000
--- a/lib/docbuilder/doc/pdf/.gitignore
+++ /dev/null
diff --git a/lib/docbuilder/doc/src/book.xml b/lib/docbuilder/doc/src/book.xml
deleted file mode 100644
index a13d56dd8a..0000000000
--- a/lib/docbuilder/doc/src/book.xml
+++ /dev/null
@@ -1,50 +0,0 @@
-<?xml version="1.0" encoding="latin1" ?>
-<!DOCTYPE book SYSTEM "book.dtd">
-
-<book xmlns:xi="http://www.w3.org/2001/XInclude">
- <header titlestyle="normal">
- <copyright>
- <year>1997</year><year>2009</year>
- <holder>Ericsson AB. All Rights Reserved.</holder>
- </copyright>
- <legalnotice>
- The contents of this file are subject to the Erlang Public License,
- Version 1.1, (the "License"); you may not use this file except in
- compliance with the License. You should have received a copy of the
- Erlang Public License along with this software. If not, it can be
- retrieved online at http://www.erlang.org/.
-
- Software distributed under the License is distributed on an "AS IS"
- basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
- the License for the specific language governing rights and limitations
- under the License.
-
- </legalnotice>
-
- <title>DocBuilder</title>
- <prepared></prepared>
- <docno></docno>
- <date></date>
- <rev></rev>
- </header>
- <insidecover>
- </insidecover>
- <pagetext>Docbuilder</pagetext>
- <preamble>
- <contents level="2"></contents>
- </preamble>
- <parts lift="no">
- <xi:include href="part.xml"/>
- </parts>
- <applications>
- <xi:include href="ref_man.xml"/>
- </applications>
- <releasenotes>
- <xi:include href="notes.xml"/>
- </releasenotes>
- <listoffigures></listoffigures>
- <listoftables></listoftables>
- <listofterms></listofterms>
- <index></index>
-</book>
-
diff --git a/lib/docbuilder/doc/src/docb_gen.xml b/lib/docbuilder/doc/src/docb_gen.xml
deleted file mode 100644
index d4ebfd0f84..0000000000
--- a/lib/docbuilder/doc/src/docb_gen.xml
+++ /dev/null
@@ -1,213 +0,0 @@
-<?xml version="1.0" encoding="iso-8859-1" ?>
-<!DOCTYPE erlref SYSTEM "erlref.dtd">
-
-<erlref>
- <header>
- <copyright>
- <year>1999</year>
- <year>2011</year>
- <holder>Ericsson AB, All Rights Reserved</holder>
- </copyright>
- <legalnotice>
- The contents of this file are subject to the Erlang Public License,
- Version 1.1, (the "License"); you may not use this file except in
- compliance with the License. You should have received a copy of the
- Erlang Public License along with this software. If not, it can be
- retrieved online at http://www.erlang.org/.
-
- Software distributed under the License is distributed on an "AS IS"
- basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
- the License for the specific language governing rights and limitations
- under the License.
-
- The Initial Developer of the Original Code is Ericsson AB.
- </legalnotice>
- <title>docb_gen</title>
- <prepared></prepared>
- <docno></docno>
- <date></date>
- <rev></rev>
- </header>
- <module>docb_gen</module>
- <modulesummary>Generate XML from EDoc comments in Erlang source code.
- </modulesummary>
-
- <description>
- <p><c>docb_gen</c> contains functions for generating XML
- documentation source code according to the <c>erlref</c> or
- <c>chapter</c> DTD from
- <seealso marker="edoc:chapter">EDoc</seealso> comments in Erlang
- source code or an <c>overview.edoc</c> file, using EDoc.</p>
- </description>
-
- <funcs>
- <func>
- <name>module(File) -> ok | {error, Reason}</name>
- <name>module(File, Options) -> ok | {error, Reason}</name>
- <fsummary>Generate XML from EDoc comments in Erlang source code.
- </fsummary>
- <type>
- <v>File = string()</v>
- <v>Options = [Opt]</v>
- <v>Opt = {def,Defs} | {includes,Dirs} | {preprocess,Bool}
- | {sort_functions,Bool}</v>
- <v>Defs = [{atom(),string()}]</v>
- <v>Dirs = [string()]</v>
- <v>Bool = bool()</v>
- <v>Reason = badfile | {badopt,term()} | term()</v>
- </type>
- <desc>
- <p>Generates XML documentation source code according to
- the <c>erlref</c> DTD from EDoc comments <c>File</c>, using
- the EDoc application.</p>
-
- <p><c>File</c> is an Erlang source file, given with or without
- the <c>.erl</c> extension as <c>Name.erl</c> or <c>Name</c>.
- The resulting XML file is created in the current working
- directory and named <c>Name.xml</c>.</p>
-
- <p><c>Options</c> is a list of options, see below.</p>
-
- <p>Returns <c>ok</c> if successful, and an error tuple
- otherwise.</p>
- </desc>
- </func>
-
- <func>
- <name>users_guide(File) -> ok | {error, Reason}</name>
- <name>users_guide(File, Options) -> ok | {error, Reason}</name>
- <fsummary>Generate XML from EDoc comments in Erlang source code
- </fsummary>
- <type>
- <v>File -- see module/1,2</v>
- <v>Options -- see module/1,2</v>
- <v>Reason -- see module/1,2</v>
- </type>
- <desc>
- <p>Like <c>module/1,2</c> but generates XML source code
- according to the <c>chapter</c> DTD from an
- <c>overview.edoc</c> or similar file.</p>
-
- <p>The resulting file is named <c>chapter.xml</c>.</p>
- </desc>
- </func>
- </funcs>
-
- <section>
- <title>Options</title>
- <taglist>
- <tag><c>{def, [{Name,Text}]}</c></tag>
- <item>Specifies EDoc macro definitions. See
- <seealso marker="edoc:edoc">edoc:get_doc/2</seealso>.</item>
-
- <tag><c>{includes, [Dir]}</c></tag>
- <item>Specifies directories where EDoc should search for include
- files. See
- <seealso marker="edoc:edoc">edoc:read_source/2</seealso>.</item>
-
- <tag><c>{preprocess, true|false}</c></tag>
- <item>Specifies if EDoc should read the source file via the Erlang
- preprocessor. Default is <c>false</c>. See
- <seealso marker="edoc:edoc">edoc:read_source/2</seealso>.</item>
-
- <tag><c>{sort_functions, true|false}</c></tag>
- <item>Specifies if the functions in the resulting XML file should
- be sorted alphabetically. Default is <c>true</c>.</item>
- </taglist>
- </section>
-
- <section>
- <title>Limitations</title>
- <p>The mapping from the EDoc XHTML output to valid Erlang/OTP XML
- is not complete. An attempt has been made to cover the most
- commonly used XHTML constructs, but there will still be cases
- where XML generation fails or where the resulting XML is
- inadequate. This is especially true for <c>users_guide/1,2</c>.
- </p>
-
- <p>Known limitations for some XHTML tags:</p>
- <taglist>
- <tag><c><![CDATA[<a>]]></c></tag>
- <item>
- <p>All attributes except the first <c>href</c> or <c>name</c>
- attribute are ignored.</p>
- <p>A <c>href</c> attribute means the <c><![CDATA[<a>]]></c> tag
- will be transformed to a <c><![CDATA[<seealso>]]></c> or
- <c><![CDATA[<url>]]></c> tag and an attempt is made to
- resolve the reference if necessary.</p>
-
- <p>A <c>name</c> attribute means the <c><![CDATA[<a>]]></c> tag
- will be transformed to a <c><![CDATA[<marker>]]></c> tag.</p>
- </item>
-
- <tag><c><![CDATA[<b>, <em>, <pre>]]></c></tag>
- <item>Cannot contain other tags in Erlang/OTP XML, content is
- converted to plain text.
- </item>
-
- <tag><c><![CDATA[<center>]]></c></tag>
- <item>No corresponding Erlang/OTP XML tag, converted to plain
- text.
- </item>
-
- <tag><c><![CDATA[<font>]]></c></tag>
- <item>No corresponding Erlang/OTP XML tag, converted to plain
- text.
- </item>
-
- <tag><c><![CDATA[<h1>, <h2>, ...]]></c></tag>
- <item>There is no tag corresponding to a header in Erlang/OTP XML,
- so these are converted to plain text instead, with
- the exception of <c><![CDATA[<h3>]]></c> and
- <c><![CDATA[<h4>]]></c> tags within <c>overview.edoc</c>, see
- part about "<c>chapter</c> DTD" below.
- </item>
-
- <tag><c><![CDATA[<sup>]]></c></tag>
- <item>There is no tag corresponding to superscript in Erlang/OTP
- XML, so this is converted to plain text within brackets "(..)".
- </item>
-
- <tag>References</tag>
- <item>The markers automatically inserted by EDoc at each heading
- and function will override the markers automatically inserted
- by DocBuilder, with the unfortunate result that the links in
- the left-hand frame of the User's Guide will not work, and
- also that cross referencing a function in a module the usual
- Erlang/OTP way
- "<c><![CDATA[<seealso marker="edoc:edoc#run/3...>]]></c>" does
- not work. (But
- "<c><![CDATA[<seealso marker="edoc:edoc#run-3...>]]></c>" does.)
- </item>
- </taglist>
-
- <p><em>erlref DTD</em></p>
- <taglist>
- <tag>Tables</tag>
- <item>Tables are not allowed. The contents of a table is
- converted to text instead, each row corresponding to one line
- of text.
- </item>
- </taglist>
-
- <p><em>chapter DTD</em></p>
- <taglist>
- <tag>Sections</tag>
- <item>Only two levels of sections. <c><![CDATA[<h3>]]></c>
- (equivalent to EDoc headings "<c>== Heading ==</c>") is
- interpreted as start of top-level section, or if there is no
- <c><![CDATA[<h3>]]></c> tag, the entire document is made into
- one top-level section. <c><![CDATA[<h4>]]></c> (equivalent to
- EDoc sub-headings ("<c><![CDATA[=== Sub-heading ===]]></c>") is
- interpreted as start of second-level section.
- </item>
-
- <tag>Tables</tag>
- <item>Tables without borders are converted to text in the same
- manner as for the <c>erlref</c> DTD.
- </item>
- </taglist>
- </section>
-
-</erlref>
-
diff --git a/lib/docbuilder/doc/src/docb_transform.xml b/lib/docbuilder/doc/src/docb_transform.xml
deleted file mode 100644
index 06a04c8c02..0000000000
--- a/lib/docbuilder/doc/src/docb_transform.xml
+++ /dev/null
@@ -1,224 +0,0 @@
-<?xml version="1.0" encoding="latin1" ?>
-<!DOCTYPE erlref SYSTEM "erlref.dtd">
-
-<erlref>
- <header>
- <copyright>
- <year>2001</year>
- <year>2011</year>
- <holder>Ericsson AB, All Rights Reserved</holder>
- </copyright>
- <legalnotice>
- The contents of this file are subject to the Erlang Public License,
- Version 1.1, (the "License"); you may not use this file except in
- compliance with the License. You should have received a copy of the
- Erlang Public License along with this software. If not, it can be
- retrieved online at http://www.erlang.org/.
-
- Software distributed under the License is distributed on an "AS IS"
- basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
- the License for the specific language governing rights and limitations
- under the License.
-
- The Initial Developer of the Original Code is Ericsson AB.
- </legalnotice>
-
- <title>docb_transform</title>
- <prepared></prepared>
- <docno></docno>
- <date></date>
- <rev></rev>
- </header>
- <module>docb_transform</module>
- <modulesummary>Transform XML to HTML</modulesummary>
- <description>
- <p><c>docb_transform</c> contains functions for transforming XML
- documentation source code to HTML.</p>
- </description>
-
- <funcs>
- <func>
- <name>file(File) -> ok | {error, Reason}</name>
- <name>file(File, Options) -> ok | {error, Reason}</name>
- <fsummary>Transform XML to HTML</fsummary>
- <type>
- <v>File = string()</v>
- <v>Options = [Opt]</v>
- <v>Opt -- see below</v>
- </type>
- <desc>
- <p>Transforms XML documentation source code to HTML.</p>
-
- <p><c>File</c> is a documentation source file, given with or
- without the <c>.xml</c> extension as <c>Name.xml</c> or
- <c>Name</c>.</p>
-
- <p>If <c>File</c> contains XML code according to a basic DTD
- (<c>chapter</c>, <c>erlref</c>, ...), the resulting HTML
- file is named <c>Name.html</c>.</p>
-
- <p>If <c>File</c> contains XML code according to a compound DTD
- (<c>application</c> or <c>part</c>), several files are
- created:</p>
- <list>
- <item>A cover page for the application with two frames,
- <c>Name_frame.html</c>.</item>
- <item>The contents of the left frame and a front page,
- <c>Name.html</c> and <c>Name_first.html</c>.</item>
- <item>A bibliography and a glossary, <c>Name_cite.html</c>
- and <c>Name_term.html</c>.</item>
- <item>In the case of an <c>application</c> DTD an index
- is created, <c>Name.kwc</c> and <c>Name_index.html</c>.
- </item>
- <item>One HTML file for each file included from <c>File</c>.
- </item>
- <item>Also, if there exists a <c>fascicules.xml</c> file where
- the value of the <c>entry</c> attribute for <c>File</c> is
- <c>"yes"</c>, the cover page is copied to <c>index.html</c>.
- </item>
- </list>
- </desc>
- </func>
- </funcs>
-
- <section>
- <title>Options</title>
- <taglist>
- <tag><c>{html_mod, Module}, Module=atom()</c></tag>
- <item>
- <p>A callback module can be used for specifying HTML snippets
- that should be included in the generated HTML files, see
- below.</p>
- </item>
-
- <tag><c>{outdir, Dir}, Dir=string()</c></tag>
- <item>
- <p>Destination for generated files. Default is current working
- directory.</p>
- </item>
-
- <tag><c>{number, Number}, Number=int()</c></tag>
- <item>
- <p>First chapter number when transforming a <c>chapter</c>
- file. Default is 1.</p>
- </item>
-
- <tag><c>{ptype, unix|windows}</c></tag>
- <item>
- <p>For <c>path</c> elements, the specified file path should be
- presented.</p>
- </item>
-
- <tag><c>silent</c></tag>
- <item>
- <p>Silent - no warnings, only error information is printed.</p>
- </item>
-
- <tag><c>{top, Index}, Index=string()</c></tag>
- <item>
- <p>Specifies the value of "Top" in the left frame of a front
- page, which normally should be some kind of top index file
- for the documentation.</p>
- </item>
-
- <tag><c>{vsn, Vsn}, Vsn=string()</c></tag>
- <item>
- <p>Application version number. Overrides a version number
- defined in the XML document. Visible in the left frame and
- on the front page.</p>
- </item>
-
- <tag><c>{term_defs, File}, File=string()</c></tag>
- <item>
- <p>Use the global glossary definitions in <c>File</c>, which
- should contain a list of tuples <c>{Id, Name, Definition,
- Owner}</c>. See the section
- <seealso marker="inline_tags#termTAG">&lt;term&gt;,
- &lt;termdef&gt; - Glossary</seealso> in the User's Guide.
- </p>
- </item>
-
- <tag><c>{cite_defs, File}, File=string()</c></tag>
- <item>
- <p>Use the global bibliography definitions in <c>File</c>, which
- should contain a list of tuples <c>{Id, Title, Info,
- Owner}</c>. See the section
- <seealso marker="inline_tags#citeTAG">&lt;cite&gt;,
- &lt;citedef&gt; - Bibliography</seealso> in the User's
- Guide.</p>
- </item>
- </taglist>
- </section>
-
- <section>
- <title>Callback Module</title>
-
- <p>A <c>html_mod</c> callback module can include the functions
- specified below. Note that there is no check that the resulting
- HTML code is valid. All functions are optional.</p>
- </section>
-
- <funcs>
- <func>
- <name>Module:head() -> string()</name>
- <fsummary>Snippet to be included in head of a document.</fsummary>
- <desc>
- <p>Defines a HTML snippet to be included in the head of
- a document, after the <c>&lt;HEAD></c> start tag and
- <c>&lt;TITLE></c> tag:</p>
- <pre>
-&lt;HTML>
-&lt;HEAD>
- &lt;TITLE>...&lt;/TITLE>
- - snippet is included here -
- ...
-&lt;/HEAD>
-...
-&lt;/HTML>
- </pre>
- </desc>
- </func>
-
- <func>
- <name>Module:top() -> string()</name>
- <fsummary>Snippet to be included at the top of a document.
- </fsummary>
- <desc>
- <p>Defines a HTML snippet to be included at the top of a
- document, after the <c>&lt;BODY></c> start tag.</p>
- </desc>
- </func>
-
- <func>
- <name>Module:bottom() -> string()</name>
- <fsummary>Snippet to be included at the bottom of a document.
- </fsummary>
- <desc>
- <p>Defines a HTML snippet to be included at the bottom of a
- document, before the <c>&lt;/BODY></c> end tag.</p>
- </desc>
- </func>
-
- <func>
- <name>Module:seealso(SeeAlso) -> Href</name>
- <fsummary></fsummary>
- <type>
- <v>SeeAlso = Href = string()</v>
- </type>
- <desc>
- <p>When referring to another part of the document, or another
- document, the XML tag <c>&lt;seealso&gt;</c> is used:
- <c><![CDATA[<seealso marker="File#Marker">...text...</seealso>]]></c>.
- By default, this is translated to
- <c><![CDATA[<A HREF="File.html#Marker>...text...</A>]]></c>.</p>
-
- <p>This function makes it possible to specify an alternative
- translation <c>Href</c> of the <c>marker</c> attribute value
- <c>SeeAlso</c>. For example, in OTP this is used to resolve
- cross references between applications.</p>
- </desc>
- </func>
- </funcs>
-
-</erlref>
-
diff --git a/lib/docbuilder/doc/src/docbuilder_app.xml b/lib/docbuilder/doc/src/docbuilder_app.xml
deleted file mode 100644
index 58b8daf598..0000000000
--- a/lib/docbuilder/doc/src/docbuilder_app.xml
+++ /dev/null
@@ -1,57 +0,0 @@
-<?xml version="1.0" encoding="latin1" ?>
-<!DOCTYPE appref SYSTEM "appref.dtd">
-
-<appref>
- <header>
- <copyright>
- <year>2007</year>
- <year>2011</year>
- <holder>Ericsson AB, All Rights Reserved</holder>
- </copyright>
- <legalnotice>
- The contents of this file are subject to the Erlang Public License,
- Version 1.1, (the "License"); you may not use this file except in
- compliance with the License. You should have received a copy of the
- Erlang Public License along with this software. If not, it can be
- retrieved online at http://www.erlang.org/.
-
- Software distributed under the License is distributed on an "AS IS"
- basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
- the License for the specific language governing rights and limitations
- under the License.
-
- The Initial Developer of the Original Code is Ericsson AB.
- </legalnotice>
-
- <title>docbuilder</title>
- <prepared></prepared>
- <docno></docno>
- <date></date>
- <rev></rev>
- </header>
- <app>docbuilder</app>
- <appsummary>The DocBuilder Application</appsummary>
- <description>
- <p>DocBuilder provides functionality for generating HTML
- documentation for Erlang modules and Erlang/OTP applications
- from XML source code and/or EDoc comments in Erlang source code.
- </p>
- </description>
-
- <section>
- <title>Limitations</title>
- <p>DocBuilder is primarily intended for generating documentation
- for Erlang/OTP itself. That is, no attempt has been made to create
- a tool suitable for generating documentation in general.</p>
- </section>
-
- <section>
- <title>See Also</title>
- <p>DocBuilder User's Guide,
- <seealso marker="docb_gen">docb_gen(3)</seealso>,
- <seealso marker="docb_transform">docb_transform(3)</seealso>
- <seealso marker="docb_xml_check"></seealso></p>
- </section>
-
-</appref>
-
diff --git a/lib/docbuilder/doc/src/make.dep b/lib/docbuilder/doc/src/make.dep
deleted file mode 100644
index d9b075e114..0000000000
--- a/lib/docbuilder/doc/src/make.dep
+++ /dev/null
@@ -1,33 +0,0 @@
-# ----------------------------------------------------
-# >>>> Do not edit this file <<<<
-# This file was automaticly generated by
-# /home/otp/bin/docdepend
-# ----------------------------------------------------
-
-
-# ----------------------------------------------------
-# TeX files that the DVI file depend on
-# ----------------------------------------------------
-
-book.dvi: block_tags.tex book.tex character_entities.tex \
- docb_gen.tex docb_transform.tex docb_xml_check.tex \
- docbuilder_app.tex fasc_dtds.tex header_tags.tex \
- inline_tags.tex overview.tex part.tex ref_man.tex \
- refman_dtds.tex user_guide_dtds.tex
-
-# ----------------------------------------------------
-# Source inlined when transforming from source to LaTeX
-# ----------------------------------------------------
-
-block_tags.tex: gazonk
-
-book.tex: ref_man.xml
-
-inline_tags.tex: ../../../../system/doc/definitions/term.defs
-
-# ----------------------------------------------------
-# Pictures that the DVI file depend on
-# ----------------------------------------------------
-
-book.dvi: man.ps
-
diff --git a/lib/docbuilder/doc/src/man.ps b/lib/docbuilder/doc/src/man.ps
deleted file mode 100644
index b4d7ef7636..0000000000
--- a/lib/docbuilder/doc/src/man.ps
+++ /dev/null
@@ -1,750 +0,0 @@
-%!PS-Adobe-2.0 EPSF-2.0
-%%Title: /clearcase/otp/internal_tools/sgml/test/man.ps
-%%Creator: XV Version 3.10a Rev: 12/29/94 - by John Bradley
-%%BoundingBox: 243 308 369 484
-%%Pages: 1
-%%DocumentFonts:
-%%EndComments
-%%EndProlog
-
-%%Page: 1 1
-
-% remember original state
-/origstate save def
-
-% build a temporary dictionary
-20 dict begin
-
-% define string to hold a scanline's worth of data
-/pix 126 string def
-
-% define space for color conversions
-/grays 126 string def % space for gray scale line
-/npixls 0 def
-/rgbindx 0 def
-
-% lower left corner
-243 308 translate
-
-% size of image (on paper, in 1/72inch coords)
-126.00000 175.96800 scale
-
-126 176 8 % dimensions of data
-[126 0 0 -176 0 176] % mapping matrix
-{currentfile pix readhexstring pop}
-image
-
-110000110011111111111100111111110011110011111111111100111111112222222222
-33445544446655665555665566666655666666888888778899888899aabbaabbbbbbaabb
-bbaaaaaaaabbbbbbaabbccddbbaaaaccccccddddccddddccbbccccccbbccccaabbaaaaaa
-9999aaaa8899887777554455666655555544
-000000110011110000001100112222111111001111111100001111111111112222112233
-55334444446666775544555555775577777766888888889988889999aaccbbaabb99aaaa
-bbbbaaaaaaaabbbbccccccccccccbbccccccccddccddddccbbaaccddccbbaaccbbbbaaaa
-999999889977667755554455666655444444
-110011000011000000111111111100111100112211111111110011111111112222222233
-3344444455446677665555667777667788888888667788aa88999999aabbaabbaa889999
-aabbbbbbaaaaaabbddccccccbbccccccbbaaccccccccccccbbccccccccbbbbbbbbaaaa99
-9999aa888877666655555555555544333344
-110000110011110000001111111111000011001122110011111111002211222211224433
-3333444444556677666655667777667777888877666688998899aa99aabbaaaaaaaabbaa
-99aabbaabbbbbbbbbbccbbddaabbccbbaa99ccddccccccbbccccccddccbbbbaaccaa9988
-889988887766665566665544443344554444
-000000000000110011000000110000110000001111000000111100221111111133222222
-33444433444455667777555555776666778888667777778888aa998888bbaa99aaaaaabb
-bbbbbbaabbccbbbbbbccbbbbbbccccaabbbbbbccccccbbbbbbbbccbbbbbbbbbbbbaa7788
-aa9988889966666655666655553355556644
-110011111111111100111100110011000000001100002211111122221122111122222222
-33443333334455776666776666667766778855668866777788448899889988889999bbaa
-aaaabbaaaabbbbaabbbbbbbbbbbbaa99bbaabbccddccccccbbccbbbbaabbbbaaaa777788
-aa9999aa9988776677777755555544556655
-110000001111111122111111000000001111110011111111110022111111111133222233
-223322445555445544667777667777667777887788887799883377999999998899aaaaaa
-99aabbbbccbbbbbbbbbbaaaaaabb99aaaabbbbbbccccccbbccccbbbbaabbaaccaa886688
-9999aaaa9988888866667744555544445544
-110000111122111111221100111111110011111111111100111111222222221122333333
-22222244556655445555667788778888aaaa88aa889999aabbaaaa998888998899aa99aa
-bbaabbccbbbbaaaabbbbbbbbbbbbaabbaaaaccccccbbccddccbbaabbaabbaabb99888888
-99aa99aa9988888866446655554444444444
-110000001111111111110011110000111100221111001111000011222222222222333344
-223322444466664455667766777788777755556666333344557788aa9999888888aa88aa
-aabbbbaabbaaccbbaaaaaaccbbccaa99bbccccccccbbccccccbbbbbbbbaabbaaaa99aa88
-999988999988887766664455445555555544
-110011111100001111111111110000000011111111110011111122111111112233222222
-443333555544444455777788775522000000000000000000000000447799aaaa99888899
-aaaabbaaaaccbbaaaabbbbbbbbaa7788bbddccccbbbbbbbbccbbbbaabbaaaaaaaaaa9999
-aa999988aa99887766666655444455445544
-000000110011110000110000110011001100001111110000111122112211112211222222
-5544444455443333446677772200000000000000000000000000000000337799999999aa
-9999aabbbbbbaaaa88aaaabbbb889988ccccccbbccbbbbaaaa9999bb8855889999999988
-998888998888886655667755554455554433
-110011001111001100001100111111000000001100111100111111222211113333222211
-44555544444433445555550000000000000000000000000011000000000000003377aa99
-888899aa99aa9999aaaabbaabb99aabbaabbbbccaabbaaaabb88aaaa995588aaaaaa8888
-8888aa998888887755777766554444332222
-111111110011111111001111001111110000000011000011001111111122332222223322
-334466554444444455441100000000000000000000000000000000001155220000113366
-998888aa99998899bbbbaabbbbaaaaaabbbbbbbbbbaabbaaaa99aaaa8888aa9999889988
-7799aa888888665566666655554433334422
-221111110011000011111111110000000000110011110000111111001111333311223333
-443344443344554488440011553300000000000000000000000000227788883300000011
-4444559999887799aaaaaaccbbaaaa9988ccccbbaabbbbaaaa99aa9988aa999988888888
-776688888877667766554455444444444433
-221111110011111100110011000011000000000000110000110011001111112222221122
-2222333333111111448899ccffddbb77442222221111000000000044bbddccaa33000000
-00000000558888998899bbaabbaabbaa99bbaabbaaaabbaa99aa99999988778888777777
-663355778877776666665544444433333322
-221100222211001111112200111111000011000000000011001100111111112211112211
-332244220011000055ddffeeeeeeeeeeddddddeeddcc88330000000044ddddcc55000000
-000000000077aaaa999999aaaabbbbbbaa99aabbbbaaaabbaaaaaa999999888888557755
-664466666677666655667755443333223322
-221111222211221111111100000011110000110000001100111111110011111122112222
-3322000000000044ddffffeeffeeeeeeeeeeeeeeffeeffdd885511000033aaddaa330011
-2211000000339988889999aaaaaabbaabbbbbbbbbbaaaaaabb99aa8899aa999988665577
-665577777766555544443366443344333322
-221111111122221111001111111100000000000000001111111111111111111111223344
-22000000000077ddeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeffeebb440000005588661100
-11000000001188888888aa9999aabbbbbbaaaabbaabbbbbbaa8899888899888888776666
-556666776666443366555555445533333333
-112211111122221111221100111100110000000000001111001100000000111122112211
-000000000088eeeeeeeeeeeeffeeeeffffeeeeeeffeeeeeeeeeeffee8811000000118866
-0000000000118899888899aaaabbbbbbbbbbbb99aabbaaaaaa9988888877888877555566
-555555666655446655556655444444443344
-221111111100111111110011111111110011001100110000111100110011111111000000
-0000000088ffeeddeeeeeeeeeeeeeeeeeeeeffeeeeffffeeeeeeeeffffbb775566aaeeee
-aa332233000088aa88888899bbaaaa99aabbaaaabbaabbbbaaaa88888877888877555555
-445577666655554455555566665544665533
-110000111111110011111111111111110000000000001100111111000011111111110000
-00000088ddddddddddffeeffeeeeeeeeeeeeffeeeeeeeeffeeeeeeeeeeffffffffffeedd
-eecc441111002288997788aa99aaaa99aa99aabbbbaabbaaaa9977778888777777776655
-555577776666666666666677775555555555
-001111110011001100111111112211111100110000000011110011111111001111000000
-000022aaddccddddeeeeeeeeeeeeeeeeeeeeeeeeeeffeeffeeeeeeffeeffeeeeeeeeeeee
-eeffdd3311110044998899999999aaaaaaaaaabbaabbbbaaaa8888778877888866776677
-665566667755556644665555554444666666
-110011110011111111001100002211111100110011111100111100111111111100000000
-000022bbcccccccceeeeeeeeeeeeeeeeeeeeffeeffeeffffffeeeeffeeffeeffeeeeeeee
-eeddeebb6644000088998899bbbbbbaabbbbbbaabbbbbbcc999988888877888877667777
-557777777766665544555555555555665566
-110011221111111111111111111111221100001100110011111111221100221100000000
-00001199aabbccccddeeeeeeeeeeeeeeeeeeeeeeffffeeffeeffeeeeffeeffeeeeeeeeee
-eeddeeeebb88110066aa99aabbccbbaabbbbbbaabbbbbbbbbb99aaaa9988777766667777
-666677777777665544665566555566664455
-221111222222111111111111221111111111111111001111111100221122221100000000
-000022aabbbbaaccddeeeeeeeeddeeeeeeffeeeeeeeeffeeffeeffeeffffeeeeeeeeeeee
-eeeeeeeeeecc220066aaaaaaaabbbbbbccaabbaaaabbccbbaaaaaa998888886677887777
-777777888866776655667755665566666655
-222211222222111122111122111111000000001111111111111122111122220000000000
-00002299bbaaaabbddeeeeeeddeeffeeeeeeeeeeffeeeeeeeeffeeeeffffffeeeeeeeeee
-eeeeeeeeeecc330044aaaabbaabbbbbbaaaabb99aabbbbbbbbaaaa889988888877888888
-887777778888776644777777666677667766
-222222332233222211221111221111110000111111222222222211222222221100000000
-00001188cc99aabbddddddeeeeeeeeeeeeeeffeeeeeeeeeeffeeeeffeeffeeeeeeeeeeee
-eeeeeeeeeeee440044bbaabbbbaabbbb9999aaaabbaabbbbbb9999998888887788888899
-887777778888887755776677667755667755
-221122442222222222332211222222111111001111222222221133112222220000000000
-00001177bbaaaaaaeeddeeddeeeeddeeeeeeeeeeeeeeeeeeffeeffffeeeeeeffeeeeeedd
-eeeeffeeddffaa0022aabbbbbbbbbbaaaa99bbbbaabbaabbaa9988888888998888887777
-888866777788888888888877666655445566
-331133442233333333332222332211111111111111112222222233221122220000000000
-0000115599aabbccddddeeddeeeeeeeeeeeeeeeeffeeeeffeeffeeffffffeeffeeffddee
-eeeeeeeeeeffdd110088bbbbbbccbbaa99bbaabbaaaabbbbbbbb99888888888888666677
-777777778888666677888877775544444455
-332222332222334422222233222233110011222222112233223322222211221100000000
-000000228899aabbddddeeddeeeeeeeeeeeeeeeeffeeeeeeffeeffeeeeffeeffeeeeeedd
-eeffeeeeeeeecc220066bbaabbbbbbaaaa999999aaaaaaaa9999aaaa9988888877776688
-888877778888776677887777666666665544
-333311332233333333222222222233331111113322222222223322332222220000000000
-000000225577aabbccddddddeeeeeeeeeeeeeeeeeeeeeeffffffffeeffffeeeeeeeeeeee
-eeeeeeeeeeeedd110044bbaaaabbaabb99999999aabbaa999999aa999999998888777788
-888855888888886677777788777777555555
-222211222222224444111122222211222233221133443344332233333322551100000000
-00000022557788aaccddeeddddeeddeeeeeeeeeeffffeeffeeeeffeeeeeeeeffeeffeedd
-eeeeeeeeeeeedd33003399aaaabbbbaaaa88999999aaaaaa99aaaabbaaaaaa9999778888
-887766888888885577776666777766556644
-222211222222222233334422222222112233222233554444332222222222440000000000
-0000001144779988bbccddddddffddeeeeeeffeeeeeeeeffffffeeeeeeffeeffffeeeedd
-eeeeeeeeeeeedd2200228899aaaaaa88888899999999bbaa99aabbbbbbaa999988888888
-887777778877665566886666666677775566
-443322111133331111222233332222332222332233223333333333332233331100000000
-000000115555668899ddddddddeeeeeeeeffeeffffffeeffeeeeffeeeeeeeeeeeeeeeedd
-eeeeeeeeeeeedd2200339999aabbaa889999aaaa99aabbaaaa99bbbbaaaa998899998888
-888888997777775577777777777777666666
-332211223322222222221122223333221122112233333333332244333333330000000000
-0000000033444466aaccccddddeeeeeeeeeeeeffeeeeeeffeeeeeeeeeeffeeeeffffeedd
-eeeeeeeeeeeecc2200228899aaaa9988aaaaaaaa99aa99bbaabbaaaa99999988aa999988
-888888887777776677666666776666556644
-332222222233222233332222333333331133332233224433333344554444331100000000
-000000110044777788aaeeeeddeeeeddddddeeeeeeeeeeffeeffeeeeeeeeeeeeeeeedddd
-ddeeddeeeeeedd220011aa9999aa999999bbbbbb99bbbbbbbbbbbbaaaaaa999999888899
-998888888888666677556677666655555555
-332222222222333333443333333322443333443344334433444455553333330000000000
-000000002233557788ccccccccaa775555446688ccddcceeeeeeeeeeddeeeeeeeeeedddd
-eeddeeeeeeeedd44003399aa88aaaa99aaaaaaaa99bbbbbbbbbbbbbbbbbbaa999999aa88
-888866887788775577667755556655555544
-331122332222444433333333223333333344444444554433445555664444441100000000
-00000000332244889999777788330000000000116688aaddccddddccddddaa88aa99aadd
-ddddeeeeeeddee660022aa99999999bb99bbbbaaaabbbbbbbbccbbbbbbbbaa99aaaa8888
-888877776677667755777755445555556655
-331122333333335544554433333322443344555555554433334433556655441100000000
-000000000000225544221100110000000000001111557799ccbb88778877110011003388
-bbddeeeeeeddee55002299aa999999aaaabbaabbaabbbbbbaaaaaabbaaaabbaa99998888
-887777667788666666666666555555554444
-333333333322444444555555444444444455556666555544334455336666551100000000
-000000001111001100000000000000000000000011224455889966111111000000000011
-66aaddeeeeeeee550033aa99aa999999bb99bbccaabbbbaaaaaaaabbaaaabbaabb888888
-667777777777775577554455553344444444
-223344332233555544556666665533335544556655555533446655555555661100000000
-00001100111100000000000011000000000000000011449999bb77000000000000004433
-225588cceeeeff660044aaaa888899aa9999aaaa99aabbaaaaaa99bbbb9999aaaa998888
-886677777777667766555555443355554455
-443344332233556655666655666633555544555555555555555566555555662200000000
-0000001111110000000000001100000000000000000066ddeeee990000000000000066bb
-bb88bbcceeeeee880066aaaa9999bb9999aa99998899aa999999aaaabbaaaaaa99889988
-778888776677666655444455665555554433
-443333442233445577665566666655444444666655667766666666666644443300000000
-0000001133220000000000000000000000000000000055eeeeeebb110000000000000022
-bbffddddeeeeff88007799999999aabbaa9999999988aa99999999bbaaaa888877888888
-887777777766666655664455554455443344
-444422335566557766776666555544444455556666555555556666668899aa5500000000
-0000002233220000000000000044110011110000000055ffeeffcc110000000000000000
-0077ddddddddeebb118899999999aaaaaa8888aa88aaaaaa9999aabbaaaa997755889988
-887766777766775555665555444444443344
-555544333344556666556666445566556666555555665566665555335566999922000000
-0000002244332200000000001177663366330000000088eeeeffdd110000001100112200
-000066cceeeeeebb66ccbbaa9999aaaa998899aaaabbbbaa9988aaaabb99998888888877
-777755776666666655555555554444444444
-445555554444555555557766445544666677665566666666776611000000002233000000
-00000022445544112233442255442211110000000033bbeeeeeeee880000002255999966
-330033ddeeeeeeddddeeeeffccaa99998899aaaabbbbaaaa999999999999999988888877
-777766665566666655665544444444553333
-444444556666445555776666555566667777775566666655665500000000000000000000
-00000000334433337799999988775533112244225599ccddeeeeffee885533111166bbcc
-bb6666ddffeeeeeeeeeeaa66aa99aa889999bbbbbbbb99aa999999999999998888888877
-667766555555555555444433444444333322
-334444445577665555556666665566665577666644444466664400000000000000000000
-000000002255667788bbbbbbaabb998866556688aabbddeeeeeeeeeedd8888bbaaccddee
-eeeeddeeeeeeddeebb22000066aa88aabbaaccbbaa99aa99889988999999889999888877
-777766666666665544334455443333333333
-333355444466557766776655555555556666664455446666665500000000000000000000
-0000000011335577aaccddddddccbb998899ccddddccddeeffeeeeeeeedd8899ddeeeeee
-eeddffeeeeeedddd3322220066aaaaaabb99bbbb99aaaa88888899888888888877887777
-556688553355665533444433334433333344
-444444225555445566888866666666777777776666556666664400000000000000000000
-0000000011224477aaddddeeddddddddddddddddddddeeeeeeffeeeeeeeecc88aaddeeee
-eeeeeeeeeeeeeecc66dd8800779988bbbbaabbbbaaaa9988888888999977776677776666
-557766553355556644443333333344221133
-77bbccbb9988774455667777667788888877886666667777666611000000000000000000
-0000001111335577bbccddddeeeeeeddeeeeddddccddeeeeffeeeeeeeeeeffddddddeeee
-eeeeffeeeeeeddccddeedd22999988aa99aaaa8899aa9988888888888888776677777766
-776666665555555544444444332222112211
-bbeeffffffeeeedd88444455668899998866776666666677775533000000000000000000
-0011114433446688bbccccccddddeeeeddddbbddeeddeeeeffffeeffeeffeeffffffeeee
-ffeeeeffeeeeeebb77eeee88cc889999aaaa99aa99998888778888888888668888997777
-777777667766665533334433332222222222
-77ddeeffeeffeeeeee995555557788888888776677775577776655221100000000001100
-1122225555665588aabbbbccddddddeeccaabbeeddccddeeeeeeffeeffeeeeeeffeeeeee
-eeffeeffeeeeffcc33bbeeeebbaaaaaa99aaaa9999888877889999999988777788887777
-888866556677665533334433112211222222
-4499bbbbeeeeeeeeeeee6633667799889988778877667788777777332200110000001100
-444477888866667799aabbccccddddddbb8888aa7755779999bbddeeffffeeeeeeffeeee
-eeddeeeeffeeeedd44bbeeeebbaaaa99aaaaaa99889999888888aa99aa88776677888877
-887777666666554433554422222222222211
-003322446677cceeeeeeaa66777788888888888877667788887788662211113300002222
-66887777665566667799aabbccccccaa88443322000011223344446677ccffeeeeeeeeff
-eebbeeeeeecceeeeaacceeeebbbbaaaaaabbaabbaa999988778899998888888888778888
-777766776677665555442222222233222222
-00220000000066ccffeeffaa776677887777887777777788888877773311005566115533
-7788996666445566667799bbccbbaaaa9933000000000000000000000066ffeeeeffeeee
-eeddeeffeeffeeffeeddeeddbbaaaa99aaaaaabbccaaaa88889988999988888877888877
-888877667766666644332244442222223322
-1111000000000044aaeeffdd777755777788778877777788888888776611221122888844
-88aa77776655445555778899aa7788aaaa44000000000000000000000077ffeeeeddeeee
-eeeeeeeeeeeeeeeeeeeeffccaaaaaa9999aaaaaabbaaaa9999888899bb99888866778888
-777777665555554444333322222222221122
-22000000001111001177dddd999999886666888877887788778888888844115544aa8888
-9988888866555555446666666666bbcc99330000000000000000000055eeffeeeeccddee
-eeeeeeeeffeeffeeeeeeeeccaaaabbbbaaaabbbbaaaaaa88889999aa8899886688777766
-778888775566554433332233333322331111
-4400000000443300000033bbffeeffeebb666677888888888888777766663333bbbb88bb
-aa998888885555554444221144aaccbb330000000000000000000033ccffeeeeffddcccc
-cceeeeeeeeffeeeeeeffeebbbbbbbbbbbbaaaaaaaabbaa8899aa99889999888877888877
-667777668888998844332244442244332222
-770000000077ccbb996677eeeeeeeeeeeebb5566777788889988777777777755ccbbaacc
-bbaa9988775577664400000055bb6633110000000000000000000077bbddeeeeeeffddaa
-bbddddddddddffeeffeeeebbbbccccbbbbbbaaaaaaaa8888888888998899888888888888
-776677aaddeeeedd77223344443344333311
-dd77000011aa99aaddeecccceeeeeeeeeeeebbaa6677888899887788778888cceeccbbbb
-ccaa998888888855110000337733000000000000000000000000005599ddccddeeeeeedd
-aa99ccddaacceeffeeeeeeeebbaaccbbbbaa99aa99998888887799998899998877888888
-8888cceeeeeeeeddbb553344333333333322
-eeee88000077220033998866aaeeeeeeeeeeeeeeaa777788aa8899997788aaddccbbcccc
-ccbbaaaabb9977440000335522000000000000000000000000000000227788aaeeeeeeee
-bb8899ccddaaaaeeeeeeeeffcc99aaaa99999999aaaa8888888888777777888877777788
-88cceeeeeeeeddeeeeaa3344444433443333
-eeeedd55004488000011110077ffeeeeeeeeeeeeffbb8877889988999999ddddddddddcc
-ddccccbb8866332200113300000000000000000000000000000000000000334488cceeee
-ddccaa88bbbb6655bbffeeeeeeccaa9999aaaa99998899997777889999aa998888888866
-3388ddddddddcc88ccdd9944334433443322
-eeeeee88110066110000000088eeeeeeeeeeffeeeeeecc9977889999aacceeddeeeedddd
-ddddaa88663300000000000000000000000000000000000000000011000000000022aadd
-eeddccbb99aa88111188eeffeeffddaa99aaaaaa88998888888888aaeeeeeebbbbddddaa
-1155ccaa55443311aaeedd88222222332211
-ddccdd88440000000000000077ddeeeeeeeeeeffeeeeffeebb99aaaaccddeeeeeeeeeeee
-ddbb777777442200000000000000000000000000001188ccbb9999bb8833000000002222
-77ddddddccbb8844000044ddffffffeeaa88aa9999998888888888cceeddeeddeeeeeedd
-2288bb991100000066bbddcc551122222222
-cc666622221100000000000055ddeeeeeeeeeeeeeeeeeeeeee9999ccddeeeeffeeeeeeee
-eeddccaa884422331100000000000000000000001177eeeeeeeedddddd99550000001133
-1155ddeeddddcc8855000033aaeeeeffdd9999aa9999aa88995555cceeeeddeeeeeeeebb
-00559999440000000055bbddbb3322223322
-ffdd4400001100000000000044ddeeeeeeeeeeeeeeeeeeeeeeccbbeeffeeeeeeeeffeeee
-eeddeeccbb8866772200000000000000000000001144668899aabbddddccbb66110044bb
-bbbbcccceeeeddddcc8877332277cceeeeeebb88999999aadd7799eeeeeeeeeeeeddddaa
-4444775577220000000044bbee7711222211
-eeeecc33000000000000000033cceeeeeeeeeeeeeeeeeeffeeffeeffeeeeffeeffeeffff
-eeffeeddeeccbb884411000000000000000011000000000000000088ccddddaa6644bbee
-ddffeeddeeeeeeeeeeffffeeddbbddeeffeeeeddaa88aaccddbbeeddeeddddeeeeee8844
-7711221100000000001177ccddbb44112211
-eeeeffaa000000000000000066eeeeeeddddeeeeffeeeeeeffeeeeeeffeeeeffeeeeffff
-eeeeeeeeeeeeeecc66110000000000000022666655334433446688bbeeddeeddbbccddee
-eeeeeeeeeeddeeeeffffeeeeffffffeeeeeeeeffdd99cceeddbbddeeddddeeddeecc2200
-22000000000000003399ccccdddd88111122
-eeeeeeee550000000000000088eeddddddccddddeeeeddeeeeeeeeeeffeeffeeeeffffee
-ffffeeeeffeeeeee99220000000011336688bbddddddddeeeeffeeeeeeeeeeeeeeeeeeee
-ffeeffeeeeeeeeffeeeeeeffeeffeeeeffeeeeeeffddddeedd99ccddddddeeeedd660000
-00000000000000001166ccddddeeaa222222
-eeeeeeee880000000000000099eecc888888ddccccaa88ccddeeeeeeeeeeffeeffeeffee
-ffeeeeffeeeeeeddbb3300001122336688aaddeeeeddeeeeeeeeeeffffeeeeffeeeeeeee
-eeffeeffeeeeeeeeeeffeeeeffeeeeeeeeeeeeeeeeccccddcc5588aacceeddeecc220000
-0000000000000000004499bbccddcc331111
-eeeeeeee990000000000000088ddccdd6622bbddbb4455ddbbaaeeeeffeeffeeeeeeffff
-eeffeeeeeeeeddcc996633335522335588aaccddeeeeeeeeeeeeeeeeeeffeeffffeeeeff
-ffeeeeffffeeeeeeeeffeeeeeeffeeeeeeeeeeeeff99779988003377ccddeeee99000000
-000000000000000000000055bbddcc441122
-ffeeeeeedd3300000000000077cceeee880044aabb55ccffddccddffeeeeffeeeeeeeeff
-eeffeeeeeeddccbb776644442211223377aaccddeeeeeeeeeeeeffffffeeffeeeeeeffee
-ffeeeeeeeeeeeeffffeeeeffeeeeffffeeffeeffff8811333300001199ddeeee66000000
-0000000000000000001155ccddccdd551111
-eeeeeeeedd991100000000000077ccdd555577111133ddffeeddddffffffeeffffffeeee
-ffffeeeeffddccbb7733110000000011336688bbcccceeeeeeeeeeffeeeeffffffeeeeee
-ffeeffeeffeeffeeeeffeeffeeffffeeffeeffeeff99000000000066ddddeecc22000000
-00000000000000004499ccdddddddd771122
-eeeeeeeeeedd6600000000000000226677ddee66000088bbcc8866777799ccbbaabbbbcc
-ddeeffffffeeeeeebb6644110000000000113355668899bbbbddddddeeeeeeddeeeeeeff
-eeeeeeeeeeeeeeffffeeffffeeeeddddccddddddee990000000000aaffeeeeaa00000000
-00000000000000005588bbccccdddd880011
-eeeeffeeeeeebb99220000000000000055bbaa3300000011220000003399aa9988886666
-66888888bbddeeeeeeddcc9933000000000000000011224466778888aabbddddeeeeeeee
-ffffeeffffeeeeeeccbbbbaaaa777777774411222211000000000055aaaaaa6622000000
-00000000000000004499bbccddddee991111
-eeeeeeffeeddddcc4422220000000000001133000000000000000000669999aaaa99aa99
-999911000011445588aacccc88110000000000000000222222223322336699bbddeeffee
-ffeeeeddccccccaaaaaaaabbbbaabbbbbb66000000220000000000001111110000000000
-000000000000001155aabbddccddddbb2211
-ffeeffeeeeeecccc99aa55000000000000000000000000000000001188888899aaaaaaaa
-99770000000000000000113333000000000000000000000011000000002277cceeeeddaa
-8888ccccccccccccbbbbccddbbbbbbbbcc88000000000000000000000000000000000000
-00000000000000116699ccddddddeecc2211
-eeeeeeeeeeeeddccddccbb661100000000000000000000000000227788778877889999aa
-660000000000000000000000000000000000000000111100000000000011445544331100
-0088ccccccccccccccbbbbccccbbbbbbaa99110000000000000000000000000000000000
-000000000000002266aaccddddddddcc3300
-eeeeeeeeeeeeddddbbccccccaa88887788aa440000000000004488778888887788779977
-110000000000000000000000000000000000001111111111001111000000000000000000
-55ccccbbccccbbccccbbbbbbbbbbbb999999772200000000000000000000000000000000
-000000000000002277aaddddccccdddd5511
-eeeeeeffffddddddddddeeddddeeddeeddcc773311000000337766777777667766776611
-000000000000000000000000000000000000000000000000000000000000000000000055
-ccbbbbccbbccccbbbbbbbbbbbbaaaaaaaa99997711000000000000000000000000000000
-000000000000001166aabbccccdddddd7711
-eeeeffeeeeeeeeeeeeddeeddeeddddddccbb996611001144777777776677776666771100
-0000110000000000000000000000000000000000000000000000000000000000000022dd
-8844ccbbbbaabbaabbbbaabbaaaaaa99aa99aa7766110000000000000000000011557777
-66330000000000003388aaccdddddddd9911
-ddeeddeeeeeeeeeeddeeddddeeddddccbbaa883300004466667777666655666688440000
-0000001111000000000000000000000000000000000000000000000000000000000099ff
-aa0077bb99aabbbbbbbb99aaaa99999999aa887766440000000000000000003388bbccbb
-cc773300110000002277bbbbccccddddaa22
-ddeeddeeeeeeddeeeeddddddddddddbb9988330000336655886688776655556688220000
-00000011222211000000000000000000000000000000000000000000000000000077eeff
-bb001199ccbbaaaaaaaaaa889988999999997777777733000000000000001166aaccccdd
-ccbb770066550000336699ccddccdddddd55
-99aabbddddeeddeeddddddcceeddcc887755110011556666667777776677775522000000
-000011224455441100000000000000000000000000000000000000000000000066eeeeee
-cc0000338899bb999999999988888888aa998888777755000000000000002277bbccccdd
-ddcc991177882200336699bbddccddddddaa
-22333366ccddddddddccddbbaa9977333311001144666655666688889966330000000000
-0000115555777777551100000000000000000000000000000000000000000044ddeeeeee
-ee220000002277aabbaaaaaa99888899aa99aa88777766220000000000000055aaccddcc
-ddcc991133885522113388ccccddddccccdd
-0000000088aa888888887733221100000000115566776677777799994411000000000000
-00001155777788998877773300000000000000110000000000000000000077cceeeeeeee
-ee2200000000003377aabbbbaaaa9988aaaaaa999977665500000000000000117799aabb
-ccbb883311443311112266bbccccdddddddd
-000000002233001122111100000000002244667766668866888899220000000000000000
-000000777799aaaa99aaaa99550000000000000000000000000000003388ddeeeeeeffee
-ee33000000001100003388ccbbaa99999999999988775566330000000000000011558899
-aa9977220011000011335588ccddddeeddee
-00000000000000000000000000001144667766667788aa99aa8811000000000000000000
-0000003377aabb99bbbbccaa77663300000000000000000000000055cceeeeeeeeeeeeff
-ee3300000000001100000055aaccaaaa9988778888887755553300000000000000115566
-776622000000000000113377bbddccdddddd
-00000000000000000000000000336677777788777788aa99661100000000000000000000
-000000117799aaccccccccbbbbaa99440000000000000000002288ddeeeeeeeeffeeeeee
-dd22000000000000110000002288aaaaaa99778888778877776644000000000000002222
-22110000000000000000003388aaccddddee
-000000000000000000000022667777887788777799884411000000000000000000000000
-0000000077aabbccddddccccddccddbb88442200000000000088ffeeeeeeeeffeeeeeeff
-dd1100000000000000110000000044aabbaa999999888888665566440000000000000000
-0000000000000000000000001155bbccdddd
-000000000000000022556688776688888877887733000000000000000000000000000000
-0000000055bbccddccddddddddeeeedddddd8800000011110000bbffeeeeeeeeffeeeeff
-dd1100000000000000001100000000224444667777778888887766555500000000000000
-00000000000000000000000000003388ccdd
-000000001133558899998888887788998899660000000000000000000000000000000000
-0000000022aaccddddddeeeeeeeeeeeeeedd330000117766447733ddeeeeffeeeeeeeeff
-aa0000000000000000000000000000000000000000113344667788887766110000000000
-000000000000000000000000000000117799
-0000446688aabb88aa999988998888999977000000000000000000000000000000000000
-0000000000aaccddeeeeeeeeeeeeeeeeffaa00000044dd7788ee77aaeeffeeeeffeeffff
-880000000000000000000000000000000000000000000000001122222233441100000000
-000000000000000000000000000000000033
-777788aa9988888888888899aa8899886600000000000000000000000000000000000000
-000000000088ddeeeeeeeeeeeeeeeeffeeaa550066bbdd99cceeccaaffeeeeeeeeffeeff
-550000000000000000000000000000000000000000000000000000000000113322000000
-000000000000000000000000000000000000
-884422331100000000000022331100000000000000000000000000000000000000000000
-000000000077ddeeeeeeffeeffffffffbbaa6611aaddeecceeeeeebbeeffeeffffeeffee
-440000000000000000000000000000000000000000000000000000000000000022110000
-000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000000000000000000000000000
-000000000077ddeeeeeeeeffeeeeffcc1111113399bbee88cceeee99aaffffeeffeeeeee
-330000000000000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000000000000000000000000000
-000000000044ddeeeeeeeeffeeeeff66002266001166ee66aaeeee6666ffeeeeeeeeffdd
-110000000000000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000000000000000000000000000
-000000000022ddeeeeeeeeeeffffcc11001155003388eeddddeebb2211ddffeeffeeffcc
-110000000000000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000000000000000000000000000
-000000000000aaffeeeeffeeeeff8800000088221155cceebbbb55000088ffeeeeeeffcc
-000000000000000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000000000000000000000000000
-00000000000077eeeeeeeeeeeeee3300000088660055ccdd554411000044ffffffeeffbb
-000000000000000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000000000000000000000000000
-00000000000022ddffeeffffff990055330055990077dddd221111330011ccffeeffff88
-000000000000000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000000000000000000000000000
-00000000000000bbffeeeeeeee442299770022aa0077dddd442266bb9944aaffeeffff88
-000000000000000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000000000000000000000000000
-0000000000000066ffeeeeff882288ddaa000077331188993399eeeeffcc99eeeeeeff77
-000000000000000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000000000000000000000000000
-0000000000000011ddffeeffaa99ddeecc11001111001199bbeeeeeeeeeebbddffeecc11
-000000000000000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000000000000000000000000000
-000000000000000066ffeeeeffeeeeeeee2200000066bbddeeeeeeeeeeffddcceebb5500
-000000000000000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000000000000000000000000000
-00000000000000000055ddeeeeeeeeffee550055aaaacceeccddffffeeeeeeeeeeffcc00
-000000000000000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000000000000000000000000000
-00000000000000000000aaffeeffeeeeee66337788bbeeeeeeeeffeeffeeeeeeeeffcc00
-000000000000000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000000000000000000000000000
-00000000000000000033cceeeeeeeeeeee440066ddeeeeeeeeeeeeeeeeffeeffeeffbb00
-000000000000000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000000000000000000000000000
-00000000000000000055eeeeffeeffeeee88aacceeddeeeeeeeeeeeeffeeeeffeeff8800
-000000000000000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000000000000000000000000000
-00000000000000000011ddeeeeeeeeeeeeddddddeeeeeeeeffeeeeffeeffffeeffff6600
-000000000000000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000000000000000000000000000
-0000000000000000000088ffeeffeeeeeeeeeeddeeeeeeffeeeeeeeeffeeeeffeeff4400
-000000000000000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000000000000000000000000000
-0000000000000000000033eeeeeeffeeeeeeeeeeffeeeeeeeeeeddeeeeeeeeffeeee3300
-000000000000000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000000000000000000000000000
-0000000000000000000011bbffeeeeffeeddeeddddbbaaaaddddcceeffeeffeeffee2200
-000000000000000000000000000000000000000000000000000000002200220000000000
-000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000000000000000000000000000
-000000000000000000000088ffeeeeeeddddcc9999aaaaddeeeeeeffeeffeeeeffcc0000
-000000000000000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000000000000000000000000000
-000000000000000000000044eeffeeffccddddccddeeeeeeeeeeeeeeeeeeffffffaa0000
-000000000000000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000000000000000000000000000
-00000000000000000000000099ffcc5544cceeddddeeddccddeeddddeeeeeeeeff990000
-000000000000000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000000000000000000000000000
-00000000000000000000000044ff9911004499aabbccccccccddbbaabbccddffff660000
-000000000000000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000000000000000000000000000
-00000000000000000000000011ccbb996655bbbbaaccbbbbddddaaaaccddcceeee550000
-000000000000000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000006688000066ddcccceeeeeeeeffeeddccaabbeeff330000
-000000000000000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000001144000066eeeeeeddccbbbbbb7722220022bbee110000
-000000000000000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000022665599aaccbbaabb775588778899cc000000
-000000000000000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000002211001177bbddbbaabbaa99ddeedd8844000000
-000000000000000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000110077bbddddeeffeeeeffeeffaa00000000
-000000000000000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000000000000000000000000000
-00000000000000000000000000000000000088aaeeffeeddccbbcc776655996600000000
-000000000000000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000778877555533445588113355882200000000
-441100000000000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000000000007799ccccddbbddeeee3300000000
-331100000000000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000001155bbeeeeeeeeffeeeeeeff5500000000
-000000000000000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000004488ddeeeeeeeeeeeeeeeedd2200000000
-000000000000000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000000033bbddeeeeeeffeeeeffaa0000000000
-000000000000000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000000000000000000000000000
-00000000000000000000000000000000000000000088ccddeeeeeeeeeeff880000000000
-000000000000000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000000000000000000000000000
-00000000000000000000000000000000000000000044aaeeeeffeeeeeeff550000000000
-000000000000000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000000000000000000000000000
-0000000000000000000000000000000000000000001188ddccccddbb9988000000000000
-000000000000000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000000000000022222233774422000000000000
-000000000000000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000000000000000000000000000
-00000000000000000000000000000000000000000000116699aaccddbb44000000000000
-000000000000000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000000000002288888888992200000000000000
-000000000000000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000002255661100000000000000
-000000000000000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000000011000000000000000000
-000000000000000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000113355882200000000000000
-000000000000000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000000000000011778899771100000000000000
-000000000000000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000002244110000000000000000
-000000000000000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000000000000000000000110000
-000000000000000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000000000000000000000001100
-000000000000000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000000000000000000000001100
-000000000000000000000000000000000000000000000000000000000033110000000000
-000000000000000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000000000000022440000000000
-000000000000000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000000000000011220000000000
-000000000000000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000000000000000001100000000
-000000000000000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000000000000000001100000000
-000000000000000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000000000000000001100000000
-000000000000000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000000000000000000000110000
-000000000000000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000000000001100000000000000000000000000
-000000000000000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000000000000000000000000000000000000000
-000000000000000000000000000000000000
-001100110011001100110011001100110000000000000000000000000000000000000000
-000000000000000000000000000000000000000000221100000000000000000000001111
-110000001100001100110000110000000000000000000000000000000000000000001100
-001100000000000000000000110000001100
-
-showpage
-
-% stop using temporary dictionary
-end
-
-% restore original state
-origstate restore
-
-%%Trailer
diff --git a/lib/docbuilder/doc/src/notes.xml b/lib/docbuilder/doc/src/notes.xml
deleted file mode 100644
index 95f24ea9ca..0000000000
--- a/lib/docbuilder/doc/src/notes.xml
+++ /dev/null
@@ -1,256 +0,0 @@
-<?xml version="1.0" encoding="latin1" ?>
-<!DOCTYPE chapter SYSTEM "chapter.dtd">
-
-<chapter>
- <header>
- <copyright>
- <year>2007</year><year>2011</year>
- <holder>Ericsson AB. All Rights Reserved.</holder>
- </copyright>
- <legalnotice>
- The contents of this file are subject to the Erlang Public License,
- Version 1.1, (the "License"); you may not use this file except in
- compliance with the License. You should have received a copy of the
- Erlang Public License along with this software. If not, it can be
- retrieved online at http://www.erlang.org/.
-
- Software distributed under the License is distributed on an "AS IS"
- basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
- the License for the specific language governing rights and limitations
- under the License.
-
- </legalnotice>
-
- <title>DocBuilder Release Notes</title>
- <prepared>otp_appnotes</prepared>
- <docno>nil</docno>
- <date>nil</date>
- <rev>nil</rev>
- <file>notes.xml</file>
- </header>
- <p>This document describes the changes made to the DocBuilder
- application.</p>
-
-<section><title>Docbuilder 0.9.8.11</title>
-
- <section><title>Improvements and New Features</title>
- <list>
- <item>
- <p>
- The docbuilder application has been deprecated and will
- be removed in the R15 release.</p>
- <p>
- Own Id: OTP-9509</p>
- </item>
- </list>
- </section>
-
-</section>
-
-<section><title>Docbuilder 0.9.8.10</title>
-
- <section><title>Fixed Bugs and Malfunctions</title>
- <list>
- <item>
- <p> fop 1.0 crashed when building the docbuilder pdf with
- the following message
- "java.lang.IllegalArgumentException: factor &lt; 0; was:
- -1". <br/> This is a known bug in fop 1.0 (fop bug id:
- Bug 50524) when there is a word that consist of a single
- soft hyphen (&amp;shy;). this has been fixed in fop
- source archive but not it's not in a release yet. It's
- fixed in our documentation by removing the soft hyphens
- where this is a problem. </p>
- <p>
- Own Id: OTP-9143</p>
- </item>
- </list>
- </section>
-
-</section>
-
-<section><title>Docbuilder 0.9.8.9</title>
-
- <section><title>Improvements and New Features</title>
- <list>
- <item>
- <p> Fix compatibility issues with docbuilder for R11
- documentation patches. </p>
- <p>
- Own Id: OTP-8946</p>
- </item>
- </list>
- </section>
-
-</section>
-
-<section><title>Docbuilder 0.9.8.8</title>
-
- <section><title>Fixed Bugs and Malfunctions</title>
- <list>
- <item>
- <p> Fixed problem with a centered table that was
- transformed into an xml document which then produced
- mis-formatted html. </p>
- <p>
- Own Id: OTP-8784</p>
- </item>
- </list>
- </section>
-
-</section>
-
-<section><title>Docbuilder 0.9.8.7</title>
-
- <section><title>Improvements and New Features</title>
- <list>
- <item>
- <p>The documentation is now possible to build in an open
- source environment after a number of bugs are fixed and
- some features are added in the documentation build
- process. </p>
- <p>- The arity calculation is updated.</p>
- <p>- The module prefix used in the function names for
- bif's are removed in the generated links so the links
- will look like
- "http://www.erlang.org/doc/man/erlang.html#append_element-2"
- instead of
- "http://www.erlang.org/doc/man/erlang.html#erlang:append_element-2".</p>
- <p>- Enhanced the menu positioning in the html
- documentation when a new page is loaded.</p>
- <p>- A number of corrections in the generation of man
- pages (thanks to Sergei Golovan)</p>
- <p>- The legal notice is taken from the xml book file so
- OTP's build process can be used for non OTP
- applications.</p>
- <p>
- Own Id: OTP-8343</p>
- </item>
- </list>
- </section>
-
-</section>
-
-<section><title>Docbuilder 0.9.8.6</title>
-
- <section><title>Improvements and New Features</title>
- <list>
- <item>
- <p>
- The documentation is now built with open source tools
- (xsltproc and fop) that exists on most platforms. One
- visible change is that the frames are removed.</p>
- <p>
- Own Id: OTP-8201</p>
- </item>
- </list>
- </section>
-
-</section>
-
-<section><title>Docbuilder 0.9.8.5</title>
-
- <section><title>Improvements and New Features</title>
- <list>
- <item>
- <p>The copyright notices have been updated.</p>
- <p>
- Own Id: OTP-7851</p>
- </item>
- </list>
- </section>
-
-</section>
-
-<section><title>Docbuilder 0.9.8.4</title>
-
- <section><title>Fixed Bugs and Malfunctions</title>
- <list>
- <item>
- <p>
- The element "code" with multiple CDATA or CDATA plus
- other data now works as expected, previously it caused a
- crash.</p>
- <p>
- Own Id: OTP-7236</p>
- </item>
- </list>
- </section>
-
-</section>
-
-<section><title>Docbuilder 0.9.8</title>
-
- <section><title>Improvements and New Features</title>
- <list>
- <item>
- <p>
- The generated html should now be valid xhtml (with a few
- exceptions to be fixed in next version).</p>
- <p>
- Own Id: OTP-7027</p>
- </item>
- </list>
- </section>
-
-</section>
-
- <section><title>Docbuilder 0.9.7</title>
-
- <section><title>Improvements and New Features</title>
- <list>
- <item>
- <p>
- New fonts and new CSS style included in generated html documents.
- </p>
- </item>
- <item>
- <p>
- Updated DTD's with new header elements copyright and legalnotice.
- Element authors changed to optional instead of mandatory.
-
- </p>
- </item>
- </list>
- </section>
- </section>
-
- <section><title>Docbuilder 0.9.1</title>
-
- <section><title>Fixed Bugs and Malfunctions</title>
- <list>
- <item>
- <p>
- Line breaks within <c>pre</c> are now always preserved.</p>
- <p>
- The definition of <c>name</c> in the cref DTD is now
- correctly handled.</p>
- <p>
- <c>docb_transform</c>: The HTML snippet returned by the
- <c>Module:head()</c> callback function is now placed
- below the title in the HTML file (as specified in the
- documentation), not on the same line.</p>
- <p>
- <c>docb_gen</c>: Added option <c>sort_functions</c>.</p>
- <p>
- Fixed bugs in cites and terms DTD, and also in book,
- bookinsidecover and report DTDs which are not officially
- supported (yet).</p>
- <p>
- License info added to all DTD files.</p>
- <p>
- Corrections and clarifications made to the User's Guide.</p>
- <p>
- Own Id: OTP-6775</p>
- </item>
- </list>
- </section>
- </section>
-
- <section>
- <title>DocBuilder 0.9</title>
- <p>First version of DocBuilder released as part of Erlang/OTP.
- Previously it has been used as an internal tool only.</p>
- </section>
-</chapter>
-
diff --git a/lib/docbuilder/doc/src/part_notes.xml b/lib/docbuilder/doc/src/part_notes.xml
deleted file mode 100644
index 2f824630fb..0000000000
--- a/lib/docbuilder/doc/src/part_notes.xml
+++ /dev/null
@@ -1,37 +0,0 @@
-<?xml version="1.0" encoding="latin1" ?>
-<!DOCTYPE part SYSTEM "part.dtd">
-
-<part xmlns:xi="http://www.w3.org/2001/XInclude">
- <header>
- <copyright>
- <year>2007</year><year>2009</year>
- <holder>Ericsson AB. All Rights Reserved.</holder>
- </copyright>
- <legalnotice>
- The contents of this file are subject to the Erlang Public License,
- Version 1.1, (the "License"); you may not use this file except in
- compliance with the License. You should have received a copy of the
- Erlang Public License along with this software. If not, it can be
- retrieved online at http://www.erlang.org/.
-
- Software distributed under the License is distributed on an "AS IS"
- basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
- the License for the specific language governing rights and limitations
- under the License.
-
- </legalnotice>
-
- <title>DocBuilder Release Notes</title>
- <prepared></prepared>
- <docno></docno>
- <date></date>
- <rev></rev>
- </header>
- <description>
- <p><em>Docbuilder</em> provides functionality for generating HTML
- documentation for Erlang modules and Erlang/OTP applications
- from XML source code and/or EDoc comments in Erlang source code.</p>
- </description>
- <xi:include href="notes.xml"/>
-</part>
-
diff --git a/lib/docbuilder/dtd/Makefile b/lib/docbuilder/dtd/Makefile
deleted file mode 100644
index 05c656f3fc..0000000000
--- a/lib/docbuilder/dtd/Makefile
+++ /dev/null
@@ -1,91 +0,0 @@
-# ``The contents of this file are subject to the Erlang Public License,
-# Version 1.1, (the "License"); you may not use this file except in
-# compliance with the License. You should have received a copy of the
-# Erlang Public License along with this software. If not, it can be
-# retrieved via the world wide web at http://www.erlang.org/.
-#
-# Software distributed under the License is distributed on an "AS IS"
-# basis, WITHOUT WARRANTY OF ANY KIND, either expressed or implied. See
-# the License for the specific language governing rights and limitations
-# under the License.
-#
-# The Initial Developer of the Original Code is Ericsson Utvecklings AB.
-# Portions created by Ericsson are Copyright 1999-2000, Ericsson
-# Utvecklings AB. All Rights Reserved.''
-#
-# $Id$
-#
-
-include $(ERL_TOP)/make/target.mk
-include $(ERL_TOP)/make/$(TARGET)/otp.mk
-
-# ----------------------------------------------------
-# Application version
-# ----------------------------------------------------
-include ../vsn.mk
-VSN=$(DOCB_VSN)
-
-# ----------------------------------------------------
-# Release directory specification
-# ----------------------------------------------------
-RELSYSDIR = $(RELEASE_PATH)/lib/docbuilder-$(VSN)
-
-# ----------------------------------------------------
-# Common Macros
-# ----------------------------------------------------
-
-DTD_FILES = \
- application.dtd \
- appref.dtd \
- book.dtd \
- bookinsidecover.dtd \
- chapter.dtd \
- cites.dtd \
- common.dtd \
- common.entities.dtd \
- common.header.dtd \
- common.image.dtd \
- common.refs.dtd \
- common.table.dtd \
- comref.dtd \
- cref.dtd \
- erlref.dtd \
- fascicules.dtd \
- fileref.dtd \
- part.dtd \
- report.dtd \
- terms.dtd \
- xhtml-lat1.ent \
- xhtml-special.ent \
- xhtml-symbol.ent \
- xhtml1-frameset.dtd \
- xhtml1-strict.dtd \
- xhtml1-transitional.dtd
-
-# ----------------------------------------------------
-# Targets
-# ----------------------------------------------------
-
-debug opt:
-
-clean:
-
-docs:
-
-# ----------------------------------------------------
-# Release Target
-# ----------------------------------------------------
-include $(ERL_TOP)/make/otp_release_targets.mk
-
-release_spec:
- $(INSTALL_DIR) $(RELSYSDIR)/dtd
- $(INSTALL_DATA) $(DTD_FILES) $(RELSYSDIR)/dtd
-
-release_docs_spec:
-
-
-
-
-
-
-
diff --git a/lib/docbuilder/dtd/common.dtd b/lib/docbuilder/dtd/common.dtd
deleted file mode 100644
index 2c4ad51ab1..0000000000
--- a/lib/docbuilder/dtd/common.dtd
+++ /dev/null
@@ -1,87 +0,0 @@
-<!--
- ``The contents of this file are subject to the Erlang Public License,
- Version 1.1, (the "License"); you may not use this file except in
- compliance with the License. You should have received a copy of the
- Erlang Public License along with this software. If not, it can be
- retrieved via the world wide web at http://www.erlang.org/.
-
- Software distributed under the License is distributed on an "AS IS"
- basis, WITHOUT WARRANTY OF ANY KIND, either expressed or implied. See
- the License for the specific language governing rights and limitations
- under the License.
-
- The Initial Developer of the Original Code is Ericsson AB.
- Portions created by Ericsson are Copyright 1999-2007, Ericsson AB.
- All Rights Reserved.''
-
- $Id$
--->
-<!-- This file contains common stuff for all dtds. -->
-
-<!ENTITY % common.entities SYSTEM "common.entities.dtd" >
-%common.entities;
-
-<!ENTITY % block "p|pre|code|list|taglist|codeinclude|
- erleval" >
-<!ENTITY % inline "#PCDATA|c|em|term|cite|br|path|seealso|
- url|marker" >
-<!-- XXX -->
-<!ELEMENT p (%inline;)* >
-<!ELEMENT pre (#PCDATA|seealso|url|input)* >
-<!ELEMENT input (#PCDATA|seealso|url)* >
-<!ELEMENT code (#PCDATA) >
-<!ATTLIST code type (erl|c|none) "none" >
-<!ELEMENT quote (p)* >
-<!ELEMENT warning (%block;|quote|br|marker)* >
-<!ELEMENT note (%block;|quote|br|marker)* >
-<!ELEMENT c (#PCDATA) >
-<!ELEMENT em (#PCDATA|c)* >
-
-<!-- XXX -->
-<!ELEMENT term (termdef?) >
-<!ATTLIST term id CDATA #REQUIRED >
-<!ELEMENT termdef (#PCDATA) >
-<!ELEMENT cite (citedef?) >
-<!ATTLIST cite id CDATA #REQUIRED >
-<!ELEMENT citedef (ctitle,cauthor,chowpublished) >
-<!ELEMENT ctitle (#PCDATA) >
-<!ELEMENT cauthor (#PCDATA) >
-<!ELEMENT chowpublished (#PCDATA) >
-
-<!-- XXX -->
-<!ELEMENT br EMPTY >
-
-<!-- Path -->
-
-<!ELEMENT path (#PCDATA) >
-<!ATTLIST path unix CDATA ""
- windows CDATA "" >
-
-<!-- List -->
-
-<!ELEMENT list (item+) >
-<!ATTLIST list type (ordered|bulleted) "bulleted" >
-<!ELEMENT taglist (tag,item)+ >
-<!ELEMENT tag (#PCDATA|c|em|seealso|url)* >
-<!ELEMENT item (%inline;|%block;)* >
-
-<!-- References -->
-
-<!ELEMENT seealso (#PCDATA) >
-<!ATTLIST seealso marker CDATA #REQUIRED >
-<!ELEMENT url (#PCDATA) >
-<!ATTLIST url href CDATA #REQUIRED >
-<!ELEMENT marker EMPTY >
-<!ATTLIST marker id CDATA #REQUIRED >
-
-<!-- CodeInclude -->
-
-<!ELEMENT codeinclude EMPTY >
-<!ATTLIST codeinclude file CDATA #REQUIRED
- tag CDATA ""
- type (erl|c|none) "none" >
-
-<!-- ErlEval -->
-
-<!ELEMENT erleval EMPTY >
-<!ATTLIST erleval expr CDATA #REQUIRED >
diff --git a/lib/docbuilder/dtd/common.refs.dtd b/lib/docbuilder/dtd/common.refs.dtd
deleted file mode 100644
index 7b9974fbda..0000000000
--- a/lib/docbuilder/dtd/common.refs.dtd
+++ /dev/null
@@ -1,40 +0,0 @@
-<!--
- ``The contents of this file are subject to the Erlang Public License,
- Version 1.1, (the "License"); you may not use this file except in
- compliance with the License. You should have received a copy of the
- Erlang Public License along with this software. If not, it can be
- retrieved via the world wide web at http://www.erlang.org/.
-
- Software distributed under the License is distributed on an "AS IS"
- basis, WITHOUT WARRANTY OF ANY KIND, either expressed or implied. See
- the License for the specific language governing rights and limitations
- under the License.
-
- The Initial Developer of the Original Code is Ericsson AB.
- Portions created by Ericsson are Copyright 1999-2007, Ericsson AB.
- All Rights Reserved.''
-
- $Id$
--->
-<!-- This file contains common stuff for the *ref.dtd files.
- Note that `name' is defined in each *ref.dtd. -->
-
-<!ENTITY % common SYSTEM "common.dtd" >
-%common;
-<!ENTITY % common.header SYSTEM "common.header.dtd" >
-%common.header;
-
-<!ELEMENT description (%block;|quote|br|marker|warning|note)* >
-<!ELEMENT funcs (func)+ >
-<!ELEMENT func (name+,fsummary,type?,desc?) >
-<!-- ELEMENT name is defined in each ref dtd -->
-<!ELEMENT fsummary (#PCDATA|c|em)* >
-<!ELEMENT type (v,d?)+ >
-<!ELEMENT v (#PCDATA) >
-<!ELEMENT d (#PCDATA|c|em)* >
-<!ELEMENT desc (%block;|quote|br|marker|warning|note)* >
-<!ELEMENT authors (aname,email)+ >
-<!ELEMENT aname (#PCDATA) >
-<!ELEMENT email (#PCDATA) >
-<!ELEMENT section (marker*,title,(%block;|quote|br|marker|
- warning|note)*) >
diff --git a/lib/docbuilder/dtd/erlref.dtd b/lib/docbuilder/dtd/erlref.dtd
deleted file mode 100644
index 21656a1446..0000000000
--- a/lib/docbuilder/dtd/erlref.dtd
+++ /dev/null
@@ -1,31 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!--
- ``The contents of this file are subject to the Erlang Public License,
- Version 1.1, (the "License"); you may not use this file except in
- compliance with the License. You should have received a copy of the
- Erlang Public License along with this software. If not, it can be
- retrieved via the world wide web at http://www.erlang.org/.
-
- Software distributed under the License is distributed on an "AS IS"
- basis, WITHOUT WARRANTY OF ANY KIND, either expressed or implied. See
- the License for the specific language governing rights and limitations
- under the License.
-
- The Initial Developer of the Original Code is Ericsson AB.
- Portions created by Ericsson are Copyright 1999-2007, Ericsson AB.
- All Rights Reserved.''
-
- $Id$
--->
-
-<!ENTITY % common.refs SYSTEM "common.refs.dtd" >
-%common.refs;
-
-<!ELEMENT erlref (header,module,modulesummary,description,
- (section|funcs)*,authors?) >
-<!ELEMENT module (#PCDATA) >
-<!ELEMENT modulesummary (#PCDATA) >
-
-<!-- `name' is used in common.refs.dtd and must therefore
- be defined in each *ref. dtd -->
-<!ELEMENT name (#PCDATA) >
diff --git a/lib/docbuilder/dtd/xhtml-lat1.ent b/lib/docbuilder/dtd/xhtml-lat1.ent
deleted file mode 100644
index aaae738cfc..0000000000
--- a/lib/docbuilder/dtd/xhtml-lat1.ent
+++ /dev/null
@@ -1,196 +0,0 @@
-<!-- Portions (C) International Organization for Standardization 1986
- Permission to copy in any form is granted for use with
- conforming SGML systems and applications as defined in
- ISO 8879, provided this notice is included in all copies.
--->
-<!-- Character entity set. Typical invocation:
- <!ENTITY % HTMLlat1 PUBLIC
- "-//W3C//ENTITIES Latin 1 for XHTML//EN"
- "http://www.w3.org/TR/xhtml1/DTD/xhtml-lat1.ent">
- %HTMLlat1;
--->
-
-<!ENTITY nbsp "&#160;"> <!-- no-break space = non-breaking space,
- U+00A0 ISOnum -->
-<!ENTITY iexcl "&#161;"> <!-- inverted exclamation mark, U+00A1 ISOnum -->
-<!ENTITY cent "&#162;"> <!-- cent sign, U+00A2 ISOnum -->
-<!ENTITY pound "&#163;"> <!-- pound sign, U+00A3 ISOnum -->
-<!ENTITY curren "&#164;"> <!-- currency sign, U+00A4 ISOnum -->
-<!ENTITY yen "&#165;"> <!-- yen sign = yuan sign, U+00A5 ISOnum -->
-<!ENTITY brvbar "&#166;"> <!-- broken bar = broken vertical bar,
- U+00A6 ISOnum -->
-<!ENTITY sect "&#167;"> <!-- section sign, U+00A7 ISOnum -->
-<!ENTITY uml "&#168;"> <!-- diaeresis = spacing diaeresis,
- U+00A8 ISOdia -->
-<!ENTITY copy "&#169;"> <!-- copyright sign, U+00A9 ISOnum -->
-<!ENTITY ordf "&#170;"> <!-- feminine ordinal indicator, U+00AA ISOnum -->
-<!ENTITY laquo "&#171;"> <!-- left-pointing double angle quotation mark
- = left pointing guillemet, U+00AB ISOnum -->
-<!ENTITY not "&#172;"> <!-- not sign = discretionary hyphen,
- U+00AC ISOnum -->
-<!ENTITY shy "&#173;"> <!-- soft hyphen = discretionary hyphen,
- U+00AD ISOnum -->
-<!ENTITY reg "&#174;"> <!-- registered sign = registered trade mark sign,
- U+00AE ISOnum -->
-<!ENTITY macr "&#175;"> <!-- macron = spacing macron = overline
- = APL overbar, U+00AF ISOdia -->
-<!ENTITY deg "&#176;"> <!-- degree sign, U+00B0 ISOnum -->
-<!ENTITY plusmn "&#177;"> <!-- plus-minus sign = plus-or-minus sign,
- U+00B1 ISOnum -->
-<!ENTITY sup2 "&#178;"> <!-- superscript two = superscript digit two
- = squared, U+00B2 ISOnum -->
-<!ENTITY sup3 "&#179;"> <!-- superscript three = superscript digit three
- = cubed, U+00B3 ISOnum -->
-<!ENTITY acute "&#180;"> <!-- acute accent = spacing acute,
- U+00B4 ISOdia -->
-<!ENTITY micro "&#181;"> <!-- micro sign, U+00B5 ISOnum -->
-<!ENTITY para "&#182;"> <!-- pilcrow sign = paragraph sign,
- U+00B6 ISOnum -->
-<!ENTITY middot "&#183;"> <!-- middle dot = Georgian comma
- = Greek middle dot, U+00B7 ISOnum -->
-<!ENTITY cedil "&#184;"> <!-- cedilla = spacing cedilla, U+00B8 ISOdia -->
-<!ENTITY sup1 "&#185;"> <!-- superscript one = superscript digit one,
- U+00B9 ISOnum -->
-<!ENTITY ordm "&#186;"> <!-- masculine ordinal indicator,
- U+00BA ISOnum -->
-<!ENTITY raquo "&#187;"> <!-- right-pointing double angle quotation mark
- = right pointing guillemet, U+00BB ISOnum -->
-<!ENTITY frac14 "&#188;"> <!-- vulgar fraction one quarter
- = fraction one quarter, U+00BC ISOnum -->
-<!ENTITY frac12 "&#189;"> <!-- vulgar fraction one half
- = fraction one half, U+00BD ISOnum -->
-<!ENTITY frac34 "&#190;"> <!-- vulgar fraction three quarters
- = fraction three quarters, U+00BE ISOnum -->
-<!ENTITY iquest "&#191;"> <!-- inverted question mark
- = turned question mark, U+00BF ISOnum -->
-<!ENTITY Agrave "&#192;"> <!-- latin capital letter A with grave
- = latin capital letter A grave,
- U+00C0 ISOlat1 -->
-<!ENTITY Aacute "&#193;"> <!-- latin capital letter A with acute,
- U+00C1 ISOlat1 -->
-<!ENTITY Acirc "&#194;"> <!-- latin capital letter A with circumflex,
- U+00C2 ISOlat1 -->
-<!ENTITY Atilde "&#195;"> <!-- latin capital letter A with tilde,
- U+00C3 ISOlat1 -->
-<!ENTITY Auml "&#196;"> <!-- latin capital letter A with diaeresis,
- U+00C4 ISOlat1 -->
-<!ENTITY Aring "&#197;"> <!-- latin capital letter A with ring above
- = latin capital letter A ring,
- U+00C5 ISOlat1 -->
-<!ENTITY AElig "&#198;"> <!-- latin capital letter AE
- = latin capital ligature AE,
- U+00C6 ISOlat1 -->
-<!ENTITY Ccedil "&#199;"> <!-- latin capital letter C with cedilla,
- U+00C7 ISOlat1 -->
-<!ENTITY Egrave "&#200;"> <!-- latin capital letter E with grave,
- U+00C8 ISOlat1 -->
-<!ENTITY Eacute "&#201;"> <!-- latin capital letter E with acute,
- U+00C9 ISOlat1 -->
-<!ENTITY Ecirc "&#202;"> <!-- latin capital letter E with circumflex,
- U+00CA ISOlat1 -->
-<!ENTITY Euml "&#203;"> <!-- latin capital letter E with diaeresis,
- U+00CB ISOlat1 -->
-<!ENTITY Igrave "&#204;"> <!-- latin capital letter I with grave,
- U+00CC ISOlat1 -->
-<!ENTITY Iacute "&#205;"> <!-- latin capital letter I with acute,
- U+00CD ISOlat1 -->
-<!ENTITY Icirc "&#206;"> <!-- latin capital letter I with circumflex,
- U+00CE ISOlat1 -->
-<!ENTITY Iuml "&#207;"> <!-- latin capital letter I with diaeresis,
- U+00CF ISOlat1 -->
-<!ENTITY ETH "&#208;"> <!-- latin capital letter ETH, U+00D0 ISOlat1 -->
-<!ENTITY Ntilde "&#209;"> <!-- latin capital letter N with tilde,
- U+00D1 ISOlat1 -->
-<!ENTITY Ograve "&#210;"> <!-- latin capital letter O with grave,
- U+00D2 ISOlat1 -->
-<!ENTITY Oacute "&#211;"> <!-- latin capital letter O with acute,
- U+00D3 ISOlat1 -->
-<!ENTITY Ocirc "&#212;"> <!-- latin capital letter O with circumflex,
- U+00D4 ISOlat1 -->
-<!ENTITY Otilde "&#213;"> <!-- latin capital letter O with tilde,
- U+00D5 ISOlat1 -->
-<!ENTITY Ouml "&#214;"> <!-- latin capital letter O with diaeresis,
- U+00D6 ISOlat1 -->
-<!ENTITY times "&#215;"> <!-- multiplication sign, U+00D7 ISOnum -->
-<!ENTITY Oslash "&#216;"> <!-- latin capital letter O with stroke
- = latin capital letter O slash,
- U+00D8 ISOlat1 -->
-<!ENTITY Ugrave "&#217;"> <!-- latin capital letter U with grave,
- U+00D9 ISOlat1 -->
-<!ENTITY Uacute "&#218;"> <!-- latin capital letter U with acute,
- U+00DA ISOlat1 -->
-<!ENTITY Ucirc "&#219;"> <!-- latin capital letter U with circumflex,
- U+00DB ISOlat1 -->
-<!ENTITY Uuml "&#220;"> <!-- latin capital letter U with diaeresis,
- U+00DC ISOlat1 -->
-<!ENTITY Yacute "&#221;"> <!-- latin capital letter Y with acute,
- U+00DD ISOlat1 -->
-<!ENTITY THORN "&#222;"> <!-- latin capital letter THORN,
- U+00DE ISOlat1 -->
-<!ENTITY szlig "&#223;"> <!-- latin small letter sharp s = ess-zed,
- U+00DF ISOlat1 -->
-<!ENTITY agrave "&#224;"> <!-- latin small letter a with grave
- = latin small letter a grave,
- U+00E0 ISOlat1 -->
-<!ENTITY aacute "&#225;"> <!-- latin small letter a with acute,
- U+00E1 ISOlat1 -->
-<!ENTITY acirc "&#226;"> <!-- latin small letter a with circumflex,
- U+00E2 ISOlat1 -->
-<!ENTITY atilde "&#227;"> <!-- latin small letter a with tilde,
- U+00E3 ISOlat1 -->
-<!ENTITY auml "&#228;"> <!-- latin small letter a with diaeresis,
- U+00E4 ISOlat1 -->
-<!ENTITY aring "&#229;"> <!-- latin small letter a with ring above
- = latin small letter a ring,
- U+00E5 ISOlat1 -->
-<!ENTITY aelig "&#230;"> <!-- latin small letter ae
- = latin small ligature ae, U+00E6 ISOlat1 -->
-<!ENTITY ccedil "&#231;"> <!-- latin small letter c with cedilla,
- U+00E7 ISOlat1 -->
-<!ENTITY egrave "&#232;"> <!-- latin small letter e with grave,
- U+00E8 ISOlat1 -->
-<!ENTITY eacute "&#233;"> <!-- latin small letter e with acute,
- U+00E9 ISOlat1 -->
-<!ENTITY ecirc "&#234;"> <!-- latin small letter e with circumflex,
- U+00EA ISOlat1 -->
-<!ENTITY euml "&#235;"> <!-- latin small letter e with diaeresis,
- U+00EB ISOlat1 -->
-<!ENTITY igrave "&#236;"> <!-- latin small letter i with grave,
- U+00EC ISOlat1 -->
-<!ENTITY iacute "&#237;"> <!-- latin small letter i with acute,
- U+00ED ISOlat1 -->
-<!ENTITY icirc "&#238;"> <!-- latin small letter i with circumflex,
- U+00EE ISOlat1 -->
-<!ENTITY iuml "&#239;"> <!-- latin small letter i with diaeresis,
- U+00EF ISOlat1 -->
-<!ENTITY eth "&#240;"> <!-- latin small letter eth, U+00F0 ISOlat1 -->
-<!ENTITY ntilde "&#241;"> <!-- latin small letter n with tilde,
- U+00F1 ISOlat1 -->
-<!ENTITY ograve "&#242;"> <!-- latin small letter o with grave,
- U+00F2 ISOlat1 -->
-<!ENTITY oacute "&#243;"> <!-- latin small letter o with acute,
- U+00F3 ISOlat1 -->
-<!ENTITY ocirc "&#244;"> <!-- latin small letter o with circumflex,
- U+00F4 ISOlat1 -->
-<!ENTITY otilde "&#245;"> <!-- latin small letter o with tilde,
- U+00F5 ISOlat1 -->
-<!ENTITY ouml "&#246;"> <!-- latin small letter o with diaeresis,
- U+00F6 ISOlat1 -->
-<!ENTITY divide "&#247;"> <!-- division sign, U+00F7 ISOnum -->
-<!ENTITY oslash "&#248;"> <!-- latin small letter o with stroke,
- = latin small letter o slash,
- U+00F8 ISOlat1 -->
-<!ENTITY ugrave "&#249;"> <!-- latin small letter u with grave,
- U+00F9 ISOlat1 -->
-<!ENTITY uacute "&#250;"> <!-- latin small letter u with acute,
- U+00FA ISOlat1 -->
-<!ENTITY ucirc "&#251;"> <!-- latin small letter u with circumflex,
- U+00FB ISOlat1 -->
-<!ENTITY uuml "&#252;"> <!-- latin small letter u with diaeresis,
- U+00FC ISOlat1 -->
-<!ENTITY yacute "&#253;"> <!-- latin small letter y with acute,
- U+00FD ISOlat1 -->
-<!ENTITY thorn "&#254;"> <!-- latin small letter thorn with,
- U+00FE ISOlat1 -->
-<!ENTITY yuml "&#255;"> <!-- latin small letter y with diaeresis,
- U+00FF ISOlat1 -->
diff --git a/lib/docbuilder/ebin/.gitignore b/lib/docbuilder/ebin/.gitignore
deleted file mode 100644
index e69de29bb2..0000000000
--- a/lib/docbuilder/ebin/.gitignore
+++ /dev/null
diff --git a/lib/docbuilder/etc/Makefile b/lib/docbuilder/etc/Makefile
deleted file mode 100644
index a2f669d749..0000000000
--- a/lib/docbuilder/etc/Makefile
+++ /dev/null
@@ -1,67 +0,0 @@
-# ``The contents of this file are subject to the Erlang Public License,
-# Version 1.1, (the "License"); you may not use this file except in
-# compliance with the License. You should have received a copy of the
-# Erlang Public License along with this software. If not, it can be
-# retrieved via the world wide web at http://www.erlang.org/.
-#
-# Software distributed under the License is distributed on an "AS IS"
-# basis, WITHOUT WARRANTY OF ANY KIND, either expressed or implied. See
-# the License for the specific language governing rights and limitations
-# under the License.
-#
-# The Initial Developer of the Original Code is Ericsson Utvecklings AB.
-# Portions created by Ericsson are Copyright 1999-2000, Ericsson
-# Utvecklings AB. All Rights Reserved.''
-#
-# $Id$
-#
-
-include $(ERL_TOP)/make/target.mk
-include $(ERL_TOP)/make/$(TARGET)/otp.mk
-
-# ----------------------------------------------------
-# Application version
-# ----------------------------------------------------
-include ../vsn.mk
-VSN=$(DOCB_VSN)
-
-# ----------------------------------------------------
-# Release directory specification
-# ----------------------------------------------------
-RELSYSDIR = $(RELEASE_PATH)/lib/docbuilder-$(VSN)
-
-# ----------------------------------------------------
-# Common Macros
-# ----------------------------------------------------
-
-VAR_FILES = \
- note.gif \
- warning.gif
-
-# ----------------------------------------------------
-# Targets
-# ----------------------------------------------------
-
-debug opt:
-
-clean:
-
-docs:
-
-# ----------------------------------------------------
-# Release Target
-# ----------------------------------------------------
-include $(ERL_TOP)/make/otp_release_targets.mk
-
-release_spec:
- $(INSTALL_DIR) $(RELSYSDIR)/etc
- $(INSTALL_DATA) $(VAR_FILES) $(RELSYSDIR)/etc
-
-release_docs_spec:
-
-
-
-
-
-
-
diff --git a/lib/docbuilder/etc/note.gif b/lib/docbuilder/etc/note.gif
deleted file mode 100644
index 6fffe30419..0000000000
--- a/lib/docbuilder/etc/note.gif
+++ /dev/null
Binary files differ
diff --git a/lib/docbuilder/etc/warning.gif b/lib/docbuilder/etc/warning.gif
deleted file mode 100644
index 96af52360e..0000000000
--- a/lib/docbuilder/etc/warning.gif
+++ /dev/null
Binary files differ
diff --git a/lib/docbuilder/info b/lib/docbuilder/info
deleted file mode 100644
index 60daa212c8..0000000000
--- a/lib/docbuilder/info
+++ /dev/null
@@ -1,2 +0,0 @@
-group: doc
-short: Tool for generating HTML documentation for applications.
diff --git a/lib/docbuilder/src/Makefile b/lib/docbuilder/src/Makefile
deleted file mode 100644
index e8a07a54e8..0000000000
--- a/lib/docbuilder/src/Makefile
+++ /dev/null
@@ -1,121 +0,0 @@
-# ``The contents of this file are subject to the Erlang Public License,
-# Version 1.1, (the "License"); you may not use this file except in
-# compliance with the License. You should have received a copy of the
-# Erlang Public License along with this software. If not, it can be
-# retrieved via the world wide web at http://www.erlang.org/.
-#
-# Software distributed under the License is distributed on an "AS IS"
-# basis, WITHOUT WARRANTY OF ANY KIND, either expressed or implied. See
-# the License for the specific language governing rights and limitations
-# under the License.
-#
-# The Initial Developer of the Original Code is Ericsson Utvecklings AB.
-# Portions created by Ericsson are Copyright 1999-2000, Ericsson
-# Utvecklings AB. All Rights Reserved.''
-#
-# $Id$
-#
-
-include $(ERL_TOP)/make/target.mk
-include $(ERL_TOP)/make/$(TARGET)/otp.mk
-
-# ----------------------------------------------------
-# Application version
-# ----------------------------------------------------
-include ../vsn.mk
-VSN=$(DOCB_VSN)
-
-# ----------------------------------------------------
-# Release directory specification
-# ----------------------------------------------------
-RELSYSDIR = $(RELEASE_PATH)/lib/docbuilder-$(VSN)
-
-# ----------------------------------------------------
-# Common Macros
-# ----------------------------------------------------
-
-MODULES= \
- docb_edoc_xml_cb \
- docb_gen \
- docb_html \
- docb_html_layout \
- docb_html_ref \
- docb_html_util \
- docb_html_util_iso \
- docb_main \
- docb_pretty_format \
- docb_tr_application2html \
- docb_tr_appref2html \
- docb_tr_chapter2html \
- docb_tr_cite2html \
- docb_tr_comref2html \
- docb_tr_cref2html \
- docb_tr_erlref2html \
- docb_tr_fileref2html \
- docb_tr_first2html \
- docb_tr_index2html \
- docb_tr_part2html \
- docb_tr_refs2kwic \
- docb_tr_report2html \
- docb_tr_term2html \
- docb_transform \
- docb_util \
- docb_xmerl_tree_cb \
- docb_xmerl_xml_cb \
- docb_xml_check
-
-HRL_FILES= \
- docb_util.hrl
-
-ERL_FILES= $(MODULES:%=%.erl)
-
-TARGET_FILES= $(MODULES:%=$(EBIN)/%.$(EMULATOR))
-
-APP_FILE= docbuilder.app
-APPUP_FILE= docbuilder.appup
-APP_SRC= $(APP_FILE).src
-APPUP_SRC= $(APPUP_FILE).src
-APP_TARGET= $(EBIN)/$(APP_FILE)
-APPUP_TARGET= $(EBIN)/$(APPUP_FILE)
-
-# ----------------------------------------------------
-# FLAGS
-# ----------------------------------------------------
-ERL_FLAGS +=
-XMERL = ../../xmerl
-ERL_COMPILE_FLAGS += -I$(XMERL)/include
-
-# ----------------------------------------------------
-# Targets
-# ----------------------------------------------------
-
-debug opt: $(TARGET_FILES) $(APP_TARGET) $(APPUP_TARGET)
-
-clean:
- rm -f $(TARGET_FILES) $(APP_TARGET)
- rm -f errs core *~
-
-$(APP_TARGET): $(APP_SRC) ../vsn.mk
- sed -e 's;%VSN%;$(VSN);' $< > $@
-$(APPUP_TARGET): $(APPUP_SRC) ../vsn.mk
- sed -e 's;%VSN%;$(VSN);' $< > $@
-
-docs:
-
-# ----------------------------------------------------
-# Release Target
-# ----------------------------------------------------
-include $(ERL_TOP)/make/otp_release_targets.mk
-
-release_spec: opt
- $(INSTALL_DIR) $(RELSYSDIR)/src
- $(INSTALL_DATA) $(ERL_FILES) $(HRL_FILES) $(RELSYSDIR)/src
- $(INSTALL_DIR) $(RELSYSDIR)/ebin
- $(INSTALL_DATA) $(TARGET_FILES) $(APP_TARGET) $(APPUP_TARGET) $(RELSYSDIR)/ebin
-
-release_docs_spec:
-
-
-
-
-
diff --git a/lib/docbuilder/src/docb_gen.erl b/lib/docbuilder/src/docb_gen.erl
deleted file mode 100644
index 75494314f1..0000000000
--- a/lib/docbuilder/src/docb_gen.erl
+++ /dev/null
@@ -1,142 +0,0 @@
-%% ``The contents of this file are subject to the Erlang Public License,
-%% Version 1.1, (the "License"); you may not use this file except in
-%% compliance with the License. You should have received a copy of the
-%% Erlang Public License along with this software. If not, it can be
-%% retrieved via the world wide web at http://www.erlang.org/.
-%%
-%% Software distributed under the License is distributed on an "AS IS"
-%% basis, WITHOUT WARRANTY OF ANY KIND, either expressed or implied. See
-%% the License for the specific language governing rights and limitations
-%% under the License.
-%%
-%% The Initial Developer of the Original Code is Ericsson Utvecklings AB.
-%% Portions created by Ericsson are Copyright 1999-2000, Ericsson
-%% Utvecklings AB. All Rights Reserved.''
-%%
-%% $Id$
-%%
--module(docb_gen).
-
--export([module/1, module/2, users_guide/1, users_guide/2]).
--deprecated([{module,1,next_major_release},
- {module,2,next_major_release},
- {users_guide,1,next_major_release},
- {users_guide,2,next_major_release}]).
-
--record(args, {suffix=".xml",
- layout=docb_edoc_xml_cb,
- def=[],
- includes=[],
- preprocess=false,
- sort_functions=true}).
-
-%% module(File) -> ok | {error, Reason}
-%% module(File, Opts) -> ok | {error, Reason}
-%% File = string(), file name with or without ".erl" extension
-%% Opts -- see code
-%% Reason = badfile | {badopt, Term}
-module(File0) ->
- module(File0, []).
-module(File0, RawOpts) ->
- File = case filename:extension(File0) of
- ".erl" -> File0;
- _ -> File0++".erl"
- end,
- case filelib:is_regular(File) of
- true ->
- case parse(RawOpts, #args{}) of
- {ok, Args} ->
- Opts = [{def, Args#args.def},
- {includes, Args#args.includes},
- {preprocess, Args#args.preprocess},
- {sort_functions, Args#args.sort_functions},
-
- {app_default, "OTPROOT"},
- {file_suffix, Args#args.suffix},
- {dir, "."},
- {layout, Args#args.layout}],
- edoc:file(File, Opts);
- Error ->
- Error
- end;
- false ->
- {error, badfile}
- end.
-
-%% users_guide(File) -> ok | {error, Reason}
-%% users_guide(File, Opts) -> ok | {error, Reason}
-%% File = string()
-%% Opts -- see code
-%% Reason = badfile | {badopt, Opt}
-users_guide(File) ->
- users_guide(File, []).
-users_guide(File, RawOpts) ->
- case filelib:is_regular(File) of
- true ->
- case parse(RawOpts, #args{}) of
- {ok, Args} ->
- Opts = [{def, Args#args.def},
- {app_default, "OTPROOT"},
- {file_suffix, Args#args.suffix},
- {layout, Args#args.layout}],
-
- Env = edoc_lib:get_doc_env(Opts),
-
- {ok, Tags} =
- edoc_extract:file(File, overview, Env, Opts),
- Data =
- edoc_data:overview("Overview", Tags, Env, Opts),
- F = fun(M) -> M:overview(Data, Opts) end,
- Text = edoc_lib:run_layout(F, Opts),
-
- OutFile = "chapter" ++ Args#args.suffix,
- edoc_lib:write_file(Text, ".", OutFile);
- Error ->
- Error
- end;
- false ->
- {error, badfile}
- end.
-
-parse([{output,xml} | RawOpts], Args) ->
- parse(RawOpts, Args); % default, no update of record necessary
-parse([{output,sgml} | RawOpts], Args) ->
- parse(RawOpts, Args#args{suffix=".sgml", layout=docb_edoc_sgml_cb});
-parse([{def,Defs} | RawOpts], Args) ->
- case parse_defs(Defs) of
- true ->
- Args2 = Args#args{def=Args#args.def++Defs},
- parse(RawOpts, Args2);
- false ->
- {error, {badopt, {def,Defs}}}
- end;
-parse([{includes,Dirs} | RawOpts], Args) ->
- case parse_includes(Dirs) of
- true ->
- Args2 = Args#args{includes=Args#args.includes++Dirs},
- parse(RawOpts, Args2);
- false ->
- {error, {badopt, {includes,Dirs}}}
- end;
-parse([{preprocess,Bool} | RawOpts], Args) when Bool==true;
- Bool==false ->
- parse(RawOpts, Args#args{preprocess=Bool});
-parse([{sort_functions,Bool} | RawOpts], Args) when Bool==true;
- Bool==false ->
- parse(RawOpts, Args#args{sort_functions=Bool});
-parse([], Args) ->
- {ok, Args};
-parse([Opt | _RawOpts], _Args) ->
- {error, {badopt, Opt}}.
-
-parse_defs(Defs) ->
- lists:all(fun({Key,Val}) when is_atom(Key), is_list(Val) -> true;
- (_) -> false
- end,
- Defs).
-
-parse_includes(Dirs) ->
- lists:all(fun(Dir) when is_list(Dir) -> true;
- (_) -> false
- end,
- Dirs).
diff --git a/lib/docbuilder/src/docb_html.erl b/lib/docbuilder/src/docb_html.erl
deleted file mode 100644
index bdfc5ea876..0000000000
--- a/lib/docbuilder/src/docb_html.erl
+++ /dev/null
@@ -1,393 +0,0 @@
-%% ``The contents of this file are subject to the Erlang Public License,
-%% Version 1.1, (the "License"); you may not use this file except in
-%% compliance with the License. You should have received a copy of the
-%% Erlang Public License along with this software. If not, it can be
-%% retrieved via the world wide web at http://www.erlang.org/.
-%%
-%% Software distributed under the License is distributed on an "AS IS"
-%% basis, WITHOUT WARRANTY OF ANY KIND, either expressed or implied. See
-%% the License for the specific language governing rights and limitations
-%% under the License.
-%%
-%% The Initial Developer of the Original Code is Ericsson Utvecklings AB.
-%% Portions created by Ericsson are Copyright 1999-2000, Ericsson
-%% Utvecklings AB. All Rights Reserved.''
-%%
-%% $Id$
-%%
--module(docb_html).
-
--export([rule/2, rule/3]).
-
-rule([p, item, list|_], {_, _, _}) ->
- {"", "<br />\n"};
-rule([p, item, taglist|_], {_, _, _}) ->
- {"", "<br />\n"};
-rule([p|_], _) ->
- {"\n<p>", "\n</p>"};
-
-rule([pre|_], _) ->
- {"\n<div class=\"example\"><pre>\n", "\n</pre></div>\n"};
-
-rule([input|_], _) ->
- {"<strong>", "</strong>"};
-
-rule([quote|_], _) ->
- {"\n<blockquote>\n", "\n</blockquote>\n"};
-
-rule([i|_], _) ->
- {"<em>", "</em>"};
-
-rule([b|_], _) ->
- {"<strong>", "</strong>"};
-
-rule([c|_], _) ->
- {"<span class=\"code\">", "</span>"};
-
-rule([em|_], _) ->
- {"<strong>", "</strong>"};
-
-rule([sub|_], _) ->
- {"<sub>", "</sub>"};
-
-rule([sup|_], _) ->
- {"<sup>", "</sup>"};
-
-rule([termdef|_], _) ->
- {drop, ""};
-
-rule([citedef|_], _) ->
- {drop, ""};
-
-rule([br|_], _) ->
- {"<br />\n", ""};
-
-rule([digression|_], _) ->
- {"<table>\n"
- " <tr>\n"
- " <td width=\"23\"></td>\n"
- " <td>\n"
- " <font size=\"-1\">\n",
- " </font>\n"
- " </td>\n"
- " </tr>\n"
- "</table>\n"};
-
-rule([list, item, list|_], {_, ["ORDERED"], _}) ->
- {"\n<ol>\n", "\n</ol>\n"};
-rule([list, item, taglist|_], {_, ["ORDERED"], _}) ->
- {"\n<ol>\n", "\n</ol>\n"};
-rule([list|_], {_, ["ORDERED"], _}) ->
- {"\n<ol>\n", "\n</ol>\n"};
-rule([list, item, list|_], {_, ["BULLETED"], _}) ->
- {"\n<ul>\n", "\n</ul>\n"};
-rule([list, item, taglist|_], {_, ["BULLETED"], _}) ->
- {"\n<ul>\n", "\n</ul>\n"};
-rule([list|_], {_, ["BULLETED"], _}) ->
- {"\n<ul>\n", "\n</ul>\n"};
-
-rule([taglist, item, taglist|_], _) ->
- {"\n<dl>\n", "\n</dl>\n"};
-rule([taglist, item, list|_], _) ->
- {"\n<dl>\n", "\n</dl>\n"};
-rule([taglist|_], _) ->
- {"\n<dl>\n", "\n</dl>\n"};
-
-rule([tag|_], _) ->
- {"\n<dt>\n", "\n</dt>\n"};
-
-rule([item, list|_], _) ->
- {"\n<li>\n", "\n</li>\n\n"};
-rule([item, taglist|_], _) ->
- {"\n<dd>\n", "\n</dd>\n"};
-
-rule([image|_], {_, [File], _}) ->
- File2 =
- case filename:extension(File) of
- [] -> File ++ ".gif";
- _ -> File
- end,
- {["\n<center>\n", "<img alt=\"", File2, "\" src=\"", File2,
- "\"/><br/>\n"],
- "\n</center>\n"};
-
-rule([icaption|_], _) ->
- {"<em>", "</em>\n"};
-
-rule([url|_], {_, [HREF], _}) ->
- URI = docb_html_util:make_uri(HREF),
- {io_lib:format("<a target=\"_top\" href=\"~s\">", [URI]), "</a>"};
-
-rule([marker|_], {_, [ID], _}) ->
- %% remove all chars before first # including the #
- {ok, NewID, _} = regexp:sub(ID, "^[^#]*#", ""),
- %% replace "/" with "-" because "/" xhtml does not
- %% allow "/" in the name attribute of element <a>
- %% so we have to do the same as for marker i.e
- %% Function/Arity is translated to an anchor in xhtml
- %% like this : <a name="Function-Arity"/>
- NewID2 = [case X of $/ -> $-;_->X end||X <- NewID],
- {drop, ["<a name=\"", NewID2, "\"><!-- Empty --></a>"]};
-
-rule([table|_], {_, ["", ""], Ts}) ->
- {newargs,
- "\n<center>\n"
- "<table cellspacing=\"0\" cellpadding=\"2\" border=\"1\">\n",
- reorder_table(Ts),
- "\n</table>\n"
- "</center>\n"};
-rule([table|_], {_, [Width, ""], Ts}) ->
- {newargs,
- ["\n<center>\n"
- "<table cellspacing=\"0\" cellpadding=\"2\" border=\"1\" ",
- "width=\"", Width, "%\">\n"],
- reorder_table(Ts),
- "\n</table>\n"
- "</center>\n"};
-
-%% The clauses above are for the report DTD. This one is for the other
-%% DTDs.
-rule([table|_], {_, ["LEFT"], Ts}) ->
- {newargs,
- "\n"
- "<table cellspacing=\"0\" cellpadding=\"2\" border=\"1\">\n",
- reorder_table(Ts),
- "\n</table>\n"};
-
-rule([table|_], {_, _, Ts}) ->
- {newargs,
- "\n<center>\n"
- "<table cellspacing=\"0\" cellpadding=\"2\" border=\"1\">\n",
- reorder_table(Ts),
- "\n</table>\n"
- "</center>\n"};
-
-rule([row|_], _) ->
- {" <tr>\n", "\n </tr>\n"};
-
-rule([cell|_], {_, ["", ""], _}) ->
- {" <td>\n", "\n </td>\n"};
-rule([cell|_], {_, [Align, ""], _}) ->
- {[" <td align=\"", string:to_lower(Align), "\">\n"], "\n </td>\n"};
-rule([cell|_], {_, ["", VAlign], _}) ->
- {[" <td valign=\"", string:to_lower(VAlign), "\">\n"], "\n </td>\n"};
-rule([cell|_], {_, [Align, VAlign], _}) ->
- {[" <td align=\"", string:to_lower(Align), "\" valign=\"", string:to_lower(VAlign), "\">\n"],
- "\n </td>\n"};
-
-rule([tcaption|_], _) ->
- {" <caption align=\"bottom\"><em>", "</em></caption>\n"};
-
-rule([codeinclude|_], {_, [File, Tag, _Type], _}) ->
-%% Type can be "ERL", "C" or "NONE"
- {ok,Data} = docb_html_util:code_include(File, Tag),
- {drop, ["\n<div class=\"example\"><pre>\n", Data,
- "\n</pre></div>\n"]};
-
-rule([erleval|_], {_, [Expr], _}) ->
- docb_html_util:erl_eval(Expr);
-
-rule([pcdata, pre|_], {_, _, Data}) ->
- %% Do not remove leading spaces.
- {drop, docb_html_util:pcdata_to_html(Data, false)};
-
-rule([pcdata|_], {_, _, Data}) ->
- {drop, docb_html_util:pcdata_to_html(Data)}.
-
-rule([seealso|_], {_, [Marker], _}, Opts) ->
- Href =
- case docb_util:html_snippet(seealso, Marker, Opts) of
- "" ->
- %% DocBuilder default behavior:
- %% Marker is of format "Path#Fragment", both optional.
- %% Translated to <A HREF="Path.html#Fragment">
- case string:chr(Marker, $#) of
- 0 -> % No Fragment
- Marker++".html";
- 1 -> % No Path
- %% replace "/" with "-" because "/" xhtml does not
- %% allow "/" in the name attribute of element <a>
- %% so we have to do the same as for marker i.e
- %% Function/Arity is translated to an anchor in xhtml
- %% like this : <a name="Function-Arity"/>
- [case X of $/ -> $-;_->X end||X <- Marker];
- _ ->
- Marker1 = [case X of $/ -> $-;_->X end||X <- Marker],
- case string:tokens(Marker1, "#") of
- [Path] -> % # at end, remove it
- Path++".html";
- [Path | Frag0] ->
- Path++".html#"++
- docb_util:join(Frag0, "#")
- end
- end;
- Href0 ->
- %% User defined behavior, use result as-is
- Href0
- end,
- {{["<a href=\"", Href, "\">"], "</a>"}, Opts};
-
-rule([warning|_], _, Opts) ->
- docb_html_util:copy_pics("warning.gif", "warning.gif", Opts),
- {{"\n<div class=\"warning\">\n"
- "<div class=\"label\">Warning</div>\n"
- "<div class=\"content\">\n",
- "\n</div>"
- "\n</div>\n"}, Opts};
-
-rule([note|_], _, Opts) ->
- docb_html_util:copy_pics("note.gif", "note.gif", Opts),
- {{"\n<div class=\"note\">\n"
- "<div class=\"label\">Note</div>\n"
- "<div class=\"content\">",
- "\n</div>"
- "\n</div>\n"}, Opts};
-
-rule([path|_], {_, [UNIX, Windows], [{pcdata, _, Text}]}, Opts) ->
- UnixPart =
- docb_util:an_option({ptype,"unix"}, Opts) and (UNIX/=""),
- WinPart =
- docb_util:an_option({ptype,"windows"}, Opts) and (Windows/=""),
- if
- UnixPart, WinPart ->
- {{drop, [docb_html_util:pcdata_to_html(Text),
- " <font size=\"-2\">(<code>UNIX: ",
- docb_html_util:attribute_cdata_to_html(UNIX),
- ", ",
- "Windows: ",
- docb_html_util:attribute_cdata_to_html(Windows),
- "</code>)</font>"]},
- Opts};
- UnixPart ->
- {{drop, [docb_html_util:pcdata_to_html(Text),
- " <font size=\"-1\">(<code>UNIX: ",
- docb_html_util:attribute_cdata_to_html(UNIX),
- "</code>)</font>"]},
- Opts};
- WinPart ->
- {{drop, [docb_html_util:pcdata_to_html(Text),
- " <font size=\"-1\">(<code>Windows: ",
- docb_html_util:attribute_cdata_to_html(Windows),
- "</code>)</font>"]},
- Opts};
- true ->
- {{drop, docb_html_util:pcdata_to_html(Text)}, Opts}
- end;
-
-rule([term|_], {_, [ID], _}, Opts) ->
- case docb_util:an_option(dict, Opts) of
- false ->
- case docb_util:lookup_option({defs, term}, Opts) of
- false ->
- {{drop, ["<em><strong>",
- ID,
- "</strong></em> "]}, Opts};
- TermList ->
- case lists:keyfind(ID, 1, TermList) of
- false ->
- {{drop, ["<em><strong>", ID,
- "</strong></em> "]},
- Opts};
- {ID, Name, _Description, _Resp} ->
- {{drop, ["<em><strong>", Name,
- "</strong></em> "]},
- Opts};
- {ID, Name, _Description} ->
- {{drop, [ "<em><strong>", Name,
- "</strong></em> "]},
- Opts}
- end
- end;
- true ->
- case docb_util:lookup_option({defs, term}, Opts) of
- false ->
- {{drop, ["<em><strong>", ID,
- "</strong></em> "]}, Opts};
- TermList ->
- PartApplication =
- docb_util:lookup_option(part_application, Opts),
- case lists:keyfind(ID, 1, TermList) of
- false ->
- {{drop, ["<a href=\"", PartApplication,
- "_term.html#", ID, "\">", ID,
- "</a> "]}, Opts};
- {ID, Name, _Description, _Resp} ->
- {{drop, ["<a href=\"", PartApplication,
- "_term.html#", ID, "\">", Name,
- "</a> "]}, Opts};
- {ID, Name, _Description} ->
- {{drop, ["<a href=\"", PartApplication,
- "_term.html#", ID, "\">", Name,
- "</a> "]}, Opts}
- end
- end
- end;
-
-rule([cite|_], {_, [ID], _}, Opts) ->
- case docb_util:an_option(dict, Opts) of
- false ->
- case docb_util:lookup_option({defs, cite}, Opts) of
- false ->
- {{drop, ["<em><strong>", ID, "</strong></em> "]},
- Opts};
- CiteList ->
- case lists:keyfind(ID, 1, CiteList) of
- false ->
- {{drop,
- ["<em><strong>", ID, "</strong></em> "]},
- Opts};
- {ID, Name, _Description, _Resp} ->
- {{drop, ["<em><strong>", Name,
- "</strong></em> "]},
- Opts};
- {ID, Name, _Description} ->
- {{drop, ["<em><strong>", Name,
- "</strong></em> "]},
- Opts}
- end
- end;
- true ->
- case docb_util:lookup_option({defs, cite}, Opts) of
- false ->
- {{drop, ["<em><strong>", ID, "</strong></em> "]},
- Opts};
- CiteList ->
- PartApp =
- docb_util:lookup_option(part_application, Opts),
- case lists:keyfind(ID, 1, CiteList) of
- false ->
- {{drop, ["<a href=\"", PartApp,
- "_cite.html#", ID, "\">", ID,
- "</a> "]},
- Opts};
- {ID, Name, _Description, _Resp} ->
- {{drop, ["<a href=\"", PartApp,
- "_cite.html#", ID, "\">", Name,
- "</a> "]},
- Opts};
- {ID, Name, _Description} ->
- {{drop, ["<a href=\"", PartApp,
- "_cite.html#", ID, "\">", Name,
- "</a> "]},
- Opts}
- end
- end
- end;
-
-rule([code|_], {_, [Type], [{pcdata, _, Code}]}, Opts) ->
- case lists:member(Type, ["ERL","C","NONE"]) of
- true ->
- {{drop, ["\n<div class=\"example\"><pre>\n", docb_html_util:element_cdata_to_html(Code),
- "\n</pre></div>\n"]}, Opts};
- false ->
- exit({error,"unknown type of <code>"})
- end.
-
-reorder_table(TableContent) ->
- reorder_table(TableContent, [], []).
-reorder_table([], Caption, NewTableContent) ->
- Caption ++ lists:reverse(NewTableContent);
-reorder_table([{tcaption,_,_} = Caption | TableContent], _, NewTableContent) ->
- reorder_table(TableContent, [Caption], NewTableContent);
-reorder_table([Row | TableContent], Caption, NewTableContent) ->
- reorder_table(TableContent, Caption, [Row | NewTableContent]).
diff --git a/lib/docbuilder/src/docb_html_layout.erl b/lib/docbuilder/src/docb_html_layout.erl
deleted file mode 100644
index dca80ac58e..0000000000
--- a/lib/docbuilder/src/docb_html_layout.erl
+++ /dev/null
@@ -1,380 +0,0 @@
-%% ``The contents of this file are subject to the Erlang Public License,
-%% Version 1.1, (the "License"); you may not use this file except in
-%% compliance with the License. You should have received a copy of the
-%% Erlang Public License along with this software. If not, it can be
-%% retrieved via the world wide web at http://www.erlang.org/.
-%%
-%% Software distributed under the License is distributed on an "AS IS"
-%% basis, WITHOUT WARRANTY OF ANY KIND, either expressed or implied. See
-%% the License for the specific language governing rights and limitations
-%% under the License.
-%%
-%% The Initial Developer of the Original Code is Ericsson Utvecklings AB.
-%% Portions created by Ericsson are Copyright 1999-2000, Ericsson
-%% Utvecklings AB. All Rights Reserved.''
-%%
-%% $Id$
-%%
--module(docb_html_layout).
-
--export([report_top/2, report_bot/1,
- first_top/2, first_bot/1,
- ref_top/2, ref_bot/1,
- chapter_top/2, chapter_bot/1,
- application_toc_top/3, application_toc_top/4,
- part_toc_top/3, part_toc_top/4, part_toc_bot/0,
- index_top/1, index_bot/0]).
-
-%% Report
-
-report_top(Data, Opts) ->
- [Title, Prepared, _Responsible, DocNo, _Approved, _Checked, _Date,
- Vsn0, _File] = Data,
- html_header(Title, Opts) ++
- docb_util:html_snippet(top, Opts) ++
-"<center>
-<h1>" ++ Title ++ "</h1>
-<big>
- " ++ DocNo ++ version(Opts, Vsn0) ++ "<br />
- " ++ Prepared ++ "<br />
-</big>
-</center>
-".
-
-report_bot(Opts) ->
- docb_util:html_snippet(bottom, Opts) ++
-"</body>
-</html>
-".
-
-%% First
-
-first_top(Data, Opts) ->
- [Title, _Prepared, _Responsible, DocNo, _Approved, _Checked, _Date,
- Vsn0, _File] = Data,
- html_header(Title, Opts) ++
- docb_util:html_snippet(top, Opts) ++
-"<center>
-<h1>" ++ Title ++ "</h1>
-<big>" ++ DocNo ++ version(Opts, Vsn0) ++ "<br />
-</big>
-</center>
-".
-
-first_bot(Opts) ->
- report_bot(Opts).
-
-%% Reference
-
-ref_top(Data, Opts) ->
- [Title, _Prepared, _Responsible, _DocNo, _Approved, _Checked,
- _Date, _Rev, _File] = Data,
- ref_html_header(Title, Opts) ++
-"<!-- refpage -->\n" ++
- docb_util:html_snippet(top, Opts) ++
-"<center>
-<h1>" ++ Title ++ "</h1>
-</center>".
-
-ref_bot(Opts) ->
- docb_util:html_snippet(bottom, Opts) ++
-"</body>
-</html>
-".
-
-%% Chapter
-
-chapter_top(Data, Opts) ->
- [Title, _Prepared, _Responsible, _DocNo, _Approved, _Checked,
- _Date, _Rev, _File] = Data,
- html_header(Title, Opts) ++
- docb_util:html_snippet(top, Opts).
-
-chapter_bot(Opts) ->
- report_bot(Opts).
-
-%% Application ToC
-
-application_toc_top(Data, DocName, Opts) ->
- [Title, _Prepared, _Responsible, DocNo, _Approved, _Checked,
- _Date, Vsn0, _File] = Data,
- html_header(Title, []) ++
-"<center>
-<strong>" ++ Title ++ "</strong>
-<p>
-<small>
- " ++ DocNo ++ version(Opts, Vsn0) ++ "
-</small>
-</p>
-<p>
-<small>
- <a target=\"document\" href=\"" ++ DocName ++ "_cite.html\">Bibliography</a> |
- <a target=\"document\" href=\"" ++ DocName ++ "_term.html\">Glossary</a> |
- <a target=\"document\" href=\"" ++ DocName ++ "_index.html\">Index</a> |
- <a target=\"document\" href=\"" ++ DocName ++ "_first.html\">Cover</a>" ++ top_index(Opts) ++
-"</small>
-</p>
-</center>
-<p>
-<small>
-<strong>Table of Contents</strong>
-</small>
-</p>
-".
-
-application_toc_top(Data, DocName, Opts, HRefTexts) ->
- [Title, _Prepared, _Responsible, DocNo, _Approved, _Checked,
- _Date, Vsn0, _File] = Data,
- html_header(Title, []) ++
-"<center>
-<small>
-" ++
- docb_util:join(
- lists:map(
- fun({HRef, Text}) ->
- "<a target=\"_top\" href=\"" ++ HRef ++ "\">" ++
- Text ++ "</a>"
- end,
- HRefTexts), " | ") ++ top_index(Opts) ++
-"</small>
-<p>
-<strong>" ++ Title ++ "</strong>
-</p>
-<p>
-<small>" ++ DocNo ++ version(Opts, Vsn0) ++ "<br />
-</small>
-</p>
-<p>
-<small>
- <a target=\"document\" href=\"" ++ DocName ++ "_cite.html\">Bibliography</a> |
- <a target=\"document\" href=\"" ++ DocName ++ "_term.html\">Glossary</a> |
- <a target=\"document\" href=\"" ++ DocName ++ "_index.html\">Index</a> |
- <a target=\"document\" href=\"" ++ DocName ++ "_first.html\">Cover</a>
-</small>
-</p>
-</center>
-<p>
-<small>
-<strong>Table of Contents</strong>
-</small>
-</p>
-".
-
-%% Part ToC
-
-part_toc_top(Data, DocName, Opts) ->
- [Title, _Prepared, _Responsible, DocNo, _Approved, _Checked,
- _Date, Vsn0, _File] = Data,
- html_header(Title, []) ++
-"<center>
-<p>
-<strong>" ++ Title ++ "</strong>
-</p>
-<p>
-<small>" ++ DocNo ++ version(Opts, Vsn0) ++ "<br />
-</small>
-</p>
-<p>
-<small>
- <a target=\"document\" href=\"" ++ DocName ++ "_cite.html\">Bibliography</a> |
- <a target=\"document\" href=\"" ++ DocName ++ "_term.html\">Glossary</a> |
- <a target=\"document\" href=\"" ++ DocName ++ "_first.html\">Cover</a>" ++
- top_index(Opts) ++
-"</small>
-</p>
-</center>
-<p>
-<small>
-<strong>Table of Contents</strong>
-</small>
-</p>
-".
-
-part_toc_top(Data, DocName, Opts, HRefTexts) ->
- [Title, _Prepared, _Responsible, DocNo, _Approved, _Checked,
- _Date, Vsn0, _File] = Data,
- html_header(Title, []) ++
-"<center>
-<p>
-<small>
-" ++
- docb_util:join(
- lists:map(
- fun({HRef, Text}) ->
- "<a target=\"_top\" href=\"" ++ HRef ++ "\">" ++
- Text ++ "</a>"
- end,
- HRefTexts), " | ") ++ top_index(Opts) ++
-"</small>
-</p>
-<p>
-<strong>" ++ Title ++ "</strong>
-</p>
-<p>
-<small>
- " ++ DocNo ++ version(Opts, Vsn0) ++ "<br />
-</small>
-</p>
-<p>
-<small>
- <a target=\"document\" href=\"" ++ DocName ++ "_cite.html\">Bibliography</a> |
- <a target=\"document\" href=\"" ++ DocName ++ "_term.html\">Glossary</a> |
- <a target=\"document\" href=\"" ++ DocName ++ "_first.html\">Cover</a>
-</small>
-</p>
-</center>
-<p>
-<small>
-<strong>Table of Contents</strong>
-</small>
-</p>
-".
-
-part_toc_bot() ->
-"</body >
-</html>
-".
-
-%% Index
-
-index_top(_Data) ->
- ref_html_header("INDEX", []) ++
-"<h1>INDEX</h1>
-<p><em>Emphasized</em> index entries refer to <em>modules</em>
-and <code>Courier</code> ditos to <code>functions</code>.\n</p>\n".
-
-index_bot() ->
- part_toc_bot().
-
-%% Internal functions
-
-html_header(Title, Opts) ->
- Vsn = docb_util:version(),
-%%"<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">
-"<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"
- \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">
-<!-- This document was generated using DocBuilder-" ++ Vsn ++ " -->
-<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">
-<head>
- <title>" ++ Title ++ "</title>
- <meta http-equiv=\"Content-Type\" content=\"text/html; charset=ISO-8859-1\"/>
- " ++ docb_util:html_snippet(head, Opts) ++ "
- <style type=\"text/css\">
-<!--
- body { font-family: Verdana, Arial, Helvetica, sans-serif }
- span.bold_code { font-family: courier;font-weight: bold}
- span.code { font-family: courier;font-weight: normal}
-
-.note, .warning {
- border: solid black 1px;
- margin: 1em 3em;
-}
-
-.note .label {
- background: #30d42a;
- color: white;
- font-weight: bold;
- padding: 5px 10px;
-}
-.note .content {
- background: #eafeea;
- color: black;
- line-height: 120%;
- font-size: 90%;
- padding: 5px 10px;
-}
-.warning .label {
- background: #C00;
- color: white;
- font-weight: bold;
- padding: 5px 10px;
-}
-.warning .content {
- background: #FFF0F0;
- color: black;
- line-height: 120%;
- font-size: 90%;
- padding: 5px 10px;
-}
-
- .example { background-color:#eeeeff }
- pre { font-family: courier; font-weight: normal }
- .REFBODY { margin-left: 13mm }
- .REFTYPES { margin-left: 8mm }
--->
- </style>
-</head>
-<body bgcolor=\"#FFFFFF\" text=\"#000000\" link=\"#0000FF\" vlink=\"#FF00FF\" alink=\"#FF0000\">
-".
-
-ref_html_header(Title, Opts) ->
- Vsn = docb_util:version(),
-%%"<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">
-"<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"
- \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">
-<!-- This document was generated using DocBuilder-" ++ Vsn ++ " -->
-<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">
-<head>
- <title>" ++ Title ++ "</title>
- <meta http-equiv=\"Content-Type\" content=\"text/html; charset=ISO-8859-1\"/>
- " ++ docb_util:html_snippet(head, Opts) ++ "
- <style type=\"text/css\">
-<!--
- body { font-family: Verdana, Arial, Helvetica, sans-serif }
- span.bold_code { font-family: courier;font-weight: bold}
- span.code { font-family: courier;font-weight: normal}
-
-.note, .warning {
- border: solid black 1px;
- margin: 1em 3em;
-}
-
-.note .label {
- background: #30d42a;
- color: white;
- font-weight: bold;
- padding: 5px 10px;
-}
-.note .content {
- background: #eafeea;
- color: black;
- line-height: 120%;
- font-size: 90%;
- padding: 5px 10px;
-}
-.warning .label {
- background: #C00;
- color: white;
- font-weight: bold;
- padding: 5px 10px;
-}
-.warning .content {
- background: #FFF0F0;
- color: black;
- line-height: 120%;
- font-size: 90%;
- padding: 5px 10px;
-}
-
- .example { background-color:#eeeeff }
- pre { font-family: courier; font-weight: normal }
- .REFBODY { margin-left: 13mm }
- .REFTYPES { margin-left: 8mm }
--->
- </style>
-</head>
-<body bgcolor=\"#FFFFFF\" text=\"#000000\" link=\"#0000FF\" vlink=\"#FF00FF\" alink=\"#FF0000\">
-".
-
-version(Opts, Vsn0) ->
- case docb_util:lookup_option(vsn, Opts, Vsn0) of
- "" -> "";
- Vsn -> " Version " ++ Vsn
- end.
-
-top_index(Opts) ->
- case docb_util:lookup_option(top, Opts) of
- false -> "";
- TIFile ->
- " | <a target=\"_top\" href=\"" ++ TIFile ++ "\">Top</a>"
- end.
diff --git a/lib/docbuilder/src/docb_html_ref.erl b/lib/docbuilder/src/docb_html_ref.erl
deleted file mode 100644
index c5c166f1ae..0000000000
--- a/lib/docbuilder/src/docb_html_ref.erl
+++ /dev/null
@@ -1,79 +0,0 @@
-%% ``The contents of this file are subject to the Erlang Public License,
-%% Version 1.1, (the "License"); you may not use this file except in
-%% compliance with the License. You should have received a copy of the
-%% Erlang Public License along with this software. If not, it can be
-%% retrieved via the world wide web at http://www.erlang.org/.
-%%
-%% Software distributed under the License is distributed on an "AS IS"
-%% basis, WITHOUT WARRANTY OF ANY KIND, either expressed or implied. See
-%% the License for the specific language governing rights and limitations
-%% under the License.
-%%
-%% The Initial Developer of the Original Code is Ericsson Utvecklings AB.
-%% Portions created by Ericsson are Copyright 1999-2000, Ericsson
-%% Utvecklings AB. All Rights Reserved.''
-%%
-%% $Id$
-%%
--module(docb_html_ref).
-
--export([rule/2, rule/3]).
-
-rule([description|_],_) ->
- {"\n<h3>DESCRIPTION</h3>\n<div class=\"REFBODY\">\n","\n</div>\n"};
-
-rule([funcs|_],_) ->
- {"\n<h3>EXPORTS</h3>\n",""};
-
-rule([func|_],_) ->
- {"\n<p>",""};
-
-rule([name, func, funcs, RefType|_], {_,_,[{pcdata,[],Name0}]}) ->
- Name1 = docb_html_util:make_anchor_name_short(Name0, RefType),
- {"<a name=\"" ++ Name1 ++ "\"><span class=\"bold_code\">",
- "</span></a><br/>\n"};
-
-rule([fsummary|_],_) ->
- {drop, "\n</p>\n"};
-
-rule([type|_], _) ->
- {"\n<div class=\"REFBODY\"><p>Types:</p>\n <div class=\"REFTYPES\">\n<p>\n",
- "\n </p> </div>\n</div>\n"};
-
-rule([v|_], _) ->
- {"<span class=\"bold_code\">","</span><br/>\n"};
-
-rule([d|_], _) ->
- {"\n<div class=\"REFBODY\">\n","\n</div>\n"};
-
-rule([desc|_], _) ->
- {"\n<div class=\"REFBODY\">\n","\n</div>\n"};
-
-rule([authors|_], _) ->
- {"\n<h3>AUTHORS</h3>\n<div class=\"REFBODY\">\n","\n</div>\n"};
-
-rule([aname|_], _) ->
- {"", " - "};
-
-rule([section|_], {1,_,_}) ->
- {"", ""};
-rule([section|_], {_N,_,_}) ->
- {"", "\n</div>\n"};
-
-rule([title|_], _) ->
- {"\n<h3>", "</h3>\n<div class=\"REFBODY\">\n"};
-
-rule(TagHistory, TagBody) ->
- docb_html:rule(TagHistory, TagBody).
-
-rule([email|_], _, Opts) ->
- case docb_util:html_snippet(email, Opts) of
- "" ->
- {{"","<br/>\n"}, Opts};
- Email ->
- {{drop, Email++"<br/>\n"}, Opts}
- end;
-
-rule(TagHistory, TagBody, Opts) ->
- docb_html:rule(TagHistory, TagBody, Opts).
-
diff --git a/lib/docbuilder/src/docb_html_util.erl b/lib/docbuilder/src/docb_html_util.erl
deleted file mode 100644
index 02ce8b52a7..0000000000
--- a/lib/docbuilder/src/docb_html_util.erl
+++ /dev/null
@@ -1,542 +0,0 @@
-%% ``The contents of this file are subject to the Erlang Public License,
-%% Version 1.1, (the "License"); you may not use this file except in
-%% compliance with the License. You should have received a copy of the
-%% Erlang Public License along with this software. If not, it can be
-%% retrieved via the world wide web at http://www.erlang.org/.
-%%
-%% Software distributed under the License is distributed on an "AS IS"
-%% basis, WITHOUT WARRANTY OF ANY KIND, either expressed or implied. See
-%% the License for the specific language governing rights and limitations
-%% under the License.
-%%
-%% The Initial Developer of the Original Code is Ericsson Utvecklings AB.
-%% Portions created by Ericsson are Copyright 1999-2000, Ericsson
-%% Utvecklings AB. All Rights Reserved.''
-%%
-%% $Id$
-%%
--module(docb_html_util).
-
--export([attribute_cdata_to_html/1,
- element_cdata_to_html/1,
- pcdata_to_html/1, pcdata_to_html/2]).
--export([copy_pics/3]).
--export([extract_header_data/2, all_header_data/1]).
--export([make_uri/1,
- make_anchor_href/1, make_anchor_href_short/3,
- make_anchor_name_short/2,
- make_funcdef_short/2]).
--export([erl_include/2, code_include/2, erl_eval/1]).
--export([number/3, count_sections/1]).
--export([format_toc/1]).
--export([html_latin1_sort_order/1]).
-
-%%--Handle CDATA and PCDATA---------------------------------------------
-
-%% NB: Functions for transforming sgmls/XMerL data output to html.
-%% Do not use these for included text files (cf code_include and
-%% erl_include).
-
-attribute_cdata_to_html(Data) ->
- data2html(Data, false).
-
-element_cdata_to_html(Data) ->
- data2html(Data, false).
-
-pcdata_to_html(Data) ->
- data2html(Data, true).
-
-pcdata_to_html(Data, RmSp) ->
- data2html(Data, RmSp).
-
-%% PCDATA, CDATA: Replace entities, and optionally delete
-%% leading and multiple spaces. CDATA never contains entities to
-%% replace.
-
-%% data2html(Cs, RmSpace)
-data2html([246| Cs], RmSp) ->
- [$&, $#, $2, $4, $6, $;| data2html(Cs, RmSp)];
-data2html([$>| Cs], RmSp) ->
- [$&, $#, $6, $2, $;| data2html(Cs, RmSp)];
-data2html([$<| Cs], RmSp) ->
- [$&, $#, $6, $0, $;| data2html(Cs, RmSp)];
-data2html([$&| Cs], RmSp) ->
- [$&, $#, $3, $8, $;| data2html(Cs, RmSp)];
-data2html([$\"| Cs], RmSp) ->
- [$&, $#, $3, $4, $;| data2html(Cs, RmSp)];
-data2html([$\n| Cs], RmSp) ->
- data2html(Cs, RmSp);
-data2html([$\\, $n| Cs], false) ->
- [$\n| data2html(Cs, false)];
-data2html([$\\, $n| Cs], true) ->
- [$\n| data2html(delete_leading_space(Cs), true)];
-data2html([$ , $ | Cs], true) -> % delete multiple space
- [$ | data2html(delete_leading_space(Cs), true)];
-data2html([$\\, $|| Cs0], RmSp) ->
- {Ent, Cs1} = collect_entity(Cs0),
- [entity_to_html(Ent)| data2html(Cs1, RmSp)];
-data2html([$\\, $0, $1, $2| Cs], RmSp) ->
- data2html(Cs, RmSp);
-data2html([$\\, $\\, $n| Cs], RmSp) ->
- [$\\, $n| data2html(Cs, RmSp)];
-data2html([$\\, O1, O2, O3| Cs], RmSp)
- when O1 >= $0, O1 =< $7, O2 >= $0, O2 =< $7, O3 >= $0, O3 =< $7 ->
- case octal2dec(O1, O2, O3) of
- 173 -> % soft hyphen
- data2html(Cs, RmSp);
- C when C > 31, C < 256 ->
- Ent = io_lib:format("&#~w;", [C]),
- [Ent| data2html(Cs, RmSp)];
- C ->
- [C| data2html(Cs, RmSp)]
- end;
-data2html([$\\, $\\| Cs], RmSp) ->
- [$\\| data2html(Cs, RmSp)];
-data2html([C| Cs], RmSp) ->
- [C| data2html(Cs, RmSp)];
-data2html([], _) ->
- [].
-
-delete_leading_space([$ | Cs]) ->
- delete_leading_space(Cs);
-delete_leading_space(Cs) ->
- Cs.
-
-collect_entity(Data) ->
- collect_entity(Data, []).
-
-collect_entity([$\\, $|| Cs], Rs) ->
- {lists:reverse(Rs), Cs};
-collect_entity([C| Cs], Rs) ->
- collect_entity(Cs, [C| Rs]);
-collect_entity([], Rs) ->
- {[], lists:reverse(Rs)}.
-
-entity_to_html("&") -> "&#38;";
-entity_to_html("\"") -> "&#34;";
-entity_to_html("<") -> "&#60;";
-entity_to_html(">") -> "&#62;";
-entity_to_html([$\\, O1, O2, O3])
- when O1 >= $0, O1 =< $7, O2 >= $0, O2 =< $7, O3 >= $0, O3 =< $7 ->
- case octal2dec(O1, O2, O3) of
- 173 -> % soft hyphen
- "";
- Value ->
- io_lib:format("&#~w;", [Value])
- end;
-entity_to_html(Other) ->
- docb_html_util_iso:entity_to_html(Other).
-
-octal2dec(O1, O2, O3) ->
- (O1*8+O2)*8+O3-73*$0.
-
-%%--Copy images---------------------------------------------------------
-
-copy_pics(Src, Dest, Opts) ->
- Dir = code:lib_dir(docbuilder),
- InFile = filename:join([Dir, "etc", Src]),
- OutFile = docb_util:outfile(Dest, "", Opts),
- case filelib:last_modified(OutFile) of
- 0 -> % File doesn't exist
- file:copy(InFile, OutFile);
-
- OutMod2 ->
- InMod1s = calendar:datetime_to_gregorian_seconds(
- filelib:last_modified(InFile)),
- OutMod2s = calendar:datetime_to_gregorian_seconds(OutMod2),
- if
- InMod1s > OutMod2s -> % InFile is newer than OutFile
- file:copy(InFile, OutFile);
- true ->
- ok
- end
- end.
-
-%%--Resolve header data-------------------------------------------------
-
-extract_header_data(Key, {header, [], List}) ->
- case lists:keyfind(Key, 1, List) of
- {Key, [], []} ->
- "";
- {Key, [], [{pcdata, [], Value}]} ->
- pcdata_to_html(Value);
- false ->
- ""
- end.
-
-all_header_data(Header) ->
- all_header_data(Header,
- [title, prepared, responsible, docno, approved,
- checked, date, rev, file]).
-
-all_header_data(_Header, []) ->
- [];
-all_header_data(Header, [Key| Rest]) ->
- [extract_header_data(Key, Header) | all_header_data(Header, Rest)].
-
-%%--Resolve hypertext references----------------------------------------
-
-%% URI regular expression (RFC 2396):
-%% "^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\\?([^#]*))?(#(.*))?"
-%% We split it in five parts:
-%% scheme: "^(([^:/?#]+):)?" (includes trailing `:')
-%% authority: "^(//([^/?#]*))?" (includes leading `//')
-%% path: "^([^?#]*)"
-%% query: "^(\\?([^#]*))?" (includes leading `?')
-%% fragment: "^(#(.*))?" (includes leading `#')
-
-make_uri(Cs) ->
- lists:flatmap(
- fun({path, S}) ->
- case regexp:match(S, "\.xml?\$") of
- {match, _, _} ->
- {ok, NS, _} = regexp:sub(S, "\.xml?\$", ".html"),
- NS;
- _ ->
- S
- end;
- ({_, S}) ->
- S
- end,
- split_uri(Cs)).
-
-split_uri(URI) ->
- split_uri(URI, [{scheme, "^(([^:/?#]+):)?"},
- {authority, "^(//([^/?#]*))?"},
- {path, "^([^?#]*)"},
- {'query', "^(\\?([^#]*))?"},
- {fragment, "^(#(.*))?"}]).
-
-split_uri("", [{Tag, _R}| T]) ->
- [{Tag, ""}| split_uri("", T)];
-split_uri(Cs0, [{Tag, R}| T]) ->
- {match, 1, N} = regexp:match(Cs0, R),
- Cs1 = string:substr(Cs0, 1, N),
- Cs2 = strip_and_escape_uri_component(Tag, Cs1),
- [{Tag, Cs2}| split_uri(string:substr(Cs0, N+1), T)];
-split_uri(_, []) ->
- [].
-
-strip_and_escape_uri_component(authority, "//" ++ Cs) ->
- "//" ++ escape_uri(string:strip(Cs));
-strip_and_escape_uri_component(path, Cs) ->
- escape_uri(string:strip(Cs));
-strip_and_escape_uri_component('query', "?" ++ Cs) ->
- "?" ++ escape_uri(string:strip(Cs));
-strip_and_escape_uri_component(fragment, "#" ++ Cs) ->
- "#" ++ escape_uri(string:strip(Cs));
-strip_and_escape_uri_component(_, "") ->
- "";
-strip_and_escape_uri_component(_, Cs) ->
- escape_uri(string:strip(Cs)).
-
-escape_uri([C|Cs]) when C =< 32;
- C == $<; C == $<; C == $#; C == $%; C == $";
- C == $?;
- C == ${; C == $}; C ==$|; C == $\\; C == $^;
- C == $[; C == $]; C ==$';
- C >= 127 ->
- [$%, mk_hex(C div 16), mk_hex(C rem 16)| escape_uri(Cs)];
-escape_uri([C|Cs]) ->
- [C|escape_uri(Cs)];
-escape_uri([]) ->
- [].
-
-mk_hex(C) when C<10 ->
- C + $0;
-mk_hex(C) ->
- C - 10 + $a.
-
-make_anchor_href(HRef) ->
- case regexp:split(HRef, "#") of
- {ok, [HRef]} ->
- %% No `#' in HRef, i.e. only path
- make_anchor_href(HRef, "");
- {ok, [Path, Fragment]} ->
- make_anchor_href(Path, Fragment)
- end.
-
-make_anchor_href(Path0, Frag0) ->
- Frag1 = string:strip(Frag0),
- Path1 = case Path0 of
- "" ->
- "";
- _ ->
- case regexp:match(Path0, "\.xml?\$") of
- nomatch ->
- Path0 ++ ".html";
- _ ->
- {ok, NewPath, _} = regexp:sub(Path0,
- "\.xml?\$",
- ".html"),
- NewPath
- end
- end,
- case Frag1 of
- "" ->
- attribute_cdata_to_html(Path1);
- _ ->
- attribute_cdata_to_html(Path1) ++
- "#" ++
- attribute_cdata_to_html([case Ch of $/ -> $-; _ -> Ch end||
- Ch <-Frag1])
- end.
-
-make_anchor_href_short(Path, Frag, RefType) ->
- ShortFrag = make_funcdef_short(Frag, RefType,"-"),
- make_anchor_href(Path, ShortFrag).
-
-make_anchor_name_short(FuncName0, RefType) ->
- FuncName1 = make_funcdef_short(FuncName0, RefType,"-"),
- attribute_cdata_to_html(FuncName1).
-
-make_funcdef_short(FuncDef0, RefType) ->
- make_funcdef_short(FuncDef0, RefType, "/").
-
-make_funcdef_short(FuncDef0, RefType,Delimiter) ->
- FuncDef1 = docb_util:trim(FuncDef0),
- Any0 = case lists:member(RefType, [cref, erlref]) of
- true ->
- case catch docb_util:fknidx(FuncDef1, Delimiter) of
- {'EXIT', _} ->
- false;
- Any1 ->
- Any1
- end;
- false ->
- false
- end,
- case Any0 of
- false ->
- case string:tokens(FuncDef1, " ") of
- [Any2| _] ->
- Any2;
- _ ->
- FuncDef1
- end;
- _ ->
- Any0
- end.
-
-%%--Include tags--------------------------------------------------------
-
-%% Only used in report DTD
-erl_include(File, Tag) ->
- case docb_main:include_file(File, Tag) of
- {ok, Cs} ->
- {drop, "\n<pre>\n" ++ text_to_html(Cs) ++ "\n</pre>\n"};
- error ->
- {drop, ""}
- end.
-
-code_include(File, Tag) ->
- case docb_main:include(File, Tag, Tag) of
- {ok, Cs} ->
- {ok,text_to_html(Cs)};
- error ->
- {error, {codeinclude,File}}
- end.
-
-erl_eval(Expr) ->
- Cs = docb_main:eval_str(Expr),
- {drop, "\n<pre>\n" ++ text_to_html(Cs) ++ "\n</pre>\n"}.
-
-%% Only replaces certain characters. Spaces and new lines etc are kept.
-%% Used for plain text (e.g. inclusions of code).
-text_to_html([$>| Cs]) ->
- [$&, $#, $6, $2, $;| text_to_html(Cs)];
-text_to_html([$<| Cs]) ->
- [$&, $#, $6, $0, $;| text_to_html(Cs)];
-text_to_html([$&| Cs]) ->
- [$&, $#, $3, $8, $;| text_to_html(Cs)];
-text_to_html([$\"| Cs]) ->
- [$&, $#, $3, $4, $;| text_to_html(Cs)];
-text_to_html([C| Cs]) ->
- [C| text_to_html(Cs)];
-text_to_html([]) ->
- [].
-
-%%--Number sections-----------------------------------------------------
-
-number({Tag, Attrs, More}, none, File) ->
- {Tag, Attrs, do_number(More, [1], File)};
-number({Tag, Attrs, More}, Prefix, File) ->
- {Tag, Attrs, do_number(More, [list_to_integer(Prefix)], File)}.
-
-do_number([], _, _) ->
- [];
-do_number([{header, Attrs, More}| Rest], NN, File) ->
- [{header, Attrs, More}| do_number(Rest, NN, File)];
-do_number([{section, Attrs, More}| Rest], [N| NN], File) ->
- [{section, Attrs, do_number(More, [1, N| NN], File)}|
- do_number(Rest, [N+1| NN], File)];
-do_number([{title, _, [{pcdata, _, Title}]}| More], [N| NN], File) ->
- Format = make_format(length(NN)),
- Number = lists:flatten(io_lib:format(Format, lists:reverse(NN))),
- [{marker, [{"ID", "CDATA", Number}], []},
- {title, [{"NUMBER", "CDATA", Number},
- {"FILE", "CDATA", File}],
- [{pcdata, [], Title}]}| do_number(More, [N| NN], File)];
-do_number([{pcdata, Attrs, More}| Rest], NN, File) ->
- [{pcdata, Attrs, More}| do_number(Rest, NN, File)];
-do_number([{Tag, Attrs, More}| Rest], NN, File) ->
- [{Tag, Attrs, do_number(More, NN, File)}|do_number(Rest, NN, File)].
-
-make_format(1) ->
- "~w";
-make_format(N) ->
- "~w." ++ make_format(N-1).
-
-count_sections([section| Rest]) ->
- 1 + count_sections(Rest);
-count_sections([_| Rest]) ->
- count_sections(Rest);
-count_sections([]) ->
- 0.
-
-%%--Make a ToC----------------------------------------------------------
-
-format_toc(Toc) ->
- [format_toc1(T) || T <- Toc].
-
-format_toc1({Number, Title}) ->
- [Number, " <a href = \"#", Number, "\">", Title, "</a><br/>\n"].
-
-%%--Convert HTML ISO Latin 1 characters to ordinary characters----------
-
-%% To be used for sorting. Cs must be flat.
-html_latin1_sort_order(Cs) ->
- hlso(Cs).
-
-hlso([]) ->
- [];
-hlso([$&, $#, C2, C1, C0, $;| Cs])
- when $0 =< C2, C2 =< $9, $0 =< C1, C1 =< $9, $0 =< C0, C0 =< $9 ->
- C = ((C2-$0)*10 + (C1-$0))*10 + C0-$0,
- hlso0(C, Cs);
-hlso([$&, $#, C1, C0, $;| Cs])
- when $0 =< C1, C1 =< $9, $0 =< C0, C0 =< $9 ->
- C = (C1-$0)*10 + C0-$0,
- hlso0(C, Cs);
-hlso([C| Cs]) ->
- [C| hlso(Cs)].
-
-hlso0(C, Cs) when 0 =< C, C =< 159 ->
- [C| hlso(Cs)];
-hlso0(160, Cs) -> %% no-break space
- hlso(Cs); % Remove it.
-hlso0(161, Cs) -> %% inverted exclamation mark
- [$? |hlso(Cs)];
-hlso0(162, Cs) -> %% cent sign
- [$$|hlso(Cs)];
-hlso0(163, Cs) -> %% pound sterling sign
- [$$|hlso(Cs)];
-hlso0(164, Cs) -> %% general currency sign
- [$$|hlso(Cs)];
-hlso0(165, Cs) -> %% yen sign
- [$$|hlso(Cs)];
-hlso0(166, Cs) -> %% broken (vertical) bar
- [$| |hlso(Cs)];
-hlso0(167, Cs) -> %% section sign
- [$$|hlso(Cs)];
-hlso0(168, Cs) -> %% umlaut (dieresis)
- [$: |hlso(Cs)];
-hlso0(169, Cs) -> %% copyright sign
- [$c |hlso(Cs)];
-hlso0(170, Cs) -> %% ordinal indicator, feminine
- [$f |hlso(Cs)];
-hlso0(171, Cs) -> %% angle quotation mark, left
- [$" |hlso(Cs)];
-hlso0(172, Cs) -> %% not sign
- [$- |hlso(Cs)];
-hlso0(173, Cs) -> %% soft hyphen
- [$- |hlso(Cs)];
-hlso0(174, Cs) -> %% registered sign
- [$r |hlso(Cs)];
-hlso0(175, Cs) -> %% macron
- [$- |hlso(Cs)];
-hlso0(176, Cs) -> %% degree sign
- [$d |hlso(Cs)];
-hlso0(177, Cs) -> %% plus-or-minus sign
- [$+ |hlso(Cs)];
-hlso0(178, Cs) -> %% superscript two
- [$2 |hlso(Cs)];
-hlso0(179, Cs) -> %% superscript three
- [$3 |hlso(Cs)];
-hlso0(180, Cs) -> %% acute accent
- [$' |hlso(Cs)];
-hlso0(181, Cs) -> %% micro sign
- [$' |hlso(Cs)];
-hlso0(182, Cs) -> %% pilcrow (paragraph sign)
- [$$|hlso(Cs)];
-hlso0(183, Cs) -> %% middle dot
- [$. |hlso(Cs)];
-hlso0(184, Cs) -> %% cedilla
- [$c |hlso(Cs)];
-hlso0(185, Cs) -> %% superscript one
- [$1 |hlso(Cs)];
-hlso0(186, Cs) -> %% ordinal indicator, masculine
- [$m |hlso(Cs)];
-hlso0(187, Cs) -> %% angle quotation mark, right
- [$" |hlso(Cs)];
-hlso0(188, Cs) -> %% fraction one-quarter
- [$4 |hlso(Cs)];
-hlso0(189, Cs) -> %% fraction one-half
- [$2 |hlso(Cs)];
-hlso0(190, Cs) -> %% fraction three-quarters
- [$3 |hlso(Cs)];
-hlso0(191, Cs) -> %% inverted question mark
- [$? |hlso(Cs)];
-
-hlso0(C, Cs) when 192 =< C, C =< 198 -> %% capital A
- [$A |hlso(Cs)];
-hlso0(199, Cs) -> %% capital C, cedilla
- [$C |hlso(Cs)];
-hlso0(C, Cs) when 200 =< C, C =< 203 -> %% capital E
- [$E |hlso(Cs)];
-hlso0(C, Cs) when 204 =< C, C =< 207 -> %% capital I
- [$I |hlso(Cs)];
-hlso0(208, Cs) -> %% capital Eth, Icelandic
- [$D |hlso(Cs)];
-hlso0(209, Cs) -> %% capital N, tilde
- [$N |hlso(Cs)];
-hlso0(C, Cs) when 210 =< C, C =< 214 -> %% capital O
- [$O |hlso(Cs)];
-hlso0(215, Cs) -> %% multiply sign
- [$x |hlso(Cs)];
-hlso0(216, Cs) -> %% capital O, slash
- [$O |hlso(Cs)];
-hlso0(C, Cs) when 217 =< C, C =< 220 -> %% capital U
- [$U |hlso(Cs)];
-hlso0(221, Cs) -> %% capital Y, acute accent
- [$Y |hlso(Cs)];
-hlso0(222, Cs) -> %% capital THORN, Icelandic
- [$T |hlso(Cs)];
-hlso0(223, Cs) -> %% small sharp s, German (sz
- [$s |hlso(Cs)];
-hlso0(C, Cs) when 224 =< C, C =< 230-> %% small a
- [$a |hlso(Cs)];
-hlso0(231, Cs) -> %% small c, cedilla
- [$c |hlso(Cs)];
-hlso0(C, Cs) when 232 =< C, C =< 235 -> %% small e
- [$e |hlso(Cs)];
-hlso0(C, Cs) when 236 =< C, C =< 239 -> %% small i
- [$i |hlso(Cs)];
-hlso0(240, Cs) -> %% small eth, Icelandic
- [$d |hlso(Cs)];
-hlso0(241, Cs) -> %% small n, tilde
- [$n |hlso(Cs)];
-hlso0(C, Cs) when 242 =< C, C =< 246 -> %% small o
- [$o |hlso(Cs)];
-hlso0(247, Cs) -> %% divide sign
- [$/ |hlso(Cs)];
-hlso0(248, Cs) -> %% small o, slash
- [$o |hlso(Cs)];
-hlso0(C, Cs) when 249 =< C, C =< 252 -> %% small u
- [$u |hlso(Cs)];
-hlso0(253, Cs) -> %% small y, acute accent
- [$y |hlso(Cs)];
-hlso0(254, Cs) -> %% small thorn, Icelandic
- [$t |hlso(Cs)];
-hlso0(255, Cs) -> %% small y, dieresis or umlaut
- [$y |hlso(Cs)].
diff --git a/lib/docbuilder/src/docb_html_util_iso.erl b/lib/docbuilder/src/docb_html_util_iso.erl
deleted file mode 100644
index c836805cd2..0000000000
--- a/lib/docbuilder/src/docb_html_util_iso.erl
+++ /dev/null
@@ -1,204 +0,0 @@
-%% ``The contents of this file are subject to the Erlang Public License,
-%% Version 1.1, (the "License"); you may not use this file except in
-%% compliance with the License. You should have received a copy of the
-%% Erlang Public License along with this software. If not, it can be
-%% retrieved via the world wide web at http://www.erlang.org/.
-%%
-%% Software distributed under the License is distributed on an "AS IS"
-%% basis, WITHOUT WARRANTY OF ANY KIND, either expressed or implied. See
-%% the License for the specific language governing rights and limitations
-%% under the License.
-%%
-%% The Initial Developer of the Original Code is Ericsson Utvecklings AB.
-%% Portions created by Ericsson are Copyright 1999-2000, Ericsson
-%% Utvecklings AB. All Rights Reserved.''
-%%
-%% $Id$
-%%
--module(docb_html_util_iso).
--export([entity_to_html/1]).
-
-%% Encodes ISOtech, ISOnum and ISOgrk3.
-%%
-%% All entities are of the form "[abcdef]".
-%%
-entity_to_html(Entity) when is_list(Entity), hd(Entity) =/= $[ ->
- Entity;
-entity_to_html(Entity) ->
- case (catch enc(Entity)) of
- {'EXIT', _} ->
- Entity;
- Enc ->
- "<font face=symbol>" ++ Enc ++ "</font>"
- end.
-
-enc("[Delta ]") -> "&#68;";
-%% enc("[Dot ]") -> "&#0;";
-%% enc("[DotDot]") -> "&#0;";
-enc("[Gamma ]") -> "&#71;";
-enc("[Lambda]") -> "&#76;";
-enc("[Omega ]") -> "&#87;";
-enc("[Phi ]") -> "&#70;";
-enc("[Pi ]") -> "&#80;";
-enc("[Prime ]") -> "&#178;";
-enc("[Psi ]") -> "&#89;";
-enc("[Sigma ]") -> "&#83;";
-enc("[Theta ]") -> "&#81;";
-enc("[Upsi ]") -> "&#161;";
-%% enc("[Verbar]") -> "&#0;";
-enc("[Xi ]") -> "&#88;";
-
-enc("[aleph ]") -> "&#192;";
-enc("[alpha ]") -> "&#97;";
-enc("[amp ]") -> "&#38;";
-enc("[and ]") -> "&#217;";
-enc("[ang ]") -> "&#208;";
-%% enc("[ang90 ]") -> "&#0;";
-%% enc("[angsph]") -> "&#0;";
-%% enc("[angst ]") -> "&#0;";
-enc("[ap ]") -> "&#187;";
-
-%% enc("[becaus]") -> "&#0;";
-%% enc("[bernou]") -> "&#0;";
-enc("[bepsi ]") -> "&#39;";
-enc("[beta ]") -> "&#98;";
-enc("[bottom]") -> "&#94;";
-enc("[bull ]") -> "&#183;";
-
-enc("[cap ]") -> "&#199;";
-enc("[chi ]") -> "&#99;";
-enc("[clubs ]") -> "&#167;";
-%% enc("[compfn]") -> "&#0;";
-enc("[cong ]") -> "&#64;";
-enc("[copy ]") -> "&#211;";
-%% enc("[conint]") -> "&#0;";
-enc("[cup ]") -> "&#200;";
-
-enc("[dArr ]") -> "&#223;";
-enc("[darr ]") -> "&#175;";
-enc("[deg ]") -> "&#176;";
-enc("[delta ]") -> "&#100;";
-enc("[diam ]") -> "&#224;";
-enc("[diams ]") -> "&#168;";
-enc("[divide]") -> "&#184;";
-
-enc("[empty ]") -> "&#198;";
-%% enc("[epsi ]") -> "&#0;";
-%% enc("[epsis ]") -> "&#0;";
-enc("[epsiv ]") -> "&#101;";
-enc("[equiv ]") -> "&#186;";
-enc("[eta ]") -> "&#104;";
-enc("[exist ]") -> "&#36;";
-
-enc("[fnof ]") -> "&#166;";
-enc("[forall]") -> "&#34;";
-
-enc("[gamma ]") -> "&#103;";
-%% enc("[gammad]") -> "&#0;";
-enc("[ge ]") -> "&#179;";
-enc("[gt ]") -> "&#62;";
-
-%% enc("[hamilt]") -> "&#0;";
-enc("[hArr ]") -> "&#219;";
-enc("[harr ]") -> "&#171;";
-enc("[hearts]") -> "&#169;";
-enc("[horbar]") -> "&#190;";
-
-enc("[iff ]") -> "&#219;";
-enc("[image ]") -> "&#193;";
-enc("[infin ]") -> "&#165;";
-enc("[int ]") -> "&#242;";
-enc("[iota ]") -> "&#105;";
-enc("[isin ]") -> "&#206;";
-
-enc("[kappa ]") -> "&#107;";
-%%enc("[kappav]") -> "&#0;";
-
-enc("[lArr ]") -> "&#220;";
-%% enc("[lagran]") -> "&#0;";
-enc("[lambda]") -> "&#108;";
-enc("[lang ]") -> "&#225;";
-enc("[larr ]") -> "&#172;";
-enc("[le ]") -> "&#163;";
-%% enc("[lowast]") -> "&#0;";
-enc("[lowbar]") -> "&#95;";
-enc("[lt ]") -> "&#60;";
-
-enc("[middot]") -> "&#215;";
-enc("[minus ]") -> "&#45;";
-%% enc("[mnplus]") -> "&#0;";
-enc("[mu ]") -> "&#109;";
-
-enc("[nabla ]") -> "&#209;";
-enc("[ne ]") -> "&#185;";
-enc("[ni ]") -> "&#39;";
-enc("[nsub ]") -> "&#203;";
-enc("[not ]") -> "&#216;";
-enc("[notin ]") -> "&#207;";
-enc("[nu ]") -> "&#110;";
-
-enc("[omega ]") -> "&#119;";
-enc("[or ]") -> "&#218;";
-%% enc("[order ]") -> "&#0;";
-enc("[oplus ]") -> "&#197;";
-enc("[otimes]") -> "&#196;";
-
-%% enc("[par ]") -> "&#0;";
-enc("[part ]") -> "&#182;";
-%% enc("[permil]") -> "&#0;";
-enc("[perp ]") -> "&#94;"; % bottom
-enc("[phis ]") -> "&#102;";
-enc("[phiv ]") -> "&#106;";
-%% enc("[phmmat]") -> "&#0;";
-enc("[pi ]") -> "&#112;";
-enc("[piv ]") -> "&#118;";
-enc("[plus ]") -> "&#43;";
-enc("[plusmn]") -> "&#177;";
-enc("[prime ]") -> "&#162;";
-enc("[prod ]") -> "&#213;";
-enc("[prop ]") -> "&#181;";
-enc("[psi ]") -> "&#121;";
-
-enc("[radic ]") -> "&#214;";
-enc("[rang ]") -> "&#241;";
-enc("[rArr ]") -> "&#222;";
-enc("[rarr ]") -> "&#174;";
-enc("[real ]") -> "&#194;";
-enc("[reg ]") -> "&#210;";
-enc("[rho ]") -> "&#114;";
-%% enc("[rhov ]") -> "&#0;";
-
-enc("[sigma ]") -> "&#115;";
-enc("[sigmav]") -> "&#86;";
-enc("[sim ]") -> "&#126;";
-%% enc("[sime ]") -> "&#0;";
-%% enc("[square]") -> "&#0;";
-enc("[sol ]") -> "&#164;";
-enc("[spades]") -> "&#170;";
-enc("[sub ]") -> "&#204;";
-enc("[sube ]") -> "&#205;";
-enc("[sup ]") -> "&#201;";
-enc("[supe ]") -> "&#202;";
-enc("[sum ]") -> "&#229;";
-
-enc("[tau ]") -> "&#116;";
-enc("[tdot ]") -> "&#188;";
-enc("[there4]") -> "&#92;";
-enc("[thetas]") -> "&#113;";
-enc("[thetav]") -> "&#74;";
-enc("[times ]") -> "&#180;";
-%% enc("[tprime]") -> "&#0;";
-enc("[trade ]") -> "&#212;";
-
-enc("[uArr ]") -> "&#221;";
-enc("[uarr ]") -> "&#173;";
-enc("[upsi ]") -> "&#117;";
-
-enc("[verbar]") -> "&#189;";
-
-%% enc("[wedgeq]") -> "&#0;";
-enc("[weierp]") -> "&#195;";
-
-enc("[xi ]") -> "&#120;";
-
-enc("[zeta ]") -> "&#122;".
diff --git a/lib/docbuilder/src/docb_main.erl b/lib/docbuilder/src/docb_main.erl
deleted file mode 100644
index 4f5f035a65..0000000000
--- a/lib/docbuilder/src/docb_main.erl
+++ /dev/null
@@ -1,657 +0,0 @@
-%% ``The contents of this file are subject to the Erlang Public License,
-%% Version 1.1, (the "License"); you may not use this file except in
-%% compliance with the License. You should have received a copy of the
-%% Erlang Public License along with this software. If not, it can be
-%% retrieved via the world wide web at http://www.erlang.org/.
-%%
-%% Software distributed under the License is distributed on an "AS IS"
-%% basis, WITHOUT WARRANTY OF ANY KIND, either expressed or implied. See
-%% the License for the specific language governing rights and limitations
-%% under the License.
-%%
-%% The Initial Developer of the Original Code is Ericsson Utvecklings AB.
-%% Portions created by Ericsson are Copyright 1999-2000, Ericsson
-%% Utvecklings AB. All Rights Reserved.''
-%%
-%% $Id$
-%%
--module(docb_main).
-
--export([process/2,
- parse/2, parse1/2,
- pp/2,
- insert_after/3,
- transform/5, pp/5,
- include_file/2, include/3,
- eval_str/1,
- validate_html/1
- ]).
--export([do_parse_sgmls/1]).
-
-%%----------------------------------------------------------------------
-
-%% process(File, Opts) -> errors | ok
-%% Parses the source file File and transforms the result to html,
-%% latex and/or man page format.
-process(File, Opts) ->
-
- SrcType = docb_util:lookup_option(src_type, Opts),
-
- File1 =
- case SrcType of
- ".xml" ->
- FileTmp = File ++ ".tmpconv",
- os:cmd("sed -e 's/xi:include[ \t]*href/include file/g' -e 's/xmlns:xi=\"http:\\/\\/www.w3.org\\/2001\\/XInclude\"//g' < " ++
- File ++ ".xml > " ++ FileTmp ++ ".xml"),
- FileTmp;
- ".sgml" ->
- File
- end,
-
- case parse1(File1, Opts) of
- errors ->
- delete_tmp_file(SrcType, File1),
- errors;
- {ok, Tree} ->
- From = element(1, Tree),
- Tos0 =
- lists:foldl(
- fun(latex, Acc) -> [latex|Acc];
- (html, Acc) -> [html|Acc];
- ({man, _Section}, Acc) -> [man|Acc];
- (_, Acc) -> Acc
- end, [], Opts),
-
- %% If no target format is specified, assume HTML:
- Tos = if
- Tos0 =:= [] -> [html];
- true -> Tos0
- end,
-
- Result = [transform(From, To, Opts, File, Tree)||To <- Tos],
- case lists:member(transformation_error,Result) of
- true ->
- delete_tmp_file(SrcType, File1),
- errors;
- _ ->
- delete_tmp_file(SrcType, File1),
- ok
- end
-
- end.
-
-
-delete_tmp_file(".xml", File) ->
- file:delete(File ++ ".xml");
-delete_tmp_file(_, _) ->
- ok.
-
-%%----------------------------------------------------------------------
-
-%% parse(File, Opts) -> {ok, Tree} | errors
-%% Parses the source file File, resulting in a tree structure.
-parse(File, Opts) ->
- case docb_util:lookup_option(src_type, Opts) of
- ".xml" ->
- parse_xml(File++".xml", Opts);
- ".sgml" ->
- parse_sgml(File, Opts)
- end.
-
-%% parse1(File, Opts) -> {ok, Tree} | errors
-%% Like parse/2, but in the SGML case also prints the parse errors
-%% (in File.html.sgmls_errs) information to stdout.
-parse1(File, Opts) ->
- parse(File, [{print_parse_errs, true}|Opts]).
-
-
-validate_html(InFile) ->
- ScanOpts = [{validation,true}, {fetch_fun, fun fetch_dtd/2}],
- case xmerl_scan:file(InFile, ScanOpts) of
- {_XMLTuple,[]} -> % ok
- {InFile,ok};
- {'EXIT',Reason} ->
- {InFile,Reason}
- end.
-
-fetch_dtd({public,_,"http://www.w3.org/TR/xhtml1/DTD/"++ Rest},GlobalState) ->
- Filename = filename:join(docb_util:dtd_dir(),Rest),
- {ok,{file,Filename},GlobalState};
-fetch_dtd({public,_,Str},GlobalState) ->
- {ok,{file,filename:join(docb_util:dtd_dir(),Str)},GlobalState}.
-
-
-
-parse_xml(InFile, Opts) ->
- DtdDir = docb_util:dtd_dir(),
- ScanOpts = [{validation,true}, {fetch_path, [DtdDir]}],
- PrintP = docb_util:lookup_option(print_parse_errs, Opts),
- case catch xmerl_scan:file(InFile, ScanOpts) of
- {'EXIT', Error} when PrintP ->
- docb_util:message(error,
- "XML validation error:~n~p", [Error]),
- errors;
- {'EXIT', _Error} ->
- errors;
- {error, Reason} -> % probably file error
- docb_util:message(error, "XML scan error: ~p", [Reason]),
- errors;
- {Doc, []} ->
- case catch xmerl:export([Doc], docb_xmerl_tree_cb) of
- [Tree] ->
- verify(Tree),
- {ok, Tree};
- {'EXIT', Error} ->
- docb_util:message(error,
- "XML export error:~n~p", [Error]),
- errors
- end
- end.
-
-parse_sgml(InFile, Opts) ->
-
- Pfx = tmp_file_prefix(InFile, Opts),
- OutFile = Pfx ++ "sgmls_output",
- ErrFile = Pfx ++ "sgmls_errs",
-
- EntVals = lists:usort(docb_util:lookup_options(ent, Opts)),
- Ents = lists:flatten([" -ent " ++ Val || Val <- EntVals]),
- Cmd = docb_util:old_docb_dir() ++ "/bin/docb_sgmls_run " ++
- Ents ++ " " ++ InFile ++ ".sgml " ++ OutFile ++ " " ++ ErrFile,
-
- case os:cmd(Cmd) of
- [] ->
- PrintP = docb_util:lookup_option(print_parse_errs, Opts),
- case filelib:file_size(ErrFile) of
- 0 -> % implies no errors
- parse_sgmls(InFile, OutFile);
- _ when PrintP ->
- cat(ErrFile),
- errors;
- _ ->
- errors
- end;
- Msg ->
- docb_util:message(error, "~p", [Msg]),
- errors
- end.
-
-tmp_file_prefix(File, Opts) ->
- lists:concat(
- [File, "." | lists:foldl(
- fun(latex, Acc) -> ["latex."|Acc];
- (html, Acc) -> ["html."|Acc];
- ({man, Section}, Acc) -> ["man", Section, "."|Acc];
- (_, Acc) -> Acc
- end, [], Opts)]).
-
-parse_sgmls(InFile, SgmlsFile) ->
- case file:open(SgmlsFile, [read]) of
- {ok, Fd} ->
- Res = case (catch do_parse_sgmls(Fd)) of
- {ok, Tree} ->
- {ok, Tree};
- {'EXIT', Reason} ->
- docb_util:message(
- error,
- "Cannot parse sgmls output file "
- "~s, obtained from parsing ~s, "
- "reason: ~w",
- [SgmlsFile, InFile, Reason]),
- errors;
- {error, Reason} ->
- docb_util:message(
- error,
- "Cannot parse sgmls output file "
- "~s, obtained from parsing ~s, "
- "reason: ~w",
- [SgmlsFile, InFile, Reason]),
- errors
- end,
- file:close(Fd),
- case Res of
- {ok, Tree0} ->
- verify(Tree0),
- {ok, Tree0};
- _Other ->
- errors
- end;
- {error, Reason} ->
- docb_util:message(error,
- "Cannot open sgmls output file ~s, "
- "obtained from parsing ~s, reason: ~w",
- [SgmlsFile, InFile, Reason]),
- errors
- end.
-
-do_parse_sgmls(Fd) ->
- do_parse_sgmls(Fd, []).
-
-do_parse_sgmls(Fd, Attrs) ->
- case get_line(Fd) of
- {attrs, A} ->
- do_parse_sgmls(Fd, [A|Attrs]);
- {startTag, Tag} ->
- {ok, {Tag, Attrs, get_args(Fd)}};
- Other ->
- {error, Other}
- end.
-
-get_args(Fd) ->
- case get_line(Fd) of
- {startTag, Tag} ->
- H = {Tag, [], get_args(Fd)},
- [H|get_args(Fd)];
- {dataTag, Str} ->
- [{pcdata, [], Str}|get_args(Fd)];
- {attrs, A} ->
- get_args_attr(Fd, [A]);
- close ->
- [];
- ok ->
- []
- end.
-
-get_args_attr(Fd, Attrs) ->
- case get_line(Fd) of
- {startTag, Tag} ->
- H = {Tag, lists:reverse(Attrs), get_args(Fd)},
- [H|get_args(Fd)];
- {dataTag, Str} ->
- [{pcdata, lists:reverse(Attrs), Str}|get_args(Fd)];
- {attrs, A} ->
- get_args_attr(Fd, [A|Attrs]);
- close ->
- [];
- ok ->
- []
- end.
-
-get_line(Fd) ->
- Str = io:get_line(Fd, ''),
- case Str of
- [$(|T] ->
- {startTag, tag_name(T)};
- [$-|T] ->
- {dataTag, T};
- [$)|_T] ->
- close;
- [$A|T] ->
- {attrs, attrs(remove_nl(T))};
- [$?|_T] ->
- get_line(Fd);
- [$C|_] ->
- ok
- end.
-
-remove_nl([$\n|_]) -> [];
-remove_nl([H|T]) -> [H|remove_nl(T)];
-remove_nl([]) -> [].
-
-%% attrs
-%% splits a string like
-%% AAAAA BBBBB ......
-%% into {"AAA", "BBB", Rest}
-
-attrs(T) ->
- {X, T1} = get_item(T),
- {Y, T2} = get_item(T1),
- T3 = skip_blanks(T2),
- {X, Y, T3}.
-
-get_item(T) -> get_item(skip_blanks(T), []).
-
-get_item([$ |T], L) -> {lists:reverse(L), [$ |T]};
-get_item([H|T], L) -> get_item(T, [H|L]);
-get_item([], L) -> {lists:reverse(L), []}.
-
-skip_blanks([$ |T]) -> skip_blanks(T);
-skip_blanks(T) -> T.
-
-tag_name(Str) -> tag_name(Str, []).
-
-tag_name([H|T], L) when $A =< H, H =< $Z ->
- tag_name(T, [H-$A+$a|L]);
-tag_name([$\n], L) ->
- list_to_atom(lists:reverse(L));
-tag_name([H|T], L) ->
- tag_name(T, [H|L]).
-
-cat(File) ->
- case file:open(File, [read]) of
- {ok, Fd} ->
- cat1(Fd),
- file:close(Fd);
- Other ->
- Other
- end.
-
-cat1(Fd) ->
- case io:get_line(Fd, '') of
- eof ->
- eof;
- Str ->
- io:format("~s", [Str]),
- cat1(Fd)
- end.
-
-%%----------------------------------------------------------------------
-
-verify(Tree) -> verify(Tree, [], 1).
-
-verify({pcdata, Optional, _}, Path, Level) ->
- verify_optional(Optional, Path, Level);
-verify({Tag, Optional, Args}, Path, Level) when is_list(Args) ->
- verify_optional(Optional, Path, Level)
- andalso verify_list(Args, [Tag|Path], Level);
-verify(Other, Path, Level) ->
- verify_error(Other, Path, Level).
-
-verify_error(X, Path, Level) ->
- docb_util:message(error, "Invalid object found at: ~p level:~w~n~s",
- [Path, Level, docb_pretty_format:term(X)]),
- false.
-
-verify_list([H|T], Path, Level) ->
- verify(H, Path, Level) andalso verify_list(T, Path, Level + 1);
-verify_list([], _, _) ->
- true.
-
-verify_optional([{_, _, _}|T], Path, Level) ->
- verify_optional(T, Path, Level);
-verify_optional([], _Path, _Level) ->
- true;
-verify_optional(X, Path, Level) ->
- verify_error(X, Path, Level).
-
-%%----------------------------------------------------------------------
-
-%% pp(File, Opts) -> {ok, OutFile} | errors
-%% Parses the source file and, if successful, prints the resulting tree
-%% structure to a file with the extension ".pp".
-pp(File, Opts) ->
- case parse(File, Opts) of
- {ok, Tree} ->
- OutFile = File ++ ".pp",
- dump(OutFile, Tree),
- {ok, OutFile};
- errors ->
- errors
- end.
-
-dump(File, Struct) ->
- {ok, Stream} = file:open(File, [write]),
- io:format("Info: Dump on ~p ...", [File]),
- io:format(Stream, "~n~s~n", [docb_pretty_format:term(Struct)]),
- io:format(" done.\n"),
- file:close(Stream).
-
-%%----------------------------------------------------------------------
-
-%% insert_after(Tag, Tree, Obj) -> Tree | {'EXIT', Reason}
-%% Insert an element in a tree structure
-insert_after(Tag, Tree, Obj) ->
- edit(Tag, Tree, {insert_after, Obj}).
-
-%% edit Op = delete, insert_before, insert_after
-edit(Tag, Tree, Op) ->
- case catch edit1(Tag, Tree, Op) of
- error ->
- docb_util:message(error, "Cannot do ~p to ~w", [Op, Tag]),
- Tree;
- Other ->
- Other
- end.
-
-edit1(Tag, {Tag, _O, _A}, _Op) ->
- throw(error);
-edit1(Tag, {Tag1, O, A}, Op) ->
- {Tag1, O, edit1_list(Tag, A, Op)};
-edit1(_, _, _) ->
- throw(error).
-
-edit1_list(Tag, [{pcdata, Str}|T], Op) ->
- [{pcdata, Str}|edit1_list(Tag, T, Op)];
-edit1_list(Tag, [{Tag, O, A}|T], {insert_after, Obj}) ->
- [{Tag, O, A}, Obj|T];
-edit1_list(Tag, [H|T], Op) ->
- [H|edit1_list(Tag, T, Op)];
-edit1_list(_Tag, [], _Op) ->
- [].
-
-%%______________________________________________________________________
-
-%% transform(From, To, Opts, File, Tree) -> void()
-%% Actual transformation of tree structure to desired format.
-transform(From, To, Opts, File, Tree) ->
- Filter = if
- To =:= html; To =:= kwic ->
- list_to_atom("docb_tr_" ++ atom_to_list(From) ++
- [$2|atom_to_list(To)]);
- true ->
- list_to_atom("sgml_tr_" ++ atom_to_list(From) ++
- [$2|atom_to_list(To)])
- end,
-
- case catch Filter:transform(File, Tree, Opts) of
-
- %% R5C
- {'EXIT', {undef, [{Filter, transform, [File, Tree, Opts]}|_]}}->
- %% No transformation defined
- finish_transform(Tree, File, Opts, Filter);
-
- {'EXIT', {undef, {Filter, transform, [File, Tree, Opts]}}} ->
- %% No transformation defined
- finish_transform(Tree, File, Opts, Filter);
-
- {'EXIT', What} ->
- docb_util:message(error,
- "Transformation trouble in ~P", [What, 9]),
- transformation_error;
-
- {error, Reason} ->
- docb_util:message(error, Reason),
- transformation_error;
-
- {Tree1, Opts1} ->
- %% transformation returning both new parse and new options
- finish_transform(Tree1, File, Opts1, Filter);
-
- Tree1 ->
- %% transformation returning only new parse
- finish_transform(Tree1, File, Opts, Filter)
- end.
-
-finish_transform(Tree, File, Opts, Filter) ->
- {Str, NewOpts} = pp(Tree, [], 1, Filter, Opts),
- Extension =
- case catch Filter:extension(NewOpts) of
- {'EXIT', _} ->
- Filter:extension();
- Others ->
- Others
- end,
- {ok, Out} =
- file:open(docb_util:outfile(File, Extension, NewOpts), [write]),
- put_chars(Out, Str),
- file:close(Out).
-
-put_chars(Out, Str) -> put_chars(Out, Str, 0).
-
-put_chars(Out, [$\n|Cs], _Pos) ->
- io:put_chars(Out, [$\n]),
- put_chars(Out, Cs, 0);
-
-put_chars(Out, [$\011|Cs], Pos) -> % tab
- TabbedPos = 8*((Pos div 8)+1),
- Nblanks = TabbedPos - Pos,
- io:put_chars(Out, lists:duplicate(Nblanks, $ )),
- put_chars(Out, Cs, Pos+Nblanks);
-
-put_chars(Out, [C|Cs], Pos) when is_integer(C) ->
- io:put_chars(Out, [C]),
- put_chars(Out, Cs, Pos+1);
-
-put_chars(Out, [L|Cs], Pos) when is_list(L) ->
- put_chars(Out, Cs, put_chars(Out, L, Pos));
-
-put_chars(_Out, [], Pos) ->
- Pos.
-
-pp({Tag, Optional, Args}, TagPath, Level, Filter, Opts) ->
- TagPath1 = [Tag|TagPath],
- Optional1 = reduce_optional(Optional),
-
- %% First try Filter:rule/3. It returns {Return, NewOpts}
- %% where Return is as from rule/2:
- Rule_3_result =
- case catch Filter:rule(TagPath1, {Level,Optional1,Args},Opts) of
- %% R5C
- {'EXIT', {undef, [{_, rule, _}|_]}} -> % No rule/3 defined
- failed;
-
- {'EXIT', {undef, {_, rule, _}}} -> % No rule/3 defined
- failed;
- %% R5C
- {'EXIT', {function_clause, [{_, rule, _}|_]}} -> % No MATCHING rule/3
- failed;
-
- {'EXIT', {function_clause, {_, rule, _}}} -> % No MATCHING rule/3
- failed;
-
- {'EXIT', What} ->
- docb_util:message(error,
- "Serious Error: ~P", [What, 9]);
- Others ->
- Others
- end,
- handle_rule_call_result({r3, Rule_3_result}, Filter, TagPath1, Tag,
- Level, Optional1, Args, Opts).
-
-handle_rule_call_result({r3, failed}, Filter, TagPath1, Tag, Level, Optional1,
- Args, Opts) ->
- %% Hmmm, try Filter:rule/2
- Rule_2_result = (catch Filter:rule(TagPath1, {Level, Optional1, Args})),
- handle_rule_call_result({r2, Rule_2_result}, Filter, TagPath1, Tag,
- Level, Optional1, Args, Opts);
-handle_rule_call_result({r3, {Result, NewOpts}}, Filter, TagPath1, Tag, Level,
- Optional1, Args, _Opts) ->
- handle_rule_call_result({r2, Result}, Filter, TagPath1, Tag, Level,
- Optional1, Args, NewOpts);
-handle_rule_call_result({_, {func, F}}, _Filter, _TagPath1, _Tag, _Level,
- _Optional1, Args, Opts) ->
- {F(Args), Opts};
-handle_rule_call_result({_, {'EXIT', Why}}, _Filter, TagPath1, _Tag, Level,
- Optional1, Args, Opts) ->
- report_error(TagPath1, Why, {Level, Optional1, Args}),
- {[], Opts};
-handle_rule_call_result({_, {drop, Str}}, _Filter, _TagPath1, _Tag, _Level,
- _Optional1, _Args, Opts) ->
- {[Str], Opts};
-handle_rule_call_result({_, {newargs, NewArgs}}, Filter, TagPath1, _Tag, _Level,
- _Optional1, _Args, Opts) ->
- {List, NewOpts} = pp_list(NewArgs, TagPath1, 1, Filter, Opts),
- {[List], NewOpts};
-handle_rule_call_result({_, {newargs, Before, NewArgs, After}}, Filter, TagPath1, _Tag, _Level,
- _Optional1, _Args, Opts) ->
- {List, NewOpts} = pp_list(NewArgs, TagPath1, 1, Filter, Opts),
- {[Before, List, After], NewOpts};
-handle_rule_call_result({_, {Before, After}}, Filter, TagPath1, _Tag, _Level,
- _Optional1, Args, Opts) when is_list(Before) ->
- {List, NewOpts} = pp_list(Args, TagPath1, 1, Filter, Opts),
- {[Before, List, After], NewOpts}.
-
-pp_list([H|T], TagPath, Level, Rules, Opts) ->
- {Hpp, Hopts} = pp(H, TagPath, Level, Rules, Opts),
- {Tpp, Tops} = pp_list(T, TagPath, Level + 1, Rules, Hopts),
- {[Hpp|Tpp], Tops};
-pp_list([], _, _, _, Opts) ->
- {[], Opts}.
-
-reduce_optional([{_, _, H}|T]) -> [H|reduce_optional(T)];
-reduce_optional([]) -> [].
-
-report_error(Arg1, Cause, Arg2) ->
- [Tag|_] = Arg1,
- docb_util:message(error,
- "Formatting trouble in ~p: ~p", [Tag, Cause]),
- docb_util:message(error, "Failure in rule(~p, ~p)", [Arg1, Arg2]).
-
-%%----------------------------------------------------------------------
-
-%% include_file(File, Tag) -> {ok, String} | error
-include_file(File, Tag) ->
- include(File, "%S" ++ Tag, "%E" ++ Tag).
-
-%% include(File, StartTag, StopTag) -> {ok, String} | error
-include(File, "", "") ->
- case file:open(File, [read]) of
- {ok, Fd} ->
- String = include_all(Fd),
- file:close(Fd),
- {ok, String};
- _ ->
- docb_util:message(error,
- "Include file ~s not found", [File]),
- error
- end;
-include(File, StartTag, StopTag) ->
- case file:open(File, [read]) of
- {ok, Fd} ->
- String = extract(File, Fd, StartTag, StopTag, searching),
- file:close(Fd),
- {ok, lists:flatten(String)};
- _ ->
- docb_util:message(error,
- "Include file ~s not found", [File]),
- error
- end.
-
-include_all(Fd) ->
- case io:get_line(Fd, '') of
- eof ->
- [];
- ListOfChars ->
- ListOfChars ++ include_all(Fd)
- end.
-
-extract(File, Fd, StartTag, StopTag, State) ->
- Line=io:get_line(Fd, ''),
- extract(File, Fd, StartTag, StopTag, State, Line).
-
-extract(File, _, _, _, _, eof) ->
- docb_util:message(error,
- "Premature end of file in include file ~p",
- [File]),
- [];
-extract(File, Fd, StartTag, StopTag, searching, Line) ->
- case regexp:match(Line, "^" ++ StartTag) of
- {match, _Start, _Length} ->
- extract(File, Fd, StartTag, StopTag, copying);
- nomatch ->
- extract(File, Fd, StartTag, StopTag, searching);
- {error, _Error} ->
- docb_util:message(error, "Bad syntax in ~s", [File]),
- []
- end;
-extract(File, Fd, StartTag, StopTag, copying, Line) ->
- case regexp:match(Line, "^" ++ StopTag) of
- {match, _Start, _Length} ->
- [];
- nomatch ->
- [Line|extract(File, Fd, StartTag, StopTag, copying)];
- {error, _Error} ->
- docb_util:message(error, "Bad syntax in ~s", [File]),
- []
- end.
-
-%%----------------------------------------------------------------------
-
-eval_str(Str) ->
- case lib:eval_str(Str) of
- {error, Report} ->
- docb_util:message(error,
- "ErlEval failed: ~s (~s)", [Str, Report]);
- {ok, S} ->
- io_lib:format("~p~n", [S])
- end.
diff --git a/lib/docbuilder/src/docb_pretty_format.erl b/lib/docbuilder/src/docb_pretty_format.erl
deleted file mode 100644
index 25dcd8987b..0000000000
--- a/lib/docbuilder/src/docb_pretty_format.erl
+++ /dev/null
@@ -1,177 +0,0 @@
-%% ``The contents of this file are subject to the Erlang Public License,
-%% Version 1.1, (the "License"); you may not use this file except in
-%% compliance with the License. You should have received a copy of the
-%% Erlang Public License along with this software. If not, it can be
-%% retrieved via the world wide web at http://www.erlang.org/.
-%%
-%% Software distributed under the License is distributed on an "AS IS"
-%% basis, WITHOUT WARRANTY OF ANY KIND, either expressed or implied. See
-%% the License for the specific language governing rights and limitations
-%% under the License.
-%%
-%% The Initial Developer of the Original Code is Ericsson Utvecklings AB.
-%% Portions created by Ericsson are Copyright 1999-2000, Ericsson
-%% Utvecklings AB. All Rights Reserved.''
-%%
-%% $Id$
-%%
--module(docb_pretty_format).
-
--export([term/1]).
-
-%% pretty_format:term(Term) -> PNF list of characters
-%%
-%% Note: this is usually used in expressions like:
-%% io:format('~s\n', [pretty_format:term(Term)]).
-%%
-%% Uses the following simple heuristics:
-%%
-%% 1) Simple tuples are printed across the page.
-%% (Simple means *all* the elements are "flat")
-%% 2) The complex tuple {Arg1, Arg2, Arg3,....} is printed thus:
-%% {Arg1,
-%% Arg2,
-%% Arg3,
-%% ...}
-%% 3) Lists are treated as for tuples.
-%% 4) Lists of printable characters are treated as strings.
-%%
-%% This method seems to work reasonable well for {Tag, ...} type
-%% data structures.
-term(Term) ->
- element(2, term(Term, 0)).
-
-%% pretty_format:term(Term, Indent} -> {Indent', Chars}
-%% Format <Term> -- use <Indent> to indent the *next* line.
-%% Note: Indent' is a new indentaion level (sometimes printing <Term>
-%% the next line to need an "extra" indent!).
-term([], Indent) ->
- {Indent, [$[,$]]};
-term(L, Indent) when is_list(L) ->
- case is_string(L) of
- true ->
- {Indent, io_lib:write_string(L)};
- false ->
- case complex_list(L) of
- true ->
- write_complex_list(L, Indent);
- false ->
- write_simple_list(L, Indent)
- end
- end;
-term(T, Indent) when is_tuple(T) ->
- case complex_tuple(T) of
- true ->
- write_complex_tuple(T, Indent);
- false ->
- write_simple_tuple(T, Indent)
- end;
-term(A, Indent) ->
- {Indent, io_lib:write(A)}.
-
-%% write_simple_list([H|T], Indent) -> {Indent', Chars}
-write_simple_list([H|T], Indent) ->
- {_, S1} = term(H, Indent),
- {_, S2} = write_simple_list_tail(T, Indent),
- {Indent, [$[,S1|S2]}.
-
-write_simple_list_tail([H|T], Indent) ->
- {_, S1} = term(H, Indent),
- {_, S2} = write_simple_list_tail(T, Indent),
- {Indent, [$,,S1| S2]};
-write_simple_list_tail([], Indent) ->
- {Indent, "]"};
-write_simple_list_tail(Other, Indent) ->
- {_, S} = term(Other, Indent),
- {Indent, [$|,S,$]]}.
-
-%% write_complex_list([H|T], Indent) -> {Indent', Chars}
-write_complex_list([H|T], Indent) ->
- {I1, S1} = term(H, Indent+1),
- {_, S2} = write_complex_list_tail(T, I1),
- {Indent, [$[,S1|S2]}.
-
-write_complex_list_tail([H|T], Indent) ->
- {I1, S1} = term(H, Indent),
- {_, S2} = write_complex_list_tail(T, I1),
- {Indent, [$,,nl_indent(Indent),S1,S2]};
-write_complex_list_tail([], Indent) ->
- {Indent, "]"};
-write_complex_list_tail(Other, Indent) ->
- {_, S} = term(Other, Indent),
- {Indent, [$|,S,$]]}.
-
-%% complex_list(List) -> true | false
-%% Returns true if the list is complex otherwise false.
-complex_list([]) ->
- false;
-complex_list([H|T]) when is_list(H) ->
- case is_string(H) of
- true ->
- complex_list(T);
- false ->
- true
- end;
-complex_list([H|_]) when is_tuple(H) -> true;
-complex_list(_) -> false.
-
-%% complex_tuple(Tuple) -> true | false
-%% Returns true if the tuple is complex otherwise false.
-complex_tuple(T) ->
- complex_list(tuple_to_list(T)).
-
-%% write_simple_tuple(Tuple, Indent} -> {Indent', Chars}
-write_simple_tuple({}, Indent) ->
- {Indent, "{}"};
-write_simple_tuple(Tuple, Indent) ->
- {_, S} = write_simple_tuple_args(tuple_to_list(Tuple), Indent),
- {Indent, [${, S, $}]}.
-
-write_simple_tuple_args([X], Indent) ->
- term(X, Indent);
-write_simple_tuple_args([H|T], Indent) ->
- {_, SH} = term(H, Indent),
- {_, ST} = write_simple_tuple_args(T, Indent),
- {Indent, [SH, $,, ST]}.
-
-%% write_complex_tuple(Tuple, Indent} -> {Indent', Chars}
-write_complex_tuple(Tuple, Indent) ->
- [H|T] = tuple_to_list(Tuple),
- {I1, SH} = term(H, Indent+2),
- {_, ST} = write_complex_tuple_args(T, I1),
- {Indent, [${, SH, ST, $}]}.
-
-write_complex_tuple_args([X], Indent) ->
- {_, S} = term(X, Indent),
- {Indent, [$,, nl_indent(Indent), S]};
-write_complex_tuple_args([H|T], Indent) ->
- {I1, SH} = term(H, Indent),
- {_, ST} = write_complex_tuple_args(T, I1),
- {Indent, [$,, nl_indent(Indent) , SH, ST]};
-write_complex_tuple_args([], Indent) ->
- {Indent, []}.
-
-%% utilities
-
-nl_indent(I) when I >= 0 ->
- ["\n"|indent(I)];
-nl_indent(_I) ->
- [$ ].
-
-indent(I) when I >= 8 ->
- [$\t|indent(I-8)];
-indent(I) when I > 0 ->
- [$ |indent(I-1)];
-indent(_) ->
- [].
-
-is_string([9|T]) ->
- is_string(T);
-is_string([10|T]) ->
- is_string(T);
-is_string([H|T]) when H >31, H < 127 ->
- is_string(T);
-is_string([]) ->
- true;
-is_string(_) ->
- false.
diff --git a/lib/docbuilder/src/docb_tr_application2html.erl b/lib/docbuilder/src/docb_tr_application2html.erl
deleted file mode 100644
index d8cb214d0a..0000000000
--- a/lib/docbuilder/src/docb_tr_application2html.erl
+++ /dev/null
@@ -1,286 +0,0 @@
-%% ``The contents of this file are subject to the Erlang Public License,
-%% Version 1.1, (the "License"); you may not use this file except in
-%% compliance with the License. You should have received a copy of the
-%% Erlang Public License along with this software. If not, it can be
-%% retrieved via the world wide web at http://www.erlang.org/.
-%%
-%% Software distributed under the License is distributed on an "AS IS"
-%% basis, WITHOUT WARRANTY OF ANY KIND, either expressed or implied. See
-%% the License for the specific language governing rights and limitations
-%% under the License.
-%%
-%% The Initial Developer of the Original Code is Ericsson Utvecklings AB.
-%% Portions created by Ericsson are Copyright 1999-2000, Ericsson
-%% Utvecklings AB. All Rights Reserved.''
-%%
-%% $Id$
-%%
--module(docb_tr_application2html).
-
--export([extension/0, transform/3, rule/2, rule/3]).
-
-extension() ->
- ".html".
-
-transform(File, {application, _Attrs, [Header|Rest]}, Opts0) ->
-
- %% Extract header data
- Title = docb_html_util:extract_header_data(title, Header),
-
- case docb_util:an_option(kwicindex_only, Opts0) of
- false ->
-
- %% Create the framing HTML document
- OutFile = docb_util:outfile(File++"_frame", ".html", Opts0),
- case file:open(OutFile, [write]) of
- {ok, Fd} ->
- io:format(Fd,
-"<!DOCTYPE HTML PUBLIC \"-//W3C//DTD XHTML 1.0 Frameset//EN\"
-\"http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd\">
-<!-- This document was generated using DocBuilder-" ++ docb_util:version() ++ " -->
-<html>
-<head>
- <title>~s</title>
- " ++ docb_util:html_snippet(head, Opts0) ++ "
-</head>
-<frameset cols=\"150, *\">
- <frame src=\"~s\" name=\"toc\">
- <frame src=\"~s\" name=\"document\">
- <noframes>
- <body bgcolor=\"#FFFFFF\" text=\"#000000\" link=\"#0000FF\"
- vlink=\"#FF00FF\" alink=\"#FF0000\">
- <p>This documentation requires a browser that can handle frames</p>
- </body>
- </noframes>
-</frameset>
-</html>
-",
- [Title,
- File++".html", File++"_first.html"]),
- file:close(Fd)
- end,
-
- %% Create the front HTML document
- docb_main:transform(first, html, Opts0, File ++ "_first",
- {first, [], [Header|Rest]});
-
- true ->
- ok
- end,
-
- %% Extract files to include
- Files = case Rest of
- [{description, _, _}|NewRest] ->
- lists:map(fun({include, [{_, _, F}], _}) ->filename:rootname(F) end,
- NewRest);
- [{include, _, _}|_NewRest] ->
- lists:map(fun({include, [{_, _, F}], _}) -> filename:rootname(F) end,
- Rest)
- end,
-
- %% Concat all reference manuals into a *big* parse tree
- ConcatTree = concat_files(Files, Opts0),
-
- %% Create the kwic index src file to be put in outdir
- docb_main:transform(refs, kwic, Opts0, File, {refs,[],ConcatTree}),
-
- case docb_util:an_option(kwicindex_only, Opts0) of
- false ->
-
- %% Create an index
- docb_main:transform(index, html, Opts0, File ++ "_index",
- {index, [], [Header|ConcatTree]}),
- %% Create a cite dictionary
- docb_main:transform(cite, html, Opts0, File ++ "_cite",
- {cite, [], [Header|ConcatTree]}),
-
- %% Create a term dictionary
- docb_main:transform(term, html, Opts0, File ++ "_term",
- {term, [], [Header|ConcatTree]}),
-
- %% Transform each reference page
- case docb_util:an_option(framework_only, Opts0) of
- true ->
- ok;
- false ->
- transform_refs(Files,
- [dict,{part_application,File}|Opts0])
- end;
- true ->
- ok
- end,
-
- %% Find all fascicules to be put in the top menu of the table of
- %% contents
- Ext = docb_util:lookup_option(src_type, Opts0),
- Opts2 =
- case filelib:is_regular("fascicules"++Ext) of
- true ->
- case docb_main:parse1("fascicules", Opts0) of
- {ok, Parse} ->
- FascData = get_fasc_data(Parse),
- case lists:keyfind(File, 1, FascData) of
- {_, _, "YES", _} ->
- OrigFile =
- docb_util:outfile(File++"_frame",
- ".html", Opts0),
- EntryFile =
- docb_util:outfile("index",
- ".html",Opts0),
- docb_util:message(info,
- "Copying ~s to ~s",
- [OrigFile,EntryFile]),
- file:copy(OrigFile, EntryFile);
- _ ->
- ok
- end,
- [{fascdata, FascData}| Opts0];
- errors ->
- %% Do not bother
- docb_util:message(
- warning,
- "fascicules~s could not be parsed,"
- " no index.html created",
- [Ext]),
- Opts0
- end;
- false ->
- %% do not bother
- docb_util:message(warning,
- "fascicules~s not found, "
- "no index.html created",
- [Ext]),
- Opts0
- end,
-
- %% Create ToC parse tree
- {{toc, [{"FILE", "CDATA", File}], [Header|make_toc(ConcatTree)]},
- Opts2}.
-
-concat_files(Files, Opts) ->
- concat_files(Files, [], Opts).
-
-concat_files([File|Rest], Body, Opts) ->
- case docb_main:parse1(File, Opts) of
- {ok, Parse} ->
- NewParse=expand([Parse], File),
- %% Remove the reference manual header
- [{Ref, [], [_Hdr| NewBody]}] = NewParse,
- RefParse = [{Ref, [], NewBody}],
- Body ++ concat_files(Rest, RefParse, Opts);
- errors ->
- errors
- end;
-concat_files([], Body, _Opts) ->
- Body.
-
-expand([], _) ->
- [];
-expand([{pcdata, Attrs, More}|Rest], File) ->
- [{pcdata, Attrs, More}|expand(Rest, File)];
-expand([{name, Attrs, More}|Rest], File) ->
- [{name, [{"FILE", "CDATA", File}|Attrs], More}|expand(Rest, File)];
-expand([{module, Attrs, More}|Rest], File) ->
- [{module, [{"FILE", "CDATA", File}|Attrs], More}|expand(Rest,File)];
-expand([{file, Attrs, More}|Rest], File) ->
- [{file, [{"FILE", "CDATA", File}|Attrs], More}|expand(Rest, File)];
-expand([{app, Attrs, More}|Rest], File) ->
- [{app, [{"FILE", "CDATA", File}|Attrs], More}|expand(Rest, File)];
-expand([{lib, Attrs, More}|Rest], File) ->
- [{lib, [{"FILE", "CDATA", File}|Attrs], More}|expand(Rest, File)];
-expand([{com, Attrs, More}|Rest], File) ->
- [{com, [{"FILE", "CDATA", File}|Attrs], More}|expand(Rest, File)];
-expand([{Tag, Attrs, More}|Rest], File) ->
- [{Tag, Attrs, expand(More, File)}|expand(Rest, File)].
-
-transform_refs([], _) ->
- ok;
-transform_refs([File|Rest], Opts) ->
- Ext = docb_util:lookup_option(src_type, Opts),
- docb_util:message(info, "Processing \"~s~s\"", [File, Ext]),
- docb_main:process(File, Opts),
- transform_refs(Rest, Opts).
-
-make_toc([]) ->
- [];
-make_toc([{pcdata, _Attrs, _More}|Rest]) ->
- make_toc(Rest);
-make_toc([{module, Attrs, More}|Rest]) ->
- [{module, Attrs, More}|make_toc(Rest)];
-make_toc([{file, Attrs, More}|Rest]) ->
- [{file, Attrs, More}|make_toc(Rest)];
-make_toc([{app, Attrs, More}|Rest]) ->
- [{app, Attrs, More}|make_toc(Rest)];
-make_toc([{lib, Attrs, More}|Rest]) ->
- [{lib, Attrs, More}|make_toc(Rest)];
-make_toc([{com, Attrs, More}|Rest]) ->
- [{com, Attrs, More}|make_toc(Rest)];
-make_toc([{_Tag, _Attrs, More}|Rest]) ->
- make_toc(More) ++ make_toc(Rest).
-
-rule([module|_], {_, [File], _}) ->
- {"<small><a target=\"document\" href=\"" ++
- docb_html_util:make_anchor_href(File) ++ "\">",
- "</a></small><br/>\n"};
-
-rule([file|_], {_, [File], _}) ->
- {"<small><a target=\"document\" href=\"" ++
- docb_html_util:make_anchor_href(File) ++ "\">",
- "</a></small><br/>\n"};
-
-rule([app|_], {_, [File], _}) ->
- {"<small><a target=\"document\" href=\"" ++
- docb_html_util:make_anchor_href(File) ++ "\">",
- "</a></small><br/>\n"};
-
-rule([lib|_], {_, [File], _}) ->
- {"<small><a target=\"document\" href=\"" ++
- docb_html_util:make_anchor_href(File) ++ "\">",
- "</a></small><br/>\n"};
-
-rule([com|_], {_, [File], _}) ->
- {"<small><a target=\"document\" href=\"" ++
- docb_html_util:make_anchor_href(File) ++ "\">",
- "</a></small><br/>\n"};
-
-rule([pcdata|_], {_, _, Data}) ->
- {drop, docb_html_util:pcdata_to_html(Data)};
-
-rule(_, _) ->
- {drop, ""}.
-
-rule([toc|_], {_Depth, [File], [Header|_]}, Opts) ->
- case docb_util:lookup_option(fascdata, Opts) of
- false ->
- {{docb_html_layout:application_toc_top(
- docb_html_util:all_header_data(Header),
- File, Opts),
- docb_html_layout:part_toc_bot()}, Opts};
- FascData ->
- HRefTexts =
- lists:map(
- fun({_File, HRef, _Entry, PCText}) ->
- {HRef, docb_html_util:pcdata_to_html(PCText)}
- end,
- FascData),
- {{docb_html_layout:application_toc_top(
- docb_html_util:all_header_data(Header),
- File, Opts, HRefTexts) ++ "\n",
- docb_html_layout:part_toc_bot()}, Opts}
- end.
-
-%% Returns: [{File, HRef, Entry, Text}].
-get_fasc_data({fascicules, _, Fascs}) ->
- lists:map(
- fun({fascicule, Atts, Trees}) ->
- AVals = get_avals(Atts),
- PCText = get_pc_text(Trees),
- list_to_tuple(lists:append([AVals, [PCText]]))
- end,
- Fascs).
-
-get_avals(Atts) ->
- [element(3, Tuple) || Tuple <- Atts].
-
-get_pc_text([{pcdata, _, Text}]) ->
- Text.
diff --git a/lib/docbuilder/src/docb_tr_appref2html.erl b/lib/docbuilder/src/docb_tr_appref2html.erl
deleted file mode 100644
index 6b4cc0f815..0000000000
--- a/lib/docbuilder/src/docb_tr_appref2html.erl
+++ /dev/null
@@ -1,48 +0,0 @@
-%% ``The contents of this file are subject to the Erlang Public License,
-%% Version 1.1, (the "License"); you may not use this file except in
-%% compliance with the License. You should have received a copy of the
-%% Erlang Public License along with this software. If not, it can be
-%% retrieved via the world wide web at http://www.erlang.org/.
-%%
-%% Software distributed under the License is distributed on an "AS IS"
-%% basis, WITHOUT WARRANTY OF ANY KIND, either expressed or implied. See
-%% the License for the specific language governing rights and limitations
-%% under the License.
-%%
-%% The Initial Developer of the Original Code is Ericsson Utvecklings AB.
-%% Portions created by Ericsson are Copyright 1999-2000, Ericsson
-%% Utvecklings AB. All Rights Reserved.''
-%%
-%% $Id$
-%%
--module(docb_tr_appref2html).
-
--export([extension/0, transform/3, rule/2, rule/3]).
-
-extension() ->
- ".html".
-
-%% Transform the parse tree. Header data is stored in an extra
-%% argument to make life easier later on.
-transform(_File, {appref,_,[Header|Rest]}, _Opts) ->
- Data = [{[], [], docb_html_util:all_header_data(Header)}],
- {appref, Data, [{header,[],[]}|Rest]}.
-
-rule([header|_],_) ->
- {drop, ""};
-
-rule([app|_],_) ->
- {"\n<h3>APPLICATION</h3>\n<div class=\"REFBODY\">\n","\n</div>\n"};
-
-rule([appsummary|_],_) ->
- {"\n<h3>APPLICATION SUMMARY</h3>\n<div class=\"REFBODY\">\n","\n</div>\n"};
-
-rule(TagHistory, TagBody) ->
- docb_html_ref:rule(TagHistory,TagBody).
-
-rule([appref|_], {_,[Data],_}, Opts) ->
- {{docb_html_layout:ref_top(Data, Opts),
- docb_html_layout:ref_bot(Opts)}, Opts};
-
-rule(TagHistory, TagBody, Opts) ->
- docb_html_ref:rule(TagHistory, TagBody, Opts).
diff --git a/lib/docbuilder/src/docb_tr_chapter2html.erl b/lib/docbuilder/src/docb_tr_chapter2html.erl
deleted file mode 100644
index 185cdc7cc3..0000000000
--- a/lib/docbuilder/src/docb_tr_chapter2html.erl
+++ /dev/null
@@ -1,59 +0,0 @@
-%% ``The contents of this file are subject to the Erlang Public License,
-%% Version 1.1, (the "License"); you may not use this file except in
-%% compliance with the License. You should have received a copy of the
-%% Erlang Public License along with this software. If not, it can be
-%% retrieved via the world wide web at http://www.erlang.org/.
-%%
-%% Software distributed under the License is distributed on an "AS IS"
-%% basis, WITHOUT WARRANTY OF ANY KIND, either expressed or implied. See
-%% the License for the specific language governing rights and limitations
-%% under the License.
-%%
-%% The Initial Developer of the Original Code is Ericsson Utvecklings AB.
-%% Portions created by Ericsson are Copyright 1999-2000, Ericsson
-%% Utvecklings AB. All Rights Reserved.''
-%%
-%% $Id$
-%%
--module(docb_tr_chapter2html).
-
--export([extension/0, transform/3, rule/2, rule/3]).
-
-extension() ->
- ".html".
-
-transform(File, {chapter,_,[Header|Rest]}, Opts) ->
- Data = [{[], [], docb_html_util:all_header_data(Header)}],
- Tree = {chapter, Data, [{header,[],[]}|Rest]},
- ChapterLevel =
- case docb_util:lookup_option(number, Opts) of
- false -> none;
- Value -> Value
- end,
- docb_html_util:number(Tree, ChapterLevel, File).
-
-rule([header|_], _) ->
- {drop, ""};
-
-rule([toc|_], {_,_,ToC}) ->
- {drop,
- "\n<h3>Table of Contents</h3>\n" ++
- docb_html_util:format_toc(ToC) ++ "\n"};
-
-rule([section|_], _) ->
- {"", ""};
-
-rule([title|Rest], {_,[Number,_File], [{pcdata,_,Title}]}) ->
- N = integer_to_list(docb_html_util:count_sections(Rest)+1),
- {drop,"\n<h" ++ N ++ ">" ++ Number ++ " " ++
- docb_html_util:pcdata_to_html(Title) ++ "</h" ++ N ++ ">\n"};
-
-rule(TagHistory, TagBody) ->
- docb_html:rule(TagHistory, TagBody).
-
-rule([chapter|_], {_,[Data],_}, Opts) ->
- {{docb_html_layout:chapter_top(Data, Opts),
- docb_html_layout:chapter_bot(Opts)}, Opts};
-
-rule(TagHistory, TagBody, Opts) ->
- docb_html:rule(TagHistory, TagBody, Opts).
diff --git a/lib/docbuilder/src/docb_tr_cite2html.erl b/lib/docbuilder/src/docb_tr_cite2html.erl
deleted file mode 100644
index 77f1c4e636..0000000000
--- a/lib/docbuilder/src/docb_tr_cite2html.erl
+++ /dev/null
@@ -1,134 +0,0 @@
-%% ``The contents of this file are subject to the Erlang Public License,
-%% Version 1.1, (the "License"); you may not use this file except in
-%% compliance with the License. You should have received a copy of the
-%% Erlang Public License along with this software. If not, it can be
-%% retrieved via the world wide web at http://www.erlang.org/.
-%%
-%% Software distributed under the License is distributed on an "AS IS"
-%% basis, WITHOUT WARRANTY OF ANY KIND, either expressed or implied. See
-%% the License for the specific language governing rights and limitations
-%% under the License.
-%%
-%% The Initial Developer of the Original Code is Ericsson Utvecklings AB.
-%% Portions created by Ericsson are Copyright 1999-2000, Ericsson
-%% Utvecklings AB. All Rights Reserved.''
-%%
-%% $Id$
-%%
--module(docb_tr_cite2html).
-
--export([extension/0, transform/3, rule/2, rule/3]).
-
-extension() ->
- ".html".
-
-transform(_File, Tree, Opts) ->
- purge(Tree, Opts).
-
-purge({Tag, Attrs, [Header|Body]}, Opts) ->
- CiteList = case docb_util:lookup_option({defs,cite}, Opts) of
- false -> [];
- Value -> Value
- end,
- B1 = purge_body(Body, CiteList),
- B2 = lists:ukeysort(2, B1),
- {Tag, Attrs, [Header|B2]}.
-
-purge_body([], _) ->
- [];
-purge_body([{pcdata,_Attrs,_More}|Rest], CiteList) ->
- purge_body(Rest, CiteList);
-purge_body([{cite,[{"ID","CDATA",ID}],More}|Rest], CiteList) ->
- case lists:keyfind(ID, 1, CiteList) of
- false ->
- [{cite, [{"NAME","CDATA",ID}, {"ID","CDATA",ID}], More}|
- purge_body(Rest, CiteList)];
- {ID, Name, _Description, _Responsible} ->
- [{cite, [{"NAME","CDATA",Name}, {"ID","CDATA",ID}], More}|
- purge_body(Rest, CiteList)];
- {ID, Name, _Description} ->
- [{cite, [{"NAME","CDATA",Name}, {"ID","CDATA",ID}], More}|
- purge_body(Rest, CiteList)]
- end;
-purge_body([{_Tag,_Attrs,More}|Rest], CiteList) ->
- purge_body(More, CiteList) ++ purge_body(Rest, CiteList).
-
-rule([header|_], _) ->
- {drop, ""};
-rule(_, _) ->
- {drop, ""}.
-
-rule([cite|_], {_,[],[Header]}, Opts) ->
- HeaderData = docb_html_util:all_header_data(Header),
- {{docb_html_layout:chapter_top(HeaderData, Opts) ++
- "\n<center><h1>Bibliography</h1></center>\n",
- docb_html_layout:chapter_bot(Opts)}, Opts};
-
-rule([cite|_], {_,[],[Header|_]}, Opts) ->
- HeaderData = docb_html_util:all_header_data(Header),
- {{docb_html_layout:chapter_top(HeaderData, Opts) ++
- "\n<center><h1>Bibliography</h1></center>\n<dl>\n",
- "\n</dl>\n" ++ docb_html_layout:chapter_bot(Opts)}, Opts};
-
-rule([cite|_], {_,[Data],_}, Opts) ->
- {{docb_html_layout:chapter_top(Data, Opts) ++
- "\n<center><h1>Bibliography</h1></center>\n<dl>\n",
- "\n</dl>\n" ++ docb_html_layout:chapter_bot(Opts)}, Opts};
-
-rule([cite|T], {A, B, [{citedef,C,
- [{ctitle, [], [{pcdata,[],CTitle}]},
- {cauthor, [], [{pcdata,[],CAuthor}]},
- {chowpublished, [],
- [{pcdata,[],Chowpublished}]}]}]}, Opts) ->
- CiteDef = CTitle ++ " " ++ CAuthor ++ " " ++ Chowpublished,
- rule([cite|T], {A,B,[{citedef,C,[{pcdata,[],CiteDef}]}]}, Opts);
-
-rule([cite|_], {_,[Name,ID], [{citedef,[],[{pcdata,[],Def}]}]}, Opts) ->
- CiteList =
- case docb_util:lookup_option({defs,cite}, Opts) of
- false -> [];
- Value -> Value
- end,
- case lists:keyfind(ID, 1, CiteList) of
- false ->
- {{drop,"\n<dt><a name=\"" ++ ID ++ "\">" ++
- "<strong>" ++ ID ++ "</strong></a></dt>\n<dd>" ++
- docb_html_util:pcdata_to_html(Def) ++ "\n</dd>\n"}, Opts};
- {ID, Name, Description, _Responsible} ->
- docb_util:message(warning,
- "Global cite ~s overriding local", [ID]),
- {{drop,"\n<dt><a name=\"" ++ ID ++ "\">" ++
- "<strong>" ++ Name ++ "</strong></a></dt>\n<dd>" ++
- docb_html_util:pcdata_to_html(Description) ++ "\n</dd>\n"},
- Opts};
- {ID, Name, Description} ->
- docb_util:message(warning,
- "Global cite ~s overriding local", [ID]),
- {{drop,"\n<dt><a name=\"" ++ ID ++ "\">" ++
- "<strong>" ++ Name ++ "</strong></a></dt>\n<dd>" ++
- docb_html_util:pcdata_to_html(Description) ++ "\n</dd>\n"}, Opts}
- end;
-
-rule([cite|_], {_,[Name,ID],_}, Opts) ->
- CiteList =
- case docb_util:lookup_option({defs,cite}, Opts) of
- false -> [];
- Value -> Value
- end,
- case lists:keyfind(ID, 1, CiteList) of
- false ->
- docb_util:message(error,
- "The cite ~s has no definition", [ID]),
- {{drop,"\n<dt><a name=\"" ++ ID ++ "\">" ++
- "<strong>" ++ ID ++ "</strong></a></dt>\n<dd>" ++
- "??" ++ "\n</dd>\n"}, Opts};
- {ID, Name, Description, _Responsible} ->
- {{drop,"\n<dt><a name=\"" ++ ID ++ "\">" ++
- "<strong>" ++ Name ++ "</strong></a></dt>\n<dd>" ++
- docb_html_util:pcdata_to_html(Description) ++ "\n</dd>\n"},
- Opts};
- {ID, Name, Description} ->
- {{drop,"\n<dt><a name=\"" ++ ID ++ "\">" ++
- "<strong>" ++ Name ++ "</strong></a></dt>\n<dd>" ++
- docb_html_util:pcdata_to_html(Description) ++ "\n</dd>\n"}, Opts}
- end.
diff --git a/lib/docbuilder/src/docb_tr_comref2html.erl b/lib/docbuilder/src/docb_tr_comref2html.erl
deleted file mode 100644
index 25207dccb4..0000000000
--- a/lib/docbuilder/src/docb_tr_comref2html.erl
+++ /dev/null
@@ -1,46 +0,0 @@
-%% ``The contents of this file are subject to the Erlang Public License,
-%% Version 1.1, (the "License"); you may not use this file except in
-%% compliance with the License. You should have received a copy of the
-%% Erlang Public License along with this software. If not, it can be
-%% retrieved via the world wide web at http://www.erlang.org/.
-%%
-%% Software distributed under the License is distributed on an "AS IS"
-%% basis, WITHOUT WARRANTY OF ANY KIND, either expressed or implied. See
-%% the License for the specific language governing rights and limitations
-%% under the License.
-%%
-%% The Initial Developer of the Original Code is Ericsson Utvecklings AB.
-%% Portions created by Ericsson are Copyright 1999-2000, Ericsson
-%% Utvecklings AB. All Rights Reserved.''
-%%
-%% $Id$
-%%
--module(docb_tr_comref2html).
-
--export([extension/0, transform/3, rule/2, rule/3]).
-
-extension() ->
- ".html".
-
-transform(_File, {comref,_,[Header|Rest]}, _Opts) ->
- Data = [{[], [], docb_html_util:all_header_data(Header)}],
- {comref, Data, [{header,[],[]}|Rest]}.
-
-rule([header|_],_) ->
- {drop,""};
-
-rule([com|_],_) ->
- {"\n<h3>COMMAND</h3>\n<div class=\"REFBODY\">\n","\n</div>\n"};
-
-rule([comsummary|_],_) ->
- {"\n<h3>COMMAND SUMMARY</h3>\n<div class=\"REFBODY\">\n","\n</div>\n"};
-
-rule(TagHistory, TagBody) ->
- docb_html_ref:rule(TagHistory, TagBody).
-
-rule([comref|_], {_,[Data],_}, Opts) ->
- {{docb_html_layout:ref_top(Data, Opts),
- docb_html_layout:ref_bot(Opts)}, Opts};
-
-rule(TagHistory, TagBody, Opts) ->
- docb_html_ref:rule(TagHistory, TagBody, Opts).
diff --git a/lib/docbuilder/src/docb_tr_cref2html.erl b/lib/docbuilder/src/docb_tr_cref2html.erl
deleted file mode 100644
index 06748b8c57..0000000000
--- a/lib/docbuilder/src/docb_tr_cref2html.erl
+++ /dev/null
@@ -1,61 +0,0 @@
-%% ``The contents of this file are subject to the Erlang Public License,
-%% Version 1.1, (the "License"); you may not use this file except in
-%% compliance with the License. You should have received a copy of the
-%% Erlang Public License along with this software. If not, it can be
-%% retrieved via the world wide web at http://www.erlang.org/.
-%%
-%% Software distributed under the License is distributed on an "AS IS"
-%% basis, WITHOUT WARRANTY OF ANY KIND, either expressed or implied. See
-%% the License for the specific language governing rights and limitations
-%% under the License.
-%%
-%% The Initial Developer of the Original Code is Ericsson Utvecklings AB.
-%% Portions created by Ericsson are Copyright 1999-2000, Ericsson
-%% Utvecklings AB. All Rights Reserved.''
-%%
-%% $Id$
-%%
--module(docb_tr_cref2html).
-
--export([extension/0, transform/3, rule/2, rule/3]).
-
-extension() ->
- ".html".
-
-transform(_File, {cref,_,[Header|Rest]}, _Opts) ->
- Data = [{[], [], docb_html_util:all_header_data(Header)}],
- {cref, Data, [{header,[],[]}|Rest]}.
-
-rule([header|_],_) ->
- {drop, ""};
-
-rule([ret|_],_) ->
- {"",""};
-
-rule([nametext|_],_) ->
- {" ",""};
-
-rule([name|_], {_,_,[_Ret,{nametext,[],[{pcdata,[],Name}]}]}) ->
- FName = lists:flatten(docb_html_util:pcdata_to_html(Name)),
- TName = docb_util:trim(FName),
- CAnchor = docb_util:fknidx(TName, "/"),
- {"<A NAME=\"" ++ CAnchor ++ "\"><STRONG><CODE>",
- "</CODE></STRONG></A><BR>\n"};
-rule([name|T], {I,As,[Ret,{pcdata,[],Name}]}) -> % For SGML DTD
- rule([name|T], {I,As,[Ret,{nametext,[],[{pcdata,[],Name}]}]});
-
-rule([lib|_],_) ->
- {"\n<H3>C LIBRARY</H3>\n<DIV CLASS=REFBODY>\n","\n</DIV>\n"};
-
-rule([libsummary|_],_) ->
- {"\n<H3>C LIBRARY SUMMARY</H3>\n<DIV CLASS=REFBODY>\n","\n</DIV>\n"};
-
-rule(TagHistory, TagBody) ->
- docb_html_ref:rule(TagHistory, TagBody).
-
-rule([cref|_], {_,[Data],_}, Opts) ->
- {{docb_html_layout:ref_top(Data, Opts),
- docb_html_layout:ref_bot(Opts)}, Opts};
-
-rule(TagHistory, TagBody, Opts) ->
- docb_html_ref:rule(TagHistory, TagBody, Opts).
diff --git a/lib/docbuilder/src/docb_tr_erlref2html.erl b/lib/docbuilder/src/docb_tr_erlref2html.erl
deleted file mode 100644
index b264c46bce..0000000000
--- a/lib/docbuilder/src/docb_tr_erlref2html.erl
+++ /dev/null
@@ -1,46 +0,0 @@
-%% ``The contents of this file are subject to the Erlang Public License,
-%% Version 1.1, (the "License"); you may not use this file except in
-%% compliance with the License. You should have received a copy of the
-%% Erlang Public License along with this software. If not, it can be
-%% retrieved via the world wide web at http://www.erlang.org/.
-%%
-%% Software distributed under the License is distributed on an "AS IS"
-%% basis, WITHOUT WARRANTY OF ANY KIND, either expressed or implied. See
-%% the License for the specific language governing rights and limitations
-%% under the License.
-%%
-%% The Initial Developer of the Original Code is Ericsson Utvecklings AB.
-%% Portions created by Ericsson are Copyright 1999-2000, Ericsson
-%% Utvecklings AB. All Rights Reserved.''
-%%
-%% $Id$
-%%
--module(docb_tr_erlref2html).
-
--export([extension/0, transform/3, rule/2, rule/3]).
-
-extension() ->
- ".html".
-
-transform(_File, {erlref,_,[Header|Rest]}, _Opts) ->
- Data = [{[], [], docb_html_util:all_header_data(Header)}],
- {erlref, Data, [{header,[],[]}|Rest]}.
-
-rule([header|_],_) ->
- {drop, ""};
-
-rule([module|_],_) ->
- {"\n<h3>MODULE</h3>\n<div class=\"REFBODY\">\n","\n</div>\n"};
-
-rule([modulesummary|_],_) ->
- {"\n<h3>MODULE SUMMARY</h3>\n<div class=\"REFBODY\">\n","\n</div>\n"};
-
-rule(TagHistory, TagBody) ->
- docb_html_ref:rule(TagHistory, TagBody).
-
-rule([erlref|_], {_,[Data],_}, Opts) ->
- {{docb_html_layout:ref_top(Data, Opts),
- docb_html_layout:ref_bot(Opts)}, Opts};
-
-rule(TagHistory, TagBody, Opts) ->
- docb_html_ref:rule(TagHistory, TagBody, Opts).
diff --git a/lib/docbuilder/src/docb_tr_fileref2html.erl b/lib/docbuilder/src/docb_tr_fileref2html.erl
deleted file mode 100644
index 60280543a8..0000000000
--- a/lib/docbuilder/src/docb_tr_fileref2html.erl
+++ /dev/null
@@ -1,46 +0,0 @@
-%% ``The contents of this file are subject to the Erlang Public License,
-%% Version 1.1, (the "License"); you may not use this file except in
-%% compliance with the License. You should have received a copy of the
-%% Erlang Public License along with this software. If not, it can be
-%% retrieved via the world wide web at http://www.erlang.org/.
-%%
-%% Software distributed under the License is distributed on an "AS IS"
-%% basis, WITHOUT WARRANTY OF ANY KIND, either expressed or implied. See
-%% the License for the specific language governing rights and limitations
-%% under the License.
-%%
-%% The Initial Developer of the Original Code is Ericsson Utvecklings AB.
-%% Portions created by Ericsson are Copyright 1999-2000, Ericsson
-%% Utvecklings AB. All Rights Reserved.''
-%%
-%% $Id$
-%%
--module(docb_tr_fileref2html).
-
--export([extension/0, transform/3, rule/2, rule/3]).
-
-extension() ->
- ".html".
-
-transform(_File, {fileref,_,[Header|Rest]}, _Opts) ->
- Data = [{[], [], docb_html_util:all_header_data(Header)}],
- {fileref, Data, [{header,[],[]}|Rest]}.
-
-rule([header|_],_) ->
- {drop, ""};
-
-rule([file|_],_) ->
- {"\n<h3>FILE</h3>\n<div class=\"REFBODY\">\n","\n</div>\n"};
-
-rule([filesummary|_],_) ->
- {"\n<h3>FILE SUMMARY</h3>\n<div class=\"REFBODY\">\n","\n</div>\n"};
-
-rule(TagHistory, TagBody) ->
- docb_html_ref:rule(TagHistory, TagBody).
-
-rule([fileref|_], {_,[Data],_}, Opts) ->
- {{docb_html_layout:ref_top(Data, Opts),
- docb_html_layout:ref_bot(Opts)}, Opts};
-
-rule(TagHistory, TagBody, Opts) ->
- docb_html_ref:rule(TagHistory, TagBody, Opts).
diff --git a/lib/docbuilder/src/docb_tr_first2html.erl b/lib/docbuilder/src/docb_tr_first2html.erl
deleted file mode 100644
index e9ecbe73cb..0000000000
--- a/lib/docbuilder/src/docb_tr_first2html.erl
+++ /dev/null
@@ -1,46 +0,0 @@
-%% ``The contents of this file are subject to the Erlang Public License,
-%% Version 1.1, (the "License"); you may not use this file except in
-%% compliance with the License. You should have received a copy of the
-%% Erlang Public License along with this software. If not, it can be
-%% retrieved via the world wide web at http://www.erlang.org/.
-%%
-%% Software distributed under the License is distributed on an "AS IS"
-%% basis, WITHOUT WARRANTY OF ANY KIND, either expressed or implied. See
-%% the License for the specific language governing rights and limitations
-%% under the License.
-%%
-%% The Initial Developer of the Original Code is Ericsson Utvecklings AB.
-%% Portions created by Ericsson are Copyright 1999-2000, Ericsson
-%% Utvecklings AB. All Rights Reserved.''
-%%
-%% $Id$
-%%
--module(docb_tr_first2html).
-
--export([extension/0, transform/3, rule/2, rule/3]).
-
-extension() ->
- ".html".
-
-transform(_File, Tree, _Opts) ->
- Tree.
-
-rule([header|_], _) ->
- {drop, ""};
-
-rule([description|_], _) ->
- {"", ""};
-
-rule([include|_], _) ->
- {drop, ""};
-
-rule(TagHistory, TagBody) ->
- docb_html:rule(TagHistory, TagBody).
-
-rule([first|_], {_,[],[Header|_]}, Opts) ->
- HeaderData = docb_html_util:all_header_data(Header),
- {{docb_html_layout:first_top(HeaderData, Opts),
- docb_html_layout:first_bot(Opts)}, Opts};
-
-rule(TagHistory, TagBody, Opts) ->
- docb_html:rule(TagHistory, TagBody, Opts).
diff --git a/lib/docbuilder/src/docb_tr_index2html.erl b/lib/docbuilder/src/docb_tr_index2html.erl
deleted file mode 100644
index 312342add2..0000000000
--- a/lib/docbuilder/src/docb_tr_index2html.erl
+++ /dev/null
@@ -1,195 +0,0 @@
-%% ``The contents of this file are subject to the Erlang Public License,
-%% Version 1.1, (the "License"); you may not use this file except in
-%% compliance with the License. You should have received a copy of the
-%% Erlang Public License along with this software. If not, it can be
-%% retrieved via the world wide web at http://www.erlang.org/.
-%%
-%% Software distributed under the License is distributed on an "AS IS"
-%% basis, WITHOUT WARRANTY OF ANY KIND, either expressed or implied. See
-%% the License for the specific language governing rights and limitations
-%% under the License.
-%%
-%% The Initial Developer of the Original Code is Ericsson Utvecklings AB.
-%% Portions created by Ericsson are Copyright 1999-2000, Ericsson
-%% Utvecklings AB. All Rights Reserved.''
-%%
-%% $Id$
-%%
--module(docb_tr_index2html).
-
--export([extension/0, transform/3, rule/2]).
-
-extension() ->
- ".html".
-
-transform(_File0, {index, Attrs, [Header| Trees0]}, _Opts) ->
- Trees1 = prune_flat(Trees0, false),
- %%
- %% Now each element of Trees1 is a tree with tag `name' and
- %% attribute `File', and with one `pcdata' subtree containing the
- %% name `Func' of the function. We extract `File' and `Func', and
- %% create new trees.
- %%
- %% `File' is attribute CDATA (from an <include file=...>), and
- %% `Func' is PCDATA.
- %%
- FileFuncs =
- [{File, RefType, Func} ||
- {name, [{_, _, File}, {_, _, RefType}|_],
- [{pcdata, [], Func}]}
- <- Trees1],
- Trees2 = new_trees(FileFuncs),
- {index, Attrs, [Header| Trees2]}.
-
-%% Remove all elements except those with tag equal to `name'.
-%% Within `name' remove all elements except those equal to `pcdata'.
-%% Add attribute `filetype' to `name'.
-%%
-%% Refs: appref, comref, cref, erlref, fileref
-prune_flat([{appref, _Attrs, More}| Rest], _) ->
- RefType = appref,
- lists:append(prune_flat(More, RefType), prune_flat(Rest, RefType));
-prune_flat([{comref, _Attrs, More}| Rest], _) ->
- RefType = comref,
- lists:append(prune_flat(More, RefType), prune_flat(Rest, RefType));
-prune_flat([{cref, _Attrs, More}| Rest], _) ->
- RefType = cref,
- lists:append(prune_flat(More, RefType), prune_flat(Rest, RefType));
-prune_flat([{erlref, _Attrs, More}| Rest], _) ->
- RefType = erlref,
- lists:append(prune_flat(More, RefType), prune_flat(Rest, RefType));
-prune_flat([{fileref, _Attrs, More}| Rest], _) ->
- RefType = fileref,
- lists:append(prune_flat(More, RefType), prune_flat(Rest, RefType));
-prune_flat([{name, [Attr0|Attrs0], More}| Rest], RefType) ->
- Attrs = [Attr0, {"FILETYPE", "CDATA", RefType} |
- Attrs0],
- [{name, Attrs, keep_pcdata(More)}| prune_flat(Rest, RefType)];
-prune_flat([{pcdata, _, _}| Rest], RefType) -> % special case
- prune_flat(Rest, RefType);
-prune_flat([{_Tag, _Attrs, More}| Rest], RefType) ->
- lists:append(prune_flat(More, RefType), prune_flat(Rest, RefType));
-prune_flat([], _) ->
- [].
-
-keep_pcdata(Trees) ->
- [T || T = {pcdata, _, _} <- Trees].
-
-new_trees(FileFuncs) ->
- Files0 = [{File, RefType} || {File, RefType, _} <- FileFuncs],
- Files1 = lists:usort(Files0),
- FileEntries = [{reffile, File, RefType,
- [Fu || {Fi, _, Fu} <- FileFuncs, Fi == File]}
- || {File, RefType} <- Files1],
- FuncEntries = [{func, Func, RefType, [File]}
- || {File, RefType, Func} <- FileFuncs],
- Entries = FileEntries ++ FuncEntries,
- SortedEntries = sort_entries(Entries),
- %%
- %% We create a tree according to the following "dtd":
- %%
- %% element index (reffile | funcdef)*
- %% element reffile (funcdef2)*
- %% attribute reffile filename CDATA
- %% attribute reffile filetype CDATA
- %% element funcdef2 PCDATA
- %% attribute funcdef2 filename CDATA
- %% attribute funcdef2 filetype CDATA
- %% element funcdef PCDATA
- %% attribute funcdef filename CDATA
- %% attribute funcdef filetype CDATA
- %%
- %% For example:
- %% <index>
- %% <reffile filename="mymod" filetype="erlref">
- %% <funcdef2 filename="mymod" filetype="erlref">myfunca(A)</>
- %% <funcdef2 filename="mymod" filetype="erlref">myfuncb(A, B)</>
- %% </>
- %% <funcdef filename="mymod" filetype="erlref">myfunca(A)</>
- %% <funcdef filename="mymod" filetype="erlref">myfuncb(A, B)</>
- %% </>
- lists:flatmap(
- fun({reffile, File, RefType, Funcs}) ->
- %% A reffile tree
- [{reffile, [{"FILENAME", "CDATA", File},
- {"FILETYPE", "CDATA", RefType}],
- [{funcdef2, [{"FILENAME", "CDATA", File},
- {"FILETYPE", "CDATA", RefType}],
- [{pcdata, [], Func}]} || Func <- Funcs]}];
- ({func, Func, RefType, [File]}) ->
- %% A func tree
- [{funcdef, [{"FILENAME", "CDATA", File},
- {"FILETYPE", "CDATA", RefType}],
- [{pcdata, [], Func}]}]
- end, SortedEntries).
-
-%% Sorting of entries
-%%
-%% The sorting is based on how names of files and functions are
-%% presented (in a browser).
-%% Requires conversion to "function/2" etc.
-%%
-sort_entries(Entries) ->
- ExpEntries =
- lists:map(
- fun({reffile, File, RefType, Funcs}) ->
- HFile = filename_sort_order(File),
- HFuncs = [{funcdef_sort_order(Fu, RefType), Fu} || Fu <- Funcs],
- {reffile, HFile, File, RefType, lists:sort(HFuncs)};
- ({func, Func, RefType, [File]}) ->
- HFunc = funcdef_sort_order(Func, RefType),
- HFile = filename_sort_order(File),
- {func, HFunc, Func, RefType, [{HFile, File}]}
- end, Entries),
- SortedExpEntries = lists:keysort(2, ExpEntries),
- lists:map(
- fun({Tag, _HName, Name, RefType, Vals}) ->
- NVals = lists:map(fun({_HVal, Val}) -> Val end, Vals),
- {Tag, Name, RefType, NVals}
- end, SortedExpEntries).
-
-rule([index| _], _) ->
- {docb_html_layout:index_top("") ++
- "<dl>\n",
- "</dl>\n" ++ docb_html_layout:index_bot()};
-
-rule([header| _], _) ->
- {drop, ""};
-
-rule([reffile| _], {_, [File, _RefType|_], _}) ->
- CFile = docb_html_util:attribute_cdata_to_html(File),
- {"<dt><em>" ++ CFile ++ "</em></dt>\n", ""};
-
-rule([funcdef2| _], {_, [File, RefType|_], [{pcdata, [], FuncDef}]}) ->
- FFuncDef = lists:flatten(docb_html_util:pcdata_to_html(FuncDef)),
- TFuncDef = docb_util:trim(FFuncDef),
- ShortFuncDef = docb_html_util:make_funcdef_short(TFuncDef, RefType),
- HRef =
- docb_html_util:make_anchor_href_short(File, TFuncDef, RefType),
- {drop,
- "<dd><a href=\"" ++ HRef ++ "\"><code>" ++
- ShortFuncDef ++ "</code></a></dd>\n"};
-
-rule([funcdef| _], {_, [File, RefType|_], [{pcdata, [], FuncDef}]}) ->
- FFuncDef = lists:flatten(docb_html_util:pcdata_to_html(FuncDef)),
- TFuncDef = docb_util:trim(FFuncDef),
- ShortFuncDef = docb_html_util:make_funcdef_short(TFuncDef, RefType),
- HRef =
- docb_html_util:make_anchor_href_short(File, TFuncDef, RefType),
- CFile = docb_html_util:attribute_cdata_to_html(File),
- {drop,
- "<dt><code>" ++ ShortFuncDef ++ "</code></dt>\n"
- "<dd><a href=\"" ++ HRef ++ "\"><em>" ++
- CFile ++ "</em></a></dd>\n"};
-
-rule(_, _) ->
- {drop, ""}.
-
-filename_sort_order(File) ->
- docb_html_util:html_latin1_sort_order(
- lists:flatten(
- docb_html_util:attribute_cdata_to_html(string:strip(File)))).
-
-funcdef_sort_order(FuncDef, RefType) ->
- docb_html_util:html_latin1_sort_order(
- docb_html_util:make_anchor_name_short(FuncDef, RefType)).
diff --git a/lib/docbuilder/src/docb_tr_part2html.erl b/lib/docbuilder/src/docb_tr_part2html.erl
deleted file mode 100644
index 30befe8432..0000000000
--- a/lib/docbuilder/src/docb_tr_part2html.erl
+++ /dev/null
@@ -1,237 +0,0 @@
-%% ``The contents of this file are subject to the Erlang Public License,
-%% Version 1.1, (the "License"); you may not use this file except in
-%% compliance with the License. You should have received a copy of the
-%% Erlang Public License along with this software. If not, it can be
-%% retrieved via the world wide web at http://www.erlang.org/.
-%%
-%% Software distributed under the License is distributed on an "AS IS"
-%% basis, WITHOUT WARRANTY OF ANY KIND, either expressed or implied. See
-%% the License for the specific language governing rights and limitations
-%% under the License.
-%%
-%% The Initial Developer of the Original Code is Ericsson Utvecklings AB.
-%% Portions created by Ericsson are Copyright 1999-2000, Ericsson
-%% Utvecklings AB. All Rights Reserved.''
-%%
-%% $Id$
-%%
--module(docb_tr_part2html).
-
--export([extension/0, transform/3, rule/2, rule/3]).
-
-extension() ->
- ".html".
-
-transform(File, {part, _Attrs, [Header| Rest]}, Opts0) ->
-
- %% Extract header data
- Title = docb_html_util:extract_header_data(title, Header),
-
- %% Create the framing HTML document
- OutFile = docb_util:outfile(File ++ "_frame", ".html", Opts0),
- case file:open(OutFile, [write]) of
- {ok, Frame} ->
- io:format(Frame,
-"<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Frameset//EN\"
- \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd\">
-<!-- This document was generated using DocBuilder-" ++ docb_util:version() ++ " -->
-<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">
-<head>
- <title>~s</title>
- " ++ docb_util:html_snippet(head, Opts0) ++ "
-</head>
-<frameset cols=\"200, *\">
- <frame src=\"~s\" name=\"toc\"/>
- <frame src=\"~s\" name=\"document\"/>
- <noframes>
- <body bgcolor=\"#FFFFFF\" text=\"#000000\" link=\"#0000FF\"
- vlink=\"#FF00FF\" alink=\"#FF0000\">
- <p>This documentation requires a browser that can handle frames</p>
- </body>
- </noframes>
-</frameset>
-</html>
-",
- [Title, File ++ ".html", File ++ "_first.html"]),
- file:close(Frame)
- end,
-
- %% Create the front HTML document
- docb_main:transform(first, html, Opts0, File ++ "_first",
- {first, [], [Header| Rest]}),
-
- %% Extract files to include
- Files =
- case Rest of
- [{description, _, _}| NewRest] ->
- lists:map(fun({include, [{_, _, F}], _}) -> filename:rootname(F) end,
- NewRest);
- [{include, _, _}| _NewRest] ->
- lists:map(fun({include, [{_, _, F}], _}) -> filename:rootname(F) end, Rest)
- end,
-
- %% Concat all chapters into a *big* parse tree
- %% Also transform them to HTML
- TransformP = not docb_util:an_option(framework_only, Opts0),
- TOpts = [dict, {part_application,File}],
- ConcatTree = concat_files(Files, Opts0, TransformP, TOpts),
-
- %% Create a cites dictionary
- docb_main:transform(cite, html, Opts0, File ++ "_cite",
- {cite, [], [Header| ConcatTree]}),
-
- %% Create a terms dictionary
- docb_main:transform(term, html, Opts0, File ++ "_term",
- {term, [], [Header| ConcatTree]}),
-
- %% Find all fascicules to be put in the top menu of the table of
- %% contents
- Ext = docb_util:lookup_option(src_type, Opts0),
- Opts2 =
- case filelib:is_regular("fascicules"++Ext) of
- true ->
- case docb_main:parse1("fascicules", Opts0) of
- {ok, Parse} ->
- FascData = get_fasc_data(Parse),
- case lists:keyfind(File, 1, FascData) of
- {_, _, "YES", _} ->
- OrigFile =
- docb_util:outfile(File++"_frame",
- ".html", Opts0),
- EntryFile =
- docb_util:outfile("index",
- ".html", Opts0),
- docb_util:message(info,
- "Copying ~s to ~s",
- [OrigFile,EntryFile]),
- file:copy(OrigFile, EntryFile);
- _ ->
- ok
- end,
- [{fascdata, FascData}| Opts0];
- errors ->
- %% do not bother
- docb_util:message(
- warning,
- "fascicules~s could not be parsed,"
- " no index.html created~n", [Ext]),
- Opts0
- end;
- _ ->
- %% do not bother
- docb_util:message(warning,
- "fascicules~s not found, "
- "no index.html created~n",
- [Ext]),
- Opts0
- end,
-
- %% Create ToC parse tree
- {{toc, [{"FILE", "CDATA", File}], [Header| ConcatTree]}, Opts2}.
-
-concat_files(Files, Opts, TransformP, TOpts) ->
- Ext = docb_util:lookup_option(src_type, Opts),
- concat_files(Files, [], 1, Opts, TransformP, TOpts, Ext).
-
-concat_files([File | Rest], Body, ChLevel, Opts, TP, TOpts, Ext) ->
- case docb_main:parse1(File, Opts) of
- {ok, Parse} ->
- {TopTag, Attrs, [Header = {header, _, HeaderContents} | More]} = Parse,
- {title,_,Title} = lists:keyfind(title,1,HeaderContents),
- NewMore = [{section, [], [{title, [], Title}| More]}],
- NewParse = {TopTag, Attrs, [Header| NewMore]},
- if
- TP ->
- docb_util:message(info,
- "Processing \"~s~s\"",
- [File, Ext]),
- Opts2 =
- [html, {number,integer_to_list(ChLevel)}] ++
- TOpts ++ Opts,
- docb_main:transform(TopTag, html, Opts2, File,
- NewParse);
- true -> ignore
- end,
- NumberTree =
- docb_html_util:number(NewParse,
- integer_to_list(ChLevel), File),
- {_, [], [_| NewBody]} = NumberTree,
- Body ++ concat_files(Rest, NewBody, ChLevel+1, Opts,
- TP, TOpts, Ext);
- errors ->
- throw({error,"Parse error when building chapter "++File})
- end;
-concat_files([], Body, _ChLevel, _Opts, _TP, _TOpts, _Ext) ->
- Body.
-
-rule([section| _], _) ->
- {"", ""};
-
-rule(_, _) ->
- {drop, ""}.
-
-rule([toc| _], {_Depth, [File], [Header| _]}, Opts) ->
- case docb_util:lookup_option(fascdata, Opts) of
- false ->
- {{docb_html_layout:part_toc_top(
- docb_html_util:all_header_data(Header), File, Opts),
- docb_html_layout:part_toc_bot()}, Opts};
- FascData ->
- HRefTexts =
- lists:map(
- fun({_File, HRef, _Entry, PCText}) ->
- {HRef, docb_html_util:pcdata_to_html(PCText)}
- end,
- FascData),
- {{docb_html_layout:part_toc_top(
- docb_html_util:all_header_data(Header),
- File, Opts, HRefTexts),
- docb_html_layout:part_toc_bot()}, Opts}
- end;
-
-rule([title| Rest], {_, [Number, File], [{pcdata, _, Title}]}, Opts) ->
- N = docb_html_util:count_sections(Rest),
- OutFile = docb_html_util:make_anchor_href(File),
- if
- N == 1 ->
- {{drop,
- "<hr/>\n<small>" ++
- Number ++
- " <a target=\"document\" href=\"" ++ OutFile ++ "#" ++
- Number ++ "\">" ++
- docb_html_util:pcdata_to_html(Title) ++
- "</a></small><br/>\n"},
- Opts};
- N < 3 ->
- {{drop,
- "<small>" ++
- Number ++
- " <a target=\"document\" href=\"" ++ OutFile ++ "#" ++
- Number ++ "\">" ++
- docb_html_util:pcdata_to_html(Title) ++
- "</a></small><br/>\n"},
- Opts};
- true ->
- {{drop, ""}, Opts}
- end.
-
-%% Parsed fascicules:
-%% {fascicules,[],
-%% [{fascicule, [{"FILE","CDATA","refman"},
-%% {"HREF","CDATA","refman_frame.html"},
-%% {"ENTRY","TOKEN","YES"}],
-%% [{pcdata, [], "" Reference Manual\\n \n"}]},
-%% Returns: [{File, HRef, Entry, Text}].
-get_fasc_data({fascicules, _, Fascs}) ->
- lists:map(
- fun({fascicule, Atts, Trees}) ->
- AVals = get_avals(Atts),
- PCText = get_pc_text(Trees),
- list_to_tuple(lists:append([AVals, [PCText]])) end,
- Fascs).
-
-get_avals(Atts) ->
- [element(3, Tuple) || Tuple <- Atts].
-
-get_pc_text([{pcdata, _, Text}]) ->
- Text.
diff --git a/lib/docbuilder/src/docb_tr_refs2kwic.erl b/lib/docbuilder/src/docb_tr_refs2kwic.erl
deleted file mode 100644
index dc60c329fc..0000000000
--- a/lib/docbuilder/src/docb_tr_refs2kwic.erl
+++ /dev/null
@@ -1,156 +0,0 @@
-%% ``The contents of this file are subject to the Erlang Public License,
-%% Version 1.1, (the "License"); you may not use this file except in
-%% compliance with the License. You should have received a copy of the
-%% Erlang Public License along with this software. If not, it can be
-%% retrieved via the world wide web at http://www.erlang.org/.
-%%
-%% Software distributed under the License is distributed on an "AS IS"
-%% basis, WITHOUT WARRANTY OF ANY KIND, either expressed or implied. See
-%% the License for the specific language governing rights and limitations
-%% under the License.
-%%
-%% The Initial Developer of the Original Code is Ericsson Utvecklings AB.
-%% Portions created by Ericsson are Copyright 1999-2000, Ericsson
-%% Utvecklings AB. All Rights Reserved.''
-%%
-%% $Id$
-%%
--module(docb_tr_refs2kwic).
-
--export([extension/0, transform/3, rule/2]).
-
-%% Output parts of a parsetree that contains a series of reference
-%% manual pages. The tags considered are: module, file, app, com and lib
-%% (and their corresponding *summary tags), and name, fsummary, c, em,
-%% ret and pcdata.
-
-extension() ->
- ".kwc".
-
-transform(File, Tree, Opts) ->
- {refs, [], Trees} = Tree,
- FileTree = {srcfile, [], [{pcdata, [], File}]},
- AppName = docb_util:lookup_option(name, Opts, "unknown"),
- AppTree = {appname, [], [{pcdata, [], AppName}]},
- Vsn = docb_util:lookup_option(vsn, Opts, "unknown"),
- VsnTree = {appvsn, [], [{pcdata, [], Vsn}]},
- NewTree = {refs, [], [FileTree, AppTree, VsnTree| Trees]},
- {NewTree, Opts}.
-
-rule([refs|_],_) ->
- {"%% Automatically generated. Do not edit.\n", ""};
-
-rule([srcfile| _], _) ->
- {"{srcfile, \"", "\"}.\n"};
-
-rule([appname| _], _) ->
- {"{appname, \"", "\"}.\n"};
-
-rule([appvsn| _], _) ->
- {"{appvsn, \"", "\"}.\n"};
-
-rule([erlref|_ ], _) ->
- {"", ""};
-
-rule([fileref|_ ], _) ->
- {"", ""};
-
-rule([appref|_ ], _) ->
- {"", ""};
-
-rule([comref|_ ], _) ->
- {"", ""};
-
-rule([cref|_ ], _) ->
- {"", ""};
-
-rule([module| _], {_, [File], _}) ->
- {drop, "{module, \"" ++ File ++ "\"}.\n"};
-
-rule([file|_], {_, [File], _}) ->
- {drop, "{file, \"" ++ File ++ "\"}.\n"};
-
-rule([app|_], {_, [File], _}) ->
- {drop, "{app, \"" ++ File ++ "\"}.\n"};
-
-rule([com|_], {_, [File], _}) ->
- {drop, "{com, \"" ++ File ++ "\"}.\n"};
-
-rule([lib|_], {_, [File], _}) ->
- {drop, "{lib, \"" ++ File ++ "\"}.\n"};
-
-rule([modulesummary|_], _) ->
- {"{modulesummary, \"", "\"}.\n"};
-
-rule([filesummary|_], _) ->
- {"{filesummary, \"", "\"}.\n"};
-
-rule([appsummary|_], _) ->
- {"{appsummary, \"", "\"}.\n"};
-
-rule([comsummary|_], _) ->
- {"{comsummary, \"", "\"}.\n"};
-
-rule([libsummary|_], _) ->
- {"{libsummary, \"", "\"}.\n"};
-
-rule([funcs|_ ], _) ->
- {"", ""};
-
-rule([func|_ ], _) ->
- {"", ""};
-
-rule([name,func,funcs,cref|_], {_,[_File], [_Ret,{pcdata,[],Name}]}) ->
- FName = lists:flatten(docb_html_util:pcdata_to_html(Name)),
- TName = docb_util:trim(FName),
- case catch docb_util:fknidx(TName, "/") of
- {'EXIT',_} ->
- {drop, ["{name, \"", escq(TName), "\"}.\n"]};
- FuncName ->
- {drop, ["{name, \"", escq(FuncName), "\"}.\n"]}
- end;
-
-rule([name,func,funcs,erlref|_], {_,[_File], [{pcdata,[],Name}]}) ->
- FName = lists:flatten(docb_html_util:pcdata_to_html(Name)),
- TName = docb_util:trim(FName),
- case catch docb_util:fknidx(TName, "/") of
- {'EXIT',_} ->
- {drop, ["{name, \"", escq(TName), "\"}.\n"]};
- FuncName ->
- {drop, ["{name, \"", escq(FuncName), "\"}.\n"]}
- end;
-
-rule([name, func| _], {_, [_File], [{pcdata, [], Name}]}) ->
- FName = lists:flatten(docb_html_util:pcdata_to_html(Name)),
- TName = docb_util:trim(FName),
- Cmd = case string:tokens(TName, " ") of
- [Cmd0| _] ->
- Cmd0;
- _ ->
- TName
- end,
- {drop, ["{name, \"", escq(Cmd), "\"}.\n"]};
-
-rule([fsummary| _], _) ->
- {"{fsummary, \"", "\"}.\n"};
-
-rule([c, fsummary|_], _) ->
- {"", ""};
-
-rule([em, fsummary|_], _) ->
- {"", ""};
-
-rule([pcdata| _], {_, _, Data}) ->
- FData = lists:flatten(docb_html_util:pcdata_to_html(Data)),
- Out = lists:map(fun($\n) -> $ ; (C) -> C end, FData),
- {drop, escq(Out)};
-
-rule(_, _) ->
- {drop, ""}.
-
-escq(Cs) ->
- lists:flatmap(fun($") ->
- "\\\"";
- (C) -> [C]
- end,
- Cs).
diff --git a/lib/docbuilder/src/docb_tr_report2html.erl b/lib/docbuilder/src/docb_tr_report2html.erl
deleted file mode 100644
index 3386ed972a..0000000000
--- a/lib/docbuilder/src/docb_tr_report2html.erl
+++ /dev/null
@@ -1,70 +0,0 @@
-%% ``The contents of this file are subject to the Erlang Public License,
-%% Version 1.1, (the "License"); you may not use this file except in
-%% compliance with the License. You should have received a copy of the
-%% Erlang Public License along with this software. If not, it can be
-%% retrieved via the world wide web at http://www.erlang.org/.
-%%
-%% Software distributed under the License is distributed on an "AS IS"
-%% basis, WITHOUT WARRANTY OF ANY KIND, either expressed or implied. See
-%% the License for the specific language governing rights and limitations
-%% under the License.
-%%
-%% The Initial Developer of the Original Code is Ericsson Utvecklings AB.
-%% Portions created by Ericsson are Copyright 1999-2000, Ericsson
-%% Utvecklings AB. All Rights Reserved.''
-%%
-%% $Id$
-%%
--module(docb_tr_report2html).
-
--export([extension/0, transform/3, rule/2, rule/3]).
-
-%%
-%% File extension
-%%
-
-extension() ->
- ".html".
-
-transform(File, {report,_,[Header|Rest]}, Opts) ->
- Data = [{[], [], docb_html_util:all_header_data(Header)}],
- Tree = {report, Data, [{header,[],[]}|Rest]},
- ChapterLevel = case docb_util:lookup_option(number, Opts) of
- false -> none;
- Value -> Value
- end,
- NumberTree = docb_html_util:number(Tree, ChapterLevel, File),
- options(NumberTree, Opts).
-
-options(Tree, []) ->
- Tree;
-options(Tree, [_|Rest]) ->
- options(Tree, Rest).
-
-rule([header|_], _) ->
- {drop, ""};
-
-rule([toc|_], {_,_,ToC}) ->
- {drop, "\n<h3>Table of Contents</h3>\n" ++
- docb_html_util:format_toc(ToC) ++ "\n"};
-
-rule([section|_], _) ->
- {"", ""};
-
-rule([title|Rest], {_,[Number,_File], [{pcdata,_,Title}]}) ->
- N = integer_to_list(docb_html_util:count_sections(Rest)+1),
- {drop, "\n<h" ++ N ++ ">" ++ Number ++ " " ++
- docb_html_util:pcdata_to_html(Title) ++ "</h" ++ N ++ ">\n"};
-
-rule([erlinclude|_], {_,[File,Tag],_}) ->
- docb_html_util:erl_include(File, Tag);
-
-rule(TagHistory, TagBody) ->
- docb_html:rule(TagHistory, TagBody).
-
-rule([report|_], {_,[Data],_}, Opts) ->
- {{docb_html_layout:report_top(Data, Opts),
- docb_html_layout:report_bot(Opts)}, Opts};
-
-rule(TagHistory, TagBody, Opts) ->
- docb_html:rule(TagHistory, TagBody, Opts).
diff --git a/lib/docbuilder/src/docb_tr_term2html.erl b/lib/docbuilder/src/docb_tr_term2html.erl
deleted file mode 100644
index a3c4a5312a..0000000000
--- a/lib/docbuilder/src/docb_tr_term2html.erl
+++ /dev/null
@@ -1,124 +0,0 @@
-%% ``The contents of this file are subject to the Erlang Public License,
-%% Version 1.1, (the "License"); you may not use this file except in
-%% compliance with the License. You should have received a copy of the
-%% Erlang Public License along with this software. If not, it can be
-%% retrieved via the world wide web at http://www.erlang.org/.
-%%
-%% Software distributed under the License is distributed on an "AS IS"
-%% basis, WITHOUT WARRANTY OF ANY KIND, either expressed or implied. See
-%% the License for the specific language governing rights and limitations
-%% under the License.
-%%
-%% The Initial Developer of the Original Code is Ericsson Utvecklings AB.
-%% Portions created by Ericsson are Copyright 1999-2000, Ericsson
-%% Utvecklings AB. All Rights Reserved.''
-%%
-%% $Id$
-%%
--module(docb_tr_term2html).
-
--export([extension/0, transform/3, rule/2, rule/3]).
-
-extension() ->
- ".html".
-
-transform(_File, Tree, Opts) ->
- purge(Tree, Opts).
-
-purge({Tag, Attrs, [Header|Body]}, Opts) ->
- TermList = case docb_util:lookup_option({defs,term}, Opts) of
- false -> [];
- Value -> Value
- end,
- B1 = purge_body(Body, TermList),
- B2 = lists:ukeysort(2, B1),
- {Tag, Attrs, [Header|B2]}.
-
-purge_body([], _) ->
- [];
-purge_body([{pcdata,_Attrs,_More}|Rest], TermList) ->
- purge_body(Rest, TermList);
-purge_body([{term,[{"ID","CDATA",ID}],More}|Rest], TermList) ->
- case lists:keyfind(ID, 1, TermList) of
- false ->
- [{term,[{"NAME","CDATA",ID},{"ID","CDATA",ID}],More}|
- purge_body(Rest, TermList)];
- {ID, Name, _Description, _Responsible} ->
- [{term,[{"NAME","CDATA",Name},{"ID","CDATA",ID}],More}|
- purge_body(Rest, TermList)];
- {ID, Name, _Description} ->
- [{term,[{"NAME","CDATA",Name},{"ID","CDATA",ID}],More}|
- purge_body(Rest, TermList)]
- end;
-purge_body([{_Tag,_Attrs,More}|Rest], TermList) ->
- purge_body(More, TermList) ++ purge_body(Rest, TermList).
-
-rule([header|_], _) ->
- {drop, ""};
-rule(_, _) ->
- {drop, ""}.
-
-rule([term|_], {_,[],[Header]}, Opts) ->
- {{docb_html_layout:chapter_top(
- docb_html_util:all_header_data(Header), Opts) ++
- "\n<center><h1>Glossary</h1></center>\n",
- docb_html_layout:chapter_bot(Opts)}, Opts};
-
-rule([term|_], {_,[],[Header|_]},Opts) ->
- {{docb_html_layout:chapter_top(
- docb_html_util:all_header_data(Header), Opts) ++
- "\n<center><h1>Glossary</h1></center>\n<dl>\n",
- "\n</dl>\n" ++ docb_html_layout:chapter_bot(Opts)}, Opts};
-
-rule([term|_], {_,[Data],_}, Opts) ->
- {{docb_html_layout:chapter_top(Data, Opts) ++
- "\n<center><h1>Bibliography</h1></center>\n<dl>\n",
- "\n</dl>\n" ++ docb_html_layout:chapter_bot(Opts)}, Opts};
-
-rule([term|_], {_,[Name,ID],[{termdef,[],[{pcdata,[],Def}]}]}, Opts) ->
- TermList = case docb_util:lookup_option({defs,term}, Opts) of
- false -> [];
- Value -> Value
- end,
- case lists:keyfind(ID, 1, TermList) of
- false ->
- {{drop,"\n<dt><a name=\"" ++ ID ++ "\">" ++
- "<strong>" ++ ID ++ "</strong></a>\n</dt>\n<dd>" ++
- docb_html_util:pcdata_to_html(Def) ++ "\n</dd>\n"}, Opts};
- {ID, Name, Description, _Responsible} ->
- docb_util:message(warning,
- "Global term ~s overriding local", [ID]),
- {{drop,"\n<dt><a name=\"" ++ ID ++ "\">" ++
- "<strong>" ++ Name ++ "</strong></a></dt>\n<dd>" ++
- docb_html_util:pcdata_to_html(Description) ++ "\n</dd>\n"},
- Opts};
- {ID, Name, Description} ->
- docb_util:message(warning,
- "Global term ~s overriding local", [ID]),
- {{drop, "\n<dt><a name=\"" ++ ID ++ "\">" ++
- "<strong>" ++ Name ++ "</strong></a></dt>\n<dd>" ++
- docb_html_util:pcdata_to_html(Description) ++ "\n</dd>\n"}, Opts}
- end;
-
-rule([term|_], {_,[Name,ID],_}, Opts) ->
- TermList = case docb_util:lookup_option({defs,term}, Opts) of
- false -> [];
- Value -> Value
- end,
- case lists:keyfind(ID, 1, TermList) of
- false ->
- docb_util:message(error,
- "The term ~s has no definition", [ID]),
- {{drop, "\n<dt><a name=\"" ++ ID ++ "\">" ++
- "<strong>" ++ ID ++ "</strong></a></dt>\n<dd>" ++
- "??" ++ "\n</dd>\n"}, Opts};
- {ID, Name, Description, _Responsible} ->
- {{drop, "\n<dt><a name=\"" ++ ID ++ "\">" ++
- "<strong>" ++ Name ++ "</strong></a></dt>\n<dd>" ++
- docb_html_util:pcdata_to_html(Description) ++ "\n</dd>\n"},
- Opts};
- {ID, Name, Description} ->
- {{drop, "\n<dt><a name=\"" ++ ID ++ "\">" ++
- "<strong>" ++ Name ++ "</strong></a></dt>\n<dd>" ++
- docb_html_util:pcdata_to_html(Description) ++ "\n</dd>\n"}, Opts}
- end.
diff --git a/lib/docbuilder/src/docb_transform.erl b/lib/docbuilder/src/docb_transform.erl
deleted file mode 100644
index 736ac92274..0000000000
--- a/lib/docbuilder/src/docb_transform.erl
+++ /dev/null
@@ -1,163 +0,0 @@
-%% ``The contents of this file are subject to the Erlang Public License,
-%% Version 1.1, (the "License"); you may not use this file except in
-%% compliance with the License. You should have received a copy of the
-%% Erlang Public License along with this software. If not, it can be
-%% retrieved via the world wide web at http://www.erlang.org/.
-%%
-%% Software distributed under the License is distributed on an "AS IS"
-%% basis, WITHOUT WARRANTY OF ANY KIND, either expressed or implied. See
-%% the License for the specific language governing rights and limitations
-%% under the License.
-%%
-%% The Initial Developer of the Original Code is Ericsson Utvecklings AB.
-%% Portions created by Ericsson are Copyright 1999-2000, Ericsson
-%% Utvecklings AB. All Rights Reserved.''
-%%
-%% $Id$
-%%
--module(docb_transform).
-
--export([file/1, file/2]).
--deprecated([{file,1,next_major_release},
- {file,2,next_major_release}]).
-
-%% file(File) -> ok | {error, Reason}
-%% file(File, Opts) -> ok | {error, Reason}
-%% File = string(), file name with or without ".xml" extension
-%% Opts = [Opt]
-%% Reason = badfile | {badopt, Term}
-file(File0) ->
- file(File0, []).
-file(File0, RawOpts) ->
- File = filename:rootname(File0), % without extension
- Ext = case filename:extension(File0) of
- ".xml" -> ".xml";
- ".sgml" -> ".sgml";
- "" ->
- %% If the file is given without extension, we try to
- %% infer if the source file is XML or SGML.
- %% SGML is supported *internally within OTP* for
- %% backwards compatibility reasons.
- case filelib:is_regular(File++".xml") of
- true -> ".xml";
- false -> ".sgml"
- end;
- _Ext0 -> % this is probably an error...
- ".xml"
- end,
- case filelib:is_regular(File++Ext) of
- true ->
- case parse(RawOpts) of
- {ok, Opts0} ->
- {ok, Cwd} = file:get_cwd(),
- Opts = [{src_type,Ext},
- {src_dir,Cwd},
- {src_file,File},
- {{local_defs,term},[]},
- {{local_defs,cite},[]} | Opts0],
- case docb_main:process(File, Opts) of
- errors -> error;
- ok -> ok
- end;
- Error -> % {error, {badopt,Term}}
- Error
- end;
- false ->
- {error, badfile}
- end.
-
-parse(RawOpts) ->
- parse(RawOpts, []).
-
-%% Officially supported options
-
-parse([{html_mod,Module} | RawOpts], Opts) when is_atom(Module) ->
- parse(RawOpts, [{html_mod,Module} | Opts]);
-parse([{outdir,Dir} | RawOpts], Opts) when is_list(Dir) ->
- parse(RawOpts, [{outdir,Dir} | Opts]);
-parse([{number,N} | RawOpts], Opts) when is_integer(N) ->
- parse(RawOpts, [{number,integer_to_list(N)} | Opts]);
-parse([{number,Nstr} | RawOpts], Opts) -> % list when called from script
- parse(RawOpts, [{number,Nstr} | Opts]);
-parse([{ptype,Type} | RawOpts], Opts) when Type==unix;
- Type==windows ->
- parse(RawOpts, [{ptype,atom_to_list(Type)} | Opts]);
-parse([{ptype,Type} | RawOpts], Opts) -> % list when called from script
- parse(RawOpts, [{ptype,Type} | Opts]);
-parse([silent | RawOpts], Opts) ->
- put(option_silent, true),
- parse(RawOpts, [silent | Opts]);
-parse([{top,Index} | RawOpts], Opts) when is_list(Index) ->
- parse(RawOpts, [{top,Index} | Opts]);
-parse([{vsn,Vsn} | RawOpts], Opts) when is_list(Vsn) ->
- parse(RawOpts, [{vsn,Vsn} | Opts]);
-
-parse([{term_defs,File} | RawOpts], Opts) when is_list(File) ->
- Opts2 = get_defs(term, File, Opts),
- parse(RawOpts, Opts2);
-parse([{cite_defs,File} | RawOpts], Opts) when is_list(File) ->
- Opts2 = get_defs(cite, File, Opts),
- parse(RawOpts, Opts2);
-
-%% OTP internal options (SGML and PDF support etc.)
-
-parse([html | RawOpts], Opts) ->
- parse(RawOpts, [html | Opts]);
-parse([latex | RawOpts], Opts) ->
- parse(RawOpts, [latex | Opts]);
-parse([{man,Level} | RawOpts], Opts) -> % Level = 1..9
- parse(RawOpts, [{man,Level} | Opts]);
-
-parse([{booksty,StyFile} | RawOpts], Opts) -> % "otpA4" | "otpBOOK"
- parse(RawOpts, [{booksty,StyFile} | Opts]);
-parse([{includepath,Dir} | RawOpts], Opts) ->
- parse(RawOpts, [{includepath,Dir} | Opts]);
-parse([showpaths | RawOpts], Opts) ->
- parse(RawOpts, [showpaths | Opts]);
-parse([straight | RawOpts], Opts) ->
- parse(RawOpts, [straight | Opts]);
-parse([{ent,Ent} | RawOpts], Opts) ->
- parse(RawOpts, [{ent,Ent} | Opts]);
-
-%% Undocumented options
-
-parse([{name, Name} | RawOpts], Opts) ->
- parse(RawOpts, [{name, Name} | Opts]);
-parse([framework_only | RawOpts], Opts) ->
- parse(RawOpts, [framework_only | Opts]);
-parse([kwicindex_only | RawOpts], Opts) ->
- parse(RawOpts, [kwicindex_only | Opts]);
-
-parse([], Opts) ->
- {ok, Opts};
-parse([Opt | _RawOpts], _Opts) ->
- {error, {badopt, Opt}}.
-
-%% Type = term | cite
-get_defs(Type, File, Opts) ->
- Key = {defs,Type},
- {PrevDefs, Opts2} =
- case lists:keyfind(Key, 1, Opts) of
- {_, Defs0} ->
- {Defs0, lists:keydelete(Key, 1, Opts)};
- false ->
- {[], Opts}
- end,
- NewDefs = case file:consult(File) of
- {ok, [DefL]} when is_list(DefL) ->
- DefL;
- {ok, _Terms} ->
- docb_util:message(error,
- "Skipping defs file ~s, does "
- "not contain one list", [File]),
- [];
- {error, Error} ->
- Expl = lists:flatten(file:format_error(Error)),
- docb_util:message(error,
- "Skipping defs file ~s, ~s",
- [File, Expl]),
- []
- end,
- [{Key,PrevDefs++NewDefs} | Opts2].
-
-
diff --git a/lib/docbuilder/src/docb_util.erl b/lib/docbuilder/src/docb_util.erl
deleted file mode 100644
index 9b2eec7733..0000000000
--- a/lib/docbuilder/src/docb_util.erl
+++ /dev/null
@@ -1,237 +0,0 @@
-%% ``The contents of this file are subject to the Erlang Public License,
-%% Version 1.1, (the "License"); you may not use this file except in
-%% compliance with the License. You should have received a copy of the
-%% Erlang Public License along with this software. If not, it can be
-%% retrieved via the world wide web at http://www.erlang.org/.
-%%
-%% Software distributed under the License is distributed on an "AS IS"
-%% basis, WITHOUT WARRANTY OF ANY KIND, either expressed or implied. See
-%% the License for the specific language governing rights and limitations
-%% under the License.
-%%
-%% The Initial Developer of the Original Code is Ericsson Utvecklings AB.
-%% Portions created by Ericsson are Copyright 1999-2000, Ericsson
-%% Utvecklings AB. All Rights Reserved.''
-%%
-%% $Id$
-%%
--module(docb_util).
-
--export([version/0, old_docb_dir/0, dtd_dir/0]).
--export([html_snippet/2, html_snippet/3]).
--export([lookup_option/2, lookup_option/3, lookup_options/2,
- an_option/2]).
--export([outfile/3, full_file_name/4]).
--export([message/2, message/3]).
--export([ltrim/1, rtrim/1, trim/1]).
--export([join/2]).
--export([fknidx/2]).
-
--include("docb_util.hrl").
-
-%%--DocBuilder info-----------------------------------------------------
-
-%% version() -> string()
-%% Returns the DocBuilder application version.
-version() ->
- DocbDir = code:lib_dir(docbuilder),
- case string:tokens(filename:basename(DocbDir), "-") of
- [_, Vsn] -> Vsn;
- _ -> "unknown"
- end.
-
-%% old_docb_dir() -> string()
-%% Returns the root directory of Old_DocBuilder (OTP internal).
-old_docb_dir() ->
- "/home/otp/sgml/docb".
-
-%% dtd_dir() -> string()
-%% Returns the directory where the XML DTDs are located.
-dtd_dir() ->
- DocbDir = code:lib_dir(docbuilder),
- filename:join(DocbDir, "dtd").
-
-%%--User defined HTML snippets------------------------------------------
-
-%% html_snippet(What, Opts) -> HTML
-%% html_snippet(What, Arg, Opts) -> HTML
-%% What = head | seealso
-%% HTML = string()
-html_snippet(What, Opts) ->
- case lookup_option(html_mod, Opts) of
- false -> "";
- Module ->
- case catch Module:What() of
- HTML when is_list(HTML) ->
- HTML;
- {'EXIT', {undef, _}} ->
- "";
- {'EXIT', Reason} ->
- message(warning,
- "Callback function ~p:~p() => ~p",
- [Module, What, Reason]),
- "";
- Other ->
- message(warning,
- "Callback function ~p:~p() => ~p",
- [Module, What, Other]),
- ""
- end
- end.
-html_snippet(What, Arg, Opts) ->
- case lookup_option(html_mod, Opts) of
- false -> "";
- Module ->
- case catch Module:What(Arg) of
- HTML when is_list(HTML) ->
- HTML;
- {'EXIT', {undef, _}} ->
- "";
- {'EXIT', Reason} ->
- message(warning,
- "Callback function ~p:~p(~p) => ~p",
- [Module, What, Arg, Reason]),
- "";
- Other ->
- message(warning,
- "Callback function ~p:~p(~p) => ~p",
- [Module, What, Arg, Other]),
- ""
- end
- end.
-
-%%--Option utilities----------------------------------------------------
-
-%% Opts = [{Opt,Value} | Opt]
-
-%% lookup_option(Opt, Opts) -> Value | false
-lookup_option(Opt, Opts) ->
- case lists:keyfind(Opt, 1, Opts) of
- {Opt,Value} -> Value;
- false -> false
- end.
-
-%% lookup_option(Opt, Opts, DefaultValue) -> Value | DefaultValue
-lookup_option(Opt, Opts, DefaultValue) ->
- case lookup_option(Opt,Opts) of
- false -> DefaultValue;
- Value -> Value
- end.
-
-%% lookup_options(Opt, Opts) -> [Value]
-%% Used when the same option can be defined several times and returns
-%% the (possibly empty) list of values.
-lookup_options(Opt, Opts) ->
- [V || {O, V} <- Opts, O == Opt].
-
-%% an_option(Opt, Opts) -> bool()
-an_option(Opt, Opts) ->
- lists:member(Opt, Opts).
-
-%%--File handling-------------------------------------------------------
-
-%% outfile(File0, Extension, Opts) -> File
-%% Build the full filename for where to place a resulting file.
-outfile(File0, Extension, Opts) ->
- File =
- case regexp:match(File0, "[^/]*\$") of
- {match,Start,Length} ->
- string:substr(File0, Start, Length);
- _ ->
- File0
- end,
- full_file_name(File, Extension, outdir, Opts).
-
-%% full_file_name(File, Extension, What, Opts) -> File'
-%% File = string()
-%% What = outdir | includepath
-%% Prepend the full path name.
-full_file_name(File, Extension, What, Opts) ->
- Path = lookup_option(What, Opts, ""),
- full_file_name(File, Extension, Path).
-
-full_file_name(File0, Extension, Path) ->
- File = case filename:extension(File0) of
- Extension -> File0;
- _ -> File0++Extension
- end,
-
- case File of
- [$/|_] -> File;
- [$~|_] -> File;
- _ when Path=/="" -> filename:join(Path, File);
- _ -> File
- end.
-
-%%--Messages to the user------------------------------------------------
-
-%% message(Class, Format)
-%% message(Class, Format, Values) -> ok
-%% Class = info | warning | error
-%% Format, Values -- as in io:format/2
-%% Prints a warning or error message.
-%% Call as util:message(warning, "~w is undefined", [foo]).
-message(Class, Format) ->
- message(Class, Format, []).
-message(Class, Format, Values) ->
- Prefix = case Class of
- info -> "";
- warning -> "*** Warning: ";
- error -> "*** Error: "
- end,
- case get(option_silent) of
- true when Class==warning ->
- ok;
- _ ->
- io:format(Prefix, []),
- io:format(Format, Values),
- io:nl()
- end.
-
-%%--String handling-----------------------------------------------------
-
-%% ltrim(Str) -> Str'
-%% rtrim(Str) -> Str'
-%% trim(Str) -> Str'
-%% Strips whitespace from left, right or both.
-ltrim(Str) ->
- lists:dropwhile(fun white_space/1, Str).
-rtrim(Str) ->
- lists:reverse(ltrim(lists:reverse(Str))).
-trim(Str) ->
- rtrim(ltrim(Str)).
-
-white_space($ ) -> true;
-white_space(C) when C<$ -> true;
-white_space($\n) -> true;
-white_space($\t) -> true;
-white_space(_) -> false.
-
-%% join(Strings, With) -> string()
-join([H1, H2| T], S) ->
- H1 ++ S ++ join([H2| T], S);
-join([H], _) ->
- H;
-join([], _) ->
- [].
-
-%%--Other---------------------------------------------------------------
-
-%% fknidx(FNdef0, Fn_arity_sep) -> string()
-%% Get me the function name and arity.
-fknidx(FNdef0, Fn_arity_sep) ->
- FNdef = string:strip(FNdef0),
- case string:tokens(FNdef,"(") of
- [FNdef] ->
- %% No parentheses, assume variable: remove nl:s at end,
- %% and strip blanks.
- string:strip(string:strip(FNdef, right, $\n));
- [Name0|Args0] ->
- [Args1|_] = string:tokens(string:strip(hd(Args0)), "-"),
- Arity = case Args1 of
- [$)|_] -> 0;
- _ ->
- length(string:tokens(Args1, ","))
- end,
- string:strip(Name0)++Fn_arity_sep++integer_to_list(Arity)
- end.
diff --git a/lib/docbuilder/src/docb_util.hrl b/lib/docbuilder/src/docb_util.hrl
deleted file mode 100644
index 01ef3f7fca..0000000000
--- a/lib/docbuilder/src/docb_util.hrl
+++ /dev/null
@@ -1,34 +0,0 @@
-%% ``The contents of this file are subject to the Erlang Public License,
-%% Version 1.1, (the "License"); you may not use this file except in
-%% compliance with the License. You should have received a copy of the
-%% Erlang Public License along with this software. If not, it can be
-%% retrieved via the world wide web at http://www.erlang.org/.
-%%
-%% Software distributed under the License is distributed on an "AS IS"
-%% basis, WITHOUT WARRANTY OF ANY KIND, either expressed or implied. See
-%% the License for the specific language governing rights and limitations
-%% under the License.
-%%
-%% The Initial Developer of the Original Code is Ericsson Utvecklings AB.
-%% Portions created by Ericsson are Copyright 1999-2000, Ericsson
-%% Utvecklings AB. All Rights Reserved.''
-%%
-%% $Id$
-%%
-
-%%% For character conversion
-
--record(in_opts, {expand_entities=false,
- encode_filter = fun(X) -> X end}).
--record(out_opts, {escape_chars=false,
- remove_nl=false,
- delete_trailing_whitespace=false,
- delete_trailing_nl=false,
- compress_white_space=false,
- escape_filter = fun(X) -> X end}).
-
-
--define(pcdata_IN, #in_opts{expand_entities=true}).
--define(rcdata_IN, #in_opts{expand_entities=true}).
--define(cdata_IN, #in_opts{}).
-
diff --git a/lib/docbuilder/src/docb_xmerl_tree_cb.erl b/lib/docbuilder/src/docb_xmerl_tree_cb.erl
deleted file mode 100644
index bc62069230..0000000000
--- a/lib/docbuilder/src/docb_xmerl_tree_cb.erl
+++ /dev/null
@@ -1,343 +0,0 @@
-%% ``The contents of this file are subject to the Erlang Public License,
-%% Version 1.1, (the "License"); you may not use this file except in
-%% compliance with the License. You should have received a copy of the
-%% Erlang Public License along with this software. If not, it can be
-%% retrieved via the world wide web at http://www.erlang.org/.
-%%
-%% Software distributed under the License is distributed on an "AS IS"
-%% basis, WITHOUT WARRANTY OF ANY KIND, either expressed or implied. See
-%% the Licence for the specific language governing rights and limitations
-%% under the License.
-%%
-%% The Initial Developer of the Original Code is Ericsson AB.
-%% Portions created by Ericsson are Copyright 1999-2006, Ericsson AB.
-%% All Rights Reserved.��
-%%
-%% $Id$
-%%
--module(docb_xmerl_tree_cb).
-
-%% This is the XMerL callback module for exporting XML to the internal
-%% tree format used by DocBuilder.
-%% {Doc, _Misc} = xmerl_scan:file("file.xml", [{validation,true}])
-%% Tree = xmerl:export([Doc], docb_xmerl_tree_cb)
-
--export(['#xml-inheritance#'/0]).
-
--export(['#root#'/4,
- '#text#'/1,
- '#element#'/5]).
--include("xmerl.hrl").
-
-%%--Functions used by xmerl---------------------------------------------
-
-'#xml-inheritance#'() ->
- [].
-
-'#root#'(Data, _Attrs, [], _E) ->
- Data.
-
-'#text#'(Text) ->
- Text2 = strip_leading_blanks(Text),
-%% before
-%% case Text2 of
-%% [$\n|T] ->
-%% case is_empty(T) of
-%% true -> [];
-%% false -> {pcdata, [], nl(Text2)}
-%% end;
-%%
-%% _ ->
-%% {pcdata, [], nl(Text2)}
-%% end.
-%% after
- {pcdata, [], nl(Text2)}.
-
-'#element#'(Tag, Data, Attrs, Parents, _E) when Tag==pre; Tag==code ->
- [H|T] = reinsert_nl(Data),
- NewData = [strip_nl(H)|T],
- NewData2 = case Tag of
- code ->
- fix_single_pcdata(NewData);
- pre ->
- NewData
- end,
- {Tag, attrs(get_dtd(Parents), Tag, Attrs), NewData2};
-'#element#'(Tag, Data, Attrs, Parents, _E) ->
- NewData = case tag_content(Tag) of
- no_pcdata -> % remove all pcdata
- [Dat||
- Dat <- Data,
- begin
- Fun = fun({pcdata,_,_}) -> false;
- (_) -> true end,
- Fun(Dat)
- end];
- single_pcdata when length(Data)>1 ->
- %% merge several pcdata's into one single pcdata
- fix_single_pcdata(Data);
- _ ->
- lists:flatten(Data)
- end,
- {Tag, attrs(get_dtd(Parents), Tag, Attrs), NewData}.
-
-%%--Internal functions--------------------------------------------------
-
-%% is_empty(Str) -> bool()
-%% Returns true if the string Str only contains blanks, tabs and
-%% newlines, false otherwise.
-%% is_empty("\n" ++ Text) ->
-%% is_empty(Text);
-%% is_empty("\t" ++ Text) ->
-%% is_empty(Text);
-%% is_empty(" " ++ Text) ->
-%% is_empty(Text);
-%% is_empty("") ->
-%% true;
-%% is_empty(_) ->
-%% false.
-
-%% reinsert_nl(L1) -> L2
-%% Workaround for <pre>: Normally empty lines are ignored. However,
-%% Xmerl splits lines whenever it encounters an entity. In the case of
-%% <pre>, this may lead to that we ignores what we think is an empty
-%% line but is actually a line break that should be kept, for example
-%% in this case:
-%% <pre>
-%% <input>some command</input> <-- this line break is lost!
-%% &lt;some result&gt;
-%% </pre>
-%% This function reinserts line breaks where necessary.
-reinsert_nl([[]|T]) ->
- [{pcdata,[],"\\n"} | reinsert_nl(T)];
-reinsert_nl([H|T]) ->
- [H | reinsert_nl(T)];
-reinsert_nl([]) ->
- [].
-
-%% sgmls treats line breaks in a way that DocBuilder relies on and
-%% which must be imitated here. Replace all "\n" with "\\n" and add
-%% "\n" to the end of each text element.
-nl("") ->
- "\n";
-nl("\n"++Text) ->
- "\\n"++nl(Text);
-nl([Ch|Text]) ->
- [Ch|nl(Text)].
-
-
-%% strip_leading_blanks(Str) -> Str
-%% Leading spaces and tabs before a newline are always redundant
-%% and are therefore stripped of here
-%% If no newline is found the original string is returned unchanged
-
-strip_leading_blanks(Str) ->
- strip_leading_blanks(Str,Str).
-
-strip_leading_blanks([],Str) ->
- Str;
-strip_leading_blanks([$\s|T],Str) ->
- strip_leading_blanks(T,Str);
-strip_leading_blanks([$\t|T],Str) ->
- strip_leading_blanks(T,Str);
-strip_leading_blanks(Rest=[$\n|_],_) ->
- Rest;
-strip_leading_blanks(_,Str) ->
- Str.
-
-%% strip_nl(Str) -> Str
-%% The XMerL scan will often result in the contents of <pre> or <code>
-%% starting with a newline, as the format is normally:
-%% <pre>
-%% ..contents..
-%% </pre>
-%% However, this newline must be removed, or the resulting HTML will be
-%% <pre>
-%%
-%% ..content..
-%% </pre>
-strip_nl({pcdata,[],"\\n"++Str}) -> {pcdata,[],Str};
-strip_nl(E) -> E.
-
-get_dtd([]) ->
- none;
-get_dtd(Parents) ->
- {DTD, _} = lists:last(Parents),
- DTD.
-
-%% attrs(DTD, Tag, GivenAttrs) -> AllAttrs
-%% DTD = Tag = atom() DTD and tag name
-%% GivenAttrs = [#xmlAttribute{}]
-%% AllAttrs = [{Name, Type, Val}]
-%% Name = string() (uppercase) Example: "VALIGN"
-%% Type = "CDATA" | "TOKEN"
-%% Val = string() (uppercase if type is "TOKEN", as-is otherwise)
-%% The XMerL scanning of <file>.xml renders only the given attributes.
-%% However, DocBuilder needs also the optional attributes (which not
-%% necessarily have been given), so we add them here, using the default
-%% values according to the DTDs.
-%% NOTE: Uses the information from the DTDs. That is, if some change is
-%% done to the DTDs, also this file must be updated. Ideally, the DTDs
-%% should be parsed automatically in some way.
-%% It can also be noted that this check is superfluous in the case where
-%% all attributes are required (except that the attributes are sorted
-%% in the same order as in the DTD) and where an optional attribute has
-%% type "CDATA" as no sensible default value can be specified in this
-%% case.
-attrs(DTD, Tag, GivenAttrs) ->
- merge_attrs(Tag, default_attrs(DTD, Tag), GivenAttrs).
-
-merge_attrs(Tag, [{NameA, Type, DefVal}|Default], GivenAttrs) ->
- Val = case lists:keyfind(NameA, #xmlAttribute.name, GivenAttrs) of
- #xmlAttribute{value=Val0} -> Val0;
- false -> DefVal
- end,
- Attr = {attr_name(NameA), Type, attr_val(Type, Val)},
- [Attr | merge_attrs(Tag, Default, GivenAttrs)];
-merge_attrs(_Tag, [], _GivenAttrs) ->
- [].
-
-attr_name(Atom) ->
- string:to_upper(atom_to_list(Atom)).
-
-attr_val("CDATA", Val) -> Val;
-attr_val("TOKEN", Val) -> string:to_upper(Val).
-
-%% Given the DTD and element tag, return a list [{Name, Value}] where
-%% Name (atom) is the name of each possible attribute and
-%% Value (lowercase string) its default value.
-default_attrs(_, cell) ->
- [{align, "TOKEN", "left"},
- {valign, "TOKEN", "middle"}];
-default_attrs(_, cite) ->
- [{id, "CDATA", ""}]; % required
-default_attrs(_, code) ->
- [{type, "TOKEN", "none"}];
-default_attrs(_, codeinclude) ->
- [{file, "CDATA", ""}, % required
- {tag, "CDATA", ""},
- {type, "TOKEN", "none"}];
-default_attrs(book, contents) ->
- [{level, "TOKEN", "2"}];
-default_attrs(_, erleval) ->
- [{expr, "CDATA", ""}]; % required
-default_attrs(report, erlinclude) ->
- [{file, "CDATA", ""}, % required
- {tag, "CDATA", ""}]; % required
-default_attrs(_, fascicule) ->
- [{file, "CDATA", ""}, % required
- {href, "CDATA", ""}, % required
- {entry, "TOKEN", "no"}];
-default_attrs(book, header) ->
- [{titlestyle, "TOKEN", "normal"}];
-default_attrs(_, image) ->
- [{file, "CDATA", ""}]; % required
-default_attrs(_, include) ->
- [{file, "CDATA", ""}]; % required
-default_attrs(report, index) ->
- [{txt, "CDATA", ""}]; % required
-default_attrs(_, list) ->
- [{type, "TOKEN", "bulleted"}];
-default_attrs(_, marker) ->
- [{id, "CDATA", ""}]; % required
-default_attrs(book, onepart) ->
- [{lift, "TOKEN", "no"}];
-default_attrs(book, parts) ->
- [{lift, "TOKEN", "no"}];
-default_attrs(_, path) ->
- [{unix, "CDATA", ""},
- {windows, "CDATA", ""}];
-default_attrs(_, seealso) ->
- [{marker, "CDATA", ""}]; % required
-default_attrs(report, table) ->
- [{width, "CDATA", "0"},
- {colspec, "CDATA", ""}];
-default_attrs(_, table) ->
- [{align, "TOKEN", "center"}];
-default_attrs(_, term) ->
- [{id, "CDATA", ""}]; % required
-default_attrs(book, theheader) ->
- [{tag, "TOKEN", "none"}];
-default_attrs(bookinsidecover, theheader) ->
- [{tag, "TOKEN", "none"}];
-default_attrs(_, url) ->
- [{href, "CDATA", ""}]; % required
-default_attrs(_, _) -> [].
-
-%%--Single PCDATA broken into several fix-------------------------------
-
-%% When text contains an entity, then XMERL splits it into two
-%% PCDATA elements, the second starting with the entity.
-%%
-%% Example:
-%% Magnus Fr�berg => [{pcdata,[],"Magnus Fr\n"},{pcdata,[],"�berg\n"}]
-%%
-%% This is not handled by DocBuilder which expects many tags, for
-%% example title and aname, to contain a single PCDATA element. (That
-%% is also what nsgmls returned.)
-
-fix_single_pcdata([{pcdata,[],Str1}, {pcdata,[],Str2}|T]) ->
- fix_single_pcdata([{pcdata,[],Str1++Str2}|T]);
-fix_single_pcdata(FixedData) ->
- FixedData.
-
-tag_content(aname) -> single_pcdata;
-tag_content(app) -> single_pcdata;
-tag_content(approved) -> single_pcdata;
-tag_content(appsummary) -> single_pcdata;
-tag_content(b) -> single_pcdata;
-tag_content(c) -> single_pcdata;
-tag_content(cauthor) -> single_pcdata;
-tag_content(cell) -> mixed_content;
-tag_content(checked) -> single_pcdata;
-tag_content(chowpublished) -> single_pcdata;
-tag_content(code) -> single_pcdata; % mixed?
-tag_content(com) -> single_pcdata;
-tag_content(comsummary) -> single_pcdata;
-tag_content(copyright) -> mixed_content;
-tag_content(ctitle) -> single_pcdata;
-tag_content(d) -> mixed_content;
-tag_content(date) -> single_pcdata;
-tag_content(docno) -> single_pcdata;
-tag_content(em) -> mixed_content;
-tag_content(email) -> single_pcdata;
-tag_content(fascicule) -> single_pcdata;
-tag_content(file) -> single_pcdata;
-tag_content(filesummary) -> single_pcdata;
-tag_content(fsummary) -> mixed_content;
-tag_content(headline) -> single_pcdata;
-tag_content(holder) -> single_pcdata;
-tag_content(i) -> single_pcdata;
-tag_content(icaption) -> single_pcdata;
-tag_content(id) -> single_pcdata;
-tag_content(input) -> mixed_content;
-tag_content(item) -> mixed_content;
-tag_content(legalnotice) -> single_pcdata;
-tag_content(lib) -> single_pcdata;
-tag_content(libsummary) -> single_pcdata;
-tag_content(module) -> single_pcdata;
-tag_content(modulesummary) -> single_pcdata;
-tag_content(name) -> single_pcdata;
-tag_content(nametext) -> single_pcdata;
-tag_content(p) -> mixed_content;
-tag_content(pagetext) -> single_pcdata;
-tag_content(path) -> single_pcdata; % mixed?
-tag_content(pre) -> mixed_content;
-tag_content(prepared) -> single_pcdata;
-tag_content(resp) -> single_pcdata;
-tag_content(responsible) -> single_pcdata;
-tag_content(ret) -> single_pcdata;
-tag_content(rev) -> single_pcdata;
-tag_content(seealso) -> single_pcdata; % mixed?
-tag_content(shortdef) -> single_pcdata;
-tag_content(shorttitle) -> single_pcdata;
-tag_content(tag) -> mixed_content;
-tag_content(tcaption) -> single_pcdata;
-tag_content(termdef) -> single_pcdata;
-tag_content(title) -> single_pcdata;
-tag_content(url) -> single_pcdata; % mixed
-tag_content(v) -> single_pcdata;
-tag_content(year) -> single_pcdata;
-tag_content(_) -> no_pcdata.
-
-
diff --git a/lib/docbuilder/src/docbuilder.app.src b/lib/docbuilder/src/docbuilder.app.src
deleted file mode 100644
index 64c4770964..0000000000
--- a/lib/docbuilder/src/docbuilder.app.src
+++ /dev/null
@@ -1,37 +0,0 @@
-{application, docbuilder,
- [{description, "Tool for building HTML documentation"},
- {vsn, "%VSN%"},
- {modules, [docb_edoc_xml_cb,
- docb_gen,
- docb_html,
- docb_html_layout,
- docb_html_ref,
- docb_html_util,
- docb_html_util_iso,
- docb_main,
- docb_pretty_format,
- docb_tr_application2html,
- docb_tr_appref2html,
- docb_tr_chapter2html,
- docb_tr_cite2html,
- docb_tr_comref2html,
- docb_tr_cref2html,
- docb_tr_erlref2html,
- docb_tr_fileref2html,
- docb_tr_first2html,
- docb_tr_index2html,
- docb_tr_part2html,
- docb_tr_refs2kwic,
- docb_tr_report2html,
- docb_tr_term2html,
- docb_transform,
- docb_util,
- docb_xmerl_tree_cb,
- docb_xmerl_xml_cb,
- docb_xml_check
- ]},
- {registered, []},
- {applications, [kernel, stdlib]},
- {env, []}]}.
-
-
diff --git a/lib/docbuilder/src/docbuilder.appup.src b/lib/docbuilder/src/docbuilder.appup.src
deleted file mode 100644
index 54a63833e6..0000000000
--- a/lib/docbuilder/src/docbuilder.appup.src
+++ /dev/null
@@ -1 +0,0 @@
-{"%VSN%",[],[]}.
diff --git a/lib/docbuilder/test/Makefile b/lib/docbuilder/test/Makefile
deleted file mode 100644
index 53dff193dc..0000000000
--- a/lib/docbuilder/test/Makefile
+++ /dev/null
@@ -1,80 +0,0 @@
-# ``The contents of this file are subject to the Erlang Public License,
-# Version 1.1, (the "License"); you may not use this file except in
-# compliance with the License. You should have received a copy of the
-# Erlang Public License along with this software. If not, it can be
-# retrieved via the world wide web at http://www.erlang.org/.
-#
-# Software distributed under the License is distributed on an "AS IS"
-# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
-# the License for the specific language governing rights and limitations
-# under the License.
-#
-# The Initial Developer of the Original Code is Ericsson Utvecklings AB.
-# Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings
-# AB. All Rights Reserved.''
-#
-# $Id$
-#
-include $(ERL_TOP)/make/target.mk
-include $(ERL_TOP)/make/$(TARGET)/otp.mk
-
-MODULES = \
- docb_SUITE
-
-ERL_FILES= $(MODULES:%=%.erl)
-
-TARGET_FILES= $(MODULES:%=$(EBIN)/%.$(EMULATOR))
-INSTALL_PROGS= $(TARGET_FILES)
-
-EMAKEFILE=Emakefile
-
-SPEC_FILES=
-
-# ----------------------------------------------------
-# Release directory specification
-# ----------------------------------------------------
-RELSYSDIR = $(RELEASE_PATH)/docb_test
-
-# ----------------------------------------------------
-# FLAGS
-# ----------------------------------------------------
-ERL_MAKE_FLAGS +=
-ERL_COMPILE_FLAGS += -I$(ERL_TOP)/lib/test_server/include
-
-EBIN = .
-
-# ----------------------------------------------------
-# Targets
-# ----------------------------------------------------
-.PHONY: make_emakefile
-
-make_emakefile:
- $(ERL_TOP)/make/make_emakefile $(ERL_COMPILE_FLAGS) -o$(EBIN) $(MODULES)\
- > $(EMAKEFILE)
-
-tests debug opt: make_emakefile
- erl $(ERL_MAKE_FLAGS) -make
-
-clean:
- rm -f $(EMAKEFILE)
- rm -f $(TARGET_FILES)
- rm -f core
-
-docs:
-
-# ----------------------------------------------------
-# Release Target
-# ----------------------------------------------------
-include $(ERL_TOP)/make/otp_release_targets.mk
-
-release_spec: opt
-
-release_tests_spec: make_emakefile
- $(INSTALL_DIR) $(RELSYSDIR)
- $(INSTALL_DATA) $(SPEC_FILES) docb.cover $(EMAKEFILE) $(ERL_FILES) $(RELSYSDIR)
- chmod -R u+w $(RELSYSDIR)
- @tar cf - *_SUITE_data | (cd $(RELSYSDIR); tar xf -)
-
-release_docs_spec:
-
-
diff --git a/lib/docbuilder/test/docb.cover b/lib/docbuilder/test/docb.cover
deleted file mode 100644
index 80bab6eba7..0000000000
--- a/lib/docbuilder/test/docb.cover
+++ /dev/null
@@ -1,2 +0,0 @@
-{incl_app,docbuilder,details}
-
diff --git a/lib/docbuilder/test/docb_SUITE_data/cdata_problem.xml b/lib/docbuilder/test/docb_SUITE_data/cdata_problem.xml
deleted file mode 100755
index b7f6f5376e..0000000000
--- a/lib/docbuilder/test/docb_SUITE_data/cdata_problem.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<?xml version="1.0" encoding="latin1" ?>
-<!DOCTYPE chapter SYSTEM "chapter.dtd">
-<chapter>
- <header>
- <title>�Docbook&ouml; bug</title>
- <prepared>Matthias Lang</prepared>
-<docno></docno>
-<date>2008-03-31</date>
- <rev>1.0</rev>
- </header>
-
-<section><title>This is a title</title>
- <code><![CDATA[
- This works
- ]]></code>
-
- <code><![CDATA[
- This does not
- ]]> </code>
-</section>
-</chapter>
-
diff --git a/lib/docbuilder/vsn.mk b/lib/docbuilder/vsn.mk
deleted file mode 100644
index 6df438a537..0000000000
--- a/lib/docbuilder/vsn.mk
+++ /dev/null
@@ -1 +0,0 @@
-DOCB_VSN = 0.9.8.11
diff --git a/lib/docbuilder/xsd/application.xsd b/lib/docbuilder/xsd/application.xsd
deleted file mode 100755
index eb666cb6c7..0000000000
--- a/lib/docbuilder/xsd/application.xsd
+++ /dev/null
@@ -1,31 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified">
- <xs:include schemaLocation="common.xsd"/>
- <xs:include schemaLocation="common.header.xsd"/>
- <xs:element name="application">
- <xs:complexType>
- <xs:sequence>
- <xs:element ref="header"/>
- <xs:element minOccurs="0" ref="description"/>
- <xs:element maxOccurs="unbounded" ref="include"/>
- </xs:sequence>
- </xs:complexType>
- </xs:element>
- <xs:element name="description">
- <xs:complexType>
- <xs:choice minOccurs="0" maxOccurs="unbounded">
- <xs:element ref="block"/>
- <xs:element ref="quote"/>
- <xs:element ref="br"/>
- <xs:element ref="marker"/>
- <xs:element ref="warning"/>
- <xs:element ref="note"/>
- </xs:choice>
- </xs:complexType>
- </xs:element>
- <xs:element name="include">
- <xs:complexType>
- <xs:attribute name="file" use="required"/>
- </xs:complexType>
- </xs:element>
-</xs:schema>
diff --git a/lib/docbuilder/xsd/appref.xsd b/lib/docbuilder/xsd/appref.xsd
deleted file mode 100755
index b63839e494..0000000000
--- a/lib/docbuilder/xsd/appref.xsd
+++ /dev/null
@@ -1,27 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified">
- <xs:include schemaLocation="common.refs.xsd"/>
- <!-- Structure -->
- <xs:element name="appref">
- <xs:complexType>
- <xs:sequence>
- <xs:element ref="header"/>
- <xs:element ref="app"/>
- <xs:element ref="appsummary"/>
- <xs:element ref="description"/>
- <xs:choice minOccurs="0" maxOccurs="unbounded">
- <xs:element ref="section"/>
- <xs:element ref="funcs"/>
- </xs:choice>
- <xs:element ref="authors"/>
- </xs:sequence>
- </xs:complexType>
- </xs:element>
- <xs:element name="app" type="xs:string"/>
- <xs:element name="appsummary" type="xs:string"/>
- <!--
- `name' is used in common.refs.dtd and must therefore
- be defined in each *ref. dtd
- -->
- <xs:element name="name" type="xs:string"/>
-</xs:schema>
diff --git a/lib/docbuilder/xsd/book.xsd b/lib/docbuilder/xsd/book.xsd
deleted file mode 100755
index b47962263a..0000000000
--- a/lib/docbuilder/xsd/book.xsd
+++ /dev/null
@@ -1,292 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified">
- <xs:include schemaLocation="common.xsd"/>
- <xs:include schemaLocation="common.table.xsd"/>
- <xs:element name="book">
- <xs:complexType>
- <xs:sequence>
- <xs:element ref="header"/>
- <xs:element minOccurs="0" ref="insidecover"/>
- <xs:element ref="pagetext"/>
- <xs:element ref="preamble"/>
- <xs:choice maxOccurs="unbounded">
- <xs:element ref="applications"/>
- <xs:element ref="parts"/>
- <xs:element ref="headline"/>
- <xs:element ref="pagetext"/>
- </xs:choice>
- <xs:sequence>
- <xs:element minOccurs="0" ref="listoffigures"/>
- <xs:element minOccurs="0" ref="listoftables"/>
- <xs:element minOccurs="0" ref="listofterms"/>
- <xs:element minOccurs="0" ref="bibliography"/>
- <xs:element minOccurs="0" ref="index"/>
- </xs:sequence>
- </xs:sequence>
- </xs:complexType>
- </xs:element>
- <xs:element name="header">
- <xs:complexType>
- <xs:sequence>
- <xs:element ref="title"/>
- <xs:element ref="prepared"/>
- <xs:element minOccurs="0" ref="responsible"/>
- <xs:element ref="docno"/>
- <xs:element minOccurs="0" ref="approved"/>
- <xs:element minOccurs="0" ref="checked"/>
- <xs:element ref="date"/>
- <xs:element ref="rev"/>
- <xs:element minOccurs="0" ref="file"/>
- <xs:element minOccurs="0" ref="abbreviation"/>
- </xs:sequence>
- <xs:attribute name="titlestyle" default="normal">
- <xs:simpleType>
- <xs:restriction base="xs:token">
- <xs:enumeration value="special"/>
- <xs:enumeration value="normal"/>
- </xs:restriction>
- </xs:simpleType>
- </xs:attribute>
- </xs:complexType>
- </xs:element>
- <xs:element name="title">
- <xs:complexType mixed="true">
- <xs:sequence>
- <xs:element minOccurs="0" maxOccurs="unbounded" ref="br"/>
- </xs:sequence>
- </xs:complexType>
- </xs:element>
- <xs:element name="prepared">
- <xs:complexType mixed="true">
- <xs:sequence>
- <xs:element minOccurs="0" maxOccurs="unbounded" ref="br"/>
- </xs:sequence>
- </xs:complexType>
- </xs:element>
- <xs:element name="responsible">
- <xs:complexType mixed="true">
- <xs:sequence>
- <xs:element minOccurs="0" maxOccurs="unbounded" ref="br"/>
- </xs:sequence>
- </xs:complexType>
- </xs:element>
- <xs:element name="docno">
- <xs:complexType mixed="true">
- <xs:sequence>
- <xs:element minOccurs="0" maxOccurs="unbounded" ref="br"/>
- </xs:sequence>
- </xs:complexType>
- </xs:element>
- <xs:element name="approved">
- <xs:complexType mixed="true">
- <xs:sequence>
- <xs:element minOccurs="0" maxOccurs="unbounded" ref="br"/>
- </xs:sequence>
- </xs:complexType>
- </xs:element>
- <xs:element name="checked">
- <xs:complexType mixed="true">
- <xs:sequence>
- <xs:element minOccurs="0" maxOccurs="unbounded" ref="br"/>
- </xs:sequence>
- </xs:complexType>
- </xs:element>
- <xs:element name="date">
- <xs:complexType mixed="true">
- <xs:sequence>
- <xs:element minOccurs="0" maxOccurs="unbounded" ref="br"/>
- </xs:sequence>
- </xs:complexType>
- </xs:element>
- <xs:element name="rev">
- <xs:complexType mixed="true">
- <xs:sequence>
- <xs:element minOccurs="0" maxOccurs="unbounded" ref="br"/>
- </xs:sequence>
- </xs:complexType>
- </xs:element>
- <xs:element name="file">
- <xs:complexType mixed="true">
- <xs:sequence>
- <xs:element minOccurs="0" maxOccurs="unbounded" ref="br"/>
- </xs:sequence>
- </xs:complexType>
- </xs:element>
- <xs:element name="abbreviation">
- <xs:complexType mixed="true">
- <xs:sequence>
- <xs:element minOccurs="0" maxOccurs="unbounded" ref="br"/>
- </xs:sequence>
- </xs:complexType>
- </xs:element>
- <xs:element name="pagetext" type="xs:string"/>
- <xs:element name="preamble">
- <xs:complexType>
- <xs:sequence>
- <xs:element minOccurs="0" ref="preface"/>
- <xs:element minOccurs="0" ref="contents"/>
- </xs:sequence>
- </xs:complexType>
- </xs:element>
- <xs:element name="preface">
- <xs:complexType>
- <xs:sequence>
- <xs:element minOccurs="0" ref="title"/>
- <xs:choice minOccurs="0" maxOccurs="unbounded">
- <xs:element ref="block"/>
- <xs:element ref="quote"/>
- <xs:element ref="br"/>
- <xs:element ref="marker"/>
- <xs:element ref="warning"/>
- <xs:element ref="note"/>
- <xs:element ref="table"/>
- </xs:choice>
- </xs:sequence>
- </xs:complexType>
- </xs:element>
- <xs:element name="insidecover">
- <xs:complexType mixed="true">
- <xs:choice minOccurs="0" maxOccurs="unbounded">
- <xs:element ref="br"/>
- <xs:element ref="theheader"/>
- <xs:element ref="vfill"/>
- <xs:element ref="tt"/>
- <xs:element ref="bold"/>
- <xs:element ref="include"/>
- </xs:choice>
- </xs:complexType>
- </xs:element>
- <xs:element name="tt">
- <xs:complexType mixed="true">
- <xs:choice minOccurs="0" maxOccurs="unbounded">
- <xs:element ref="br"/>
- <xs:element ref="theheader"/>
- <xs:element ref="vfill"/>
- </xs:choice>
- </xs:complexType>
- </xs:element>
- <xs:element name="bold">
- <xs:complexType mixed="true">
- <xs:choice minOccurs="0" maxOccurs="unbounded">
- <xs:element ref="br"/>
- <xs:element ref="theheader"/>
- <xs:element ref="vfill"/>
- </xs:choice>
- </xs:complexType>
- </xs:element>
- <xs:element name="vfill">
- <xs:complexType/>
- </xs:element>
- <xs:element name="theheader">
- <xs:complexType>
- <xs:attribute name="tag" default="none">
- <xs:simpleType>
- <xs:restriction base="xs:token">
- <xs:enumeration value="title"/>
- <xs:enumeration value="prepared"/>
- <xs:enumeration value="responsible"/>
- <xs:enumeration value="docno"/>
- <xs:enumeration value="approved"/>
- <xs:enumeration value="checked"/>
- <xs:enumeration value="date"/>
- <xs:enumeration value="rev"/>
- <xs:enumeration value="file"/>
- <xs:enumeration value="abbreviation"/>
- <xs:enumeration value="none"/>
- </xs:restriction>
- </xs:simpleType>
- </xs:attribute>
- </xs:complexType>
- </xs:element>
- <xs:element name="applications">
- <xs:complexType>
- <xs:sequence>
- <xs:element minOccurs="0" maxOccurs="unbounded" ref="include"/>
- </xs:sequence>
- </xs:complexType>
- </xs:element>
- <xs:element name="parts">
- <xs:complexType>
- <xs:sequence>
- <xs:element minOccurs="0" ref="title"/>
- <xs:element minOccurs="0" ref="description"/>
- <xs:choice minOccurs="0" maxOccurs="unbounded">
- <xs:element ref="include"/>
- <xs:element ref="onepart"/>
- </xs:choice>
- </xs:sequence>
- <xs:attribute name="lift" default="no">
- <xs:simpleType>
- <xs:restriction base="xs:token">
- <xs:enumeration value="yes"/>
- <xs:enumeration value="no"/>
- </xs:restriction>
- </xs:simpleType>
- </xs:attribute>
- </xs:complexType>
- </xs:element>
- <xs:element name="headline" type="xs:string"/>
- <xs:element name="index">
- <xs:complexType/>
- </xs:element>
- <xs:element name="listoffigures">
- <xs:complexType/>
- </xs:element>
- <xs:element name="listoftables">
- <xs:complexType/>
- </xs:element>
- <xs:element name="listofterms">
- <xs:complexType/>
- </xs:element>
- <xs:element name="bibliography">
- <xs:complexType/>
- </xs:element>
- <xs:element name="contents">
- <xs:complexType>
- <xs:attribute name="level" default="2">
- <xs:simpleType>
- <xs:restriction base="xs:token">
- <xs:enumeration value="0"/>
- <xs:enumeration value="1"/>
- <xs:enumeration value="2"/>
- <xs:enumeration value="3"/>
- </xs:restriction>
- </xs:simpleType>
- </xs:attribute>
- </xs:complexType>
- </xs:element>
- <xs:element name="onepart">
- <xs:complexType>
- <xs:sequence>
- <xs:element minOccurs="0" ref="title"/>
- <xs:element minOccurs="0" ref="description"/>
- <xs:element maxOccurs="unbounded" ref="include"/>
- </xs:sequence>
- <xs:attribute name="lift" default="no">
- <xs:simpleType>
- <xs:restriction base="xs:token">
- <xs:enumeration value="yes"/>
- <xs:enumeration value="no"/>
- </xs:restriction>
- </xs:simpleType>
- </xs:attribute>
- </xs:complexType>
- </xs:element>
- <xs:element name="description">
- <xs:complexType>
- <xs:choice minOccurs="0" maxOccurs="unbounded">
- <xs:element ref="block"/>
- <xs:element ref="quote"/>
- <xs:element ref="br"/>
- <xs:element ref="marker"/>
- <xs:element ref="warning"/>
- <xs:element ref="note"/>
- </xs:choice>
- </xs:complexType>
- </xs:element>
- <xs:element name="include">
- <xs:complexType>
- <xs:attribute name="file" use="required"/>
- </xs:complexType>
- </xs:element>
-</xs:schema>
diff --git a/lib/docbuilder/xsd/chapter.xsd b/lib/docbuilder/xsd/chapter.xsd
deleted file mode 100755
index 4d89baa988..0000000000
--- a/lib/docbuilder/xsd/chapter.xsd
+++ /dev/null
@@ -1,45 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified">
- <xs:include schemaLocation="common.xsd"/>
- <xs:include schemaLocation="common.header.xsd"/>
- <xs:include schemaLocation="common.table.xsd"/>
- <xs:include schemaLocation="common.image.xsd"/>
- <!-- Structure -->
- <xs:element name="chapter">
- <xs:complexType>
- <xs:sequence>
- <xs:element ref="header"/>
- <xs:choice minOccurs="0" maxOccurs="unbounded">
- <xs:element ref="block"/>
- <xs:element ref="quote"/>
- <xs:element ref="warning"/>
- <xs:element ref="note"/>
- <xs:element ref="br"/>
- <xs:element ref="image"/>
- <xs:element ref="marker"/>
- <xs:element ref="table"/>
- </xs:choice>
- <xs:element maxOccurs="unbounded" ref="section"/>
- </xs:sequence>
- </xs:complexType>
- </xs:element>
- <xs:element name="section">
- <xs:complexType>
- <xs:sequence>
- <xs:element minOccurs="0" maxOccurs="unbounded" ref="marker"/>
- <xs:element ref="title"/>
- <xs:choice minOccurs="0" maxOccurs="unbounded">
- <xs:element ref="block"/>
- <xs:element ref="quote"/>
- <xs:element ref="warning"/>
- <xs:element ref="note"/>
- <xs:element ref="br"/>
- <xs:element ref="image"/>
- <xs:element ref="marker"/>
- <xs:element ref="table"/>
- <xs:element ref="section"/>
- </xs:choice>
- </xs:sequence>
- </xs:complexType>
- </xs:element>
-</xs:schema>
diff --git a/lib/docbuilder/xsd/common.entities.xsd b/lib/docbuilder/xsd/common.entities.xsd
deleted file mode 100755
index 52a5d35179..0000000000
--- a/lib/docbuilder/xsd/common.entities.xsd
+++ /dev/null
@@ -1,2 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified"/>
diff --git a/lib/docbuilder/xsd/common.header.xsd b/lib/docbuilder/xsd/common.header.xsd
deleted file mode 100755
index bfee4b8bb4..0000000000
--- a/lib/docbuilder/xsd/common.header.xsd
+++ /dev/null
@@ -1,29 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified">
- <xs:element name="header">
- <xs:complexType>
- <xs:sequence>
- <xs:element ref="title"/>
- <xs:element minOccurs="0" ref="shorttitle"/>
- <xs:element ref="prepared"/>
- <xs:element minOccurs="0" ref="responsible"/>
- <xs:element ref="docno"/>
- <xs:element minOccurs="0" ref="approved"/>
- <xs:element minOccurs="0" ref="checked"/>
- <xs:element ref="date"/>
- <xs:element ref="rev"/>
- <xs:element minOccurs="0" ref="file"/>
- </xs:sequence>
- </xs:complexType>
- </xs:element>
- <xs:element name="title" type="xs:string"/>
- <xs:element name="shorttitle" type="xs:string"/>
- <xs:element name="prepared" type="xs:string"/>
- <xs:element name="responsible" type="xs:string"/>
- <xs:element name="docno" type="xs:string"/>
- <xs:element name="approved" type="xs:string"/>
- <xs:element name="checked" type="xs:string"/>
- <xs:element name="date" type="xs:string"/>
- <xs:element name="rev" type="xs:string"/>
- <xs:element name="file" type="xs:string"/>
-</xs:schema>
diff --git a/lib/docbuilder/xsd/common.image.xsd b/lib/docbuilder/xsd/common.image.xsd
deleted file mode 100755
index 17054eb23c..0000000000
--- a/lib/docbuilder/xsd/common.image.xsd
+++ /dev/null
@@ -1,18 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified">
- <xs:element name="image">
- <xs:complexType>
- <xs:complexContent>
- <xs:extension base="icaption">
- <xs:attribute name="file" use="required"/>
- </xs:extension>
- </xs:complexContent>
- </xs:complexType>
- </xs:element>
- <xs:complexType name="icaption">
- <xs:sequence>
- <xs:element ref="icaption"/>
- </xs:sequence>
- </xs:complexType>
- <xs:element name="icaption" type="xs:string"/>
-</xs:schema>
diff --git a/lib/docbuilder/xsd/common.refs.xsd b/lib/docbuilder/xsd/common.refs.xsd
deleted file mode 100755
index 58b450669d..0000000000
--- a/lib/docbuilder/xsd/common.refs.xsd
+++ /dev/null
@@ -1,102 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--
- This file contains common stuff for the *ref.dtd files.
- Note that `name' is defined in each *ref.dtd.
--->
-<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified">
- <xs:include schemaLocation="common.xsd"/>
- <xs:include schemaLocation="common.header.xsd"/>
- <xs:element name="description">
- <xs:complexType>
- <xs:choice minOccurs="0" maxOccurs="unbounded">
- <xs:element ref="block"/>
- <xs:element ref="quote"/>
- <xs:element ref="br"/>
- <xs:element ref="marker"/>
- <xs:element ref="warning"/>
- <xs:element ref="note"/>
- </xs:choice>
- </xs:complexType>
- </xs:element>
- <xs:element name="funcs">
- <xs:complexType>
- <xs:sequence>
- <xs:element maxOccurs="unbounded" ref="func"/>
- </xs:sequence>
- </xs:complexType>
- </xs:element>
- <xs:element name="func">
- <xs:complexType>
- <xs:sequence>
- <xs:element maxOccurs="unbounded" ref="name"/>
- <xs:element ref="fsummary"/>
- <xs:element minOccurs="0" ref="type"/>
- <xs:element minOccurs="0" ref="desc"/>
- </xs:sequence>
- </xs:complexType>
- </xs:element>
- <!-- ELEMENT name is defined in each ref dtd -->
- <xs:element name="fsummary">
- <xs:complexType mixed="true">
- <xs:choice minOccurs="0" maxOccurs="unbounded">
- <xs:element ref="c"/>
- <xs:element ref="em"/>
- </xs:choice>
- </xs:complexType>
- </xs:element>
- <xs:element name="type">
- <xs:complexType>
- <xs:sequence maxOccurs="unbounded">
- <xs:element ref="v"/>
- <xs:element minOccurs="0" ref="d"/>
- </xs:sequence>
- </xs:complexType>
- </xs:element>
- <xs:element name="v" type="xs:string"/>
- <xs:element name="d">
- <xs:complexType mixed="true">
- <xs:choice minOccurs="0" maxOccurs="unbounded">
- <xs:element ref="c"/>
- <xs:element ref="em"/>
- </xs:choice>
- </xs:complexType>
- </xs:element>
- <xs:element name="desc">
- <xs:complexType>
- <xs:choice minOccurs="0" maxOccurs="unbounded">
- <xs:element ref="block"/>
- <xs:element ref="quote"/>
- <xs:element ref="br"/>
- <xs:element ref="marker"/>
- <xs:element ref="warning"/>
- <xs:element ref="note"/>
- </xs:choice>
- </xs:complexType>
- </xs:element>
- <xs:element name="authors">
- <xs:complexType>
- <xs:sequence maxOccurs="unbounded">
- <xs:element ref="aname"/>
- <xs:element ref="email"/>
- </xs:sequence>
- </xs:complexType>
- </xs:element>
- <xs:element name="aname" type="xs:string"/>
- <xs:element name="email" type="xs:string"/>
- <xs:element name="section">
- <xs:complexType>
- <xs:sequence>
- <xs:element minOccurs="0" maxOccurs="unbounded" ref="marker"/>
- <xs:element ref="title"/>
- <xs:choice minOccurs="0" maxOccurs="unbounded">
- <xs:element ref="block"/>
- <xs:element ref="quote"/>
- <xs:element ref="br"/>
- <xs:element ref="marker"/>
- <xs:element ref="warning"/>
- <xs:element ref="note"/>
- </xs:choice>
- </xs:sequence>
- </xs:complexType>
- </xs:element>
-</xs:schema>
diff --git a/lib/docbuilder/xsd/common.table.xsd b/lib/docbuilder/xsd/common.table.xsd
deleted file mode 100755
index cf63df4317..0000000000
--- a/lib/docbuilder/xsd/common.table.xsd
+++ /dev/null
@@ -1,42 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified">
- <xs:element name="table">
- <xs:complexType>
- <xs:sequence>
- <xs:element maxOccurs="unbounded" ref="row"/>
- <xs:element ref="tcaption"/>
- </xs:sequence>
- </xs:complexType>
- </xs:element>
- <xs:element name="row">
- <xs:complexType>
- <xs:sequence>
- <xs:element maxOccurs="unbounded" ref="cell"/>
- </xs:sequence>
- </xs:complexType>
- </xs:element>
- <xs:element name="cell">
- <xs:complexType mixed="true">
- <xs:group minOccurs="0" maxOccurs="unbounded" ref="inline"/>
- <xs:attribute name="align" default="left">
- <xs:simpleType>
- <xs:restriction base="xs:token">
- <xs:enumeration value="left"/>
- <xs:enumeration value="center"/>
- <xs:enumeration value="right"/>
- </xs:restriction>
- </xs:simpleType>
- </xs:attribute>
- <xs:attribute name="valign" default="middle">
- <xs:simpleType>
- <xs:restriction base="xs:token">
- <xs:enumeration value="top"/>
- <xs:enumeration value="middle"/>
- <xs:enumeration value="bottom"/>
- </xs:restriction>
- </xs:simpleType>
- </xs:attribute>
- </xs:complexType>
- </xs:element>
- <xs:element name="tcaption" type="xs:string"/>
-</xs:schema>
diff --git a/lib/docbuilder/xsd/common.xsd b/lib/docbuilder/xsd/common.xsd
deleted file mode 100755
index 3d43390bd8..0000000000
--- a/lib/docbuilder/xsd/common.xsd
+++ /dev/null
@@ -1,212 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- This file contains common stuff for all dtds. -->
-<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified">
- <xs:element name="block" abstract="true"/>
- <xs:group name="inline">
- <xs:sequence>
- <xs:choice minOccurs="0">
- <xs:element ref="c"/>
- <xs:element ref="em"/>
- <xs:element ref="term"/>
- <xs:element ref="cite"/>
- <xs:element ref="br"/>
- <xs:element ref="path"/>
- <xs:element ref="seealso"/>
- <xs:element ref="url"/>
- <xs:element ref="marker"/>
- </xs:choice>
- </xs:sequence>
- </xs:group>
- <!-- XXX -->
- <xs:element name="p" substitutionGroup="block">
- <xs:complexType mixed="true">
- <xs:group minOccurs="0" maxOccurs="unbounded" ref="inline"/>
- </xs:complexType>
- </xs:element>
- <xs:element name="pre" substitutionGroup="block">
- <xs:complexType mixed="true">
- <xs:choice minOccurs="0" maxOccurs="unbounded">
- <xs:element ref="seealso"/>
- <xs:element ref="url"/>
- <xs:element ref="input"/>
- </xs:choice>
- </xs:complexType>
- </xs:element>
- <xs:element name="input">
- <xs:complexType mixed="true">
- <xs:choice minOccurs="0" maxOccurs="unbounded">
- <xs:element ref="seealso"/>
- <xs:element ref="url"/>
- </xs:choice>
- </xs:complexType>
- </xs:element>
- <xs:element name="code" substitutionGroup="block">
- <xs:complexType mixed="true">
- <xs:attribute name="type" default="none">
- <xs:simpleType>
- <xs:restriction base="xs:token">
- <xs:enumeration value="erl"/>
- <xs:enumeration value="c"/>
- <xs:enumeration value="none"/>
- </xs:restriction>
- </xs:simpleType>
- </xs:attribute>
- </xs:complexType>
- </xs:element>
- <xs:element name="quote">
- <xs:complexType>
- <xs:sequence>
- <xs:element minOccurs="0" maxOccurs="unbounded" ref="p"/>
- </xs:sequence>
- </xs:complexType>
- </xs:element>
- <xs:element name="warning">
- <xs:complexType>
- <xs:choice minOccurs="0" maxOccurs="unbounded">
- <xs:element ref="block"/>
- <xs:element ref="quote"/>
- <xs:element ref="br"/>
- <xs:element ref="marker"/>
- </xs:choice>
- </xs:complexType>
- </xs:element>
- <xs:element name="note">
- <xs:complexType>
- <xs:choice minOccurs="0" maxOccurs="unbounded">
- <xs:element ref="block"/>
- <xs:element ref="quote"/>
- <xs:element ref="br"/>
- <xs:element ref="marker"/>
- </xs:choice>
- </xs:complexType>
- </xs:element>
- <xs:element name="c" type="xs:string"/>
- <xs:element name="em">
- <xs:complexType mixed="true">
- <xs:sequence>
- <xs:element minOccurs="0" maxOccurs="unbounded" ref="c"/>
- </xs:sequence>
- </xs:complexType>
- </xs:element>
- <!-- XXX -->
- <xs:element name="term">
- <xs:complexType>
- <xs:sequence>
- <xs:element minOccurs="0" ref="termdef"/>
- </xs:sequence>
- <xs:attribute name="id" use="required"/>
- </xs:complexType>
- </xs:element>
- <xs:element name="termdef" type="xs:string"/>
- <xs:element name="cite">
- <xs:complexType>
- <xs:sequence>
- <xs:element minOccurs="0" ref="citedef"/>
- </xs:sequence>
- <xs:attribute name="id" use="required"/>
- </xs:complexType>
- </xs:element>
- <xs:element name="citedef">
- <xs:complexType>
- <xs:sequence>
- <xs:element ref="ctitle"/>
- <xs:element ref="cauthor"/>
- <xs:element ref="chowpublished"/>
- </xs:sequence>
- </xs:complexType>
- </xs:element>
- <xs:element name="ctitle" type="xs:string"/>
- <xs:element name="cauthor" type="xs:string"/>
- <xs:element name="chowpublished" type="xs:string"/>
- <!-- XXX -->
- <xs:element name="br">
- <xs:complexType/>
- </xs:element>
- <!-- Path -->
- <xs:element name="path">
- <xs:complexType mixed="true">
- <xs:attribute name="unix" default=""/>
- <xs:attribute name="windows" default=""/>
- </xs:complexType>
- </xs:element>
- <!-- List -->
- <xs:element name="list" substitutionGroup="block">
- <xs:complexType>
- <xs:sequence>
- <xs:element maxOccurs="unbounded" ref="item"/>
- </xs:sequence>
- <xs:attribute name="type" default="bulleted">
- <xs:simpleType>
- <xs:restriction base="xs:token">
- <xs:enumeration value="ordered"/>
- <xs:enumeration value="bulleted"/>
- </xs:restriction>
- </xs:simpleType>
- </xs:attribute>
- </xs:complexType>
- </xs:element>
- <xs:element name="taglist" substitutionGroup="block">
- <xs:complexType>
- <xs:sequence maxOccurs="unbounded">
- <xs:element ref="tag"/>
- <xs:element ref="item"/>
- </xs:sequence>
- </xs:complexType>
- </xs:element>
- <xs:element name="tag">
- <xs:complexType mixed="true">
- <xs:choice minOccurs="0" maxOccurs="unbounded">
- <xs:element ref="c"/>
- <xs:element ref="em"/>
- <xs:element ref="seealso"/>
- <xs:element ref="url"/>
- </xs:choice>
- </xs:complexType>
- </xs:element>
- <xs:element name="item">
- <xs:complexType mixed="true">
- <xs:choice minOccurs="0" maxOccurs="unbounded">
- <xs:group ref="inline"/>
- <xs:element ref="block"/>
- </xs:choice>
- </xs:complexType>
- </xs:element>
- <!-- References -->
- <xs:element name="seealso">
- <xs:complexType mixed="true">
- <xs:attribute name="marker" use="required"/>
- </xs:complexType>
- </xs:element>
- <xs:element name="url">
- <xs:complexType mixed="true">
- <xs:attribute name="href" use="required"/>
- </xs:complexType>
- </xs:element>
- <xs:element name="marker">
- <xs:complexType>
- <xs:attribute name="id" use="required"/>
- </xs:complexType>
- </xs:element>
- <!-- CodeInclude -->
- <xs:element name="codeinclude" substitutionGroup="block">
- <xs:complexType>
- <xs:attribute name="file" use="required"/>
- <xs:attribute name="tag" default=""/>
- <xs:attribute name="type" default="none">
- <xs:simpleType>
- <xs:restriction base="xs:token">
- <xs:enumeration value="erl"/>
- <xs:enumeration value="c"/>
- <xs:enumeration value="none"/>
- </xs:restriction>
- </xs:simpleType>
- </xs:attribute>
- </xs:complexType>
- </xs:element>
- <!-- ErlEval -->
- <xs:element name="erleval" substitutionGroup="block">
- <xs:complexType>
- <xs:attribute name="expr" use="required"/>
- </xs:complexType>
- </xs:element>
-</xs:schema>
diff --git a/lib/docbuilder/xsd/comref.xsd b/lib/docbuilder/xsd/comref.xsd
deleted file mode 100755
index 61df4dd848..0000000000
--- a/lib/docbuilder/xsd/comref.xsd
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified">
- <xs:include schemaLocation="common.refs.xsd"/>
- <xs:element name="comref">
- <xs:complexType>
- <xs:sequence>
- <xs:element ref="header"/>
- <xs:element ref="com"/>
- <xs:element ref="comsummary"/>
- <xs:element ref="description"/>
- <xs:choice minOccurs="0" maxOccurs="unbounded">
- <xs:element ref="section"/>
- <xs:element ref="funcs"/>
- </xs:choice>
- <xs:element ref="authors"/>
- </xs:sequence>
- </xs:complexType>
- </xs:element>
- <xs:element name="com" type="xs:string"/>
- <xs:element name="comsummary" type="xs:string"/>
- <!--
- `name' is used in common.refs.dtd and must therefore
- be defined in each *ref. dtd
- -->
- <xs:element name="name" type="xs:string"/>
-</xs:schema>
diff --git a/lib/docbuilder/xsd/cref.xsd b/lib/docbuilder/xsd/cref.xsd
deleted file mode 100755
index f1cbeddfff..0000000000
--- a/lib/docbuilder/xsd/cref.xsd
+++ /dev/null
@@ -1,35 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified">
- <xs:include schemaLocation="common.refs.xsd"/>
- <xs:element name="cref">
- <xs:complexType>
- <xs:sequence>
- <xs:element ref="header"/>
- <xs:element ref="lib"/>
- <xs:element ref="libsummary"/>
- <xs:element ref="description"/>
- <xs:choice minOccurs="0" maxOccurs="unbounded">
- <xs:element ref="section"/>
- <xs:element ref="funcs"/>
- </xs:choice>
- <xs:element ref="authors"/>
- </xs:sequence>
- </xs:complexType>
- </xs:element>
- <xs:element name="lib" type="xs:string"/>
- <xs:element name="libsummary" type="xs:string"/>
- <!--
- `name' is used in common.refs.dtd and must therefore
- be defined in each *ref. dtd
- -->
- <xs:element name="name">
- <xs:complexType>
- <xs:sequence>
- <xs:element ref="ret"/>
- <xs:element ref="nametext"/>
- </xs:sequence>
- </xs:complexType>
- </xs:element>
- <xs:element name="ret" type="xs:string"/>
- <xs:element name="nametext" type="xs:string"/>
-</xs:schema>
diff --git a/lib/docbuilder/xsd/erlref.xsd b/lib/docbuilder/xsd/erlref.xsd
deleted file mode 100755
index f6011b7bea..0000000000
--- a/lib/docbuilder/xsd/erlref.xsd
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified">
- <xs:include schemaLocation="common.refs.xsd"/>
- <xs:element name="erlref">
- <xs:complexType>
- <xs:sequence>
- <xs:element ref="header"/>
- <xs:element ref="module"/>
- <xs:element ref="modulesummary"/>
- <xs:element ref="description"/>
- <xs:choice minOccurs="0" maxOccurs="unbounded">
- <xs:element ref="section"/>
- <xs:element ref="funcs"/>
- </xs:choice>
- <xs:element ref="authors"/>
- </xs:sequence>
- </xs:complexType>
- </xs:element>
- <xs:element name="module" type="xs:string"/>
- <xs:element name="modulesummary" type="xs:string"/>
- <!--
- `name' is used in common.refs.dtd and must therefore
- be defined in each *ref. dtd
- -->
- <xs:element name="name" type="xs:string"/>
-</xs:schema>
diff --git a/lib/docbuilder/xsd/fascicules.xsd b/lib/docbuilder/xsd/fascicules.xsd
deleted file mode 100755
index bfdb5bd604..0000000000
--- a/lib/docbuilder/xsd/fascicules.xsd
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Structure -->
-<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified">
- <xs:element name="fascicules">
- <xs:complexType>
- <xs:sequence>
- <xs:element maxOccurs="unbounded" ref="fascicule"/>
- </xs:sequence>
- </xs:complexType>
- </xs:element>
- <xs:element name="fascicule">
- <xs:complexType mixed="true">
- <xs:attribute name="file" use="required"/>
- <xs:attribute name="href" use="required"/>
- <xs:attribute name="entry" default="no">
- <xs:simpleType>
- <xs:restriction base="xs:token">
- <xs:enumeration value="yes"/>
- <xs:enumeration value="no"/>
- </xs:restriction>
- </xs:simpleType>
- </xs:attribute>
- </xs:complexType>
- </xs:element>
-</xs:schema>
diff --git a/lib/docbuilder/xsd/fileref.xsd b/lib/docbuilder/xsd/fileref.xsd
deleted file mode 100755
index 8038f2115f..0000000000
--- a/lib/docbuilder/xsd/fileref.xsd
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified">
- <xs:include schemaLocation="common.refs.xsd"/>
- <xs:element name="fileref">
- <xs:complexType>
- <xs:sequence>
- <xs:element ref="header"/>
- <xs:element ref="file"/>
- <xs:element ref="filesummary"/>
- <xs:element ref="description"/>
- <xs:choice minOccurs="0" maxOccurs="unbounded">
- <xs:element ref="section"/>
- <xs:element ref="funcs"/>
- </xs:choice>
- <xs:element ref="authors"/>
- </xs:sequence>
- </xs:complexType>
- </xs:element>
- <!-- Note: ELEMENT file is already defined -->
- <xs:element name="filesummary" type="xs:string"/>
- <!--
- `name' is used in common.refs.dtd and must therefore
- be defined in each *ref. dtd
- -->
- <xs:element name="name" type="xs:string"/>
-</xs:schema>
diff --git a/lib/docbuilder/xsd/part.xsd b/lib/docbuilder/xsd/part.xsd
deleted file mode 100755
index 30d6ec0120..0000000000
--- a/lib/docbuilder/xsd/part.xsd
+++ /dev/null
@@ -1,31 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified">
- <xs:include schemaLocation="common.xsd"/>
- <xs:include schemaLocation="common.header.xsd"/>
- <xs:element name="part">
- <xs:complexType>
- <xs:sequence>
- <xs:element ref="header"/>
- <xs:element minOccurs="0" ref="description"/>
- <xs:element maxOccurs="unbounded" ref="include"/>
- </xs:sequence>
- </xs:complexType>
- </xs:element>
- <xs:element name="description">
- <xs:complexType>
- <xs:choice minOccurs="0" maxOccurs="unbounded">
- <xs:element ref="block"/>
- <xs:element ref="quote"/>
- <xs:element ref="br"/>
- <xs:element ref="marker"/>
- <xs:element ref="warning"/>
- <xs:element ref="note"/>
- </xs:choice>
- </xs:complexType>
- </xs:element>
- <xs:element name="include">
- <xs:complexType>
- <xs:attribute name="file" use="required"/>
- </xs:complexType>
- </xs:element>
-</xs:schema>
diff --git a/lib/edoc/doc/Makefile b/lib/edoc/doc/Makefile
index c5f68b25d0..7a59809d9b 100644
--- a/lib/edoc/doc/Makefile
+++ b/lib/edoc/doc/Makefile
@@ -78,12 +78,3 @@ release_docs_spec: docs
release_spec:
-
-
-
-# ----------------------------------------------------
-# Include dependency
-# ----------------------------------------------------
-#-include make.dep
-
-
diff --git a/lib/edoc/doc/src/make.dep b/lib/edoc/doc/src/make.dep
deleted file mode 100644
index b46e36314f..0000000000
--- a/lib/edoc/doc/src/make.dep
+++ /dev/null
@@ -1,21 +0,0 @@
-# ----------------------------------------------------
-# >>>> Do not edit this file <<<<
-# This file was automaticly generated by
-# /home/otp/bin/docdepend
-# ----------------------------------------------------
-
-
-# ----------------------------------------------------
-# TeX files that the DVI file depend on
-# ----------------------------------------------------
-
-book.dvi: book.tex chapter.tex edoc.tex edoc_doclet.tex \
- edoc_extract.tex edoc_layout.tex edoc_lib.tex \
- edoc_run.tex part.tex ref_man.tex
-
-# ----------------------------------------------------
-# Source inlined when transforming from source to LaTeX
-# ----------------------------------------------------
-
-book.tex: ref_man.xml
-
diff --git a/lib/erl_docgen/Makefile b/lib/erl_docgen/Makefile
index 93a6353cac..68b41a1ff2 100644
--- a/lib/erl_docgen/Makefile
+++ b/lib/erl_docgen/Makefile
@@ -23,8 +23,7 @@ include $(ERL_TOP)/make/$(TARGET)/otp.mk
# Macros
#
-SUB_DIRECTORIES = src priv
-#doc/src
+SUB_DIRECTORIES = src priv doc/src
include vsn.mk
VSN = $(ERL_DOCGEN_VSN)
diff --git a/lib/docbuilder/doc/html/.gitignore b/lib/erl_docgen/doc/html/.gitignore
index e69de29bb2..e69de29bb2 100644
--- a/lib/docbuilder/doc/html/.gitignore
+++ b/lib/erl_docgen/doc/html/.gitignore
diff --git a/lib/docbuilder/doc/man3/.gitignore b/lib/erl_docgen/doc/man6/.gitignore
index e69de29bb2..e69de29bb2 100644
--- a/lib/docbuilder/doc/man3/.gitignore
+++ b/lib/erl_docgen/doc/man6/.gitignore
diff --git a/lib/docbuilder/doc/man6/.gitignore b/lib/erl_docgen/doc/pdf/.gitignore
index e69de29bb2..e69de29bb2 100644
--- a/lib/docbuilder/doc/man6/.gitignore
+++ b/lib/erl_docgen/doc/pdf/.gitignore
diff --git a/lib/docbuilder/doc/src/Makefile b/lib/erl_docgen/doc/src/Makefile
index ae34266844..a546d8da33 100644
--- a/lib/docbuilder/doc/src/Makefile
+++ b/lib/erl_docgen/doc/src/Makefile
@@ -1,21 +1,22 @@
#
# %CopyrightBegin%
-#
-# Copyright Ericsson AB 1997-2009. All Rights Reserved.
-#
+#
+# Copyright Ericsson AB 2011-2011. All Rights Reserved.
+#
# The contents of this file are subject to the Erlang Public License,
# Version 1.1, (the "License"); you may not use this file except in
# compliance with the License. You should have received a copy of the
# Erlang Public License along with this software. If not, it can be
# retrieved online at http://www.erlang.org/.
-#
+#
# Software distributed under the License is distributed on an "AS IS"
# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
# the License for the specific language governing rights and limitations
# under the License.
-#
+#
# %CopyrightEnd%
#
+#
include $(ERL_TOP)/make/target.mk
include $(ERL_TOP)/make/$(TARGET)/otp.mk
@@ -23,8 +24,8 @@ include $(ERL_TOP)/make/$(TARGET)/otp.mk
# Application version
# ----------------------------------------------------
include ../../vsn.mk
-VSN=$(DOCB_VSN)
-APPLICATION=docbuilder
+VSN=$(ERL_DOCGEN_VSN)
+APPLICATION=erl_docgen
# ----------------------------------------------------
# Release directory specification
@@ -35,45 +36,43 @@ RELSYSDIR = $(RELEASE_PATH)/lib/$(APPLICATION)-$(VSN)
# Target Specs
# ----------------------------------------------------
XML_APPLICATION_FILES = ref_man.xml
-XML_REF3_FILES = \
- docb_gen.xml \
- docb_transform.xml \
- docb_xml_check.xml
XML_REF6_FILES = \
- docbuilder_app.xml
+ erl_docgen_app.xml
+
+XML_PART_FILES = \
+ part.xml
-XML_PART_FILES = part.xml part_notes.xml
XML_CHAPTER_FILES = \
overview.xml \
user_guide_dtds.xml \
refman_dtds.xml \
- fasc_dtds.xml \
- header_tags.xml \
- block_tags.xml \
+ notes.xml \
inline_tags.xml \
+ header_tags.xml \
character_entities.xml \
- notes.xml
+ block_tags.xml
BOOK_FILES = book.xml
-GIF_FILES = \
- man.gif
+XML_FILES = $(BOOK_FILES) $(XML_APPLICATION_FILES) $(XML_REF6_FILES) \
+ $(XML_PART_FILES) $(XML_CHAPTER_FILES)
+
+TECHNICAL_DESCR_FILES =
+EXAMPLE_FILES = \
+ example.txt
-XML_FILES = \
- $(BOOK_FILES) $(XML_CHAPTER_FILES) \
- $(XML_PART_FILES) $(XML_REF3_FILES) $(XML_REF6_FILES) \
- $(XML_APPLICATION_FILES)
+GIF_FILES = \
+ man.gif
# ----------------------------------------------------
-HTML_FILES = \
- $(XML_APPLICATION_FILES:%.xml=$(HTMLDIR)/%.html) \
+HTML_FILES = $(XML_APPLICATION_FILES:%.xml=$(HTMLDIR)/%.html) \
+ $(XML_CHAPTER_FILES:%.xml=$(HTMLDIR)/%.html) \
$(XML_PART_FILES:%.xml=$(HTMLDIR)/%.html)
INFO_FILE = ../../info
-MAN3_FILES = $(XML_REF3_FILES:%.xml=$(MAN3DIR)/%.3)
MAN6_FILES = $(XML_REF6_FILES:%_app.xml=$(MAN6DIR)/%.6)
HTML_REF_MAN_FILE = $(HTMLDIR)/index.html
@@ -83,34 +82,40 @@ TOP_PDF_FILE = $(PDFDIR)/$(APPLICATION)-$(VSN).pdf
# ----------------------------------------------------
# FLAGS
# ----------------------------------------------------
+XML_FLAGS +=
DVIPS_FLAGS +=
# ----------------------------------------------------
# Targets
# ----------------------------------------------------
+docs: pdf html man
+
$(HTMLDIR)/%.gif: %.gif
$(INSTALL_DATA) $< $@
-docs: pdf html man
+$(HTMLDIR)/example.txt: example.txt
+ $(INSTALL_DATA) $< $@
$(TOP_PDF_FILE): $(XML_FILES)
pdf: $(TOP_PDF_FILE)
-html: gifs $(HTML_REF_MAN_FILE)
-
-man: $(MAN3_FILES) $(MAN6_FILES)
-
-gifs: $(GIF_FILES:%=$(HTMLDIR)/%)
-
-debug opt:
+html: gifs examples $(HTML_REF_MAN_FILE)
clean clean_docs:
rm -rf $(HTMLDIR)/*
- rm -f $(MAN3DIR)/*
rm -f $(MAN6DIR)/*
rm -f $(TOP_PDF_FILE) $(TOP_PDF_FILE:%.pdf=%.fo)
- rm -f errs core *~
+ rm -f errs core *~
+ rm -f $(JD_HTML) $(JD_PACK)
+
+man: $(MAN6_FILES)
+
+gifs: $(GIF_FILES:%=$(HTMLDIR)/%)
+
+examples: $(GIF_FILES:%=$(HTMLDIR)/%)
+
+debug opt:
# ----------------------------------------------------
# Release Target
@@ -124,9 +129,7 @@ release_docs_spec: docs
$(INSTALL_DATA) $(HTMLDIR)/* \
$(RELSYSDIR)/doc/html
$(INSTALL_DATA) $(INFO_FILE) $(RELSYSDIR)
- $(INSTALL_DIR) $(RELEASE_PATH)/man/man3
- $(INSTALL_DATA) $(MAN3DIR)/* $(RELEASE_PATH)/man/man3
$(INSTALL_DIR) $(RELEASE_PATH)/man/man6
- $(INSTALL_DATA) $(MAN6_FILES) $(RELEASE_PATH)/man/man6
+ $(INSTALL_DATA) $(MAN6DIR)/* $(RELEASE_PATH)/man/man6
release_spec:
diff --git a/lib/docbuilder/doc/src/block_tags.xml b/lib/erl_docgen/doc/src/block_tags.xml
index f5ba083f38..0900d7f008 100644
--- a/lib/docbuilder/doc/src/block_tags.xml
+++ b/lib/erl_docgen/doc/src/block_tags.xml
@@ -4,7 +4,7 @@
<chapter>
<header>
<copyright>
- <year>1997</year><year>2009</year>
+ <year>1997</year><year>2011</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -33,7 +33,7 @@
as a paragraph or a list.</p>
<p>The following subset of block tags are common for all DTDs in
- the DocBuilder DTD suite:
+ the OTP DTD suite:
<marker id="block_subset"></marker>
<seealso marker="#pTAG">&lt;p&gt;</seealso>,
<seealso marker="#preTAG">&lt;pre&gt;</seealso>,
@@ -81,7 +81,7 @@ sum([]) ->
</code>
<p>There is an attribute <c>type = "erl" | "c" | "none"</c>, but
- currently this attribute is ignored by DocBuilder. Default value
+ currently this attribute is ignored. Default value
is <c>"none"</c></p>
<note>
@@ -99,18 +99,18 @@ sum([]) ->
gives the file name and <c>tag</c> defines a string which
delimits the code snippet. Example:</p>
<pre>
-&lt;codeinclude file="gazonk" tag="%% Erlang example"/&gt;
+&lt;codeinclude file="example.txt" tag="%% Erlang example"/&gt;
</pre>
<p>results in:</p>
- <codeinclude file="gazonk" tag="%% Erlang example"/>
+ <codeinclude file="example.txt" tag="%% Erlang example"/>
- <p>provided there is a file named <c>gazonk</c> looking like this:
+ <p>provided there is a file named <c>examples.txt</c> looking like this:
</p>
<code>
...
%% Erlang example
--module(gazonk).
+-module(example).
start() ->
{error,"Pid required!"}.
@@ -125,7 +125,7 @@ start(Pid) ->
included.</p>
<p>There is also an attribute <c>type = "erl" | "c" | "none"</c>, but
- currently this attribute is ignored by DocBuilder. Default value
+ currently this attribute is ignored. Default value
is <c>"none"</c></p>
</section>
diff --git a/lib/erl_docgen/doc/src/book.xml b/lib/erl_docgen/doc/src/book.xml
index 9df5c39271..73bfb7916d 100644
--- a/lib/erl_docgen/doc/src/book.xml
+++ b/lib/erl_docgen/doc/src/book.xml
@@ -1,10 +1,10 @@
-<?xml version="1.0" encoding="latin1" ?>
+<?xml version="1.0" encoding="iso-8859-1" ?>
<!DOCTYPE book SYSTEM "book.dtd">
<book xmlns:xi="http://www.w3.org/2001/XInclude">
<header titlestyle="normal">
<copyright>
- <year>2004</year><year>2009</year>
+ <year>2004</year><year>2011</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -21,27 +21,26 @@
</legalnotice>
- <title>erl_docgen</title>
+ <title>Erl_Docgen</title>
<prepared>Lars Thorsen</prepared>
<docno></docno>
- <date>2009-11-10</date>
- <rev>0.1</rev>
+ <date>2011-11-10</date>
+ <rev>0.3</rev>
<file>book.xml</file>
</header>
- <insidecover>
- </insidecover>
<pagetext>erl_docgen</pagetext>
<preamble>
<contents level="2"></contents>
</preamble>
<parts lift="no">
+ <xi:include href="part.xml"/>
</parts>
<applications>
+ <xi:include href="ref_man.xml"/>
</applications>
<releasenotes>
<xi:include href="notes.xml"/>
</releasenotes>
- <listofterms></listofterms>
<index></index>
</book>
diff --git a/lib/docbuilder/doc/src/character_entities.xml b/lib/erl_docgen/doc/src/character_entities.xml
index 0a4ae17fb5..9f55b68d18 100644
--- a/lib/docbuilder/doc/src/character_entities.xml
+++ b/lib/erl_docgen/doc/src/character_entities.xml
@@ -32,7 +32,7 @@
<section>
<title>Added Latin 1</title>
- <p>The DocBuilder DTD suite uses the same character entities as
+ <p>The OTP DTD suite uses the same character entities as
defined in HTML 3.2
(<c>ISO 8879-1986//ENTITIES Added Latin 1//EN//HTML</c>). That is:
for an &amp; (ampersand), use the entity: <c>&amp;amp;</c>, for
diff --git a/lib/erl_docgen/doc/src/convert.howto b/lib/erl_docgen/doc/src/convert.howto
deleted file mode 100644
index 2c72de8c4c..0000000000
--- a/lib/erl_docgen/doc/src/convert.howto
+++ /dev/null
@@ -1,13 +0,0 @@
-
-- add xmlns:xi="http://www.w3.org/2001/XInclude" on top tag
- in files whith include directives
-
-- change <include file="notes"></include> <xi:include href="notes.xml"/>
-
-- change <image file="a"/> to <image file="a.gif"/>
-
-- remove chapers directly in the book and put them in the part instead
-
--change title to just the application name
-
-- fix codeinclude : xml --> xmlsrc \ No newline at end of file
diff --git a/lib/docbuilder/doc/src/docb_xml_check.xml b/lib/erl_docgen/doc/src/docgen_xml_check.xml
index eff4fc4342..58cf069d81 100644
--- a/lib/docbuilder/doc/src/docb_xml_check.xml
+++ b/lib/erl_docgen/doc/src/docgen_xml_check.xml
@@ -23,16 +23,16 @@
The Initial Developer of the Original Code is Ericsson AB.
</legalnotice>
- <title>docb_xml_check</title>
+ <title>docgen_xml_check</title>
<prepared></prepared>
<docno></docno>
<date></date>
<rev></rev>
</header>
- <module>docb_xml_check</module>
+ <module>docgen_xml_check</module>
<modulesummary>Validate XML documentation source code</modulesummary>
<description>
- <p><c>docb_xml_check</c> contains functions for validating XML
+ <p><c>docgen_xml_check</c> contains functions for validating XML
documentation source code.</p>
</description>
diff --git a/lib/erl_docgen/doc/src/erl_docgen.txt b/lib/erl_docgen/doc/src/erl_docgen.txt
deleted file mode 100644
index 14a4dc8e10..0000000000
--- a/lib/erl_docgen/doc/src/erl_docgen.txt
+++ /dev/null
@@ -1,6 +0,0 @@
-
-
-
-/home/otptest/bin/otp_wrap_ssh boddington /home/otptest/bin/otp_build_doc -rel r13b02 -view otptest_r13_daily_doc2 -csfile /usr/local/otp/config-specs/r13_dev.cs -insdir /ldisk/daily_build
-_
- \ No newline at end of file
diff --git a/lib/erl_docgen/doc/src/erl_docgen_app.xml b/lib/erl_docgen/doc/src/erl_docgen_app.xml
new file mode 100644
index 0000000000..25c473bb7e
--- /dev/null
+++ b/lib/erl_docgen/doc/src/erl_docgen_app.xml
@@ -0,0 +1,64 @@
+<?xml version="1.0" encoding="latin1" ?>
+<!DOCTYPE appref SYSTEM "appref.dtd">
+
+<appref>
+ <header>
+ <copyright>
+ <year>2011</year><year>2011</year>
+ <holder>Ericsson AB. All Rights Reserved.</holder>
+ </copyright>
+ <legalnotice>
+ The contents of this file are subject to the Erlang Public License,
+ Version 1.1, (the "License"); you may not use this file except in
+ compliance with the License. You should have received a copy of the
+ Erlang Public License along with this software. If not, it can be
+ retrieved online at http://www.erlang.org/.
+
+ Software distributed under the License is distributed on an "AS IS"
+ basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ the License for the specific language governing rights and limitations
+ under the License.
+
+ </legalnotice>
+
+ <title>erl_docgen</title>
+ <file>erl_docgen_app.xml</file>
+ </header>
+ <app>erl_docgen</app>
+ <appsummary>
+ The erl_docgen application is used to produce the OTP documentation.
+ </appsummary>
+
+ <description>
+ <p>
+ The application consists of the following parts
+ <taglist>
+ <tag>XSL</tag>
+ <item>
+ <p>
+ A number of XSL files that is used to transform the xml files to html, pdf or man pages.
+ </p>
+ </item>
+ <tag>DTDs</tag>
+ <item>
+ <p>
+ The DTDs used for the OTP documentation.
+ </p>
+ </item>
+ <tag>escripts</tag>
+ <item>
+ <p>
+ Some scripts that is used to produce xml files according to OTP DTDs from some different input.
+ </p>
+ </item>
+ <tag>misc</tag>
+ <item>
+ <p>
+ Erlang logo, javascripts and css stylesheets used in the documentation.
+ </p>
+ </item>
+ </taglist>
+ </p>
+ </description>
+
+</appref>
diff --git a/lib/docbuilder/doc/src/gazonk b/lib/erl_docgen/doc/src/example.txt
index 1cf0b8f7bc..ad86165391 100644
--- a/lib/docbuilder/doc/src/gazonk
+++ b/lib/erl_docgen/doc/src/example.txt
@@ -1,7 +1,7 @@
This example code is used in block_tags.xml.
%% Erlang example
--module(gazonk).
+-module(example).
start() ->
{error,"Pid required!"}.
diff --git a/lib/docbuilder/doc/src/fasc_dtds.xml b/lib/erl_docgen/doc/src/fasc_dtds.xml
index dec8189b55..dec8189b55 100644
--- a/lib/docbuilder/doc/src/fasc_dtds.xml
+++ b/lib/erl_docgen/doc/src/fasc_dtds.xml
diff --git a/lib/docbuilder/doc/src/fascicules.xml b/lib/erl_docgen/doc/src/fascicules.xml
index 1b9d6bc94d..1b9d6bc94d 100644
--- a/lib/docbuilder/doc/src/fascicules.xml
+++ b/lib/erl_docgen/doc/src/fascicules.xml
diff --git a/lib/docbuilder/doc/src/header_tags.xml b/lib/erl_docgen/doc/src/header_tags.xml
index b1456d679a..902bce4f68 100644
--- a/lib/docbuilder/doc/src/header_tags.xml
+++ b/lib/erl_docgen/doc/src/header_tags.xml
@@ -104,7 +104,7 @@
<section>
<title>&lt;shorttitle&gt;</title>
- <p>This optional tag is ignored by DocBuilder. It will likely be
+ <p>This optional tag is ignored. It will likely be
removed in the future.</p>
</section>
@@ -112,8 +112,7 @@
<marker id="preparedTAG"></marker>
<title>&lt;prepared&gt;</title>
- <p>This tag is intended for administrative use and is ignored by
- DocBuilder.</p>
+ <p>This tag is intended for administrative use and is ignored.</p>
</section>
<section>
@@ -121,7 +120,7 @@
<title>&lt;responsible&gt;</title>
<p>This optional tag is intended for administrative use and is
- ignored by DocBuilder.</p>
+ ignored.</p>
</section>
<section>
@@ -141,7 +140,7 @@
<title>&lt;approved&gt;</title>
<p>This optional tag is intended for administrative use and is
- ignored by DocBuilder.</p>
+ ignored.</p>
</section>
<section>
@@ -149,15 +148,14 @@
<title>&lt;checked&gt;</title>
<p>This optional tag is intended for administrative use and is
- ignored by DocBuilder.</p>
+ ignored.</p>
</section>
<section>
<marker id="dateTAG"></marker>
<title>&lt;date&gt;</title>
- <p>This tag is intended for administrative use and is ignored by
- DocBuilder.</p>
+ <p>This tag is intended for administrative use and is ignored.</p>
</section>
<section>
@@ -177,7 +175,7 @@
<title>&lt;file&gt;</title>
<p>This optional tag is intended for administrative use and is
- ignored by DocBuilder.</p>
+ ignored.</p>
</section>
</chapter>
diff --git a/lib/docbuilder/doc/src/inline_tags.xml b/lib/erl_docgen/doc/src/inline_tags.xml
index 5bcca54c05..9b27da659b 100644
--- a/lib/docbuilder/doc/src/inline_tags.xml
+++ b/lib/erl_docgen/doc/src/inline_tags.xml
@@ -92,7 +92,7 @@
inline tag.</p>
</section>
- <section>
+ <!-- section>
<marker id="pathTAG"></marker>
<title>&lt;path&gt; - Path</title>
@@ -115,7 +115,7 @@
in:</p>
<p>"Look at the <path unix=".profile" windows="win.ini">start-up file</path>
if you intend to alter the initial behavior."</p>
- </section>
+ </section -->
<section>
<marker id="seealsoTAG"></marker>
@@ -150,16 +150,10 @@
<p>Note the use of "#" before the name of the marker. Note also
that the filename extension <c>.html</c> is omitted. This is
- because the default behavior of DocBuilder is to translate
+ because the default behavior is to translate
<c><![CDATA[<seealso marker="File#Marker">text</seealso>]]></c>
to <c><![CDATA[<A HREF="File.html#Marker">text</A>]]></c>.</p>
- <p>The default behaviour can be modified by using the callback
- module option to <c>docb_transform:file/1,2</c> and defining a
- callback function
- <seealso marker="docb_transform#Module:seealso-1">Module:seealso/1</seealso>.
- This possibility is for example used in OTP to resolve cross
- references between applications.</p>
</section>
<section>
@@ -192,28 +186,6 @@
<term id="HTML"><termdef>Hyper-Text Markup Language</termdef></term>
]]></pre>
- <p>For a globally defined term, the tag is empty. Example:</p>
- <pre><![CDATA[
-<term id="HTML"/>
- ]]></pre>
-
- <p>Global definitions are given to DocBuilder in a file, using the
- <seealso marker="docb_transform#file/1">docb_transform:file/1,2</seealso>
- option <c>term_defs</c>. The file should contain a list of tuples,
- one for each term definition, on the format
- <c>{Id,Name,Definition,Owner}</c>. The <c>Owner</c> part is just
- for administration, if there are several people contributing to a
- term definition file. Example:</p>
- <pre>
-[...,
- {"HTML", "HTML", "Hyper-Text Markup Language", "Gunilla"},
- ...].
- </pre>
-
- <p>DocBuilder will collect both local and global definitions in a
- glossary, which can be reached from a link in the left frame of
- the HTML documentation.</p>
-
<p>In the generated HTML, it is the term name which will be visible.
For locally defined terms, the id and the name are the same.
The name has a hypertext link to the definition in the glossary.
@@ -237,21 +209,6 @@
<c>&lt;termdef&gt;</c>, but for a bibliography list rather than
a glossary.</p>
- <p>A global bibliography list is given to DocBuilder in a file,
- using the <seealso marker="docb_transform#file/1">docb_transform:file/1,2</seealso>
- option <c>cite_defs</c>. The file should contain a list of tuples,
- one for each cite, on the format
- <c>{Id,Title,Info,Owner}</c>. The <c>Owner</c> part is just
- for administration, if there are several people contributing to a
- bibliography file. Example:</p>
- <pre>
-[...,
- {"erlbook",
- "Concurrent Programming in ERLANG","J. Armstrong, R. Virding, C. Wikstr&ouml;m, "
- "M. Williams, Concurrent Programming in ERLANG, Prentice Hall, 1996, ISBN 0-13-508301-X",
- "jocke"},
- ...].
- </pre>
</section>
</chapter>
diff --git a/lib/docbuilder/doc/src/man.gif b/lib/erl_docgen/doc/src/man.gif
index 8656c7443d..8656c7443d 100644
--- a/lib/docbuilder/doc/src/man.gif
+++ b/lib/erl_docgen/doc/src/man.gif
Binary files differ
diff --git a/lib/erl_docgen/doc/src/notes.xml b/lib/erl_docgen/doc/src/notes.xml
index 6a0eece56d..9591b363f7 100644
--- a/lib/erl_docgen/doc/src/notes.xml
+++ b/lib/erl_docgen/doc/src/notes.xml
@@ -1,4 +1,4 @@
-<?xml version="1.0" encoding="latin1" ?>
+<?xml version="1.0" encoding="iso-8859-1" ?>
<!DOCTYPE chapter SYSTEM "chapter.dtd">
<chapter>
@@ -21,14 +21,14 @@
</legalnotice>
- <title>erl_docgen Release Notes</title>
+ <title>Erl_Docgen Release Notes</title>
<prepared>otp_appnotes</prepared>
<docno>nil</docno>
<date>nil</date>
<rev>nil</rev>
<file>notes.xml</file>
</header>
- <p>This document describes the changes made to the erl_docgen application.</p>
+ <p>This document describes the changes made to the <em>erl_docgen</em> application.</p>
<section><title>Erl_Docgen 0.2.6</title>
diff --git a/lib/docbuilder/doc/src/overview.xml b/lib/erl_docgen/doc/src/overview.xml
index ca13c5d436..f0f97d8d45 100644
--- a/lib/docbuilder/doc/src/overview.xml
+++ b/lib/erl_docgen/doc/src/overview.xml
@@ -29,28 +29,6 @@
</header>
<section>
- <title>Background</title>
-
- <p>DocBuilder has been used within the OTP project to generate
- documentation for Erlang/OTP itself for more than ten years.
- It has now been released as a regular Erlang/OTP application.</p>
-
- <p>The intention with DocBuilder is that it should be as easy to
- use and maintain as possible and generate adequate documentation
- for OTP's needs. It uses frames, which can probably be regarded as
- old-fashioned today. Hopefully, this should be improved in
- the future.</p>
-
- <p>Originally, DocBuilder input was SGML files and external tools
- was used for parsing. The internal version used in the OTP
- project can generate not only HTML code but also LaTeX (for PDF
- and PostScript) and nroff (for UNIX man pages). (Again, using
- external tools). Because of this, the parsed source code is
- transformed into a tree structure before being transformed again
- into the desired format.</p>
- </section>
-
- <section>
<title>DTD Suite</title>
<p>Input is written as XML according to one of the DTDs and output
@@ -94,10 +72,6 @@
the <c>application</c> or <c>part</c> DTD to write other types
of documentation for the application.</p>
- <p>A special kind of DTD,
- <seealso marker="fasc_dtds">fascicules</seealso>, can be used to
- specify the different parts of the documentation, and which one
- of those should be shown as default.</p>
</section>
<section>
@@ -120,7 +94,7 @@
<section>
<title>Basic Tags</title>
- <p>All DTDs in the DocBuilder DTD suite share a basic set of tags.
+ <p>All DTDs in the OTP DTD suite share a basic set of tags.
An author can easily switch from one DTD to another and still use
the same basic tags. It is furthermore easy to copy pieces of
information from one document to another, even though they do not
@@ -143,13 +117,13 @@
<p>For readability and simplicity, the examples have been kept as
short as possible. For an example of what the generated HTML
- will look like, it is recommended to look at the DocBuilder
- documentation itself:</p>
+ will look like, it is recommended to look at the documentation of
+ an OTP application.</p>
<list>
- <item>This User's Guide is written using the <c>part</c> and
+ <item>This User's Guides are written using the <c>part</c> and
<c>chapter</c> DTDs.</item>
- <item>The Reference Manual is written using
+ <item>The Reference Manuals are written using
the <c>application</c>, <c>appref</c> and <c>erlref</c> DTDs.
</item>
</list>
@@ -162,23 +136,19 @@
<item>
<p>Create the relevant XML files.</p>
- <p>If there are EDoc comments in a module, the function
- <seealso marker="docb_gen#module/1">docb_gen:module/1,2</seealso>
+ <p>If there are EDoc comments in a module, the escript
+ <!-- seealso marker="xml_from_edoc">xml_from_edoc</seealso -->
+ <c>xml_from_edoc</c>
can be used to generate an XML file according to
the <c>erlref</c> DTD for this module.</p>
</item>
- <item>
+ <!-- item>
<p>The XML files can be validated using
<seealso marker="docb_xml_check#validate/1">docb_xml_check:validate/1</seealso>.
</p>
- </item>
+ </item -->
- <item>
- <p>Generate HTML files by using
- <seealso marker="docb_transform#file/1">docb_transform:file/1,2</seealso>.
- </p>
- </item>
</list>
</section>
</chapter>
diff --git a/lib/docbuilder/doc/src/part.xml b/lib/erl_docgen/doc/src/part.xml
index 546c6c612e..4594778a2f 100644
--- a/lib/docbuilder/doc/src/part.xml
+++ b/lib/erl_docgen/doc/src/part.xml
@@ -1,10 +1,10 @@
-<?xml version="1.0" encoding="latin1" ?>
+<?xml version="1.0" encoding="iso-8859-1" ?>
<!DOCTYPE part SYSTEM "part.dtd">
<part xmlns:xi="http://www.w3.org/2001/XInclude">
<header>
<copyright>
- <year>2007</year><year>2009</year>
+ <year>2011</year><year>2011</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -20,21 +20,20 @@
under the License.
</legalnotice>
- <title>DocBuilder User's Guide</title>
+ <title>Erl_Docgen User's Guide</title>
<prepared></prepared>
<docno></docno>
<date></date>
<rev></rev>
</header>
<description>
- <p><em>Docbuilder</em> provides functionality for generating HTML
+ <p><em>Erl_Docgen</em> provides functionality for generating HTML/PDF
documentation for Erlang modules and Erlang/OTP applications
from XML source code and/or EDoc comments in Erlang source code.</p>
</description>
<xi:include href="overview.xml"/>
<xi:include href="user_guide_dtds.xml"/>
<xi:include href="refman_dtds.xml"/>
- <xi:include href="fasc_dtds.xml"/>
<xi:include href="header_tags.xml"/>
<xi:include href="block_tags.xml"/>
<xi:include href="inline_tags.xml"/>
diff --git a/lib/docbuilder/doc/src/ref_man.xml b/lib/erl_docgen/doc/src/ref_man.xml
index 7be8ace32f..a2bc1a10a0 100644
--- a/lib/docbuilder/doc/src/ref_man.xml
+++ b/lib/erl_docgen/doc/src/ref_man.xml
@@ -4,7 +4,7 @@
<application xmlns:xi="http://www.w3.org/2001/XInclude">
<header>
<copyright>
- <year>2007</year><year>2009</year>
+ <year>2011</year><year>2011</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -21,20 +21,16 @@
</legalnotice>
- <title>DocBuilder Reference Manual</title>
- <prepared></prepared>
+ <title>Erl_Docgen Reference Manual</title>
+ <prepared>OTP Team</prepared>
<docno></docno>
- <date></date>
- <rev></rev>
+ <date>2011-11-10</date>
+ <rev>0.3</rev>
+ <file>ref_man.xml</file>
</header>
<description>
- <p><em>DocBuilder</em> provides functionality for generating HTML
- documentation for Erlang modules and Erlang/OTP applications
- from XML source code and/or EDoc comments in Erlang source code.</p>
+ <p>The <em>erl_docgen</em> supports the OTP documentation build.</p>
</description>
- <xi:include href="docbuilder_app.xml"/>
- <xi:include href="docb_gen.xml"/>
- <xi:include href="docb_transform.xml"/>
- <xi:include href="docb_xml_check.xml"/>
+ <xi:include href="erl_docgen_app.xml"/>
</application>
diff --git a/lib/docbuilder/doc/src/refman_dtds.xml b/lib/erl_docgen/doc/src/refman_dtds.xml
index a7beaed708..7b01c57db4 100644
--- a/lib/docbuilder/doc/src/refman_dtds.xml
+++ b/lib/erl_docgen/doc/src/refman_dtds.xml
@@ -573,8 +573,8 @@
a <c><![CDATA[<nametext>]]></c> (function name and arguments,
plain text).</p>
- <p>In the case of an <c>erlref</c> DTD, DocBuilder will
- automatically try to add a
+ <p>In the case of an <c>erlref</c> DTD, it will
+ automatically be added a
<seealso marker="inline_tags#markerTAG">marker</seealso>,
<c><![CDATA[<marker id="Name/Arity">]]></c> or
<c><![CDATA[<marker id="Name">]]></c>, based on the contents of
@@ -585,7 +585,7 @@
<name>foo(Arg1, Arg2) -> ok | {error, Reason}</name>
]]></pre>
- <p>DocBuilder will create a marker
+ <p>Then a marker like this will be added
<c><![CDATA[<marker id="foo/2">]]></c> before the function
definition in the generated HTML. That is, referring to
the function using
diff --git a/lib/docbuilder/doc/src/user_guide_dtds.xml b/lib/erl_docgen/doc/src/user_guide_dtds.xml
index a2db44f830..a2db44f830 100644
--- a/lib/docbuilder/doc/src/user_guide_dtds.xml
+++ b/lib/erl_docgen/doc/src/user_guide_dtds.xml
diff --git a/lib/erl_docgen/info b/lib/erl_docgen/info
new file mode 100644
index 0000000000..4dc2a02bfb
--- /dev/null
+++ b/lib/erl_docgen/info
@@ -0,0 +1,3 @@
+group: doc Documentation Applications
+short: A utility used to produce the OTP documentation.
+
diff --git a/lib/erl_docgen/priv/Makefile b/lib/erl_docgen/priv/Makefile
index f50350bef2..18cf7b90dd 100644
--- a/lib/erl_docgen/priv/Makefile
+++ b/lib/erl_docgen/priv/Makefile
@@ -22,7 +22,7 @@ include $(ERL_TOP)/make/$(TARGET)/otp.mk
# Macros
#
-SUB_DIRECTORIES = bin css docbuilder_dtd dtd_html_entities dtd_man_entities images js/flipmenu xsl
+SUB_DIRECTORIES = bin css dtd dtd_html_entities dtd_man_entities images js/flipmenu xsl
SPECIAL_TARGETS =
diff --git a/lib/erl_docgen/priv/bin/specs_gen.escript b/lib/erl_docgen/priv/bin/specs_gen.escript
index 982afece7f..156311565c 100644
--- a/lib/erl_docgen/priv/bin/specs_gen.escript
+++ b/lib/erl_docgen/priv/bin/specs_gen.escript
@@ -19,7 +19,7 @@
%%% <script> [-I<dir>]... [-o<dir>] [-module Module] [File]
%%%
-%%% Use EDoc and the layout module 'otp_specs' to create an XML file
+%%% Use EDoc and the layout module 'docgen_otp_specs' to create an XML file
%%% containing Dialyzer types and specifications (-type, -spec).
%%%
%%% Options:
@@ -69,7 +69,7 @@ usage() ->
call_edoc(FileSpec, InclFs, Dir) ->
ReadOpts = [{includes, InclFs}, {preprocess, true}],
ExtractOpts = [{report_missing_type, false}],
- LayoutOpts = [{pretty_printer, erl_pp}, {layout, otp_specs}],
+ LayoutOpts = [{pretty_printer, erl_pp}, {layout, docgen_otp_specs}],
File = case FileSpec of
{file, File0} -> File0;
{module, Module0} -> Module0
diff --git a/lib/erl_docgen/priv/bin/xml_from_edoc.escript b/lib/erl_docgen/priv/bin/xml_from_edoc.escript
index ee79e82c3a..9a96a3c25a 100755
--- a/lib/erl_docgen/priv/bin/xml_from_edoc.escript
+++ b/lib/erl_docgen/priv/bin/xml_from_edoc.escript
@@ -27,7 +27,7 @@
%% Records
%%======================================================================
-record(args, {suffix=".xml",
- layout=docb_edoc_xml_cb,
+ layout=docgen_edoc_xml_cb,
def=[],
includes=[],
preprocess=false,
@@ -126,7 +126,7 @@ users_guide(File, Args) ->
parse(["-xml" |RawOpts], Type, Args) ->
parse(RawOpts, Type, Args); % default, no update of record necessary
parse(["-sgml" |RawOpts], Type, Args) ->
- parse(RawOpts, Type, Args#args{suffix=".sgml", layout=docb_edoc_sgml_cb});
+ parse(RawOpts, Type, Args#args{suffix=".sgml", layout=docgen_edoc_sgml_cb});
parse(["-chapter" |RawOpts], _Type, Args) ->
parse(RawOpts, chapter, Args);
parse(["-def", Key, Val |RawOpts], Type, Args) ->
diff --git a/lib/erl_docgen/priv/docbuilder_dtd/application.dtd b/lib/erl_docgen/priv/docbuilder_dtd/application.dtd
deleted file mode 100644
index 8a1e8832ec..0000000000
--- a/lib/erl_docgen/priv/docbuilder_dtd/application.dtd
+++ /dev/null
@@ -1,29 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!--
- ``The contents of this file are subject to the Erlang Public License,
- Version 1.1, (the "License"); you may not use this file except in
- compliance with the License. You should have received a copy of the
- Erlang Public License along with this software. If not, it can be
- retrieved via the world wide web at http://www.erlang.org/.
-
- Software distributed under the License is distributed on an "AS IS"
- basis, WITHOUT WARRANTY OF ANY KIND, either expressed or implied. See
- the License for the specific language governing rights and limitations
- under the License.
-
- The Initial Developer of the Original Code is Ericsson AB.
- Portions created by Ericsson are Copyright 1999-2007, Ericsson AB.
- All Rights Reserved.''
-
- $Id$
--->
-
-<!ENTITY % common SYSTEM "common.dtd" >
-%common;
-<!ENTITY % common.header SYSTEM "common.header.dtd" >
-%common.header;
-
-<!ELEMENT application (header,description?,include+) >
-<!ELEMENT description (%block;|quote|br|marker|warning|note)* >
-<!ELEMENT include EMPTY >
-<!ATTLIST include file CDATA #REQUIRED>
diff --git a/lib/erl_docgen/priv/docbuilder_dtd/appref.dtd b/lib/erl_docgen/priv/docbuilder_dtd/appref.dtd
deleted file mode 100644
index 70a5ff37af..0000000000
--- a/lib/erl_docgen/priv/docbuilder_dtd/appref.dtd
+++ /dev/null
@@ -1,33 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!--
- ``The contents of this file are subject to the Erlang Public License,
- Version 1.1, (the "License"); you may not use this file except in
- compliance with the License. You should have received a copy of the
- Erlang Public License along with this software. If not, it can be
- retrieved via the world wide web at http://www.erlang.org/.
-
- Software distributed under the License is distributed on an "AS IS"
- basis, WITHOUT WARRANTY OF ANY KIND, either expressed or implied. See
- the License for the specific language governing rights and limitations
- under the License.
-
- The Initial Developer of the Original Code is Ericsson AB.
- Portions created by Ericsson are Copyright 1999-2007, Ericsson AB.
- All Rights Reserved.''
-
- $Id$
--->
-
-<!ENTITY % common.refs SYSTEM "common.refs.dtd" >
-%common.refs;
-
-<!-- Structure -->
-
-<!ELEMENT appref (header,app,appsummary,description,
- (section|funcs)*,authors?) >
-<!ELEMENT app (#PCDATA) >
-<!ELEMENT appsummary (#PCDATA) >
-
-<!-- `name' is used in common.refs.dtd and must therefore
- be defined in each *ref. dtd -->
-<!ELEMENT name (#PCDATA) >
diff --git a/lib/erl_docgen/priv/docbuilder_dtd/book.dtd b/lib/erl_docgen/priv/docbuilder_dtd/book.dtd
deleted file mode 100644
index bb89a6d255..0000000000
--- a/lib/erl_docgen/priv/docbuilder_dtd/book.dtd
+++ /dev/null
@@ -1,73 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!--
- ``The contents of this file are subject to the Erlang Public License,
- Version 1.1, (the "License"); you may not use this file except in
- compliance with the License. You should have received a copy of the
- Erlang Public License along with this software. If not, it can be
- retrieved via the world wide web at http://www.erlang.org/.
-
- Software distributed under the License is distributed on an "AS IS"
- basis, WITHOUT WARRANTY OF ANY KIND, either expressed or implied. See
- the License for the specific language governing rights and limitations
- under the License.
-
- The Initial Developer of the Original Code is Ericsson AB.
- Portions created by Ericsson are Copyright 1999-2007, Ericsson AB.
- All Rights Reserved.''
-
- $Id$
--->
-
-<!ENTITY % common SYSTEM "common.dtd" >
-%common;
-<!ENTITY % common.header SYSTEM "common.header.dtd" >
-%common.header;
-<!ENTITY % common.table SYSTEM "common.table.dtd" >
-%common.table;
-
-<!ELEMENT book (header,
- insidecover?,
- pagetext,
- preamble,
- (applications|parts|headline|pagetext)+,
- (listoffigures?,
- listoftables?,
- listofterms?,
- bibliography?,
- index?)) >
-
-<!ELEMENT pagetext (#PCDATA) >
-<!ELEMENT preamble (contents?,preface?) >
-<!ELEMENT preface (title?,(%block;|quote|br|marker|warning|note|table)*) >
-
-<!ELEMENT insidecover (#PCDATA|br|theheader|vfill|vspace|tt|bold|
- include)* >
-<!ELEMENT tt (#PCDATA|br|theheader|vfill)* >
-<!ELEMENT bold (#PCDATA|br|theheader|vfill)* >
-<!ELEMENT vfill EMPTY >
-<!ELEMENT theheader EMPTY >
-<!ATTLIST theheader tag (title|prepared|responsible|docno|
- approved|checked|date|rev|file|
- abbreviation|
- none) "none" >
-
-
-<!ELEMENT applications (include)* >
-<!ELEMENT parts (title?,description?,(include|onepart)*) >
-<!ATTLIST parts lift (yes|no) "no" >
-<!ELEMENT headline (#PCDATA) >
-<!ELEMENT index EMPTY >
-<!ELEMENT listoffigures EMPTY >
-<!ELEMENT listoftables EMPTY >
-<!ELEMENT listofterms EMPTY >
-<!ELEMENT bibliography EMPTY >
-<!ELEMENT contents EMPTY >
-<!ATTLIST contents level (0|1|2|3) "2">
-
-<!ELEMENT onepart (title?,description?,include+) >
-<!ATTLIST onepart lift (yes|no) "no" >
-
-<!ELEMENT description (%block;|quote|br|marker|warning|note)* >
-
-<!ELEMENT include EMPTY >
-<!ATTLIST include file CDATA #REQUIRED>
diff --git a/lib/erl_docgen/priv/docbuilder_dtd/bookinsidecover.dtd b/lib/erl_docgen/priv/docbuilder_dtd/bookinsidecover.dtd
deleted file mode 100644
index d6efbef6a4..0000000000
--- a/lib/erl_docgen/priv/docbuilder_dtd/bookinsidecover.dtd
+++ /dev/null
@@ -1,36 +0,0 @@
-<!--
- ``The contents of this file are subject to the Erlang Public License,
- Version 1.1, (the "License"); you may not use this file except in
- compliance with the License. You should have received a copy of the
- Erlang Public License along with this software. If not, it can be
- retrieved via the world wide web at http://www.erlang.org/.
-
- Software distributed under the License is distributed on an "AS IS"
- basis, WITHOUT WARRANTY OF ANY KIND, either expressed or implied. See
- the License for the specific language governing rights and limitations
- under the License.
-
- The Initial Developer of the Original Code is Ericsson AB.
- Portions created by Ericsson are Copyright 1999-2007, Ericsson AB.
- All Rights Reserved.''
-
- $Id$
--->
-<!ENTITY % ISOlat1 SYSTEM "xhtml-lat1.ent" >
-%ISOlat1;
-
-<!ENTITY amp "&#x0026;" >
-<!ENTITY gt "&#x003E;" >
-<!ENTITY lt "&#x003C;" >
-
-<!ELEMENT bookinsidecover (#PCDATA|br|theheader|vfill|tt|bold)* >
-
-<!ELEMENT tt (#PCDATA|br|theheader|vfill)* >
-<!ELEMENT bold (#PCDATA|br|theheader|vfill)* >
-<!ELEMENT vfill EMPTY >
-<!ELEMENT theheader EMPTY >
-<!ATTLIST theheader tag (title|prepared|responsible|docno|
- approved|checked|date|rev|file|
- none) "none" >
-
-<!ELEMENT br EMPTY >
diff --git a/lib/erl_docgen/priv/docbuilder_dtd/chapter.dtd b/lib/erl_docgen/priv/docbuilder_dtd/chapter.dtd
deleted file mode 100644
index eb2c96b04f..0000000000
--- a/lib/erl_docgen/priv/docbuilder_dtd/chapter.dtd
+++ /dev/null
@@ -1,36 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!--
- ``The contents of this file are subject to the Erlang Public License,
- Version 1.1, (the "License"); you may not use this file except in
- compliance with the License. You should have received a copy of the
- Erlang Public License along with this software. If not, it can be
- retrieved via the world wide web at http://www.erlang.org/.
-
- Software distributed under the License is distributed on an "AS IS"
- basis, WITHOUT WARRANTY OF ANY KIND, either expressed or implied. See
- the License for the specific language governing rights and limitations
- under the License.
-
- The Initial Developer of the Original Code is Ericsson AB.
- Portions created by Ericsson are Copyright 1999-2007, Ericsson AB.
- All Rights Reserved.''
-
- $Id$
--->
-
-<!ENTITY % common SYSTEM "common.dtd" >
-%common;
-<!ENTITY % common.header SYSTEM "common.header.dtd" >
-%common.header;
-<!ENTITY % common.table SYSTEM "common.table.dtd" >
-%common.table;
-<!ENTITY % common.image SYSTEM "common.image.dtd" >
-%common.image;
-
-<!-- Structure -->
-
-<!ELEMENT chapter (header,(%block;|quote|warning|note|br|
- image|marker|table)*,section+) >
-<!ELEMENT section (marker*,title,
- (%block;|quote|warning|note|br|image|marker|
- table|section)*) >
diff --git a/lib/erl_docgen/priv/docbuilder_dtd/cites.dtd b/lib/erl_docgen/priv/docbuilder_dtd/cites.dtd
deleted file mode 100644
index 334574bff9..0000000000
--- a/lib/erl_docgen/priv/docbuilder_dtd/cites.dtd
+++ /dev/null
@@ -1,35 +0,0 @@
-<!--
- ``The contents of this file are subject to the Erlang Public License,
- Version 1.1, (the "License"); you may not use this file except in
- compliance with the License. You should have received a copy of the
- Erlang Public License along with this software. If not, it can be
- retrieved via the world wide web at http://www.erlang.org/.
-
- Software distributed under the License is distributed on an "AS IS"
- basis, WITHOUT WARRANTY OF ANY KIND, either expressed or implied. See
- the License for the specific language governing rights and limitations
- under the License.
-
- The Initial Developer of the Original Code is Ericsson AB.
- Portions created by Ericsson are Copyright 1999-2007, Ericsson AB.
- All Rights Reserved.''
-
- $Id$
--->
-<!ENTITY % ISOlat1 SYSTEM "xhtml-lat1.ent" >
-%ISOlat1;
-
-<!ENTITY amp "&#x0026;" >
-<!ENTITY gt "&#x003E;" >
-<!ENTITY lt "&#x003C;" >
-
-<!-- Structure -->
-
-<!ELEMENT cites (cite)* >
-<!ELEMENT cite (id, shortdef, def, resp?) >
-<!ELEMENT id (#PCDATA) >
-<!ELEMENT shortdef (#PCDATA) >
-<!ELEMENT def (#PCDATA|c|em)* >
-<!ELEMENT resp (#PCDATA) >
-<!ELEMENT c (#PCDATA) >
-<!ELEMENT em (#PCDATA|c)* >
diff --git a/lib/erl_docgen/priv/docbuilder_dtd/common.entities.dtd b/lib/erl_docgen/priv/docbuilder_dtd/common.entities.dtd
deleted file mode 100644
index f893ecd070..0000000000
--- a/lib/erl_docgen/priv/docbuilder_dtd/common.entities.dtd
+++ /dev/null
@@ -1,24 +0,0 @@
-<!--
- ``The contents of this file are subject to the Erlang Public License,
- Version 1.1, (the "License"); you may not use this file except in
- compliance with the License. You should have received a copy of the
- Erlang Public License along with this software. If not, it can be
- retrieved via the world wide web at http://www.erlang.org/.
-
- Software distributed under the License is distributed on an "AS IS"
- basis, WITHOUT WARRANTY OF ANY KIND, either expressed or implied. See
- the License for the specific language governing rights and limitations
- under the License.
-
- The Initial Developer of the Original Code is Ericsson AB.
- Portions created by Ericsson are Copyright 1999-2007, Ericsson AB.
- All Rights Reserved.''
-
- $Id$
--->
-<!ENTITY % ISOlat1 SYSTEM "xhtml-lat1.ent" >
-%ISOlat1;
-
-<!ENTITY amp "&#x0026;" >
-<!ENTITY gt "&#x003E;" >
-<!ENTITY lt "&#x003C;" >
diff --git a/lib/erl_docgen/priv/docbuilder_dtd/common.header.dtd b/lib/erl_docgen/priv/docbuilder_dtd/common.header.dtd
deleted file mode 100644
index d422a89693..0000000000
--- a/lib/erl_docgen/priv/docbuilder_dtd/common.header.dtd
+++ /dev/null
@@ -1,42 +0,0 @@
-<!--
- ``The contents of this file are subject to the Erlang Public License,
- Version 1.1, (the "License"); you may not use this file except in
- compliance with the License. You should have received a copy of the
- Erlang Public License along with this software. If not, it can be
- retrieved via the world wide web at http://www.erlang.org/.
-
- Software distributed under the License is distributed on an "AS IS"
- basis, WITHOUT WARRANTY OF ANY KIND, either expressed or implied. See
- the License for the specific language governing rights and limitations
- under the License.
-
- The Initial Developer of the Original Code is Ericsson AB.
- Portions created by Ericsson are Copyright 1999-2007, Ericsson AB.
- All Rights Reserved.''
-
- $Id$
--->
-<!ELEMENT header (copyright?,legalnotice?,title,shorttitle?,
- prepared,responsible?,docno,approved?,
- checked?,date,rev,file?) >
-
-<!--
-The titlestyle attribute is only defined to make all the book.xml files
-go through the validation. The attribute is not used for anything
--->
-<!ATTLIST header titlestyle (special|normal) "normal">
-
-<!ELEMENT title (#PCDATA) >
-<!ELEMENT shorttitle (#PCDATA) >
-<!ELEMENT prepared (#PCDATA) >
-<!ELEMENT responsible (#PCDATA) >
-<!ELEMENT docno (#PCDATA) >
-<!ELEMENT approved (#PCDATA) >
-<!ELEMENT checked (#PCDATA) >
-<!ELEMENT copyright (year+,holder*) >
-<!ELEMENT legalnotice (#PCDATA) >
-<!ELEMENT date (#PCDATA) >
-<!ELEMENT rev (#PCDATA) >
-<!ELEMENT file (#PCDATA) >
-<!ELEMENT year (#PCDATA) >
-<!ELEMENT holder (#PCDATA) >
diff --git a/lib/erl_docgen/priv/docbuilder_dtd/common.image.dtd b/lib/erl_docgen/priv/docbuilder_dtd/common.image.dtd
deleted file mode 100644
index fc95a669dd..0000000000
--- a/lib/erl_docgen/priv/docbuilder_dtd/common.image.dtd
+++ /dev/null
@@ -1,21 +0,0 @@
-<!--
- ``The contents of this file are subject to the Erlang Public License,
- Version 1.1, (the "License"); you may not use this file except in
- compliance with the License. You should have received a copy of the
- Erlang Public License along with this software. If not, it can be
- retrieved via the world wide web at http://www.erlang.org/.
-
- Software distributed under the License is distributed on an "AS IS"
- basis, WITHOUT WARRANTY OF ANY KIND, either expressed or implied. See
- the License for the specific language governing rights and limitations
- under the License.
-
- The Initial Developer of the Original Code is Ericsson AB.
- Portions created by Ericsson are Copyright 1999-2007, Ericsson AB.
- All Rights Reserved.''
-
- $Id$
--->
-<!ELEMENT image (icaption) >
-<!ATTLIST image file CDATA #REQUIRED >
-<!ELEMENT icaption (#PCDATA) >
diff --git a/lib/erl_docgen/priv/docbuilder_dtd/common.table.dtd b/lib/erl_docgen/priv/docbuilder_dtd/common.table.dtd
deleted file mode 100644
index 7741da1018..0000000000
--- a/lib/erl_docgen/priv/docbuilder_dtd/common.table.dtd
+++ /dev/null
@@ -1,25 +0,0 @@
-<!--
- ``The contents of this file are subject to the Erlang Public License,
- Version 1.1, (the "License"); you may not use this file except in
- compliance with the License. You should have received a copy of the
- Erlang Public License along with this software. If not, it can be
- retrieved via the world wide web at http://www.erlang.org/.
-
- Software distributed under the License is distributed on an "AS IS"
- basis, WITHOUT WARRANTY OF ANY KIND, either expressed or implied. See
- the License for the specific language governing rights and limitations
- under the License.
-
- The Initial Developer of the Original Code is Ericsson AB.
- Portions created by Ericsson are Copyright 1999-2007, Ericsson AB.
- All Rights Reserved.''
-
- $Id$
--->
-<!ELEMENT table (row+,tcaption) >
-<!ATTLIST table align (left|center|right) "center" >
-<!ELEMENT row (cell+) >
-<!ELEMENT cell (%inline;)* >
-<!ATTLIST cell align (left|center|right) "left"
- valign (top|middle|bottom) "middle" >
-<!ELEMENT tcaption (#PCDATA) >
diff --git a/lib/erl_docgen/priv/docbuilder_dtd/comref.dtd b/lib/erl_docgen/priv/docbuilder_dtd/comref.dtd
deleted file mode 100644
index fcdea625d5..0000000000
--- a/lib/erl_docgen/priv/docbuilder_dtd/comref.dtd
+++ /dev/null
@@ -1,31 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!--
- ``The contents of this file are subject to the Erlang Public License,
- Version 1.1, (the "License"); you may not use this file except in
- compliance with the License. You should have received a copy of the
- Erlang Public License along with this software. If not, it can be
- retrieved via the world wide web at http://www.erlang.org/.
-
- Software distributed under the License is distributed on an "AS IS"
- basis, WITHOUT WARRANTY OF ANY KIND, either expressed or implied. See
- the License for the specific language governing rights and limitations
- under the License.
-
- The Initial Developer of the Original Code is Ericsson AB.
- Portions created by Ericsson are Copyright 1999-2007, Ericsson AB.
- All Rights Reserved.''
-
- $Id$
--->
-
-<!ENTITY % common.refs SYSTEM "common.refs.dtd" >
-%common.refs;
-
-<!ELEMENT comref (header,com,comsummary,description,
- (section|funcs)*,authors?) >
-<!ELEMENT com (#PCDATA) >
-<!ELEMENT comsummary (#PCDATA) >
-
-<!-- `name' is used in common.refs.dtd and must therefore
- be defined in each *ref. dtd -->
-<!ELEMENT name (#PCDATA) >
diff --git a/lib/erl_docgen/priv/docbuilder_dtd/cref.dtd b/lib/erl_docgen/priv/docbuilder_dtd/cref.dtd
deleted file mode 100644
index e43bb2bf51..0000000000
--- a/lib/erl_docgen/priv/docbuilder_dtd/cref.dtd
+++ /dev/null
@@ -1,34 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!--
- ``The contents of this file are subject to the Erlang Public License,
- Version 1.1, (the "License"); you may not use this file except in
- compliance with the License. You should have received a copy of the
- Erlang Public License along with this software. If not, it can be
- retrieved via the world wide web at http://www.erlang.org/.
-
- Software distributed under the License is distributed on an "AS IS"
- basis, WITHOUT WARRANTY OF ANY KIND, either expressed or implied. See
- the License for the specific language governing rights and limitations
- under the License.
-
- The Initial Developer of the Original Code is Ericsson AB.
- Portions created by Ericsson are Copyright 1999-2007, Ericsson AB.
- All Rights Reserved.''
-
- $Id$
--->
-
-<!ENTITY % common.refs SYSTEM "common.refs.dtd" >
-%common.refs;
-
-<!ELEMENT cref (header,lib,libsummary,description,
- (section|funcs)*,authors?) >
-<!ELEMENT lib (#PCDATA) >
-<!ELEMENT libsummary (#PCDATA) >
-
-<!-- `name' is used in common.refs.dtd and must therefore
- be defined in each *ref. dtd -->
-<!ELEMENT name (ret,nametext) >
-<!ELEMENT ret (#PCDATA) >
-<!ELEMENT nametext (#PCDATA) >
-
diff --git a/lib/erl_docgen/priv/docbuilder_dtd/fascicules.dtd b/lib/erl_docgen/priv/docbuilder_dtd/fascicules.dtd
deleted file mode 100644
index b14276a2c0..0000000000
--- a/lib/erl_docgen/priv/docbuilder_dtd/fascicules.dtd
+++ /dev/null
@@ -1,35 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!--
- ``The contents of this file are subject to the Erlang Public License,
- Version 1.1, (the "License"); you may not use this file except in
- compliance with the License. You should have received a copy of the
- Erlang Public License along with this software. If not, it can be
- retrieved via the world wide web at http://www.erlang.org/.
-
- Software distributed under the License is distributed on an "AS IS"
- basis, WITHOUT WARRANTY OF ANY KIND, either expressed or implied. See
- the License for the specific language governing rights and limitations
- under the License.
-
- The Initial Developer of the Original Code is Ericsson AB.
- Portions created by Ericsson are Copyright 1999-2007, Ericsson AB.
- All Rights Reserved.''
-
- $Id$
--->
-
-<!ENTITY % ISOlat1 SYSTEM "xhtml-lat1.ent" >
-%ISOlat1;
-
-<!ENTITY amp "&#x0026;" >
-<!ENTITY gt "&#x003E;" >
-<!ENTITY lt "&#x003C;" >
-
-<!-- Structure -->
-
-<!ELEMENT fascicules (fascicule)+ >
-<!ELEMENT fascicule (#PCDATA) >
-<!ATTLIST fascicule file CDATA #REQUIRED
- href CDATA #REQUIRED
- entry (yes|no) "no" >
-
diff --git a/lib/erl_docgen/priv/docbuilder_dtd/fileref.dtd b/lib/erl_docgen/priv/docbuilder_dtd/fileref.dtd
deleted file mode 100644
index 5a1cc54afe..0000000000
--- a/lib/erl_docgen/priv/docbuilder_dtd/fileref.dtd
+++ /dev/null
@@ -1,31 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!--
- ``The contents of this file are subject to the Erlang Public License,
- Version 1.1, (the "License"); you may not use this file except in
- compliance with the License. You should have received a copy of the
- Erlang Public License along with this software. If not, it can be
- retrieved via the world wide web at http://www.erlang.org/.
-
- Software distributed under the License is distributed on an "AS IS"
- basis, WITHOUT WARRANTY OF ANY KIND, either expressed or implied. See
- the License for the specific language governing rights and limitations
- under the License.
-
- The Initial Developer of the Original Code is Ericsson AB.
- Portions created by Ericsson are Copyright 1999-2007, Ericsson AB.
- All Rights Reserved.''
-
- $Id$
--->
-
-<!ENTITY % common.refs SYSTEM "common.refs.dtd" >
-%common.refs;
-
-<!ELEMENT fileref (header,file,filesummary,description,
- (section|funcs)*,authors?) >
-<!-- Note: ELEMENT file is already defined -->
-<!ELEMENT filesummary (#PCDATA) >
-
-<!-- `name' is used in common.refs.dtd and must therefore
- be defined in each *ref. dtd -->
-<!ELEMENT name (#PCDATA) >
diff --git a/lib/erl_docgen/priv/docbuilder_dtd/part.dtd b/lib/erl_docgen/priv/docbuilder_dtd/part.dtd
deleted file mode 100644
index 3f97199042..0000000000
--- a/lib/erl_docgen/priv/docbuilder_dtd/part.dtd
+++ /dev/null
@@ -1,29 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!--
- ``The contents of this file are subject to the Erlang Public License,
- Version 1.1, (the "License"); you may not use this file except in
- compliance with the License. You should have received a copy of the
- Erlang Public License along with this software. If not, it can be
- retrieved via the world wide web at http://www.erlang.org/.
-
- Software distributed under the License is distributed on an "AS IS"
- basis, WITHOUT WARRANTY OF ANY KIND, either expressed or implied. See
- the License for the specific language governing rights and limitations
- under the License.
-
- The Initial Developer of the Original Code is Ericsson AB.
- Portions created by Ericsson are Copyright 1999-2007, Ericsson AB.
- All Rights Reserved.''
-
- $Id$
--->
-
-<!ENTITY % common SYSTEM "common.dtd" >
-%common;
-<!ENTITY % common.header SYSTEM "common.header.dtd" >
-%common.header;
-
-<!ELEMENT part (header,description?,include+) >
-<!ELEMENT description (%block;|quote|br|marker|warning|note)* >
-<!ELEMENT include EMPTY >
-<!ATTLIST include file CDATA #REQUIRED>
diff --git a/lib/erl_docgen/priv/docbuilder_dtd/report.dtd b/lib/erl_docgen/priv/docbuilder_dtd/report.dtd
deleted file mode 100644
index 3d07e6e5a7..0000000000
--- a/lib/erl_docgen/priv/docbuilder_dtd/report.dtd
+++ /dev/null
@@ -1,138 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<!--
- ``The contents of this file are subject to the Erlang Public License,
- Version 1.1, (the "License"); you may not use this file except in
- compliance with the License. You should have received a copy of the
- Erlang Public License along with this software. If not, it can be
- retrieved via the world wide web at http://www.erlang.org/.
-
- Software distributed under the License is distributed on an "AS IS"
- basis, WITHOUT WARRANTY OF ANY KIND, either expressed or implied. See
- the License for the specific language governing rights and limitations
- under the License.
-
- The Initial Developer of the Original Code is Ericsson AB.
- Portions created by Ericsson are Copyright 1999-2007, Ericsson AB.
- All Rights Reserved.''
-
- $Id$
--->
-
-<!ENTITY % ISOlat1 SYSTEM "xhtml-lat1.ent" >
-%ISOlat1;
-
-<!ENTITY amp "&#x0026;" >
-<!ENTITY gt "&#x003E;" >
-<!ENTITY lt "&#x003C;" >
-
-<!ENTITY % header "title,prepared,responsible,docno,approved,
- checked,date,rev,file" >
-<!ENTITY % block "p|pre|code|list|taglist|erlinclude|
- codeinclude|erleval" >
-<!ENTITY % inline "#PCDATA|i|b|c|em|term|cite|br|path|seealso|
- url|marker" >
-
-<!-- Structure -->
-
-<!ELEMENT report (header,section+) >
-<!ELEMENT header (title,prepared,responsible?,docno,approved?,
- checked?,date,rev,file?) >
-<!ELEMENT title (#PCDATA) >
-<!ELEMENT prepared (#PCDATA) >
-<!ELEMENT responsible (#PCDATA) >
-<!ELEMENT docno (#PCDATA) >
-<!ELEMENT approved (#PCDATA) >
-<!ELEMENT checked (#PCDATA) >
-<!ELEMENT date (#PCDATA) >
-<!ELEMENT rev (#PCDATA) >
-<!ELEMENT file (#PCDATA) >
-
-<!ELEMENT section (marker*,title,
- (%block;|quote|warning|note|br|image|marker|
- table|section)*) >
-<!ELEMENT p (%inline;|index)* >
-<!ELEMENT pre (#PCDATA|seealso|url|input)* >
-<!ELEMENT input (#PCDATA|seealso|url)* >
-<!ELEMENT code (#PCDATA) >
-<!ATTLIST code type (erl|c|none) "none" >
-<!ELEMENT quote (p)* >
-<!ELEMENT warning (%block;|quote|br|image|marker|table)* >
-<!ELEMENT note (%block;|quote|br|image|marker|table)* >
-<!ELEMENT i (#PCDATA|b|c|em)* >
-<!ELEMENT b (#PCDATA|i|c|em)* >
-<!ELEMENT c (#PCDATA) >
-<!ELEMENT em (#PCDATA|i|b|c)* >
-<!ELEMENT term (termdef?) >
-<!ATTLIST term id CDATA #REQUIRED >
-<!ELEMENT termdef (#PCDATA) >
-<!ELEMENT cite (citedef?) >
-<!ATTLIST cite id CDATA #REQUIRED >
-<!ELEMENT citedef (ctitle,cauthor,chowpublished) >
-<!ELEMENT ctitle (#PCDATA) >
-<!ELEMENT cauthor (#PCDATA) >
-<!ELEMENT chowpublished (#PCDATA) >
-<!ELEMENT br EMPTY >
-
-<!-- Path -->
-
-<!ELEMENT path (#PCDATA) >
-<!ATTLIST path unix CDATA ""
- windows CDATA "" >
-
-<!-- List -->
-
-<!ELEMENT list (item+) >
-<!ATTLIST list type (ordered|bulleted) "bulleted" >
-<!ELEMENT taglist (tag,item)+ >
-<!ELEMENT tag (#PCDATA|i|b|c|em|seealso|url)* >
-<!ELEMENT item (%inline;|%block;)* >
-
-<!-- Image -->
-
-<!ELEMENT image (icaption?) >
-<!ATTLIST image file CDATA #REQUIRED >
-<!ELEMENT icaption (#PCDATA) >
-
-<!-- References -->
-
-<!ELEMENT seealso (#PCDATA) >
-<!ATTLIST seealso marker CDATA #REQUIRED >
-<!ELEMENT url (#PCDATA) >
-<!ATTLIST url href CDATA #REQUIRED >
-<!ELEMENT marker EMPTY >
-<!ATTLIST marker id CDATA #REQUIRED >
-
-<!-- Table -->
-
-<!ELEMENT table (row+,tcaption?) >
-<!ATTLIST table width CDATA "0"
- colspec CDATA "" >
-<!ELEMENT row (cell+) >
-<!ELEMENT cell (%inline;)* >
-<!ATTLIST cell align (left|center|right) "left"
- valign (top|middle|bottom) "middle" >
-<!ELEMENT tcaption (#PCDATA) >
-
-<!-- ErlInclude -->
-
-<!ELEMENT erlinclude EMPTY >
-<!ATTLIST erlinclude file CDATA #REQUIRED
- tag CDATA #REQUIRED >
-
-<!-- CodeInclude -->
-
-<!ELEMENT codeinclude EMPTY >
-<!ATTLIST codeinclude file CDATA #REQUIRED
- tag CDATA ""
- type (erl|c|none) "none" >
-
-<!-- ErlEval -->
-
-<!ELEMENT erleval EMPTY >
-<!ATTLIST erleval expr CDATA #REQUIRED >
-
-<!-- Index FOR COMPATIBILITY -->
-
-<!ELEMENT index EMPTY >
-<!ATTLIST index txt CDATA #REQUIRED >
-
diff --git a/lib/erl_docgen/priv/docbuilder_dtd/terms.dtd b/lib/erl_docgen/priv/docbuilder_dtd/terms.dtd
deleted file mode 100644
index 6105ec593e..0000000000
--- a/lib/erl_docgen/priv/docbuilder_dtd/terms.dtd
+++ /dev/null
@@ -1,36 +0,0 @@
-<!--
- ``The contents of this file are subject to the Erlang Public License,
- Version 1.1, (the "License"); you may not use this file except in
- compliance with the License. You should have received a copy of the
- Erlang Public License along with this software. If not, it can be
- retrieved via the world wide web at http://www.erlang.org/.
-
- Software distributed under the License is distributed on an "AS IS"
- basis, WITHOUT WARRANTY OF ANY KIND, either expressed or implied. See
- the License for the specific language governing rights and limitations
- under the License.
-
- The Initial Developer of the Original Code is Ericsson AB.
- Portions created by Ericsson are Copyright 1999-2007, Ericsson AB.
- All Rights Reserved.''
-
- $Id$
--->
-<!ENTITY % ISOlat1 SYSTEM "xhtml-lat1.ent" >
-%ISOlat1;
-
-<!ENTITY amp "&#x0026;" >
-<!ENTITY gt "&#x003E;" >
-<!ENTITY lt "&#x003C;" >
-
-<!-- Structure -->
-
-<!ELEMENT terms (term)* >
-<!ELEMENT term (id, shortdef, def, resp?) >
-<!ELEMENT id (#PCDATA) >
-<!ELEMENT shortdef (#PCDATA) >
-<!ELEMENT def (#PCDATA|c|em)* >
-<!ELEMENT resp (#PCDATA) >
-<!ELEMENT c (#PCDATA) >
-<!ELEMENT em (#PCDATA|c)* >
-
diff --git a/lib/erl_docgen/priv/docbuilder_dtd/xhtml1-frameset.dtd b/lib/erl_docgen/priv/docbuilder_dtd/xhtml1-frameset.dtd
deleted file mode 100644
index d128f2eb7c..0000000000
--- a/lib/erl_docgen/priv/docbuilder_dtd/xhtml1-frameset.dtd
+++ /dev/null
@@ -1,1235 +0,0 @@
-<!--
- Extensible HTML version 1.0 Frameset DTD
-
- This is the same as HTML 4 Frameset except for
- changes due to the differences between XML and SGML.
-
- Namespace = http://www.w3.org/1999/xhtml
-
- For further information, see: http://www.w3.org/TR/xhtml1
-
- Copyright (c) 1998-2002 W3C (MIT, INRIA, Keio),
- All Rights Reserved.
-
- This DTD module is identified by the PUBLIC and SYSTEM identifiers:
-
- PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN"
- SYSTEM "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd"
-
- $Revision: 1.2 $
- $Date: 2002/08/01 18:37:55 $
-
--->
-
-<!--================ Character mnemonic entities =========================-->
-
-<!ENTITY % HTMLlat1 PUBLIC
- "-//W3C//ENTITIES Latin 1 for XHTML//EN"
- "xhtml-lat1.ent">
-%HTMLlat1;
-
-<!ENTITY % HTMLsymbol PUBLIC
- "-//W3C//ENTITIES Symbols for XHTML//EN"
- "xhtml-symbol.ent">
-%HTMLsymbol;
-
-<!ENTITY % HTMLspecial PUBLIC
- "-//W3C//ENTITIES Special for XHTML//EN"
- "xhtml-special.ent">
-%HTMLspecial;
-
-<!--================== Imported Names ====================================-->
-
-<!ENTITY % ContentType "CDATA">
- <!-- media type, as per [RFC2045] -->
-
-<!ENTITY % ContentTypes "CDATA">
- <!-- comma-separated list of media types, as per [RFC2045] -->
-
-<!ENTITY % Charset "CDATA">
- <!-- a character encoding, as per [RFC2045] -->
-
-<!ENTITY % Charsets "CDATA">
- <!-- a space separated list of character encodings, as per [RFC2045] -->
-
-<!ENTITY % LanguageCode "NMTOKEN">
- <!-- a language code, as per [RFC3066] -->
-
-<!ENTITY % Character "CDATA">
- <!-- a single character, as per section 2.2 of [XML] -->
-
-<!ENTITY % Number "CDATA">
- <!-- one or more digits -->
-
-<!ENTITY % LinkTypes "CDATA">
- <!-- space-separated list of link types -->
-
-<!ENTITY % MediaDesc "CDATA">
- <!-- single or comma-separated list of media descriptors -->
-
-<!ENTITY % URI "CDATA">
- <!-- a Uniform Resource Identifier, see [RFC2396] -->
-
-<!ENTITY % UriList "CDATA">
- <!-- a space separated list of Uniform Resource Identifiers -->
-
-<!ENTITY % Datetime "CDATA">
- <!-- date and time information. ISO date format -->
-
-<!ENTITY % Script "CDATA">
- <!-- script expression -->
-
-<!ENTITY % StyleSheet "CDATA">
- <!-- style sheet data -->
-
-<!ENTITY % Text "CDATA">
- <!-- used for titles etc. -->
-
-<!ENTITY % FrameTarget "NMTOKEN">
- <!-- render in this frame -->
-
-<!ENTITY % Length "CDATA">
- <!-- nn for pixels or nn% for percentage length -->
-
-<!ENTITY % MultiLength "CDATA">
- <!-- pixel, percentage, or relative -->
-
-<!ENTITY % MultiLengths "CDATA">
- <!-- comma-separated list of MultiLength -->
-
-<!ENTITY % Pixels "CDATA">
- <!-- integer representing length in pixels -->
-
-<!-- these are used for image maps -->
-
-<!ENTITY % Shape "(rect|circle|poly|default)">
-
-<!ENTITY % Coords "CDATA">
- <!-- comma separated list of lengths -->
-
-<!-- used for object, applet, img, input and iframe -->
-<!ENTITY % ImgAlign "(top|middle|bottom|left|right)">
-
-<!-- a color using sRGB: #RRGGBB as Hex values -->
-<!ENTITY % Color "CDATA">
-
-<!-- There are also 16 widely known color names with their sRGB values:
-
- Black = #000000 Green = #008000
- Silver = #C0C0C0 Lime = #00FF00
- Gray = #808080 Olive = #808000
- White = #FFFFFF Yellow = #FFFF00
- Maroon = #800000 Navy = #000080
- Red = #FF0000 Blue = #0000FF
- Purple = #800080 Teal = #008080
- Fuchsia= #FF00FF Aqua = #00FFFF
--->
-
-<!--=================== Generic Attributes ===============================-->
-
-<!-- core attributes common to most elements
- id document-wide unique id
- class space separated list of classes
- style associated style info
- title advisory title/amplification
--->
-<!ENTITY % coreattrs
- "id ID #IMPLIED
- class CDATA #IMPLIED
- style %StyleSheet; #IMPLIED
- title %Text; #IMPLIED"
- >
-
-<!-- internationalization attributes
- lang language code (backwards compatible)
- xml:lang language code (as per XML 1.0 spec)
- dir direction for weak/neutral text
--->
-<!ENTITY % i18n
- "lang %LanguageCode; #IMPLIED
- xml:lang %LanguageCode; #IMPLIED
- dir (ltr|rtl) #IMPLIED"
- >
-
-<!-- attributes for common UI events
- onclick a pointer button was clicked
- ondblclick a pointer button was double clicked
- onmousedown a pointer button was pressed down
- onmouseup a pointer button was released
- onmousemove a pointer was moved onto the element
- onmouseout a pointer was moved away from the element
- onkeypress a key was pressed and released
- onkeydown a key was pressed down
- onkeyup a key was released
--->
-<!ENTITY % events
- "onclick %Script; #IMPLIED
- ondblclick %Script; #IMPLIED
- onmousedown %Script; #IMPLIED
- onmouseup %Script; #IMPLIED
- onmouseover %Script; #IMPLIED
- onmousemove %Script; #IMPLIED
- onmouseout %Script; #IMPLIED
- onkeypress %Script; #IMPLIED
- onkeydown %Script; #IMPLIED
- onkeyup %Script; #IMPLIED"
- >
-
-<!-- attributes for elements that can get the focus
- accesskey accessibility key character
- tabindex position in tabbing order
- onfocus the element got the focus
- onblur the element lost the focus
--->
-<!ENTITY % focus
- "accesskey %Character; #IMPLIED
- tabindex %Number; #IMPLIED
- onfocus %Script; #IMPLIED
- onblur %Script; #IMPLIED"
- >
-
-<!ENTITY % attrs "%coreattrs; %i18n; %events;">
-
-<!-- text alignment for p, div, h1-h6. The default is
- align="left" for ltr headings, "right" for rtl -->
-
-<!ENTITY % TextAlign "align (left|center|right|justify) #IMPLIED">
-
-<!--=================== Text Elements ====================================-->
-
-<!ENTITY % special.extra
- "object | applet | img | map | iframe">
-
-<!ENTITY % special.basic
- "br | span | bdo">
-
-<!ENTITY % special
- "%special.basic; | %special.extra;">
-
-<!ENTITY % fontstyle.extra "big | small | font | basefont">
-
-<!ENTITY % fontstyle.basic "tt | i | b | u
- | s | strike ">
-
-<!ENTITY % fontstyle "%fontstyle.basic; | %fontstyle.extra;">
-
-<!ENTITY % phrase.extra "sub | sup">
-<!ENTITY % phrase.basic "em | strong | dfn | code | q |
- samp | kbd | var | cite | abbr | acronym">
-
-<!ENTITY % phrase "%phrase.basic; | %phrase.extra;">
-
-<!ENTITY % inline.forms "input | select | textarea | label | button">
-
-<!-- these can occur at block or inline level -->
-<!ENTITY % misc.inline "ins | del | script">
-
-<!-- these can only occur at block level -->
-<!ENTITY % misc "noscript | %misc.inline;">
-
-
-<!ENTITY % inline "a | %special; | %fontstyle; | %phrase; | %inline.forms;">
-
-<!-- %Inline; covers inline or "text-level" elements -->
-<!ENTITY % Inline "(#PCDATA | %inline; | %misc.inline;)*">
-
-<!--================== Block level elements ==============================-->
-
-<!ENTITY % heading "h1|h2|h3|h4|h5|h6">
-<!ENTITY % lists "ul | ol | dl | menu | dir">
-<!ENTITY % blocktext "pre | hr | blockquote | address | center">
-
-<!ENTITY % block
- "p | %heading; | div | %lists; | %blocktext; | isindex | fieldset | table">
-
-<!-- %Flow; mixes block and inline and is used for list items etc. -->
-<!ENTITY % Flow "(#PCDATA | %block; | form | %inline; | %misc;)*">
-
-<!--================== Content models for exclusions =====================-->
-
-<!-- a elements use %Inline; excluding a -->
-
-<!ENTITY % a.content
- "(#PCDATA | %special; | %fontstyle; | %phrase; | %inline.forms; | %misc.inline;)*">
-
-<!-- pre uses %Inline excluding img, object, applet, big, small,
- sub, sup, font, or basefont -->
-
-<!ENTITY % pre.content
- "(#PCDATA | a | %special.basic; | %fontstyle.basic; | %phrase.basic; |
- %inline.forms; | %misc.inline;)*">
-
-
-<!-- form uses %Flow; excluding form -->
-
-<!ENTITY % form.content "(#PCDATA | %block; | %inline; | %misc;)*">
-
-<!-- button uses %Flow; but excludes a, form, form controls, iframe -->
-
-<!ENTITY % button.content
- "(#PCDATA | p | %heading; | div | %lists; | %blocktext; |
- table | br | span | bdo | object | applet | img | map |
- %fontstyle; | %phrase; | %misc;)*">
-
-<!--================ Document Structure ==================================-->
-
-<!-- the namespace URI designates the document profile -->
-
-<!ELEMENT html (head, frameset)>
-<!ATTLIST html
- %i18n;
- id ID #IMPLIED
- xmlns %URI; #FIXED 'http://www.w3.org/1999/xhtml'
- >
-
-<!--================ Document Head =======================================-->
-
-<!ENTITY % head.misc "(script|style|meta|link|object|isindex)*">
-
-<!-- content model is %head.misc; combined with a single
- title and an optional base element in any order -->
-
-<!ELEMENT head (%head.misc;,
- ((title, %head.misc;, (base, %head.misc;)?) |
- (base, %head.misc;, (title, %head.misc;))))>
-
-<!ATTLIST head
- %i18n;
- id ID #IMPLIED
- profile %URI; #IMPLIED
- >
-
-<!-- The title element is not considered part of the flow of text.
- It should be displayed, for example as the page header or
- window title. Exactly one title is required per document.
- -->
-<!ELEMENT title (#PCDATA)>
-<!ATTLIST title
- %i18n;
- id ID #IMPLIED
- >
-
-<!-- document base URI -->
-
-<!ELEMENT base EMPTY>
-<!ATTLIST base
- id ID #IMPLIED
- href %URI; #IMPLIED
- target %FrameTarget; #IMPLIED
- >
-
-<!-- generic metainformation -->
-<!ELEMENT meta EMPTY>
-<!ATTLIST meta
- %i18n;
- id ID #IMPLIED
- http-equiv CDATA #IMPLIED
- name CDATA #IMPLIED
- content CDATA #REQUIRED
- scheme CDATA #IMPLIED
- >
-
-<!--
- Relationship values can be used in principle:
-
- a) for document specific toolbars/menus when used
- with the link element in document head e.g.
- start, contents, previous, next, index, end, help
- b) to link to a separate style sheet (rel="stylesheet")
- c) to make a link to a script (rel="script")
- d) by stylesheets to control how collections of
- html nodes are rendered into printed documents
- e) to make a link to a printable version of this document
- e.g. a PostScript or PDF version (rel="alternate" media="print")
--->
-
-<!ELEMENT link EMPTY>
-<!ATTLIST link
- %attrs;
- charset %Charset; #IMPLIED
- href %URI; #IMPLIED
- hreflang %LanguageCode; #IMPLIED
- type %ContentType; #IMPLIED
- rel %LinkTypes; #IMPLIED
- rev %LinkTypes; #IMPLIED
- media %MediaDesc; #IMPLIED
- target %FrameTarget; #IMPLIED
- >
-
-<!-- style info, which may include CDATA sections -->
-<!ELEMENT style (#PCDATA)>
-<!ATTLIST style
- %i18n;
- id ID #IMPLIED
- type %ContentType; #REQUIRED
- media %MediaDesc; #IMPLIED
- title %Text; #IMPLIED
- xml:space (preserve) #FIXED 'preserve'
- >
-
-<!-- script statements, which may include CDATA sections -->
-<!ELEMENT script (#PCDATA)>
-<!ATTLIST script
- id ID #IMPLIED
- charset %Charset; #IMPLIED
- type %ContentType; #REQUIRED
- language CDATA #IMPLIED
- src %URI; #IMPLIED
- defer (defer) #IMPLIED
- xml:space (preserve) #FIXED 'preserve'
- >
-
-<!-- alternate content container for non script-based rendering -->
-
-<!ELEMENT noscript %Flow;>
-<!ATTLIST noscript
- %attrs;
- >
-
-<!--======================= Frames =======================================-->
-
-<!-- only one noframes element permitted per document -->
-
-<!ELEMENT frameset (frameset|frame|noframes)*>
-<!ATTLIST frameset
- %coreattrs;
- rows %MultiLengths; #IMPLIED
- cols %MultiLengths; #IMPLIED
- onload %Script; #IMPLIED
- onunload %Script; #IMPLIED
- >
-
-<!-- reserved frame names start with "_" otherwise starts with letter -->
-
-<!-- tiled window within frameset -->
-
-<!ELEMENT frame EMPTY>
-<!ATTLIST frame
- %coreattrs;
- longdesc %URI; #IMPLIED
- name NMTOKEN #IMPLIED
- src %URI; #IMPLIED
- frameborder (1|0) "1"
- marginwidth %Pixels; #IMPLIED
- marginheight %Pixels; #IMPLIED
- noresize (noresize) #IMPLIED
- scrolling (yes|no|auto) "auto"
- >
-
-<!-- inline subwindow -->
-
-<!ELEMENT iframe %Flow;>
-<!ATTLIST iframe
- %coreattrs;
- longdesc %URI; #IMPLIED
- name NMTOKEN #IMPLIED
- src %URI; #IMPLIED
- frameborder (1|0) "1"
- marginwidth %Pixels; #IMPLIED
- marginheight %Pixels; #IMPLIED
- scrolling (yes|no|auto) "auto"
- align %ImgAlign; #IMPLIED
- height %Length; #IMPLIED
- width %Length; #IMPLIED
- >
-
-<!-- alternate content container for non frame-based rendering -->
-
-<!ELEMENT noframes (body)>
-<!ATTLIST noframes
- %attrs;
- >
-
-<!--=================== Document Body ====================================-->
-
-<!ELEMENT body %Flow;>
-<!ATTLIST body
- %attrs;
- onload %Script; #IMPLIED
- onunload %Script; #IMPLIED
- background %URI; #IMPLIED
- bgcolor %Color; #IMPLIED
- text %Color; #IMPLIED
- link %Color; #IMPLIED
- vlink %Color; #IMPLIED
- alink %Color; #IMPLIED
- >
-
-<!ELEMENT div %Flow;> <!-- generic language/style container -->
-<!ATTLIST div
- %attrs;
- %TextAlign;
- >
-
-<!--=================== Paragraphs =======================================-->
-
-<!ELEMENT p %Inline;>
-<!ATTLIST p
- %attrs;
- %TextAlign;
- >
-
-<!--=================== Headings =========================================-->
-
-<!--
- There are six levels of headings from h1 (the most important)
- to h6 (the least important).
--->
-
-<!ELEMENT h1 %Inline;>
-<!ATTLIST h1
- %attrs;
- %TextAlign;
- >
-
-<!ELEMENT h2 %Inline;>
-<!ATTLIST h2
- %attrs;
- %TextAlign;
- >
-
-<!ELEMENT h3 %Inline;>
-<!ATTLIST h3
- %attrs;
- %TextAlign;
- >
-
-<!ELEMENT h4 %Inline;>
-<!ATTLIST h4
- %attrs;
- %TextAlign;
- >
-
-<!ELEMENT h5 %Inline;>
-<!ATTLIST h5
- %attrs;
- %TextAlign;
- >
-
-<!ELEMENT h6 %Inline;>
-<!ATTLIST h6
- %attrs;
- %TextAlign;
- >
-
-<!--=================== Lists ============================================-->
-
-<!-- Unordered list bullet styles -->
-
-<!ENTITY % ULStyle "(disc|square|circle)">
-
-<!-- Unordered list -->
-
-<!ELEMENT ul (li)+>
-<!ATTLIST ul
- %attrs;
- type %ULStyle; #IMPLIED
- compact (compact) #IMPLIED
- >
-
-<!-- Ordered list numbering style
-
- 1 arabic numbers 1, 2, 3, ...
- a lower alpha a, b, c, ...
- A upper alpha A, B, C, ...
- i lower roman i, ii, iii, ...
- I upper roman I, II, III, ...
-
- The style is applied to the sequence number which by default
- is reset to 1 for the first list item in an ordered list.
--->
-<!ENTITY % OLStyle "CDATA">
-
-<!-- Ordered (numbered) list -->
-
-<!ELEMENT ol (li)+>
-<!ATTLIST ol
- %attrs;
- type %OLStyle; #IMPLIED
- compact (compact) #IMPLIED
- start %Number; #IMPLIED
- >
-
-<!-- single column list (DEPRECATED) -->
-<!ELEMENT menu (li)+>
-<!ATTLIST menu
- %attrs;
- compact (compact) #IMPLIED
- >
-
-<!-- multiple column list (DEPRECATED) -->
-<!ELEMENT dir (li)+>
-<!ATTLIST dir
- %attrs;
- compact (compact) #IMPLIED
- >
-
-<!-- LIStyle is constrained to: "(%ULStyle;|%OLStyle;)" -->
-<!ENTITY % LIStyle "CDATA">
-
-<!-- list item -->
-
-<!ELEMENT li %Flow;>
-<!ATTLIST li
- %attrs;
- type %LIStyle; #IMPLIED
- value %Number; #IMPLIED
- >
-
-<!-- definition lists - dt for term, dd for its definition -->
-
-<!ELEMENT dl (dt|dd)+>
-<!ATTLIST dl
- %attrs;
- compact (compact) #IMPLIED
- >
-
-<!ELEMENT dt %Inline;>
-<!ATTLIST dt
- %attrs;
- >
-
-<!ELEMENT dd %Flow;>
-<!ATTLIST dd
- %attrs;
- >
-
-<!--=================== Address ==========================================-->
-
-<!-- information on author -->
-
-<!ELEMENT address (#PCDATA | %inline; | %misc.inline; | p)*>
-<!ATTLIST address
- %attrs;
- >
-
-<!--=================== Horizontal Rule ==================================-->
-
-<!ELEMENT hr EMPTY>
-<!ATTLIST hr
- %attrs;
- align (left|center|right) #IMPLIED
- noshade (noshade) #IMPLIED
- size %Pixels; #IMPLIED
- width %Length; #IMPLIED
- >
-
-<!--=================== Preformatted Text ================================-->
-
-<!-- content is %Inline; excluding
- "img|object|applet|big|small|sub|sup|font|basefont" -->
-
-<!ELEMENT pre %pre.content;>
-<!ATTLIST pre
- %attrs;
- width %Number; #IMPLIED
- xml:space (preserve) #FIXED 'preserve'
- >
-
-<!--=================== Block-like Quotes ================================-->
-
-<!ELEMENT blockquote %Flow;>
-<!ATTLIST blockquote
- %attrs;
- cite %URI; #IMPLIED
- >
-
-<!--=================== Text alignment ===================================-->
-
-<!-- center content -->
-<!ELEMENT center %Flow;>
-<!ATTLIST center
- %attrs;
- >
-
-<!--=================== Inserted/Deleted Text ============================-->
-
-
-<!--
- ins/del are allowed in block and inline content, but its
- inappropriate to include block content within an ins element
- occurring in inline content.
--->
-<!ELEMENT ins %Flow;>
-<!ATTLIST ins
- %attrs;
- cite %URI; #IMPLIED
- datetime %Datetime; #IMPLIED
- >
-
-<!ELEMENT del %Flow;>
-<!ATTLIST del
- %attrs;
- cite %URI; #IMPLIED
- datetime %Datetime; #IMPLIED
- >
-
-<!--================== The Anchor Element ================================-->
-
-<!-- content is %Inline; except that anchors shouldn't be nested -->
-
-<!ELEMENT a %a.content;>
-<!ATTLIST a
- %attrs;
- %focus;
- charset %Charset; #IMPLIED
- type %ContentType; #IMPLIED
- name NMTOKEN #IMPLIED
- href %URI; #IMPLIED
- hreflang %LanguageCode; #IMPLIED
- rel %LinkTypes; #IMPLIED
- rev %LinkTypes; #IMPLIED
- shape %Shape; "rect"
- coords %Coords; #IMPLIED
- target %FrameTarget; #IMPLIED
- >
-
-<!--===================== Inline Elements ================================-->
-
-<!ELEMENT span %Inline;> <!-- generic language/style container -->
-<!ATTLIST span
- %attrs;
- >
-
-<!ELEMENT bdo %Inline;> <!-- I18N BiDi over-ride -->
-<!ATTLIST bdo
- %coreattrs;
- %events;
- lang %LanguageCode; #IMPLIED
- xml:lang %LanguageCode; #IMPLIED
- dir (ltr|rtl) #REQUIRED
- >
-
-<!ELEMENT br EMPTY> <!-- forced line break -->
-<!ATTLIST br
- %coreattrs;
- clear (left|all|right|none) "none"
- >
-
-<!ELEMENT em %Inline;> <!-- emphasis -->
-<!ATTLIST em %attrs;>
-
-<!ELEMENT strong %Inline;> <!-- strong emphasis -->
-<!ATTLIST strong %attrs;>
-
-<!ELEMENT dfn %Inline;> <!-- definitional -->
-<!ATTLIST dfn %attrs;>
-
-<!ELEMENT code %Inline;> <!-- program code -->
-<!ATTLIST code %attrs;>
-
-<!ELEMENT samp %Inline;> <!-- sample -->
-<!ATTLIST samp %attrs;>
-
-<!ELEMENT kbd %Inline;> <!-- something user would type -->
-<!ATTLIST kbd %attrs;>
-
-<!ELEMENT var %Inline;> <!-- variable -->
-<!ATTLIST var %attrs;>
-
-<!ELEMENT cite %Inline;> <!-- citation -->
-<!ATTLIST cite %attrs;>
-
-<!ELEMENT abbr %Inline;> <!-- abbreviation -->
-<!ATTLIST abbr %attrs;>
-
-<!ELEMENT acronym %Inline;> <!-- acronym -->
-<!ATTLIST acronym %attrs;>
-
-<!ELEMENT q %Inline;> <!-- inlined quote -->
-<!ATTLIST q
- %attrs;
- cite %URI; #IMPLIED
- >
-
-<!ELEMENT sub %Inline;> <!-- subscript -->
-<!ATTLIST sub %attrs;>
-
-<!ELEMENT sup %Inline;> <!-- superscript -->
-<!ATTLIST sup %attrs;>
-
-<!ELEMENT tt %Inline;> <!-- fixed pitch font -->
-<!ATTLIST tt %attrs;>
-
-<!ELEMENT i %Inline;> <!-- italic font -->
-<!ATTLIST i %attrs;>
-
-<!ELEMENT b %Inline;> <!-- bold font -->
-<!ATTLIST b %attrs;>
-
-<!ELEMENT big %Inline;> <!-- bigger font -->
-<!ATTLIST big %attrs;>
-
-<!ELEMENT small %Inline;> <!-- smaller font -->
-<!ATTLIST small %attrs;>
-
-<!ELEMENT u %Inline;> <!-- underline -->
-<!ATTLIST u %attrs;>
-
-<!ELEMENT s %Inline;> <!-- strike-through -->
-<!ATTLIST s %attrs;>
-
-<!ELEMENT strike %Inline;> <!-- strike-through -->
-<!ATTLIST strike %attrs;>
-
-<!ELEMENT basefont EMPTY> <!-- base font size -->
-<!ATTLIST basefont
- id ID #IMPLIED
- size CDATA #REQUIRED
- color %Color; #IMPLIED
- face CDATA #IMPLIED
- >
-
-<!ELEMENT font %Inline;> <!-- local change to font -->
-<!ATTLIST font
- %coreattrs;
- %i18n;
- size CDATA #IMPLIED
- color %Color; #IMPLIED
- face CDATA #IMPLIED
- >
-
-<!--==================== Object ======================================-->
-<!--
- object is used to embed objects as part of HTML pages.
- param elements should precede other content. Parameters
- can also be expressed as attribute/value pairs on the
- object element itself when brevity is desired.
--->
-
-<!ELEMENT object (#PCDATA | param | %block; | form |%inline; | %misc;)*>
-<!ATTLIST object
- %attrs;
- declare (declare) #IMPLIED
- classid %URI; #IMPLIED
- codebase %URI; #IMPLIED
- data %URI; #IMPLIED
- type %ContentType; #IMPLIED
- codetype %ContentType; #IMPLIED
- archive %UriList; #IMPLIED
- standby %Text; #IMPLIED
- height %Length; #IMPLIED
- width %Length; #IMPLIED
- usemap %URI; #IMPLIED
- name NMTOKEN #IMPLIED
- tabindex %Number; #IMPLIED
- align %ImgAlign; #IMPLIED
- border %Pixels; #IMPLIED
- hspace %Pixels; #IMPLIED
- vspace %Pixels; #IMPLIED
- >
-
-<!--
- param is used to supply a named property value.
- In XML it would seem natural to follow RDF and support an
- abbreviated syntax where the param elements are replaced
- by attribute value pairs on the object start tag.
--->
-<!ELEMENT param EMPTY>
-<!ATTLIST param
- id ID #IMPLIED
- name CDATA #REQUIRED
- value CDATA #IMPLIED
- valuetype (data|ref|object) "data"
- type %ContentType; #IMPLIED
- >
-
-<!--=================== Java applet ==================================-->
-<!--
- One of code or object attributes must be present.
- Place param elements before other content.
--->
-<!ELEMENT applet (#PCDATA | param | %block; | form | %inline; | %misc;)*>
-<!ATTLIST applet
- %coreattrs;
- codebase %URI; #IMPLIED
- archive CDATA #IMPLIED
- code CDATA #IMPLIED
- object CDATA #IMPLIED
- alt %Text; #IMPLIED
- name NMTOKEN #IMPLIED
- width %Length; #REQUIRED
- height %Length; #REQUIRED
- align %ImgAlign; #IMPLIED
- hspace %Pixels; #IMPLIED
- vspace %Pixels; #IMPLIED
- >
-
-<!--=================== Images ===========================================-->
-
-<!--
- To avoid accessibility problems for people who aren't
- able to see the image, you should provide a text
- description using the alt and longdesc attributes.
- In addition, avoid the use of server-side image maps.
--->
-
-<!ELEMENT img EMPTY>
-<!ATTLIST img
- %attrs;
- src %URI; #REQUIRED
- alt %Text; #REQUIRED
- name NMTOKEN #IMPLIED
- longdesc %URI; #IMPLIED
- height %Length; #IMPLIED
- width %Length; #IMPLIED
- usemap %URI; #IMPLIED
- ismap (ismap) #IMPLIED
- align %ImgAlign; #IMPLIED
- border %Pixels; #IMPLIED
- hspace %Pixels; #IMPLIED
- vspace %Pixels; #IMPLIED
- >
-
-<!-- usemap points to a map element which may be in this document
- or an external document, although the latter is not widely supported -->
-
-<!--================== Client-side image maps ============================-->
-
-<!-- These can be placed in the same document or grouped in a
- separate document although this isn't yet widely supported -->
-
-<!ELEMENT map ((%block; | form | %misc;)+ | area+)>
-<!ATTLIST map
- %i18n;
- %events;
- id ID #REQUIRED
- class CDATA #IMPLIED
- style %StyleSheet; #IMPLIED
- title %Text; #IMPLIED
- name NMTOKEN #IMPLIED
- >
-
-<!ELEMENT area EMPTY>
-<!ATTLIST area
- %attrs;
- %focus;
- shape %Shape; "rect"
- coords %Coords; #IMPLIED
- href %URI; #IMPLIED
- nohref (nohref) #IMPLIED
- alt %Text; #REQUIRED
- target %FrameTarget; #IMPLIED
- >
-
-<!--================ Forms ===============================================-->
-
-<!ELEMENT form %form.content;> <!-- forms shouldn't be nested -->
-
-<!ATTLIST form
- %attrs;
- action %URI; #REQUIRED
- method (get|post) "get"
- name NMTOKEN #IMPLIED
- enctype %ContentType; "application/x-www-form-urlencoded"
- onsubmit %Script; #IMPLIED
- onreset %Script; #IMPLIED
- accept %ContentTypes; #IMPLIED
- accept-charset %Charsets; #IMPLIED
- target %FrameTarget; #IMPLIED
- >
-
-<!--
- Each label must not contain more than ONE field
- Label elements shouldn't be nested.
--->
-<!ELEMENT label %Inline;>
-<!ATTLIST label
- %attrs;
- for IDREF #IMPLIED
- accesskey %Character; #IMPLIED
- onfocus %Script; #IMPLIED
- onblur %Script; #IMPLIED
- >
-
-<!ENTITY % InputType
- "(text | password | checkbox |
- radio | submit | reset |
- file | hidden | image | button)"
- >
-
-<!-- the name attribute is required for all but submit & reset -->
-
-<!ELEMENT input EMPTY> <!-- form control -->
-<!ATTLIST input
- %attrs;
- %focus;
- type %InputType; "text"
- name CDATA #IMPLIED
- value CDATA #IMPLIED
- checked (checked) #IMPLIED
- disabled (disabled) #IMPLIED
- readonly (readonly) #IMPLIED
- size CDATA #IMPLIED
- maxlength %Number; #IMPLIED
- src %URI; #IMPLIED
- alt CDATA #IMPLIED
- usemap %URI; #IMPLIED
- onselect %Script; #IMPLIED
- onchange %Script; #IMPLIED
- accept %ContentTypes; #IMPLIED
- align %ImgAlign; #IMPLIED
- >
-
-<!ELEMENT select (optgroup|option)+> <!-- option selector -->
-<!ATTLIST select
- %attrs;
- name CDATA #IMPLIED
- size %Number; #IMPLIED
- multiple (multiple) #IMPLIED
- disabled (disabled) #IMPLIED
- tabindex %Number; #IMPLIED
- onfocus %Script; #IMPLIED
- onblur %Script; #IMPLIED
- onchange %Script; #IMPLIED
- >
-
-<!ELEMENT optgroup (option)+> <!-- option group -->
-<!ATTLIST optgroup
- %attrs;
- disabled (disabled) #IMPLIED
- label %Text; #REQUIRED
- >
-
-<!ELEMENT option (#PCDATA)> <!-- selectable choice -->
-<!ATTLIST option
- %attrs;
- selected (selected) #IMPLIED
- disabled (disabled) #IMPLIED
- label %Text; #IMPLIED
- value CDATA #IMPLIED
- >
-
-<!ELEMENT textarea (#PCDATA)> <!-- multi-line text field -->
-<!ATTLIST textarea
- %attrs;
- %focus;
- name CDATA #IMPLIED
- rows %Number; #REQUIRED
- cols %Number; #REQUIRED
- disabled (disabled) #IMPLIED
- readonly (readonly) #IMPLIED
- onselect %Script; #IMPLIED
- onchange %Script; #IMPLIED
- >
-
-<!--
- The fieldset element is used to group form fields.
- Only one legend element should occur in the content
- and if present should only be preceded by whitespace.
--->
-<!ELEMENT fieldset (#PCDATA | legend | %block; | form | %inline; | %misc;)*>
-<!ATTLIST fieldset
- %attrs;
- >
-
-<!ENTITY % LAlign "(top|bottom|left|right)">
-
-<!ELEMENT legend %Inline;> <!-- fieldset label -->
-<!ATTLIST legend
- %attrs;
- accesskey %Character; #IMPLIED
- align %LAlign; #IMPLIED
- >
-
-<!--
- Content is %Flow; excluding a, form, form controls, iframe
--->
-<!ELEMENT button %button.content;> <!-- push button -->
-<!ATTLIST button
- %attrs;
- %focus;
- name CDATA #IMPLIED
- value CDATA #IMPLIED
- type (button|submit|reset) "submit"
- disabled (disabled) #IMPLIED
- >
-
-<!-- single-line text input control (DEPRECATED) -->
-<!ELEMENT isindex EMPTY>
-<!ATTLIST isindex
- %coreattrs;
- %i18n;
- prompt %Text; #IMPLIED
- >
-
-<!--======================= Tables =======================================-->
-
-<!-- Derived from IETF HTML table standard, see [RFC1942] -->
-
-<!--
- The border attribute sets the thickness of the frame around the
- table. The default units are screen pixels.
-
- The frame attribute specifies which parts of the frame around
- the table should be rendered. The values are not the same as
- CALS to avoid a name clash with the valign attribute.
--->
-<!ENTITY % TFrame "(void|above|below|hsides|lhs|rhs|vsides|box|border)">
-
-<!--
- The rules attribute defines which rules to draw between cells:
-
- If rules is absent then assume:
- "none" if border is absent or border="0" otherwise "all"
--->
-
-<!ENTITY % TRules "(none | groups | rows | cols | all)">
-
-<!-- horizontal placement of table relative to document -->
-<!ENTITY % TAlign "(left|center|right)">
-
-<!-- horizontal alignment attributes for cell contents
-
- char alignment char, e.g. char=":"
- charoff offset for alignment char
--->
-<!ENTITY % cellhalign
- "align (left|center|right|justify|char) #IMPLIED
- char %Character; #IMPLIED
- charoff %Length; #IMPLIED"
- >
-
-<!-- vertical alignment attributes for cell contents -->
-<!ENTITY % cellvalign
- "valign (top|middle|bottom|baseline) #IMPLIED"
- >
-
-<!ELEMENT table
- (caption?, (col*|colgroup*), thead?, tfoot?, (tbody+|tr+))>
-<!ELEMENT caption %Inline;>
-<!ELEMENT thead (tr)+>
-<!ELEMENT tfoot (tr)+>
-<!ELEMENT tbody (tr)+>
-<!ELEMENT colgroup (col)*>
-<!ELEMENT col EMPTY>
-<!ELEMENT tr (th|td)+>
-<!ELEMENT th %Flow;>
-<!ELEMENT td %Flow;>
-
-<!ATTLIST table
- %attrs;
- summary %Text; #IMPLIED
- width %Length; #IMPLIED
- border %Pixels; #IMPLIED
- frame %TFrame; #IMPLIED
- rules %TRules; #IMPLIED
- cellspacing %Length; #IMPLIED
- cellpadding %Length; #IMPLIED
- align %TAlign; #IMPLIED
- bgcolor %Color; #IMPLIED
- >
-
-<!ENTITY % CAlign "(top|bottom|left|right)">
-
-<!ATTLIST caption
- %attrs;
- align %CAlign; #IMPLIED
- >
-
-<!--
-colgroup groups a set of col elements. It allows you to group
-several semantically related columns together.
--->
-<!ATTLIST colgroup
- %attrs;
- span %Number; "1"
- width %MultiLength; #IMPLIED
- %cellhalign;
- %cellvalign;
- >
-
-<!--
- col elements define the alignment properties for cells in
- one or more columns.
-
- The width attribute specifies the width of the columns, e.g.
-
- width=64 width in screen pixels
- width=0.5* relative width of 0.5
-
- The span attribute causes the attributes of one
- col element to apply to more than one column.
--->
-<!ATTLIST col
- %attrs;
- span %Number; "1"
- width %MultiLength; #IMPLIED
- %cellhalign;
- %cellvalign;
- >
-
-<!--
- Use thead to duplicate headers when breaking table
- across page boundaries, or for static headers when
- tbody sections are rendered in scrolling panel.
-
- Use tfoot to duplicate footers when breaking table
- across page boundaries, or for static footers when
- tbody sections are rendered in scrolling panel.
-
- Use multiple tbody sections when rules are needed
- between groups of table rows.
--->
-<!ATTLIST thead
- %attrs;
- %cellhalign;
- %cellvalign;
- >
-
-<!ATTLIST tfoot
- %attrs;
- %cellhalign;
- %cellvalign;
- >
-
-<!ATTLIST tbody
- %attrs;
- %cellhalign;
- %cellvalign;
- >
-
-<!ATTLIST tr
- %attrs;
- %cellhalign;
- %cellvalign;
- bgcolor %Color; #IMPLIED
- >
-
-<!-- Scope is simpler than headers attribute for common tables -->
-<!ENTITY % Scope "(row|col|rowgroup|colgroup)">
-
-<!-- th is for headers, td for data and for cells acting as both -->
-
-<!ATTLIST th
- %attrs;
- abbr %Text; #IMPLIED
- axis CDATA #IMPLIED
- headers IDREFS #IMPLIED
- scope %Scope; #IMPLIED
- rowspan %Number; "1"
- colspan %Number; "1"
- %cellhalign;
- %cellvalign;
- nowrap (nowrap) #IMPLIED
- bgcolor %Color; #IMPLIED
- width %Pixels; #IMPLIED
- height %Pixels; #IMPLIED
- >
-
-<!ATTLIST td
- %attrs;
- abbr %Text; #IMPLIED
- axis CDATA #IMPLIED
- headers IDREFS #IMPLIED
- scope %Scope; #IMPLIED
- rowspan %Number; "1"
- colspan %Number; "1"
- %cellhalign;
- %cellvalign;
- nowrap (nowrap) #IMPLIED
- bgcolor %Color; #IMPLIED
- width %Pixels; #IMPLIED
- height %Pixels; #IMPLIED
- >
-
diff --git a/lib/erl_docgen/priv/docbuilder_dtd/xhtml1-strict.dtd b/lib/erl_docgen/priv/docbuilder_dtd/xhtml1-strict.dtd
deleted file mode 100644
index 2927b9ece7..0000000000
--- a/lib/erl_docgen/priv/docbuilder_dtd/xhtml1-strict.dtd
+++ /dev/null
@@ -1,978 +0,0 @@
-<!--
- Extensible HTML version 1.0 Strict DTD
-
- This is the same as HTML 4 Strict except for
- changes due to the differences between XML and SGML.
-
- Namespace = http://www.w3.org/1999/xhtml
-
- For further information, see: http://www.w3.org/TR/xhtml1
-
- Copyright (c) 1998-2002 W3C (MIT, INRIA, Keio),
- All Rights Reserved.
-
- This DTD module is identified by the PUBLIC and SYSTEM identifiers:
-
- PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
- SYSTEM "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"
-
- $Revision: 1.1 $
- $Date: 2002/08/01 13:56:03 $
-
--->
-
-<!--================ Character mnemonic entities =========================-->
-
-<!ENTITY % HTMLlat1 PUBLIC
- "-//W3C//ENTITIES Latin 1 for XHTML//EN"
- "xhtml-lat1.ent">
-%HTMLlat1;
-
-<!ENTITY % HTMLsymbol PUBLIC
- "-//W3C//ENTITIES Symbols for XHTML//EN"
- "xhtml-symbol.ent">
-%HTMLsymbol;
-
-<!ENTITY % HTMLspecial PUBLIC
- "-//W3C//ENTITIES Special for XHTML//EN"
- "xhtml-special.ent">
-%HTMLspecial;
-
-<!--================== Imported Names ====================================-->
-
-<!ENTITY % ContentType "CDATA">
- <!-- media type, as per [RFC2045] -->
-
-<!ENTITY % ContentTypes "CDATA">
- <!-- comma-separated list of media types, as per [RFC2045] -->
-
-<!ENTITY % Charset "CDATA">
- <!-- a character encoding, as per [RFC2045] -->
-
-<!ENTITY % Charsets "CDATA">
- <!-- a space separated list of character encodings, as per [RFC2045] -->
-
-<!ENTITY % LanguageCode "NMTOKEN">
- <!-- a language code, as per [RFC3066] -->
-
-<!ENTITY % Character "CDATA">
- <!-- a single character, as per section 2.2 of [XML] -->
-
-<!ENTITY % Number "CDATA">
- <!-- one or more digits -->
-
-<!ENTITY % LinkTypes "CDATA">
- <!-- space-separated list of link types -->
-
-<!ENTITY % MediaDesc "CDATA">
- <!-- single or comma-separated list of media descriptors -->
-
-<!ENTITY % URI "CDATA">
- <!-- a Uniform Resource Identifier, see [RFC2396] -->
-
-<!ENTITY % UriList "CDATA">
- <!-- a space separated list of Uniform Resource Identifiers -->
-
-<!ENTITY % Datetime "CDATA">
- <!-- date and time information. ISO date format -->
-
-<!ENTITY % Script "CDATA">
- <!-- script expression -->
-
-<!ENTITY % StyleSheet "CDATA">
- <!-- style sheet data -->
-
-<!ENTITY % Text "CDATA">
- <!-- used for titles etc. -->
-
-<!ENTITY % Length "CDATA">
- <!-- nn for pixels or nn% for percentage length -->
-
-<!ENTITY % MultiLength "CDATA">
- <!-- pixel, percentage, or relative -->
-
-<!ENTITY % Pixels "CDATA">
- <!-- integer representing length in pixels -->
-
-<!-- these are used for image maps -->
-
-<!ENTITY % Shape "(rect|circle|poly|default)">
-
-<!ENTITY % Coords "CDATA">
- <!-- comma separated list of lengths -->
-
-<!--=================== Generic Attributes ===============================-->
-
-<!-- core attributes common to most elements
- id document-wide unique id
- class space separated list of classes
- style associated style info
- title advisory title/amplification
--->
-<!ENTITY % coreattrs
- "id ID #IMPLIED
- class CDATA #IMPLIED
- style %StyleSheet; #IMPLIED
- title %Text; #IMPLIED"
- >
-
-<!-- internationalization attributes
- lang language code (backwards compatible)
- xml:lang language code (as per XML 1.0 spec)
- dir direction for weak/neutral text
--->
-<!ENTITY % i18n
- "lang %LanguageCode; #IMPLIED
- xml:lang %LanguageCode; #IMPLIED
- dir (ltr|rtl) #IMPLIED"
- >
-
-<!-- attributes for common UI events
- onclick a pointer button was clicked
- ondblclick a pointer button was double clicked
- onmousedown a pointer button was pressed down
- onmouseup a pointer button was released
- onmousemove a pointer was moved onto the element
- onmouseout a pointer was moved away from the element
- onkeypress a key was pressed and released
- onkeydown a key was pressed down
- onkeyup a key was released
--->
-<!ENTITY % events
- "onclick %Script; #IMPLIED
- ondblclick %Script; #IMPLIED
- onmousedown %Script; #IMPLIED
- onmouseup %Script; #IMPLIED
- onmouseover %Script; #IMPLIED
- onmousemove %Script; #IMPLIED
- onmouseout %Script; #IMPLIED
- onkeypress %Script; #IMPLIED
- onkeydown %Script; #IMPLIED
- onkeyup %Script; #IMPLIED"
- >
-
-<!-- attributes for elements that can get the focus
- accesskey accessibility key character
- tabindex position in tabbing order
- onfocus the element got the focus
- onblur the element lost the focus
--->
-<!ENTITY % focus
- "accesskey %Character; #IMPLIED
- tabindex %Number; #IMPLIED
- onfocus %Script; #IMPLIED
- onblur %Script; #IMPLIED"
- >
-
-<!ENTITY % attrs "%coreattrs; %i18n; %events;">
-
-<!--=================== Text Elements ====================================-->
-
-<!ENTITY % special.pre
- "br | span | bdo | map">
-
-
-<!ENTITY % special
- "%special.pre; | object | img ">
-
-<!ENTITY % fontstyle "tt | i | b | big | small ">
-
-<!ENTITY % phrase "em | strong | dfn | code | q |
- samp | kbd | var | cite | abbr | acronym | sub | sup ">
-
-<!ENTITY % inline.forms "input | select | textarea | label | button">
-
-<!-- these can occur at block or inline level -->
-<!ENTITY % misc.inline "ins | del | script">
-
-<!-- these can only occur at block level -->
-<!ENTITY % misc "noscript | %misc.inline;">
-
-<!ENTITY % inline "a | %special; | %fontstyle; | %phrase; | %inline.forms;">
-
-<!-- %Inline; covers inline or "text-level" elements -->
-<!ENTITY % Inline "(#PCDATA | %inline; | %misc.inline;)*">
-
-<!--================== Block level elements ==============================-->
-
-<!ENTITY % heading "h1|h2|h3|h4|h5|h6">
-<!ENTITY % lists "ul | ol | dl">
-<!ENTITY % blocktext "pre | hr | blockquote | address">
-
-<!ENTITY % block
- "p | %heading; | div | %lists; | %blocktext; | fieldset | table">
-
-<!ENTITY % Block "(%block; | form | %misc;)*">
-
-<!-- %Flow; mixes block and inline and is used for list items etc. -->
-<!ENTITY % Flow "(#PCDATA | %block; | form | %inline; | %misc;)*">
-
-<!--================== Content models for exclusions =====================-->
-
-<!-- a elements use %Inline; excluding a -->
-
-<!ENTITY % a.content
- "(#PCDATA | %special; | %fontstyle; | %phrase; | %inline.forms; | %misc.inline;)*">
-
-<!-- pre uses %Inline excluding big, small, sup or sup -->
-
-<!ENTITY % pre.content
- "(#PCDATA | a | %fontstyle; | %phrase; | %special.pre; | %misc.inline;
- | %inline.forms;)*">
-
-<!-- form uses %Block; excluding form -->
-
-<!ENTITY % form.content "(%block; | %misc;)*">
-
-<!-- button uses %Flow; but excludes a, form and form controls -->
-
-<!ENTITY % button.content
- "(#PCDATA | p | %heading; | div | %lists; | %blocktext; |
- table | %special; | %fontstyle; | %phrase; | %misc;)*">
-
-<!--================ Document Structure ==================================-->
-
-<!-- the namespace URI designates the document profile -->
-
-<!ELEMENT html (head, body)>
-<!ATTLIST html
- %i18n;
- id ID #IMPLIED
- xmlns %URI; #FIXED 'http://www.w3.org/1999/xhtml'
- >
-
-<!--================ Document Head =======================================-->
-
-<!ENTITY % head.misc "(script|style|meta|link|object)*">
-
-<!-- content model is %head.misc; combined with a single
- title and an optional base element in any order -->
-
-<!ELEMENT head (%head.misc;,
- ((title, %head.misc;, (base, %head.misc;)?) |
- (base, %head.misc;, (title, %head.misc;))))>
-
-<!ATTLIST head
- %i18n;
- id ID #IMPLIED
- profile %URI; #IMPLIED
- >
-
-<!-- The title element is not considered part of the flow of text.
- It should be displayed, for example as the page header or
- window title. Exactly one title is required per document.
- -->
-<!ELEMENT title (#PCDATA)>
-<!ATTLIST title
- %i18n;
- id ID #IMPLIED
- >
-
-<!-- document base URI -->
-
-<!ELEMENT base EMPTY>
-<!ATTLIST base
- href %URI; #REQUIRED
- id ID #IMPLIED
- >
-
-<!-- generic metainformation -->
-<!ELEMENT meta EMPTY>
-<!ATTLIST meta
- %i18n;
- id ID #IMPLIED
- http-equiv CDATA #IMPLIED
- name CDATA #IMPLIED
- content CDATA #REQUIRED
- scheme CDATA #IMPLIED
- >
-
-<!--
- Relationship values can be used in principle:
-
- a) for document specific toolbars/menus when used
- with the link element in document head e.g.
- start, contents, previous, next, index, end, help
- b) to link to a separate style sheet (rel="stylesheet")
- c) to make a link to a script (rel="script")
- d) by stylesheets to control how collections of
- html nodes are rendered into printed documents
- e) to make a link to a printable version of this document
- e.g. a PostScript or PDF version (rel="alternate" media="print")
--->
-
-<!ELEMENT link EMPTY>
-<!ATTLIST link
- %attrs;
- charset %Charset; #IMPLIED
- href %URI; #IMPLIED
- hreflang %LanguageCode; #IMPLIED
- type %ContentType; #IMPLIED
- rel %LinkTypes; #IMPLIED
- rev %LinkTypes; #IMPLIED
- media %MediaDesc; #IMPLIED
- >
-
-<!-- style info, which may include CDATA sections -->
-<!ELEMENT style (#PCDATA)>
-<!ATTLIST style
- %i18n;
- id ID #IMPLIED
- type %ContentType; #REQUIRED
- media %MediaDesc; #IMPLIED
- title %Text; #IMPLIED
- xml:space (preserve) #FIXED 'preserve'
- >
-
-<!-- script statements, which may include CDATA sections -->
-<!ELEMENT script (#PCDATA)>
-<!ATTLIST script
- id ID #IMPLIED
- charset %Charset; #IMPLIED
- type %ContentType; #REQUIRED
- src %URI; #IMPLIED
- defer (defer) #IMPLIED
- xml:space (preserve) #FIXED 'preserve'
- >
-
-<!-- alternate content container for non script-based rendering -->
-
-<!ELEMENT noscript %Block;>
-<!ATTLIST noscript
- %attrs;
- >
-
-<!--=================== Document Body ====================================-->
-
-<!ELEMENT body %Block;>
-<!ATTLIST body
- %attrs;
- onload %Script; #IMPLIED
- onunload %Script; #IMPLIED
- >
-
-<!ELEMENT div %Flow;> <!-- generic language/style container -->
-<!ATTLIST div
- %attrs;
- >
-
-<!--=================== Paragraphs =======================================-->
-
-<!ELEMENT p %Inline;>
-<!ATTLIST p
- %attrs;
- >
-
-<!--=================== Headings =========================================-->
-
-<!--
- There are six levels of headings from h1 (the most important)
- to h6 (the least important).
--->
-
-<!ELEMENT h1 %Inline;>
-<!ATTLIST h1
- %attrs;
- >
-
-<!ELEMENT h2 %Inline;>
-<!ATTLIST h2
- %attrs;
- >
-
-<!ELEMENT h3 %Inline;>
-<!ATTLIST h3
- %attrs;
- >
-
-<!ELEMENT h4 %Inline;>
-<!ATTLIST h4
- %attrs;
- >
-
-<!ELEMENT h5 %Inline;>
-<!ATTLIST h5
- %attrs;
- >
-
-<!ELEMENT h6 %Inline;>
-<!ATTLIST h6
- %attrs;
- >
-
-<!--=================== Lists ============================================-->
-
-<!-- Unordered list -->
-
-<!ELEMENT ul (li)+>
-<!ATTLIST ul
- %attrs;
- >
-
-<!-- Ordered (numbered) list -->
-
-<!ELEMENT ol (li)+>
-<!ATTLIST ol
- %attrs;
- >
-
-<!-- list item -->
-
-<!ELEMENT li %Flow;>
-<!ATTLIST li
- %attrs;
- >
-
-<!-- definition lists - dt for term, dd for its definition -->
-
-<!ELEMENT dl (dt|dd)+>
-<!ATTLIST dl
- %attrs;
- >
-
-<!ELEMENT dt %Inline;>
-<!ATTLIST dt
- %attrs;
- >
-
-<!ELEMENT dd %Flow;>
-<!ATTLIST dd
- %attrs;
- >
-
-<!--=================== Address ==========================================-->
-
-<!-- information on author -->
-
-<!ELEMENT address %Inline;>
-<!ATTLIST address
- %attrs;
- >
-
-<!--=================== Horizontal Rule ==================================-->
-
-<!ELEMENT hr EMPTY>
-<!ATTLIST hr
- %attrs;
- >
-
-<!--=================== Preformatted Text ================================-->
-
-<!-- content is %Inline; excluding "img|object|big|small|sub|sup" -->
-
-<!ELEMENT pre %pre.content;>
-<!ATTLIST pre
- %attrs;
- xml:space (preserve) #FIXED 'preserve'
- >
-
-<!--=================== Block-like Quotes ================================-->
-
-<!ELEMENT blockquote %Block;>
-<!ATTLIST blockquote
- %attrs;
- cite %URI; #IMPLIED
- >
-
-<!--=================== Inserted/Deleted Text ============================-->
-
-<!--
- ins/del are allowed in block and inline content, but its
- inappropriate to include block content within an ins element
- occurring in inline content.
--->
-<!ELEMENT ins %Flow;>
-<!ATTLIST ins
- %attrs;
- cite %URI; #IMPLIED
- datetime %Datetime; #IMPLIED
- >
-
-<!ELEMENT del %Flow;>
-<!ATTLIST del
- %attrs;
- cite %URI; #IMPLIED
- datetime %Datetime; #IMPLIED
- >
-
-<!--================== The Anchor Element ================================-->
-
-<!-- content is %Inline; except that anchors shouldn't be nested -->
-
-<!ELEMENT a %a.content;>
-<!ATTLIST a
- %attrs;
- %focus;
- charset %Charset; #IMPLIED
- type %ContentType; #IMPLIED
- name NMTOKEN #IMPLIED
- href %URI; #IMPLIED
- hreflang %LanguageCode; #IMPLIED
- rel %LinkTypes; #IMPLIED
- rev %LinkTypes; #IMPLIED
- shape %Shape; "rect"
- coords %Coords; #IMPLIED
- >
-
-<!--===================== Inline Elements ================================-->
-
-<!ELEMENT span %Inline;> <!-- generic language/style container -->
-<!ATTLIST span
- %attrs;
- >
-
-<!ELEMENT bdo %Inline;> <!-- I18N BiDi over-ride -->
-<!ATTLIST bdo
- %coreattrs;
- %events;
- lang %LanguageCode; #IMPLIED
- xml:lang %LanguageCode; #IMPLIED
- dir (ltr|rtl) #REQUIRED
- >
-
-<!ELEMENT br EMPTY> <!-- forced line break -->
-<!ATTLIST br
- %coreattrs;
- >
-
-<!ELEMENT em %Inline;> <!-- emphasis -->
-<!ATTLIST em %attrs;>
-
-<!ELEMENT strong %Inline;> <!-- strong emphasis -->
-<!ATTLIST strong %attrs;>
-
-<!ELEMENT dfn %Inline;> <!-- definitional -->
-<!ATTLIST dfn %attrs;>
-
-<!ELEMENT code %Inline;> <!-- program code -->
-<!ATTLIST code %attrs;>
-
-<!ELEMENT samp %Inline;> <!-- sample -->
-<!ATTLIST samp %attrs;>
-
-<!ELEMENT kbd %Inline;> <!-- something user would type -->
-<!ATTLIST kbd %attrs;>
-
-<!ELEMENT var %Inline;> <!-- variable -->
-<!ATTLIST var %attrs;>
-
-<!ELEMENT cite %Inline;> <!-- citation -->
-<!ATTLIST cite %attrs;>
-
-<!ELEMENT abbr %Inline;> <!-- abbreviation -->
-<!ATTLIST abbr %attrs;>
-
-<!ELEMENT acronym %Inline;> <!-- acronym -->
-<!ATTLIST acronym %attrs;>
-
-<!ELEMENT q %Inline;> <!-- inlined quote -->
-<!ATTLIST q
- %attrs;
- cite %URI; #IMPLIED
- >
-
-<!ELEMENT sub %Inline;> <!-- subscript -->
-<!ATTLIST sub %attrs;>
-
-<!ELEMENT sup %Inline;> <!-- superscript -->
-<!ATTLIST sup %attrs;>
-
-<!ELEMENT tt %Inline;> <!-- fixed pitch font -->
-<!ATTLIST tt %attrs;>
-
-<!ELEMENT i %Inline;> <!-- italic font -->
-<!ATTLIST i %attrs;>
-
-<!ELEMENT b %Inline;> <!-- bold font -->
-<!ATTLIST b %attrs;>
-
-<!ELEMENT big %Inline;> <!-- bigger font -->
-<!ATTLIST big %attrs;>
-
-<!ELEMENT small %Inline;> <!-- smaller font -->
-<!ATTLIST small %attrs;>
-
-<!--==================== Object ======================================-->
-<!--
- object is used to embed objects as part of HTML pages.
- param elements should precede other content. Parameters
- can also be expressed as attribute/value pairs on the
- object element itself when brevity is desired.
--->
-
-<!ELEMENT object (#PCDATA | param | %block; | form | %inline; | %misc;)*>
-<!ATTLIST object
- %attrs;
- declare (declare) #IMPLIED
- classid %URI; #IMPLIED
- codebase %URI; #IMPLIED
- data %URI; #IMPLIED
- type %ContentType; #IMPLIED
- codetype %ContentType; #IMPLIED
- archive %UriList; #IMPLIED
- standby %Text; #IMPLIED
- height %Length; #IMPLIED
- width %Length; #IMPLIED
- usemap %URI; #IMPLIED
- name NMTOKEN #IMPLIED
- tabindex %Number; #IMPLIED
- >
-
-<!--
- param is used to supply a named property value.
- In XML it would seem natural to follow RDF and support an
- abbreviated syntax where the param elements are replaced
- by attribute value pairs on the object start tag.
--->
-<!ELEMENT param EMPTY>
-<!ATTLIST param
- id ID #IMPLIED
- name CDATA #IMPLIED
- value CDATA #IMPLIED
- valuetype (data|ref|object) "data"
- type %ContentType; #IMPLIED
- >
-
-<!--=================== Images ===========================================-->
-
-<!--
- To avoid accessibility problems for people who aren't
- able to see the image, you should provide a text
- description using the alt and longdesc attributes.
- In addition, avoid the use of server-side image maps.
- Note that in this DTD there is no name attribute. That
- is only available in the transitional and frameset DTD.
--->
-
-<!ELEMENT img EMPTY>
-<!ATTLIST img
- %attrs;
- src %URI; #REQUIRED
- alt %Text; #REQUIRED
- longdesc %URI; #IMPLIED
- height %Length; #IMPLIED
- width %Length; #IMPLIED
- usemap %URI; #IMPLIED
- ismap (ismap) #IMPLIED
- >
-
-<!-- usemap points to a map element which may be in this document
- or an external document, although the latter is not widely supported -->
-
-<!--================== Client-side image maps ============================-->
-
-<!-- These can be placed in the same document or grouped in a
- separate document although this isn't yet widely supported -->
-
-<!ELEMENT map ((%block; | form | %misc;)+ | area+)>
-<!ATTLIST map
- %i18n;
- %events;
- id ID #REQUIRED
- class CDATA #IMPLIED
- style %StyleSheet; #IMPLIED
- title %Text; #IMPLIED
- name NMTOKEN #IMPLIED
- >
-
-<!ELEMENT area EMPTY>
-<!ATTLIST area
- %attrs;
- %focus;
- shape %Shape; "rect"
- coords %Coords; #IMPLIED
- href %URI; #IMPLIED
- nohref (nohref) #IMPLIED
- alt %Text; #REQUIRED
- >
-
-<!--================ Forms ===============================================-->
-<!ELEMENT form %form.content;> <!-- forms shouldn't be nested -->
-
-<!ATTLIST form
- %attrs;
- action %URI; #REQUIRED
- method (get|post) "get"
- enctype %ContentType; "application/x-www-form-urlencoded"
- onsubmit %Script; #IMPLIED
- onreset %Script; #IMPLIED
- accept %ContentTypes; #IMPLIED
- accept-charset %Charsets; #IMPLIED
- >
-
-<!--
- Each label must not contain more than ONE field
- Label elements shouldn't be nested.
--->
-<!ELEMENT label %Inline;>
-<!ATTLIST label
- %attrs;
- for IDREF #IMPLIED
- accesskey %Character; #IMPLIED
- onfocus %Script; #IMPLIED
- onblur %Script; #IMPLIED
- >
-
-<!ENTITY % InputType
- "(text | password | checkbox |
- radio | submit | reset |
- file | hidden | image | button)"
- >
-
-<!-- the name attribute is required for all but submit & reset -->
-
-<!ELEMENT input EMPTY> <!-- form control -->
-<!ATTLIST input
- %attrs;
- %focus;
- type %InputType; "text"
- name CDATA #IMPLIED
- value CDATA #IMPLIED
- checked (checked) #IMPLIED
- disabled (disabled) #IMPLIED
- readonly (readonly) #IMPLIED
- size CDATA #IMPLIED
- maxlength %Number; #IMPLIED
- src %URI; #IMPLIED
- alt CDATA #IMPLIED
- usemap %URI; #IMPLIED
- onselect %Script; #IMPLIED
- onchange %Script; #IMPLIED
- accept %ContentTypes; #IMPLIED
- >
-
-<!ELEMENT select (optgroup|option)+> <!-- option selector -->
-<!ATTLIST select
- %attrs;
- name CDATA #IMPLIED
- size %Number; #IMPLIED
- multiple (multiple) #IMPLIED
- disabled (disabled) #IMPLIED
- tabindex %Number; #IMPLIED
- onfocus %Script; #IMPLIED
- onblur %Script; #IMPLIED
- onchange %Script; #IMPLIED
- >
-
-<!ELEMENT optgroup (option)+> <!-- option group -->
-<!ATTLIST optgroup
- %attrs;
- disabled (disabled) #IMPLIED
- label %Text; #REQUIRED
- >
-
-<!ELEMENT option (#PCDATA)> <!-- selectable choice -->
-<!ATTLIST option
- %attrs;
- selected (selected) #IMPLIED
- disabled (disabled) #IMPLIED
- label %Text; #IMPLIED
- value CDATA #IMPLIED
- >
-
-<!ELEMENT textarea (#PCDATA)> <!-- multi-line text field -->
-<!ATTLIST textarea
- %attrs;
- %focus;
- name CDATA #IMPLIED
- rows %Number; #REQUIRED
- cols %Number; #REQUIRED
- disabled (disabled) #IMPLIED
- readonly (readonly) #IMPLIED
- onselect %Script; #IMPLIED
- onchange %Script; #IMPLIED
- >
-
-<!--
- The fieldset element is used to group form fields.
- Only one legend element should occur in the content
- and if present should only be preceded by whitespace.
--->
-<!ELEMENT fieldset (#PCDATA | legend | %block; | form | %inline; | %misc;)*>
-<!ATTLIST fieldset
- %attrs;
- >
-
-<!ELEMENT legend %Inline;> <!-- fieldset label -->
-<!ATTLIST legend
- %attrs;
- accesskey %Character; #IMPLIED
- >
-
-<!--
- Content is %Flow; excluding a, form and form controls
--->
-<!ELEMENT button %button.content;> <!-- push button -->
-<!ATTLIST button
- %attrs;
- %focus;
- name CDATA #IMPLIED
- value CDATA #IMPLIED
- type (button|submit|reset) "submit"
- disabled (disabled) #IMPLIED
- >
-
-<!--======================= Tables =======================================-->
-
-<!-- Derived from IETF HTML table standard, see [RFC1942] -->
-
-<!--
- The border attribute sets the thickness of the frame around the
- table. The default units are screen pixels.
-
- The frame attribute specifies which parts of the frame around
- the table should be rendered. The values are not the same as
- CALS to avoid a name clash with the valign attribute.
--->
-<!ENTITY % TFrame "(void|above|below|hsides|lhs|rhs|vsides|box|border)">
-
-<!--
- The rules attribute defines which rules to draw between cells:
-
- If rules is absent then assume:
- "none" if border is absent or border="0" otherwise "all"
--->
-
-<!ENTITY % TRules "(none | groups | rows | cols | all)">
-
-<!-- horizontal alignment attributes for cell contents
-
- char alignment char, e.g. char=':'
- charoff offset for alignment char
--->
-<!ENTITY % cellhalign
- "align (left|center|right|justify|char) #IMPLIED
- char %Character; #IMPLIED
- charoff %Length; #IMPLIED"
- >
-
-<!-- vertical alignment attributes for cell contents -->
-<!ENTITY % cellvalign
- "valign (top|middle|bottom|baseline) #IMPLIED"
- >
-
-<!ELEMENT table
- (caption?, (col*|colgroup*), thead?, tfoot?, (tbody+|tr+))>
-<!ELEMENT caption %Inline;>
-<!ELEMENT thead (tr)+>
-<!ELEMENT tfoot (tr)+>
-<!ELEMENT tbody (tr)+>
-<!ELEMENT colgroup (col)*>
-<!ELEMENT col EMPTY>
-<!ELEMENT tr (th|td)+>
-<!ELEMENT th %Flow;>
-<!ELEMENT td %Flow;>
-
-<!ATTLIST table
- %attrs;
- summary %Text; #IMPLIED
- width %Length; #IMPLIED
- border %Pixels; #IMPLIED
- frame %TFrame; #IMPLIED
- rules %TRules; #IMPLIED
- cellspacing %Length; #IMPLIED
- cellpadding %Length; #IMPLIED
- >
-
-<!ATTLIST caption
- %attrs;
- >
-
-<!--
-colgroup groups a set of col elements. It allows you to group
-several semantically related columns together.
--->
-<!ATTLIST colgroup
- %attrs;
- span %Number; "1"
- width %MultiLength; #IMPLIED
- %cellhalign;
- %cellvalign;
- >
-
-<!--
- col elements define the alignment properties for cells in
- one or more columns.
-
- The width attribute specifies the width of the columns, e.g.
-
- width=64 width in screen pixels
- width=0.5* relative width of 0.5
-
- The span attribute causes the attributes of one
- col element to apply to more than one column.
--->
-<!ATTLIST col
- %attrs;
- span %Number; "1"
- width %MultiLength; #IMPLIED
- %cellhalign;
- %cellvalign;
- >
-
-<!--
- Use thead to duplicate headers when breaking table
- across page boundaries, or for static headers when
- tbody sections are rendered in scrolling panel.
-
- Use tfoot to duplicate footers when breaking table
- across page boundaries, or for static footers when
- tbody sections are rendered in scrolling panel.
-
- Use multiple tbody sections when rules are needed
- between groups of table rows.
--->
-<!ATTLIST thead
- %attrs;
- %cellhalign;
- %cellvalign;
- >
-
-<!ATTLIST tfoot
- %attrs;
- %cellhalign;
- %cellvalign;
- >
-
-<!ATTLIST tbody
- %attrs;
- %cellhalign;
- %cellvalign;
- >
-
-<!ATTLIST tr
- %attrs;
- %cellhalign;
- %cellvalign;
- >
-
-
-<!-- Scope is simpler than headers attribute for common tables -->
-<!ENTITY % Scope "(row|col|rowgroup|colgroup)">
-
-<!-- th is for headers, td for data and for cells acting as both -->
-
-<!ATTLIST th
- %attrs;
- abbr %Text; #IMPLIED
- axis CDATA #IMPLIED
- headers IDREFS #IMPLIED
- scope %Scope; #IMPLIED
- rowspan %Number; "1"
- colspan %Number; "1"
- %cellhalign;
- %cellvalign;
- >
-
-<!ATTLIST td
- %attrs;
- abbr %Text; #IMPLIED
- axis CDATA #IMPLIED
- headers IDREFS #IMPLIED
- scope %Scope; #IMPLIED
- rowspan %Number; "1"
- colspan %Number; "1"
- %cellhalign;
- %cellvalign;
- >
-
diff --git a/lib/erl_docgen/priv/docbuilder_dtd/xhtml1-transitional.dtd b/lib/erl_docgen/priv/docbuilder_dtd/xhtml1-transitional.dtd
deleted file mode 100644
index 628f27ac50..0000000000
--- a/lib/erl_docgen/priv/docbuilder_dtd/xhtml1-transitional.dtd
+++ /dev/null
@@ -1,1201 +0,0 @@
-<!--
- Extensible HTML version 1.0 Transitional DTD
-
- This is the same as HTML 4 Transitional except for
- changes due to the differences between XML and SGML.
-
- Namespace = http://www.w3.org/1999/xhtml
-
- For further information, see: http://www.w3.org/TR/xhtml1
-
- Copyright (c) 1998-2002 W3C (MIT, INRIA, Keio),
- All Rights Reserved.
-
- This DTD module is identified by the PUBLIC and SYSTEM identifiers:
-
- PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
- SYSTEM "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"
-
- $Revision: 1.2 $
- $Date: 2002/08/01 18:37:55 $
-
--->
-
-<!--================ Character mnemonic entities =========================-->
-
-<!ENTITY % HTMLlat1 PUBLIC
- "-//W3C//ENTITIES Latin 1 for XHTML//EN"
- "xhtml-lat1.ent">
-%HTMLlat1;
-
-<!ENTITY % HTMLsymbol PUBLIC
- "-//W3C//ENTITIES Symbols for XHTML//EN"
- "xhtml-symbol.ent">
-%HTMLsymbol;
-
-<!ENTITY % HTMLspecial PUBLIC
- "-//W3C//ENTITIES Special for XHTML//EN"
- "xhtml-special.ent">
-%HTMLspecial;
-
-<!--================== Imported Names ====================================-->
-
-<!ENTITY % ContentType "CDATA">
- <!-- media type, as per [RFC2045] -->
-
-<!ENTITY % ContentTypes "CDATA">
- <!-- comma-separated list of media types, as per [RFC2045] -->
-
-<!ENTITY % Charset "CDATA">
- <!-- a character encoding, as per [RFC2045] -->
-
-<!ENTITY % Charsets "CDATA">
- <!-- a space separated list of character encodings, as per [RFC2045] -->
-
-<!ENTITY % LanguageCode "NMTOKEN">
- <!-- a language code, as per [RFC3066] -->
-
-<!ENTITY % Character "CDATA">
- <!-- a single character, as per section 2.2 of [XML] -->
-
-<!ENTITY % Number "CDATA">
- <!-- one or more digits -->
-
-<!ENTITY % LinkTypes "CDATA">
- <!-- space-separated list of link types -->
-
-<!ENTITY % MediaDesc "CDATA">
- <!-- single or comma-separated list of media descriptors -->
-
-<!ENTITY % URI "CDATA">
- <!-- a Uniform Resource Identifier, see [RFC2396] -->
-
-<!ENTITY % UriList "CDATA">
- <!-- a space separated list of Uniform Resource Identifiers -->
-
-<!ENTITY % Datetime "CDATA">
- <!-- date and time information. ISO date format -->
-
-<!ENTITY % Script "CDATA">
- <!-- script expression -->
-
-<!ENTITY % StyleSheet "CDATA">
- <!-- style sheet data -->
-
-<!ENTITY % Text "CDATA">
- <!-- used for titles etc. -->
-
-<!ENTITY % FrameTarget "NMTOKEN">
- <!-- render in this frame -->
-
-<!ENTITY % Length "CDATA">
- <!-- nn for pixels or nn% for percentage length -->
-
-<!ENTITY % MultiLength "CDATA">
- <!-- pixel, percentage, or relative -->
-
-<!ENTITY % Pixels "CDATA">
- <!-- integer representing length in pixels -->
-
-<!-- these are used for image maps -->
-
-<!ENTITY % Shape "(rect|circle|poly|default)">
-
-<!ENTITY % Coords "CDATA">
- <!-- comma separated list of lengths -->
-
-<!-- used for object, applet, img, input and iframe -->
-<!ENTITY % ImgAlign "(top|middle|bottom|left|right)">
-
-<!-- a color using sRGB: #RRGGBB as Hex values -->
-<!ENTITY % Color "CDATA">
-
-<!-- There are also 16 widely known color names with their sRGB values:
-
- Black = #000000 Green = #008000
- Silver = #C0C0C0 Lime = #00FF00
- Gray = #808080 Olive = #808000
- White = #FFFFFF Yellow = #FFFF00
- Maroon = #800000 Navy = #000080
- Red = #FF0000 Blue = #0000FF
- Purple = #800080 Teal = #008080
- Fuchsia= #FF00FF Aqua = #00FFFF
--->
-
-<!--=================== Generic Attributes ===============================-->
-
-<!-- core attributes common to most elements
- id document-wide unique id
- class space separated list of classes
- style associated style info
- title advisory title/amplification
--->
-<!ENTITY % coreattrs
- "id ID #IMPLIED
- class CDATA #IMPLIED
- style %StyleSheet; #IMPLIED
- title %Text; #IMPLIED"
- >
-
-<!-- internationalization attributes
- lang language code (backwards compatible)
- xml:lang language code (as per XML 1.0 spec)
- dir direction for weak/neutral text
--->
-<!ENTITY % i18n
- "lang %LanguageCode; #IMPLIED
- xml:lang %LanguageCode; #IMPLIED
- dir (ltr|rtl) #IMPLIED"
- >
-
-<!-- attributes for common UI events
- onclick a pointer button was clicked
- ondblclick a pointer button was double clicked
- onmousedown a pointer button was pressed down
- onmouseup a pointer button was released
- onmousemove a pointer was moved onto the element
- onmouseout a pointer was moved away from the element
- onkeypress a key was pressed and released
- onkeydown a key was pressed down
- onkeyup a key was released
--->
-<!ENTITY % events
- "onclick %Script; #IMPLIED
- ondblclick %Script; #IMPLIED
- onmousedown %Script; #IMPLIED
- onmouseup %Script; #IMPLIED
- onmouseover %Script; #IMPLIED
- onmousemove %Script; #IMPLIED
- onmouseout %Script; #IMPLIED
- onkeypress %Script; #IMPLIED
- onkeydown %Script; #IMPLIED
- onkeyup %Script; #IMPLIED"
- >
-
-<!-- attributes for elements that can get the focus
- accesskey accessibility key character
- tabindex position in tabbing order
- onfocus the element got the focus
- onblur the element lost the focus
--->
-<!ENTITY % focus
- "accesskey %Character; #IMPLIED
- tabindex %Number; #IMPLIED
- onfocus %Script; #IMPLIED
- onblur %Script; #IMPLIED"
- >
-
-<!ENTITY % attrs "%coreattrs; %i18n; %events;">
-
-<!-- text alignment for p, div, h1-h6. The default is
- align="left" for ltr headings, "right" for rtl -->
-
-<!ENTITY % TextAlign "align (left|center|right|justify) #IMPLIED">
-
-<!--=================== Text Elements ====================================-->
-
-<!ENTITY % special.extra
- "object | applet | img | map | iframe">
-
-<!ENTITY % special.basic
- "br | span | bdo">
-
-<!ENTITY % special
- "%special.basic; | %special.extra;">
-
-<!ENTITY % fontstyle.extra "big | small | font | basefont">
-
-<!ENTITY % fontstyle.basic "tt | i | b | u
- | s | strike ">
-
-<!ENTITY % fontstyle "%fontstyle.basic; | %fontstyle.extra;">
-
-<!ENTITY % phrase.extra "sub | sup">
-<!ENTITY % phrase.basic "em | strong | dfn | code | q |
- samp | kbd | var | cite | abbr | acronym">
-
-<!ENTITY % phrase "%phrase.basic; | %phrase.extra;">
-
-<!ENTITY % inline.forms "input | select | textarea | label | button">
-
-<!-- these can occur at block or inline level -->
-<!ENTITY % misc.inline "ins | del | script">
-
-<!-- these can only occur at block level -->
-<!ENTITY % misc "noscript | %misc.inline;">
-
-<!ENTITY % inline "a | %special; | %fontstyle; | %phrase; | %inline.forms;">
-
-<!-- %Inline; covers inline or "text-level" elements -->
-<!ENTITY % Inline "(#PCDATA | %inline; | %misc.inline;)*">
-
-<!--================== Block level elements ==============================-->
-
-<!ENTITY % heading "h1|h2|h3|h4|h5|h6">
-<!ENTITY % lists "ul | ol | dl | menu | dir">
-<!ENTITY % blocktext "pre | hr | blockquote | address | center | noframes">
-
-<!ENTITY % block
- "p | %heading; | div | %lists; | %blocktext; | isindex |fieldset | table">
-
-<!-- %Flow; mixes block and inline and is used for list items etc. -->
-<!ENTITY % Flow "(#PCDATA | %block; | form | %inline; | %misc;)*">
-
-<!--================== Content models for exclusions =====================-->
-
-<!-- a elements use %Inline; excluding a -->
-
-<!ENTITY % a.content
- "(#PCDATA | %special; | %fontstyle; | %phrase; | %inline.forms; | %misc.inline;)*">
-
-<!-- pre uses %Inline excluding img, object, applet, big, small,
- font, or basefont -->
-
-<!ENTITY % pre.content
- "(#PCDATA | a | %special.basic; | %fontstyle.basic; | %phrase.basic; |
- %inline.forms; | %misc.inline;)*">
-
-<!-- form uses %Flow; excluding form -->
-
-<!ENTITY % form.content "(#PCDATA | %block; | %inline; | %misc;)*">
-
-<!-- button uses %Flow; but excludes a, form, form controls, iframe -->
-
-<!ENTITY % button.content
- "(#PCDATA | p | %heading; | div | %lists; | %blocktext; |
- table | br | span | bdo | object | applet | img | map |
- %fontstyle; | %phrase; | %misc;)*">
-
-<!--================ Document Structure ==================================-->
-
-<!-- the namespace URI designates the document profile -->
-
-<!ELEMENT html (head, body)>
-<!ATTLIST html
- %i18n;
- id ID #IMPLIED
- xmlns %URI; #FIXED 'http://www.w3.org/1999/xhtml'
- >
-
-<!--================ Document Head =======================================-->
-
-<!ENTITY % head.misc "(script|style|meta|link|object|isindex)*">
-
-<!-- content model is %head.misc; combined with a single
- title and an optional base element in any order -->
-
-<!ELEMENT head (%head.misc;,
- ((title, %head.misc;, (base, %head.misc;)?) |
- (base, %head.misc;, (title, %head.misc;))))>
-
-<!ATTLIST head
- %i18n;
- id ID #IMPLIED
- profile %URI; #IMPLIED
- >
-
-<!-- The title element is not considered part of the flow of text.
- It should be displayed, for example as the page header or
- window title. Exactly one title is required per document.
- -->
-<!ELEMENT title (#PCDATA)>
-<!ATTLIST title
- %i18n;
- id ID #IMPLIED
- >
-
-<!-- document base URI -->
-
-<!ELEMENT base EMPTY>
-<!ATTLIST base
- id ID #IMPLIED
- href %URI; #IMPLIED
- target %FrameTarget; #IMPLIED
- >
-
-<!-- generic metainformation -->
-<!ELEMENT meta EMPTY>
-<!ATTLIST meta
- %i18n;
- id ID #IMPLIED
- http-equiv CDATA #IMPLIED
- name CDATA #IMPLIED
- content CDATA #REQUIRED
- scheme CDATA #IMPLIED
- >
-
-<!--
- Relationship values can be used in principle:
-
- a) for document specific toolbars/menus when used
- with the link element in document head e.g.
- start, contents, previous, next, index, end, help
- b) to link to a separate style sheet (rel="stylesheet")
- c) to make a link to a script (rel="script")
- d) by stylesheets to control how collections of
- html nodes are rendered into printed documents
- e) to make a link to a printable version of this document
- e.g. a PostScript or PDF version (rel="alternate" media="print")
--->
-
-<!ELEMENT link EMPTY>
-<!ATTLIST link
- %attrs;
- charset %Charset; #IMPLIED
- href %URI; #IMPLIED
- hreflang %LanguageCode; #IMPLIED
- type %ContentType; #IMPLIED
- rel %LinkTypes; #IMPLIED
- rev %LinkTypes; #IMPLIED
- media %MediaDesc; #IMPLIED
- target %FrameTarget; #IMPLIED
- >
-
-<!-- style info, which may include CDATA sections -->
-<!ELEMENT style (#PCDATA)>
-<!ATTLIST style
- %i18n;
- id ID #IMPLIED
- type %ContentType; #REQUIRED
- media %MediaDesc; #IMPLIED
- title %Text; #IMPLIED
- xml:space (preserve) #FIXED 'preserve'
- >
-
-<!-- script statements, which may include CDATA sections -->
-<!ELEMENT script (#PCDATA)>
-<!ATTLIST script
- id ID #IMPLIED
- charset %Charset; #IMPLIED
- type %ContentType; #REQUIRED
- language CDATA #IMPLIED
- src %URI; #IMPLIED
- defer (defer) #IMPLIED
- xml:space (preserve) #FIXED 'preserve'
- >
-
-<!-- alternate content container for non script-based rendering -->
-
-<!ELEMENT noscript %Flow;>
-<!ATTLIST noscript
- %attrs;
- >
-
-<!--======================= Frames =======================================-->
-
-<!-- inline subwindow -->
-
-<!ELEMENT iframe %Flow;>
-<!ATTLIST iframe
- %coreattrs;
- longdesc %URI; #IMPLIED
- name NMTOKEN #IMPLIED
- src %URI; #IMPLIED
- frameborder (1|0) "1"
- marginwidth %Pixels; #IMPLIED
- marginheight %Pixels; #IMPLIED
- scrolling (yes|no|auto) "auto"
- align %ImgAlign; #IMPLIED
- height %Length; #IMPLIED
- width %Length; #IMPLIED
- >
-
-<!-- alternate content container for non frame-based rendering -->
-
-<!ELEMENT noframes %Flow;>
-<!ATTLIST noframes
- %attrs;
- >
-
-<!--=================== Document Body ====================================-->
-
-<!ELEMENT body %Flow;>
-<!ATTLIST body
- %attrs;
- onload %Script; #IMPLIED
- onunload %Script; #IMPLIED
- background %URI; #IMPLIED
- bgcolor %Color; #IMPLIED
- text %Color; #IMPLIED
- link %Color; #IMPLIED
- vlink %Color; #IMPLIED
- alink %Color; #IMPLIED
- >
-
-<!ELEMENT div %Flow;> <!-- generic language/style container -->
-<!ATTLIST div
- %attrs;
- %TextAlign;
- >
-
-<!--=================== Paragraphs =======================================-->
-
-<!ELEMENT p %Inline;>
-<!ATTLIST p
- %attrs;
- %TextAlign;
- >
-
-<!--=================== Headings =========================================-->
-
-<!--
- There are six levels of headings from h1 (the most important)
- to h6 (the least important).
--->
-
-<!ELEMENT h1 %Inline;>
-<!ATTLIST h1
- %attrs;
- %TextAlign;
- >
-
-<!ELEMENT h2 %Inline;>
-<!ATTLIST h2
- %attrs;
- %TextAlign;
- >
-
-<!ELEMENT h3 %Inline;>
-<!ATTLIST h3
- %attrs;
- %TextAlign;
- >
-
-<!ELEMENT h4 %Inline;>
-<!ATTLIST h4
- %attrs;
- %TextAlign;
- >
-
-<!ELEMENT h5 %Inline;>
-<!ATTLIST h5
- %attrs;
- %TextAlign;
- >
-
-<!ELEMENT h6 %Inline;>
-<!ATTLIST h6
- %attrs;
- %TextAlign;
- >
-
-<!--=================== Lists ============================================-->
-
-<!-- Unordered list bullet styles -->
-
-<!ENTITY % ULStyle "(disc|square|circle)">
-
-<!-- Unordered list -->
-
-<!ELEMENT ul (li)+>
-<!ATTLIST ul
- %attrs;
- type %ULStyle; #IMPLIED
- compact (compact) #IMPLIED
- >
-
-<!-- Ordered list numbering style
-
- 1 arabic numbers 1, 2, 3, ...
- a lower alpha a, b, c, ...
- A upper alpha A, B, C, ...
- i lower roman i, ii, iii, ...
- I upper roman I, II, III, ...
-
- The style is applied to the sequence number which by default
- is reset to 1 for the first list item in an ordered list.
--->
-<!ENTITY % OLStyle "CDATA">
-
-<!-- Ordered (numbered) list -->
-
-<!ELEMENT ol (li)+>
-<!ATTLIST ol
- %attrs;
- type %OLStyle; #IMPLIED
- compact (compact) #IMPLIED
- start %Number; #IMPLIED
- >
-
-<!-- single column list (DEPRECATED) -->
-<!ELEMENT menu (li)+>
-<!ATTLIST menu
- %attrs;
- compact (compact) #IMPLIED
- >
-
-<!-- multiple column list (DEPRECATED) -->
-<!ELEMENT dir (li)+>
-<!ATTLIST dir
- %attrs;
- compact (compact) #IMPLIED
- >
-
-<!-- LIStyle is constrained to: "(%ULStyle;|%OLStyle;)" -->
-<!ENTITY % LIStyle "CDATA">
-
-<!-- list item -->
-
-<!ELEMENT li %Flow;>
-<!ATTLIST li
- %attrs;
- type %LIStyle; #IMPLIED
- value %Number; #IMPLIED
- >
-
-<!-- definition lists - dt for term, dd for its definition -->
-
-<!ELEMENT dl (dt|dd)+>
-<!ATTLIST dl
- %attrs;
- compact (compact) #IMPLIED
- >
-
-<!ELEMENT dt %Inline;>
-<!ATTLIST dt
- %attrs;
- >
-
-<!ELEMENT dd %Flow;>
-<!ATTLIST dd
- %attrs;
- >
-
-<!--=================== Address ==========================================-->
-
-<!-- information on author -->
-
-<!ELEMENT address (#PCDATA | %inline; | %misc.inline; | p)*>
-<!ATTLIST address
- %attrs;
- >
-
-<!--=================== Horizontal Rule ==================================-->
-
-<!ELEMENT hr EMPTY>
-<!ATTLIST hr
- %attrs;
- align (left|center|right) #IMPLIED
- noshade (noshade) #IMPLIED
- size %Pixels; #IMPLIED
- width %Length; #IMPLIED
- >
-
-<!--=================== Preformatted Text ================================-->
-
-<!-- content is %Inline; excluding
- "img|object|applet|big|small|sub|sup|font|basefont" -->
-
-<!ELEMENT pre %pre.content;>
-<!ATTLIST pre
- %attrs;
- width %Number; #IMPLIED
- xml:space (preserve) #FIXED 'preserve'
- >
-
-<!--=================== Block-like Quotes ================================-->
-
-<!ELEMENT blockquote %Flow;>
-<!ATTLIST blockquote
- %attrs;
- cite %URI; #IMPLIED
- >
-
-<!--=================== Text alignment ===================================-->
-
-<!-- center content -->
-<!ELEMENT center %Flow;>
-<!ATTLIST center
- %attrs;
- >
-
-<!--=================== Inserted/Deleted Text ============================-->
-
-<!--
- ins/del are allowed in block and inline content, but its
- inappropriate to include block content within an ins element
- occurring in inline content.
--->
-<!ELEMENT ins %Flow;>
-<!ATTLIST ins
- %attrs;
- cite %URI; #IMPLIED
- datetime %Datetime; #IMPLIED
- >
-
-<!ELEMENT del %Flow;>
-<!ATTLIST del
- %attrs;
- cite %URI; #IMPLIED
- datetime %Datetime; #IMPLIED
- >
-
-<!--================== The Anchor Element ================================-->
-
-<!-- content is %Inline; except that anchors shouldn't be nested -->
-
-<!ELEMENT a %a.content;>
-<!ATTLIST a
- %attrs;
- %focus;
- charset %Charset; #IMPLIED
- type %ContentType; #IMPLIED
- name NMTOKEN #IMPLIED
- href %URI; #IMPLIED
- hreflang %LanguageCode; #IMPLIED
- rel %LinkTypes; #IMPLIED
- rev %LinkTypes; #IMPLIED
- shape %Shape; "rect"
- coords %Coords; #IMPLIED
- target %FrameTarget; #IMPLIED
- >
-
-<!--===================== Inline Elements ================================-->
-
-<!ELEMENT span %Inline;> <!-- generic language/style container -->
-<!ATTLIST span
- %attrs;
- >
-
-<!ELEMENT bdo %Inline;> <!-- I18N BiDi over-ride -->
-<!ATTLIST bdo
- %coreattrs;
- %events;
- lang %LanguageCode; #IMPLIED
- xml:lang %LanguageCode; #IMPLIED
- dir (ltr|rtl) #REQUIRED
- >
-
-<!ELEMENT br EMPTY> <!-- forced line break -->
-<!ATTLIST br
- %coreattrs;
- clear (left|all|right|none) "none"
- >
-
-<!ELEMENT em %Inline;> <!-- emphasis -->
-<!ATTLIST em %attrs;>
-
-<!ELEMENT strong %Inline;> <!-- strong emphasis -->
-<!ATTLIST strong %attrs;>
-
-<!ELEMENT dfn %Inline;> <!-- definitional -->
-<!ATTLIST dfn %attrs;>
-
-<!ELEMENT code %Inline;> <!-- program code -->
-<!ATTLIST code %attrs;>
-
-<!ELEMENT samp %Inline;> <!-- sample -->
-<!ATTLIST samp %attrs;>
-
-<!ELEMENT kbd %Inline;> <!-- something user would type -->
-<!ATTLIST kbd %attrs;>
-
-<!ELEMENT var %Inline;> <!-- variable -->
-<!ATTLIST var %attrs;>
-
-<!ELEMENT cite %Inline;> <!-- citation -->
-<!ATTLIST cite %attrs;>
-
-<!ELEMENT abbr %Inline;> <!-- abbreviation -->
-<!ATTLIST abbr %attrs;>
-
-<!ELEMENT acronym %Inline;> <!-- acronym -->
-<!ATTLIST acronym %attrs;>
-
-<!ELEMENT q %Inline;> <!-- inlined quote -->
-<!ATTLIST q
- %attrs;
- cite %URI; #IMPLIED
- >
-
-<!ELEMENT sub %Inline;> <!-- subscript -->
-<!ATTLIST sub %attrs;>
-
-<!ELEMENT sup %Inline;> <!-- superscript -->
-<!ATTLIST sup %attrs;>
-
-<!ELEMENT tt %Inline;> <!-- fixed pitch font -->
-<!ATTLIST tt %attrs;>
-
-<!ELEMENT i %Inline;> <!-- italic font -->
-<!ATTLIST i %attrs;>
-
-<!ELEMENT b %Inline;> <!-- bold font -->
-<!ATTLIST b %attrs;>
-
-<!ELEMENT big %Inline;> <!-- bigger font -->
-<!ATTLIST big %attrs;>
-
-<!ELEMENT small %Inline;> <!-- smaller font -->
-<!ATTLIST small %attrs;>
-
-<!ELEMENT u %Inline;> <!-- underline -->
-<!ATTLIST u %attrs;>
-
-<!ELEMENT s %Inline;> <!-- strike-through -->
-<!ATTLIST s %attrs;>
-
-<!ELEMENT strike %Inline;> <!-- strike-through -->
-<!ATTLIST strike %attrs;>
-
-<!ELEMENT basefont EMPTY> <!-- base font size -->
-<!ATTLIST basefont
- id ID #IMPLIED
- size CDATA #REQUIRED
- color %Color; #IMPLIED
- face CDATA #IMPLIED
- >
-
-<!ELEMENT font %Inline;> <!-- local change to font -->
-<!ATTLIST font
- %coreattrs;
- %i18n;
- size CDATA #IMPLIED
- color %Color; #IMPLIED
- face CDATA #IMPLIED
- >
-
-<!--==================== Object ======================================-->
-<!--
- object is used to embed objects as part of HTML pages.
- param elements should precede other content. Parameters
- can also be expressed as attribute/value pairs on the
- object element itself when brevity is desired.
--->
-
-<!ELEMENT object (#PCDATA | param | %block; | form | %inline; | %misc;)*>
-<!ATTLIST object
- %attrs;
- declare (declare) #IMPLIED
- classid %URI; #IMPLIED
- codebase %URI; #IMPLIED
- data %URI; #IMPLIED
- type %ContentType; #IMPLIED
- codetype %ContentType; #IMPLIED
- archive %UriList; #IMPLIED
- standby %Text; #IMPLIED
- height %Length; #IMPLIED
- width %Length; #IMPLIED
- usemap %URI; #IMPLIED
- name NMTOKEN #IMPLIED
- tabindex %Number; #IMPLIED
- align %ImgAlign; #IMPLIED
- border %Pixels; #IMPLIED
- hspace %Pixels; #IMPLIED
- vspace %Pixels; #IMPLIED
- >
-
-<!--
- param is used to supply a named property value.
- In XML it would seem natural to follow RDF and support an
- abbreviated syntax where the param elements are replaced
- by attribute value pairs on the object start tag.
--->
-<!ELEMENT param EMPTY>
-<!ATTLIST param
- id ID #IMPLIED
- name CDATA #REQUIRED
- value CDATA #IMPLIED
- valuetype (data|ref|object) "data"
- type %ContentType; #IMPLIED
- >
-
-<!--=================== Java applet ==================================-->
-<!--
- One of code or object attributes must be present.
- Place param elements before other content.
--->
-<!ELEMENT applet (#PCDATA | param | %block; | form | %inline; | %misc;)*>
-<!ATTLIST applet
- %coreattrs;
- codebase %URI; #IMPLIED
- archive CDATA #IMPLIED
- code CDATA #IMPLIED
- object CDATA #IMPLIED
- alt %Text; #IMPLIED
- name NMTOKEN #IMPLIED
- width %Length; #REQUIRED
- height %Length; #REQUIRED
- align %ImgAlign; #IMPLIED
- hspace %Pixels; #IMPLIED
- vspace %Pixels; #IMPLIED
- >
-
-<!--=================== Images ===========================================-->
-
-<!--
- To avoid accessibility problems for people who aren't
- able to see the image, you should provide a text
- description using the alt and longdesc attributes.
- In addition, avoid the use of server-side image maps.
--->
-
-<!ELEMENT img EMPTY>
-<!ATTLIST img
- %attrs;
- src %URI; #REQUIRED
- alt %Text; #REQUIRED
- name NMTOKEN #IMPLIED
- longdesc %URI; #IMPLIED
- height %Length; #IMPLIED
- width %Length; #IMPLIED
- usemap %URI; #IMPLIED
- ismap (ismap) #IMPLIED
- align %ImgAlign; #IMPLIED
- border %Length; #IMPLIED
- hspace %Pixels; #IMPLIED
- vspace %Pixels; #IMPLIED
- >
-
-<!-- usemap points to a map element which may be in this document
- or an external document, although the latter is not widely supported -->
-
-<!--================== Client-side image maps ============================-->
-
-<!-- These can be placed in the same document or grouped in a
- separate document although this isn't yet widely supported -->
-
-<!ELEMENT map ((%block; | form | %misc;)+ | area+)>
-<!ATTLIST map
- %i18n;
- %events;
- id ID #REQUIRED
- class CDATA #IMPLIED
- style %StyleSheet; #IMPLIED
- title %Text; #IMPLIED
- name CDATA #IMPLIED
- >
-
-<!ELEMENT area EMPTY>
-<!ATTLIST area
- %attrs;
- %focus;
- shape %Shape; "rect"
- coords %Coords; #IMPLIED
- href %URI; #IMPLIED
- nohref (nohref) #IMPLIED
- alt %Text; #REQUIRED
- target %FrameTarget; #IMPLIED
- >
-
-<!--================ Forms ===============================================-->
-
-<!ELEMENT form %form.content;> <!-- forms shouldn't be nested -->
-
-<!ATTLIST form
- %attrs;
- action %URI; #REQUIRED
- method (get|post) "get"
- name NMTOKEN #IMPLIED
- enctype %ContentType; "application/x-www-form-urlencoded"
- onsubmit %Script; #IMPLIED
- onreset %Script; #IMPLIED
- accept %ContentTypes; #IMPLIED
- accept-charset %Charsets; #IMPLIED
- target %FrameTarget; #IMPLIED
- >
-
-<!--
- Each label must not contain more than ONE field
- Label elements shouldn't be nested.
--->
-<!ELEMENT label %Inline;>
-<!ATTLIST label
- %attrs;
- for IDREF #IMPLIED
- accesskey %Character; #IMPLIED
- onfocus %Script; #IMPLIED
- onblur %Script; #IMPLIED
- >
-
-<!ENTITY % InputType
- "(text | password | checkbox |
- radio | submit | reset |
- file | hidden | image | button)"
- >
-
-<!-- the name attribute is required for all but submit & reset -->
-
-<!ELEMENT input EMPTY> <!-- form control -->
-<!ATTLIST input
- %attrs;
- %focus;
- type %InputType; "text"
- name CDATA #IMPLIED
- value CDATA #IMPLIED
- checked (checked) #IMPLIED
- disabled (disabled) #IMPLIED
- readonly (readonly) #IMPLIED
- size CDATA #IMPLIED
- maxlength %Number; #IMPLIED
- src %URI; #IMPLIED
- alt CDATA #IMPLIED
- usemap %URI; #IMPLIED
- onselect %Script; #IMPLIED
- onchange %Script; #IMPLIED
- accept %ContentTypes; #IMPLIED
- align %ImgAlign; #IMPLIED
- >
-
-<!ELEMENT select (optgroup|option)+> <!-- option selector -->
-<!ATTLIST select
- %attrs;
- name CDATA #IMPLIED
- size %Number; #IMPLIED
- multiple (multiple) #IMPLIED
- disabled (disabled) #IMPLIED
- tabindex %Number; #IMPLIED
- onfocus %Script; #IMPLIED
- onblur %Script; #IMPLIED
- onchange %Script; #IMPLIED
- >
-
-<!ELEMENT optgroup (option)+> <!-- option group -->
-<!ATTLIST optgroup
- %attrs;
- disabled (disabled) #IMPLIED
- label %Text; #REQUIRED
- >
-
-<!ELEMENT option (#PCDATA)> <!-- selectable choice -->
-<!ATTLIST option
- %attrs;
- selected (selected) #IMPLIED
- disabled (disabled) #IMPLIED
- label %Text; #IMPLIED
- value CDATA #IMPLIED
- >
-
-<!ELEMENT textarea (#PCDATA)> <!-- multi-line text field -->
-<!ATTLIST textarea
- %attrs;
- %focus;
- name CDATA #IMPLIED
- rows %Number; #REQUIRED
- cols %Number; #REQUIRED
- disabled (disabled) #IMPLIED
- readonly (readonly) #IMPLIED
- onselect %Script; #IMPLIED
- onchange %Script; #IMPLIED
- >
-
-<!--
- The fieldset element is used to group form fields.
- Only one legend element should occur in the content
- and if present should only be preceded by whitespace.
--->
-<!ELEMENT fieldset (#PCDATA | legend | %block; | form | %inline; | %misc;)*>
-<!ATTLIST fieldset
- %attrs;
- >
-
-<!ENTITY % LAlign "(top|bottom|left|right)">
-
-<!ELEMENT legend %Inline;> <!-- fieldset label -->
-<!ATTLIST legend
- %attrs;
- accesskey %Character; #IMPLIED
- align %LAlign; #IMPLIED
- >
-
-<!--
- Content is %Flow; excluding a, form, form controls, iframe
--->
-<!ELEMENT button %button.content;> <!-- push button -->
-<!ATTLIST button
- %attrs;
- %focus;
- name CDATA #IMPLIED
- value CDATA #IMPLIED
- type (button|submit|reset) "submit"
- disabled (disabled) #IMPLIED
- >
-
-<!-- single-line text input control (DEPRECATED) -->
-<!ELEMENT isindex EMPTY>
-<!ATTLIST isindex
- %coreattrs;
- %i18n;
- prompt %Text; #IMPLIED
- >
-
-<!--======================= Tables =======================================-->
-
-<!-- Derived from IETF HTML table standard, see [RFC1942] -->
-
-<!--
- The border attribute sets the thickness of the frame around the
- table. The default units are screen pixels.
-
- The frame attribute specifies which parts of the frame around
- the table should be rendered. The values are not the same as
- CALS to avoid a name clash with the valign attribute.
--->
-<!ENTITY % TFrame "(void|above|below|hsides|lhs|rhs|vsides|box|border)">
-
-<!--
- The rules attribute defines which rules to draw between cells:
-
- If rules is absent then assume:
- "none" if border is absent or border="0" otherwise "all"
--->
-
-<!ENTITY % TRules "(none | groups | rows | cols | all)">
-
-<!-- horizontal placement of table relative to document -->
-<!ENTITY % TAlign "(left|center|right)">
-
-<!-- horizontal alignment attributes for cell contents
-
- char alignment char, e.g. char=':'
- charoff offset for alignment char
--->
-<!ENTITY % cellhalign
- "align (left|center|right|justify|char) #IMPLIED
- char %Character; #IMPLIED
- charoff %Length; #IMPLIED"
- >
-
-<!-- vertical alignment attributes for cell contents -->
-<!ENTITY % cellvalign
- "valign (top|middle|bottom|baseline) #IMPLIED"
- >
-
-<!ELEMENT table
- (caption?, (col*|colgroup*), thead?, tfoot?, (tbody+|tr+))>
-<!ELEMENT caption %Inline;>
-<!ELEMENT thead (tr)+>
-<!ELEMENT tfoot (tr)+>
-<!ELEMENT tbody (tr)+>
-<!ELEMENT colgroup (col)*>
-<!ELEMENT col EMPTY>
-<!ELEMENT tr (th|td)+>
-<!ELEMENT th %Flow;>
-<!ELEMENT td %Flow;>
-
-<!ATTLIST table
- %attrs;
- summary %Text; #IMPLIED
- width %Length; #IMPLIED
- border %Pixels; #IMPLIED
- frame %TFrame; #IMPLIED
- rules %TRules; #IMPLIED
- cellspacing %Length; #IMPLIED
- cellpadding %Length; #IMPLIED
- align %TAlign; #IMPLIED
- bgcolor %Color; #IMPLIED
- >
-
-<!ENTITY % CAlign "(top|bottom|left|right)">
-
-<!ATTLIST caption
- %attrs;
- align %CAlign; #IMPLIED
- >
-
-<!--
-colgroup groups a set of col elements. It allows you to group
-several semantically related columns together.
--->
-<!ATTLIST colgroup
- %attrs;
- span %Number; "1"
- width %MultiLength; #IMPLIED
- %cellhalign;
- %cellvalign;
- >
-
-<!--
- col elements define the alignment properties for cells in
- one or more columns.
-
- The width attribute specifies the width of the columns, e.g.
-
- width=64 width in screen pixels
- width=0.5* relative width of 0.5
-
- The span attribute causes the attributes of one
- col element to apply to more than one column.
--->
-<!ATTLIST col
- %attrs;
- span %Number; "1"
- width %MultiLength; #IMPLIED
- %cellhalign;
- %cellvalign;
- >
-
-<!--
- Use thead to duplicate headers when breaking table
- across page boundaries, or for static headers when
- tbody sections are rendered in scrolling panel.
-
- Use tfoot to duplicate footers when breaking table
- across page boundaries, or for static footers when
- tbody sections are rendered in scrolling panel.
-
- Use multiple tbody sections when rules are needed
- between groups of table rows.
--->
-<!ATTLIST thead
- %attrs;
- %cellhalign;
- %cellvalign;
- >
-
-<!ATTLIST tfoot
- %attrs;
- %cellhalign;
- %cellvalign;
- >
-
-<!ATTLIST tbody
- %attrs;
- %cellhalign;
- %cellvalign;
- >
-
-<!ATTLIST tr
- %attrs;
- %cellhalign;
- %cellvalign;
- bgcolor %Color; #IMPLIED
- >
-
-<!-- Scope is simpler than headers attribute for common tables -->
-<!ENTITY % Scope "(row|col|rowgroup|colgroup)">
-
-<!-- th is for headers, td for data and for cells acting as both -->
-
-<!ATTLIST th
- %attrs;
- abbr %Text; #IMPLIED
- axis CDATA #IMPLIED
- headers IDREFS #IMPLIED
- scope %Scope; #IMPLIED
- rowspan %Number; "1"
- colspan %Number; "1"
- %cellhalign;
- %cellvalign;
- nowrap (nowrap) #IMPLIED
- bgcolor %Color; #IMPLIED
- width %Length; #IMPLIED
- height %Length; #IMPLIED
- >
-
-<!ATTLIST td
- %attrs;
- abbr %Text; #IMPLIED
- axis CDATA #IMPLIED
- headers IDREFS #IMPLIED
- scope %Scope; #IMPLIED
- rowspan %Number; "1"
- colspan %Number; "1"
- %cellhalign;
- %cellvalign;
- nowrap (nowrap) #IMPLIED
- bgcolor %Color; #IMPLIED
- width %Length; #IMPLIED
- height %Length; #IMPLIED
- >
-
diff --git a/lib/erl_docgen/priv/docbuilder_dtd/Makefile b/lib/erl_docgen/priv/dtd/Makefile
index e2214107cb..9454147258 100644
--- a/lib/erl_docgen/priv/docbuilder_dtd/Makefile
+++ b/lib/erl_docgen/priv/dtd/Makefile
@@ -62,7 +62,9 @@ DTD_FILES = \
fascicules.dtd \
terms.dtd
-
+ENT_FILES = \
+ xhtml-special.ent \
+ xhtml-symbol.ent
# ----------------------------------------------------
# FLAGS
@@ -87,8 +89,8 @@ include $(ERL_TOP)/make/otp_release_targets.mk
release_spec: opt
- $(INSTALL_DIR) $(RELSYSDIR)/priv/docbuilder_dtd
- $(INSTALL_DATA) $(DTD_FILES) $(RELSYSDIR)/priv/docbuilder_dtd
+ $(INSTALL_DIR) $(RELSYSDIR)/priv/dtd
+ $(INSTALL_DATA) $(DTD_FILES) $(ENT_FILES) $(RELSYSDIR)/priv/dtd
release_docs_spec:
diff --git a/lib/docbuilder/dtd/application.dtd b/lib/erl_docgen/priv/dtd/application.dtd
index 8a1e8832ec..8a1e8832ec 100644
--- a/lib/docbuilder/dtd/application.dtd
+++ b/lib/erl_docgen/priv/dtd/application.dtd
diff --git a/lib/docbuilder/dtd/appref.dtd b/lib/erl_docgen/priv/dtd/appref.dtd
index 70a5ff37af..70a5ff37af 100644
--- a/lib/docbuilder/dtd/appref.dtd
+++ b/lib/erl_docgen/priv/dtd/appref.dtd
diff --git a/lib/docbuilder/dtd/book.dtd b/lib/erl_docgen/priv/dtd/book.dtd
index bb89a6d255..bb89a6d255 100644
--- a/lib/docbuilder/dtd/book.dtd
+++ b/lib/erl_docgen/priv/dtd/book.dtd
diff --git a/lib/docbuilder/dtd/bookinsidecover.dtd b/lib/erl_docgen/priv/dtd/bookinsidecover.dtd
index d6efbef6a4..d6efbef6a4 100644
--- a/lib/docbuilder/dtd/bookinsidecover.dtd
+++ b/lib/erl_docgen/priv/dtd/bookinsidecover.dtd
diff --git a/lib/docbuilder/dtd/chapter.dtd b/lib/erl_docgen/priv/dtd/chapter.dtd
index eb2c96b04f..eb2c96b04f 100644
--- a/lib/docbuilder/dtd/chapter.dtd
+++ b/lib/erl_docgen/priv/dtd/chapter.dtd
diff --git a/lib/docbuilder/dtd/cites.dtd b/lib/erl_docgen/priv/dtd/cites.dtd
index 334574bff9..334574bff9 100644
--- a/lib/docbuilder/dtd/cites.dtd
+++ b/lib/erl_docgen/priv/dtd/cites.dtd
diff --git a/lib/erl_docgen/priv/docbuilder_dtd/common.dtd b/lib/erl_docgen/priv/dtd/common.dtd
index fdc02c55a1..fdc02c55a1 100644
--- a/lib/erl_docgen/priv/docbuilder_dtd/common.dtd
+++ b/lib/erl_docgen/priv/dtd/common.dtd
diff --git a/lib/docbuilder/dtd/common.entities.dtd b/lib/erl_docgen/priv/dtd/common.entities.dtd
index f893ecd070..f893ecd070 100644
--- a/lib/docbuilder/dtd/common.entities.dtd
+++ b/lib/erl_docgen/priv/dtd/common.entities.dtd
diff --git a/lib/docbuilder/dtd/common.header.dtd b/lib/erl_docgen/priv/dtd/common.header.dtd
index d422a89693..d422a89693 100644
--- a/lib/docbuilder/dtd/common.header.dtd
+++ b/lib/erl_docgen/priv/dtd/common.header.dtd
diff --git a/lib/docbuilder/dtd/common.image.dtd b/lib/erl_docgen/priv/dtd/common.image.dtd
index fc95a669dd..fc95a669dd 100644
--- a/lib/docbuilder/dtd/common.image.dtd
+++ b/lib/erl_docgen/priv/dtd/common.image.dtd
diff --git a/lib/erl_docgen/priv/docbuilder_dtd/common.refs.dtd b/lib/erl_docgen/priv/dtd/common.refs.dtd
index c1237766e1..c1237766e1 100644
--- a/lib/erl_docgen/priv/docbuilder_dtd/common.refs.dtd
+++ b/lib/erl_docgen/priv/dtd/common.refs.dtd
diff --git a/lib/docbuilder/dtd/common.table.dtd b/lib/erl_docgen/priv/dtd/common.table.dtd
index 7741da1018..7741da1018 100644
--- a/lib/docbuilder/dtd/common.table.dtd
+++ b/lib/erl_docgen/priv/dtd/common.table.dtd
diff --git a/lib/docbuilder/dtd/comref.dtd b/lib/erl_docgen/priv/dtd/comref.dtd
index fcdea625d5..fcdea625d5 100644
--- a/lib/docbuilder/dtd/comref.dtd
+++ b/lib/erl_docgen/priv/dtd/comref.dtd
diff --git a/lib/docbuilder/dtd/cref.dtd b/lib/erl_docgen/priv/dtd/cref.dtd
index e43bb2bf51..e43bb2bf51 100644
--- a/lib/docbuilder/dtd/cref.dtd
+++ b/lib/erl_docgen/priv/dtd/cref.dtd
diff --git a/lib/erl_docgen/priv/docbuilder_dtd/erlref.dtd b/lib/erl_docgen/priv/dtd/erlref.dtd
index 9905086ff4..9905086ff4 100644
--- a/lib/erl_docgen/priv/docbuilder_dtd/erlref.dtd
+++ b/lib/erl_docgen/priv/dtd/erlref.dtd
diff --git a/lib/docbuilder/dtd/fascicules.dtd b/lib/erl_docgen/priv/dtd/fascicules.dtd
index b14276a2c0..b14276a2c0 100644
--- a/lib/docbuilder/dtd/fascicules.dtd
+++ b/lib/erl_docgen/priv/dtd/fascicules.dtd
diff --git a/lib/docbuilder/dtd/fileref.dtd b/lib/erl_docgen/priv/dtd/fileref.dtd
index 5a1cc54afe..5a1cc54afe 100644
--- a/lib/docbuilder/dtd/fileref.dtd
+++ b/lib/erl_docgen/priv/dtd/fileref.dtd
diff --git a/lib/docbuilder/dtd/part.dtd b/lib/erl_docgen/priv/dtd/part.dtd
index 3f97199042..3f97199042 100644
--- a/lib/docbuilder/dtd/part.dtd
+++ b/lib/erl_docgen/priv/dtd/part.dtd
diff --git a/lib/docbuilder/dtd/report.dtd b/lib/erl_docgen/priv/dtd/report.dtd
index 3d07e6e5a7..3d07e6e5a7 100644
--- a/lib/docbuilder/dtd/report.dtd
+++ b/lib/erl_docgen/priv/dtd/report.dtd
diff --git a/lib/docbuilder/dtd/terms.dtd b/lib/erl_docgen/priv/dtd/terms.dtd
index 6105ec593e..6105ec593e 100644
--- a/lib/docbuilder/dtd/terms.dtd
+++ b/lib/erl_docgen/priv/dtd/terms.dtd
diff --git a/lib/docbuilder/dtd/xhtml-special.ent b/lib/erl_docgen/priv/dtd/xhtml-special.ent
index ca358b2fec..ca358b2fec 100644
--- a/lib/docbuilder/dtd/xhtml-special.ent
+++ b/lib/erl_docgen/priv/dtd/xhtml-special.ent
diff --git a/lib/docbuilder/dtd/xhtml-symbol.ent b/lib/erl_docgen/priv/dtd/xhtml-symbol.ent
index 63c2abfa6f..63c2abfa6f 100644
--- a/lib/docbuilder/dtd/xhtml-symbol.ent
+++ b/lib/erl_docgen/priv/dtd/xhtml-symbol.ent
diff --git a/lib/docbuilder/dtd/xhtml1-frameset.dtd b/lib/erl_docgen/priv/dtd/xhtml1-frameset.dtd
index d128f2eb7c..d128f2eb7c 100644
--- a/lib/docbuilder/dtd/xhtml1-frameset.dtd
+++ b/lib/erl_docgen/priv/dtd/xhtml1-frameset.dtd
diff --git a/lib/docbuilder/dtd/xhtml1-strict.dtd b/lib/erl_docgen/priv/dtd/xhtml1-strict.dtd
index 2927b9ece7..2927b9ece7 100644
--- a/lib/docbuilder/dtd/xhtml1-strict.dtd
+++ b/lib/erl_docgen/priv/dtd/xhtml1-strict.dtd
diff --git a/lib/docbuilder/dtd/xhtml1-transitional.dtd b/lib/erl_docgen/priv/dtd/xhtml1-transitional.dtd
index 628f27ac50..628f27ac50 100644
--- a/lib/docbuilder/dtd/xhtml1-transitional.dtd
+++ b/lib/erl_docgen/priv/dtd/xhtml1-transitional.dtd
diff --git a/lib/erl_docgen/priv/xsl/db_eix.xsl b/lib/erl_docgen/priv/xsl/db_eix.xsl
index 7a648ddfd7..55540317f6 100644
--- a/lib/erl_docgen/priv/xsl/db_eix.xsl
+++ b/lib/erl_docgen/priv/xsl/db_eix.xsl
@@ -106,10 +106,14 @@
<xsl:choose>
<!-- @arity is mandatory when referring to a specification -->
<xsl:when test="string-length(@arity) > 0">
- <xsl:call-template name="spec_name"/>
+ <xsl:call-template name="spec_name">
+ <xsl:with-param name="lastfuncsblock" select="$lastfuncsblock"/>
+ </xsl:call-template>
</xsl:when>
<xsl:otherwise>
- <xsl:call-template name="name"/>
+ <xsl:call-template name="name">
+ <xsl:with-param name="lastfuncsblock" select="$lastfuncsblock"/>
+ </xsl:call-template>
</xsl:otherwise>
</xsl:choose>
</xsl:template>
diff --git a/lib/erl_docgen/priv/xsl/db_man.xsl b/lib/erl_docgen/priv/xsl/db_man.xsl
index 1df96caa36..0aca74bc97 100644
--- a/lib/erl_docgen/priv/xsl/db_man.xsl
+++ b/lib/erl_docgen/priv/xsl/db_man.xsl
@@ -137,8 +137,9 @@
(there is no spec with more than one clause) -->
<xsl:if test="count($clause/guard) > 0 or count($type) > 0">
<xsl:text>&#10;.RS</xsl:text>
- <xsl:text>&#10;.TP 3</xsl:text>
+ <xsl:text>&#10;.LP</xsl:text>
<xsl:text>&#10;Types:&#10;</xsl:text>
+ <xsl:text>&#10;.RS 3</xsl:text>
<xsl:choose>
<xsl:when test="$output_subtypes">
@@ -164,6 +165,8 @@
<xsl:with-param name="type_desc" select="$type_desc"/>
<xsl:with-param name="local_types" select="$local_types"/>
</xsl:call-template>
+ <xsl:text>&#10;.RE</xsl:text>
+
<xsl:text>&#10;.RE</xsl:text>
</xsl:if>
@@ -257,8 +260,8 @@
<!-- Similar to <d> -->
<xsl:template match="type_desc">
- <xsl:text>&#10;</xsl:text><xsl:apply-templates/>
- <xsl:text>&#10;.br</xsl:text>
+ <xsl:text>&#10;.RS 2&#10;</xsl:text><xsl:apply-templates/>
+ <xsl:text>&#10;.RE</xsl:text>
</xsl:template>
<!-- Datatypes -->
@@ -757,24 +760,26 @@
<!-- The case where @name != 0 is taken care of in "type_name" -->
<xsl:if test="string-length(@name) = 0 and string-length(@variable) = 0">
<xsl:text>&#10;.RS</xsl:text>
- <xsl:text>&#10;.TP 3</xsl:text>
+ <xsl:text>&#10;.LP</xsl:text>
<xsl:text>&#10;Types:&#10;</xsl:text>
+ <xsl:text>&#10;.RS 3</xsl:text>
<xsl:apply-templates/>
<xsl:text>&#10;.RE</xsl:text>
+ <xsl:text>&#10;.RE</xsl:text>
</xsl:if>
</xsl:template>
<!-- V -->
<xsl:template match="v">
- <xsl:text>&#10;</xsl:text><xsl:value-of select="normalize-space(text())"/>
+ <xsl:text>&#10;</xsl:text><xsl:apply-templates/>
<xsl:text>&#10;.br</xsl:text>
</xsl:template>
<!-- D -->
<xsl:template match="d">
- <xsl:text>&#10;</xsl:text><xsl:apply-templates/>
- <xsl:text>&#10;.br</xsl:text>
+ <xsl:text>&#10;.RS 2&#10;</xsl:text><xsl:apply-templates/>
+ <xsl:text>&#10;.RE</xsl:text>
</xsl:template>
<!-- Desc -->
diff --git a/lib/erl_docgen/src/Makefile b/lib/erl_docgen/src/Makefile
index 8e81bccd59..4a805697e6 100644
--- a/lib/erl_docgen/src/Makefile
+++ b/lib/erl_docgen/src/Makefile
@@ -35,7 +35,9 @@ RELSYSDIR = $(RELEASE_PATH)/lib/erl_docgen-$(VSN)
# Target Specs
# ----------------------------------------------------
MODULES = \
- otp_specs
+ docgen_otp_specs \
+ docgen_edoc_xml_cb \
+ docgen_xmerl_xml_cb
HRL_FILES =
diff --git a/lib/docbuilder/src/docb_edoc_xml_cb.erl b/lib/erl_docgen/src/docgen_edoc_xml_cb.erl
index 90491bc007..dc9bc565ee 100644
--- a/lib/docbuilder/src/docb_edoc_xml_cb.erl
+++ b/lib/erl_docgen/src/docgen_edoc_xml_cb.erl
@@ -15,17 +15,13 @@
%%
%% $Id$
%%
--module(docb_edoc_xml_cb).
+-module(docgen_edoc_xml_cb).
-%% This is the EDoc callback module for creating DocBuilder erlref
-%% documents (man pages) in XML format, and also a DocBuilder chapter
+%% This is the EDoc callback module for creating erlref
+%% documents (man pages) in XML format, and also a chapter
%% document based on "overview.edoc".
%%
-%% Usage examples:
-%% docb_gen File
-%% docb_gen -chapter overview.edoc
-%% or (from an Erlang shell)
-%% edoc:file(File, [{layout,docb_edoc_xml_cb},{file_suffix,".xml"},
+%% edoc:file(File, [{layout,docgen_edoc_xml_cb},{file_suffix,".xml"},
%% {preprocess,true}]).
%%
%% The origin of this file is the edoc module otpsgml_layout.erl
@@ -43,12 +39,12 @@
module(Element, Opts) ->
SortP = proplists:get_value(sort_functions, Opts, true),
XML = layout_module(Element, SortP),
- xmerl:export_simple([XML], docb_xmerl_xml_cb, []).
+ xmerl:export_simple([XML], docgen_xmerl_xml_cb, []).
%% CHAPTER
overview(Element, _Opts) ->
XML = layout_chapter(Element),
- xmerl:export_simple([XML], docb_xmerl_xml_cb, []).
+ xmerl:export_simple([XML], docgen_xmerl_xml_cb, []).
%%--Internal functions--------------------------------------------------
@@ -433,12 +429,11 @@ otp_xmlify_e(E) ->
%% Takes an <a> element and filters the attributes to decide wheather
%% its a seealso/url or a marker.
%% In the case of a seealso/url, the href part is checked, making
-%% sure a .xml/.html file extension is removed (as DocBuilder inserts
-%% .html extension when resolving cross references).
+%% sure a .xml/.html file extension is removed.
%% Also, references to other applications //App has a href attribute
-%% value "OTPROOT/..." (due to app_default being set to "OTPROOT" in
-%% docb_gen.erl), in this case both href attribute and content must be
-%% formatted correctly according to DocBuilder requirements.
+%% value "OTPROOT/..." (due to app_default being set to "OTPROOT")
+%% , in this case both href attribute and content must be
+%% formatted correctly according to requirements.
otp_xmlify_a(A) ->
[Attr0] = filter_a_attrs(A#xmlElement.attributes),
case Attr0 of
@@ -521,9 +516,8 @@ otp_xmlify_a_fileref(FileRef1, AppS) ->
File;
[File, Ext, Marker0] ->
%% Here is an awkward solution to an awkward problem
- %% The marker automatically inserted by DocBuilder at
- %% each function does not seem to work for EDoc generated
- %% ERLREFs.
+ %% The marker automatically inserted at each function
+ %% does not seem to work for EDoc generated ERLREFs.
%% So if the referenced marker is in an ERLREF generated
%% by EDoc, keep it "as is", ie "function-arity".
%% If the referenced marker is NOT in an ERLREF generated
diff --git a/lib/erl_docgen/src/otp_specs.erl b/lib/erl_docgen/src/docgen_otp_specs.erl
index edb437a942..3929e66515 100644
--- a/lib/erl_docgen/src/otp_specs.erl
+++ b/lib/erl_docgen/src/docgen_otp_specs.erl
@@ -17,7 +17,7 @@
%% %CopyrightEnd%
%%
--module(otp_specs).
+-module(docgen_otp_specs).
-export([module/2, package/2, overview/2, type/1]).
diff --git a/lib/docbuilder/src/docb_xmerl_xml_cb.erl b/lib/erl_docgen/src/docgen_xmerl_xml_cb.erl
index 089b8f0c7d..884932ed12 100644
--- a/lib/docbuilder/src/docb_xmerl_xml_cb.erl
+++ b/lib/erl_docgen/src/docgen_xmerl_xml_cb.erl
@@ -15,11 +15,11 @@
%%
%% $Id$
%%
--module(docb_xmerl_xml_cb).
+-module(docgen_xmerl_xml_cb).
-%% This is the callback module for exporting XHTML to a DocBuilder
+%% This is the callback module for exporting XHTML to an
%% erlref or chapter document in XML format.
-%% See docb_edoc_xml_cb.erl for further information.
+%% See docgen_edoc_xml_cb.erl for further information.
%%
%% The origin of this file is the xmerl module xmerl_otpsgml.erl
%% written by Ulf Wiger and Richard Carlsson.
@@ -83,6 +83,6 @@ is_url("http:"++_) -> true;
is_url("../"++_) -> true;
is_url(FileRef) ->
case filename:extension(FileRef) of
- "" -> false; % no extension = xml file, DocBuilder resolves
- _Ext -> true % extension, DocBuilder must not resolve
+ "" -> false; % no extension = xml file
+ _Ext -> true % extension
end.
diff --git a/lib/docbuilder/src/docb_xml_check.erl b/lib/erl_docgen/src/docgen_xml_check.erl
index 5912e22e7b..892a880269 100644
--- a/lib/docbuilder/src/docb_xml_check.erl
+++ b/lib/erl_docgen/src/docgen_xml_check.erl
@@ -15,7 +15,7 @@
%%
%% $Id$
%%
--module(docb_xml_check).
+-module(docgen_xml_check).
-export([validate/1]).
-deprecated([{validate,1,next_major_release}]).
@@ -31,7 +31,7 @@ validate(File0) ->
end,
case filelib:is_regular(File) of
true ->
- DtdDir = docb_util:dtd_dir(),
+ DtdDir = filename:join(code:priv_dir(erl_docgen), "dtd"),
case catch xmerl_scan:file(File, [{validation,true},
{fetch_path,[DtdDir]}]) of
{'EXIT', Error} ->
diff --git a/lib/erl_docgen/src/erl_docgen.app.src b/lib/erl_docgen/src/erl_docgen.app.src
index 1720464b6d..daad172106 100644
--- a/lib/erl_docgen/src/erl_docgen.app.src
+++ b/lib/erl_docgen/src/erl_docgen.app.src
@@ -1,7 +1,9 @@
{application, erl_docgen,
[{description, "Misc tools for building documentation"},
{vsn, "%VSN%"},
- {modules, [otp_specs
+ {modules, [docgen_otp_specs,
+ docgen_edoc_xml_cb,
+ docgen_xmerl_xml_cb
]
},
{registered,[]},
diff --git a/lib/erl_docgen/vsn.mk b/lib/erl_docgen/vsn.mk
index 79c8c570bf..dbd7e017b0 100644
--- a/lib/erl_docgen/vsn.mk
+++ b/lib/erl_docgen/vsn.mk
@@ -1,2 +1,2 @@
-ERL_DOCGEN_VSN = 0.2.6
+ERL_DOCGEN_VSN = 0.3
diff --git a/lib/erl_interface/configure.in b/lib/erl_interface/configure.in
index 72ac8c7bbf..abe1602be1 100644
--- a/lib/erl_interface/configure.in
+++ b/lib/erl_interface/configure.in
@@ -338,12 +338,6 @@ AC_SUBST(LIB_CFLAGS)
if test "X$host" = "Xwin32"; then
LIB_CFLAGS="$CFLAGS"
else
- case $host_os in
- darwin*)
- CFLAGS="$CFLAGS -no-cpp-precomp"
- ;;
- esac
-
if test "x$GCC" = xyes; then
LIB_CFLAGS="$CFLAGS -fPIC"
else
diff --git a/lib/erl_interface/doc/src/make.dep b/lib/erl_interface/doc/src/make.dep
deleted file mode 100644
index 3f43cf64fe..0000000000
--- a/lib/erl_interface/doc/src/make.dep
+++ /dev/null
@@ -1,24 +0,0 @@
-# ----------------------------------------------------
-# >>>> Do not edit this file <<<<
-# This file was automaticly generated by
-# /home/otp/bin//docdepend
-# ----------------------------------------------------
-
-
-# ----------------------------------------------------
-# TeX files that the DVI file depend on
-# ----------------------------------------------------
-
-book.dvi: book.tex ei.tex ei_connect.tex ei_users_guide.tex \
- erl_call.tex erl_connect.tex erl_error.tex \
- erl_eterm.tex erl_format.tex erl_global.tex \
- erl_malloc.tex erl_marshal.tex part_ei.tex \
- ref_man.tex ref_man_ei.tex ref_man_erl_interface.tex \
- registry.tex
-
-# ----------------------------------------------------
-# Source inlined when transforming from source to LaTeX
-# ----------------------------------------------------
-
-book.tex: ref_man.xml ref_man_ei.xml ref_man_erl_interface.xml
-
diff --git a/lib/erl_interface/src/Makefile.in b/lib/erl_interface/src/Makefile.in
index 8ff142a366..0d841cfa48 100644
--- a/lib/erl_interface/src/Makefile.in
+++ b/lib/erl_interface/src/Makefile.in
@@ -143,7 +143,6 @@ BINDIR = $(ERL_TOP)/lib/erl_interface/bin/$(TARGET)
vpath %.c connect:encode:decode:misc:epmd:legacy:registry
-
###########################################################################
# List targets
###########################################################################
@@ -202,11 +201,6 @@ ifeq ($(USING_VC),yes)
# Windows targets
TARGETS = \
- $(BINDIR) \
- $(OBJDIR) \
- $(MT_OBJDIR) \
- $(MD_OBJDIR) \
- $(MDD_OBJDIR) \
$(OBJ_TARGETS) \
$(EXE_TARGETS)
@@ -236,9 +230,6 @@ else
ifeq ($USING_MINGW,yes)
TARGETS = \
- $(BINDIR) \
- $(OBJDIR) \
- $(MD_OBJDIR) \
$(OBJ_TARGETS) \
$(EXE_TARGETS)
@@ -257,10 +248,6 @@ else
ifdef THR_DEFS
TARGETS = \
- $(BINDIR) \
- $(OBJDIR) \
- $(ST_OBJDIR) \
- $(MT_OBJDIR) \
$(OBJ_TARGETS) \
$(EXE_TARGETS)
@@ -283,9 +270,6 @@ FAKE_TARGETS = \
else
TARGETS = \
- $(BINDIR) \
- $(OBJDIR) \
- $(ST_OBJDIR) \
$(OBJ_TARGETS) \
$(EXE_TARGETS)
@@ -601,23 +585,7 @@ $(MDD_OBJDIR)/%.o: %.c
# Create directories
###########################################################################
-$(BINDIR):
- mkdir -p $(BINDIR)
-
-$(OBJDIR):
- mkdir -p $(OBJDIR)
-
-$(ST_OBJDIR):
- mkdir -p $(ST_OBJDIR)
-
-$(MT_OBJDIR):
- mkdir -p $(MT_OBJDIR)
-
-$(MD_OBJDIR):
- mkdir -p $(MD_OBJDIR)
-
-$(MDD_OBJDIR):
- mkdir -p $(MDD_OBJDIR)
+_create_dirs := $(shell mkdir -p $(BINDIR) $(OBJDIR) $(ST_OBJDIR) $(MT_OBJDIR) $(MD_OBJDIR) $(MDD_OBJDIR))
###########################################################################
# Special rules
diff --git a/lib/erl_interface/test/all_SUITE_data/Makefile.src b/lib/erl_interface/test/all_SUITE_data/Makefile.src
index 9be2360656..42d4c6f27f 100644
--- a/lib/erl_interface/test/all_SUITE_data/Makefile.src
+++ b/lib/erl_interface/test/all_SUITE_data/Makefile.src
@@ -30,6 +30,8 @@ CHMOD=chmod
all: $(ALL_OBJS)
+$(EI_COMMON_OBJS): gccifier@exe@
+
@IFEQ@ (@erl_interface_cross_compile@, true)
gccifier@exe@:
$(CP) gccifier.sh gccifier@exe@
diff --git a/lib/erl_interface/test/all_SUITE_data/init_tc.erl b/lib/erl_interface/test/all_SUITE_data/init_tc.erl
index 8157d590fc..8db4667bf9 100644
--- a/lib/erl_interface/test/all_SUITE_data/init_tc.erl
+++ b/lib/erl_interface/test/all_SUITE_data/init_tc.erl
@@ -40,23 +40,11 @@ run([]) ->
run1(Name) ->
CFile = Name ++ ".c",
{ok, Bin} = file:read_file(CFile),
- String = binary_to_list(Bin),
-
- %% This ConstPart stuff is because you can't retrieve part of a match.
- %% Long live Perl!
-
- ConstPart = "\nTESTCASE\\(",
- ConstPartLen = 10,
- {match, Matches} = regexp:matches(String, ConstPart++"[_a-zA-Z]*"),
- Cases = get_names(Matches, ConstPartLen, Bin, []),
+ RE = "\nTESTCASE\\(([_a-zA-Z]*)\\)",
+ {match, Cases0} = re:run(Bin, RE, [{capture,all_but_first,list},global]),
+ Cases = lists:concat(Cases0),
generate(Name, Cases).
-get_names([{Start, Length}|Rest], Skip, Bin, Result) ->
- Name = binary_to_list(Bin, Start+Skip, Start+Length-1),
- get_names(Rest, Skip, Bin, [Name|Result]);
-get_names([], _Skip, _Bin, Result) ->
- lists:reverse(Result).
-
generate(TcName, Cases) ->
Hrl = TcName ++ "_cases.hrl",
{ok, HrlFile} = file:open(Hrl, write),
diff --git a/lib/eunit/doc/src/make.dep b/lib/eunit/doc/src/make.dep
deleted file mode 100644
index d68f888403..0000000000
--- a/lib/eunit/doc/src/make.dep
+++ /dev/null
@@ -1,19 +0,0 @@
-# ----------------------------------------------------
-# >>>> Do not edit this file <<<<
-# This file was automaticly generated by
-# /home/otp/bin/docdepend
-# ----------------------------------------------------
-
-
-# ----------------------------------------------------
-# TeX files that the DVI file depend on
-# ----------------------------------------------------
-
-book.dvi: book.tex chapter.tex eunit.tex part.tex ref_man.tex
-
-# ----------------------------------------------------
-# Source inlined when transforming from source to LaTeX
-# ----------------------------------------------------
-
-book.tex: ref_man.xml
-
diff --git a/lib/eunit/src/Makefile b/lib/eunit/src/Makefile
index 4897c20ec1..bec2fdbe0b 100644
--- a/lib/eunit/src/Makefile
+++ b/lib/eunit/src/Makefile
@@ -26,8 +26,9 @@ INCLUDE=../include
ERL_COMPILE_FLAGS += -pa $(EBIN) -I$(INCLUDE) +warn_unused_vars +nowarn_shadow_vars +warn_unused_import +warn_obsolete_guard
+PARSE_TRANSFORM = eunit_autoexport.erl
+
SOURCES= \
- eunit_autoexport.erl \
eunit_striptests.erl \
eunit.erl \
eunit_tests.erl \
@@ -43,6 +44,8 @@ SOURCES= \
INCLUDE_FILES = eunit.hrl
+PARSE_TRANSFORM_BIN = $(PARSE_TRANSFORM:%.erl=$(EBIN)/%.$(EMULATOR))
+
OBJECTS=$(SOURCES:%.erl=$(EBIN)/%.$(EMULATOR)) $(APP_TARGET) $(APPUP_TARGET)
INCLUDE_DELIVERABLES = $(INCLUDE_FILES:%=$(INCLUDE)/%)
@@ -59,7 +62,7 @@ APPUP_TARGET= $(EBIN)/$(APPUP_FILE)
# Targets
# ----------------------------------------------------
-debug opt: $(OBJECTS)
+debug opt: $(PARSE_TRANSFORM_BIN) $(OBJECTS)
docs:
@@ -86,6 +89,8 @@ realclean: clean
$(EBIN)/%.$(EMULATOR):%.erl
erlc -W $(ERL_COMPILE_FLAGS) -o$(EBIN) $<
+$(OBJECTS): $(PARSE_TRANSFORM_BIN)
+
# ----------------------------------------------------
# Special Build Targets
# ----------------------------------------------------
@@ -103,9 +108,9 @@ include $(ERL_TOP)/make/otp_release_targets.mk
release_spec: opt
$(INSTALL_DIR) $(RELSYSDIR)/ebin
- $(INSTALL_DATA) $(OBJECTS) $(RELSYSDIR)/ebin
+ $(INSTALL_DATA) $(PARSE_TRANSFORM_BIN) $(OBJECTS) $(RELSYSDIR)/ebin
$(INSTALL_DIR) $(RELSYSDIR)/src
- $(INSTALL_DATA) $(SOURCES) $(RELSYSDIR)/src
+ $(INSTALL_DATA) $(PARSE_TRANSFORM) $(SOURCES) $(RELSYSDIR)/src
$(INSTALL_DIR) $(RELSYSDIR)/include
$(INSTALL_DATA) $(INCLUDE_DELIVERABLES) $(RELSYSDIR)/include
diff --git a/lib/gs/doc/src/make.dep b/lib/gs/doc/src/make.dep
deleted file mode 100644
index b33ed3b2de..0000000000
--- a/lib/gs/doc/src/make.dep
+++ /dev/null
@@ -1,58 +0,0 @@
-# ----------------------------------------------------
-# >>>> Do not edit this file <<<<
-# This file was automaticly generated by
-# /home/otp/bin/docdepend
-# ----------------------------------------------------
-
-
-# ----------------------------------------------------
-# TeX files that the DVI file depend on
-# ----------------------------------------------------
-
-book.dvi: book.tex gs.tex gs_chapter1.tex gs_chapter2.tex \
- gs_chapter3.tex gs_chapter4.tex gs_chapter5.tex \
- gs_chapter6.tex gs_chapter7.tex gs_chapter8.tex \
- part.tex ref_man.tex
-
-# ----------------------------------------------------
-# Source inlined when transforming from source to LaTeX
-# ----------------------------------------------------
-
-book.tex: ref_man.xml
-
-gs_chapter2.tex: examples/ex1.erl examples/ex2.erl
-
-gs_chapter4.tex: examples/ex3.erl examples/ex4.erl examples/ex5.erl \
- examples/ex6.erl
-
-gs_chapter5.tex: examples/ex15.erl
-
-gs_chapter6.tex: examples/ex16.erl
-
-gs_chapter7.tex: examples/ex17.erl
-
-gs_chapter8.tex: examples/ex10.erl examples/ex11.erl examples/ex12.erl \
- examples/ex13.erl examples/ex14.erl examples/ex7.erl \
- examples/ex8.erl examples/ex9.erl
-
-# ----------------------------------------------------
-# Pictures that the DVI file depend on
-# ----------------------------------------------------
-
-book.dvi: pics/gs1-1-image-1.ps pics/gs1-1-image-2.ps \
- pics/gs1-1-image-3.ps
-
-book.dvi: pics/ex1.ps pics/gs1-1-image-4.ps
-
-book.dvi: pics/ex15.ps
-
-book.dvi: pics/ex16.ps
-
-book.dvi: pics/packer1.ps pics/packer2.ps
-
-book.dvi: pics/arc.ps pics/buttons.ps pics/ex10.ps pics/ex11.ps \
- pics/ex12.ps pics/ex13.ps pics/ex14.ps pics/ex8.ps \
- pics/ex9.ps pics/image.ps pics/line.ps pics/oval.ps \
- pics/polygon.ps pics/rectangle.ps pics/text.ps \
- pics/window.ps
-
diff --git a/lib/gs/src/Makefile b/lib/gs/src/Makefile
index a648d3cf13..964966ba00 100644
--- a/lib/gs/src/Makefile
+++ b/lib/gs/src/Makefile
@@ -90,7 +90,7 @@ clean:
# Special Build Targets
# ----------------------------------------------------
-gstk_generic.hrl: gs_make.erl
+gstk_generic.hrl: gs_make.erl ../ebin/gs_make.$(EMULATOR) ../ebin/gs.$(EMULATOR)
$(ERL) -pa $(EBIN) -s gs_make -s erlang halt -noshell
$(APP_TARGET): $(APP_SRC) ../vsn.mk
@@ -99,6 +99,8 @@ $(APP_TARGET): $(APP_SRC) ../vsn.mk
$(APPUP_TARGET): $(APPUP_SRC) ../vsn.mk
sed -e 's;%VSN%;$(VSN);' $< > $@
+$(GSTK_GENERIC_TARGET): gstk_generic.hrl
+
# ----------------------------------------------------
# Release Target
# ----------------------------------------------------
diff --git a/lib/gs/src/gstk_editor.erl b/lib/gs/src/gstk_editor.erl
index 3e0c8240e4..8cc7021cc6 100644
--- a/lib/gs/src/gstk_editor.erl
+++ b/lib/gs/src/gstk_editor.erl
@@ -243,14 +243,14 @@ option(Option, Gstkid, _MainW, DB, Editor) ->
Editor, " ins ",AI," ", gstk:to_ascii(Text)]};
clear -> {c, [Editor, " delete 1.0 end"]};
{load, File} ->
- {ok, F2,_} = regexp:gsub(File, [92,92], "/"),
+ F2 = re:replace(File, [92,92], "/", [global,{return,list}]),
case gstk:call(["ed_load ", Editor, " ", gstk:to_ascii(F2)]) of
{result, _} -> none;
{bad_result,Re} ->
{error,{no_such_file,editor,load,F2,Re}}
end;
{save, File} ->
- {ok, F2,_} = regexp:gsub(File, [92,92], "/"),
+ F2 = re:replace(File, [92,92], "/", [global,{return,list}]),
case gstk:call(["ed_save ",Editor," ",gstk:to_ascii(F2)]) of
{result, _} -> none;
{bad_result,Re} ->
diff --git a/lib/gs/src/gstk_generic.erl b/lib/gs/src/gstk_generic.erl
index 3ddb69efc5..2cc6c4c2d3 100644
--- a/lib/gs/src/gstk_generic.erl
+++ b/lib/gs/src/gstk_generic.erl
@@ -414,7 +414,7 @@ gen_font(_Opt,Gstkid,_TkW,DB,_ExtraArg) ->
gen_label({text,Text},Opts,Gstkid,TkW,DB,ExtraArg,S,P,C) ->
out_opts(Opts,Gstkid,TkW,DB,ExtraArg,[" -text ", gstk:to_ascii(Text), " -bi {}"|S],P,C);
gen_label({image,Img},Opts,Gstkid,TkW,DB,ExtraArg,S,P,C) ->
- {ok, I2,_} = regexp:gsub(Img, [92,92], "/"),
+ I2 = re:replace(Img, [92,92], "/", [global,{return,list}]),
out_opts(Opts,Gstkid,TkW,DB,ExtraArg,[" -bi \"@", I2, "\" -text {}"|S],P,C).
gen_label(_Opt,_Gstkid,TkW,_DB,_ExtraArg) ->
case gstk:call([TkW, " cg -bit"]) of
diff --git a/lib/gs/src/gstk_image.erl b/lib/gs/src/gstk_image.erl
index 5ad37cf6de..9adbe42386 100644
--- a/lib/gs/src/gstk_image.erl
+++ b/lib/gs/src/gstk_image.erl
@@ -227,10 +227,10 @@ event(DB, Gstkid, Etype, Edata, Args) ->
option(Option, Gstkid, _Canvas, _DB, _AItem) ->
case Option of
{bitmap, Bitmap} ->
- {ok, BF,_} = regexp:gsub(Bitmap, [92,92], "/"),
+ BF = re:replace(Bitmap, [92,92], "/", [global,{return,list}]),
{s, [" -bi @", BF]};
{load_gif, File} ->
- {ok, F2,_} = regexp:gsub(File, [92,92], "/"),
+ F2 = re:replace(File, [92,92], "/", [global,{return,list}]),
{Photo_item, _item} = Gstkid#gstkid.widget_data,
{c,[Photo_item, " configure -file ", gstk:to_ascii(F2)]};
{pix_val, {Coords,Color}} ->
diff --git a/lib/gs/src/tool_utils.erl b/lib/gs/src/tool_utils.erl
index b07e92c4f0..d09af5f22f 100644
--- a/lib/gs/src/tool_utils.erl
+++ b/lib/gs/src/tool_utils.erl
@@ -98,7 +98,8 @@ open_help_default(Parent, File) ->
_Else -> "netscape -remote \"openURL(file:" ++ File ++ ")\""
end;
{win32,_AnyType} ->
- "netscape.exe -h " ++ regexp:gsub(File,"\\\\","/");
+ "netscape.exe -h " ++
+ re:replace(File,"\\\\","/",[global,{return,list}]);
_Other ->
unknown
end;
diff --git a/lib/hipe/cerl/erl_bif_types.erl b/lib/hipe/cerl/erl_bif_types.erl
index 4163f2dae2..1483b2aee1 100644
--- a/lib/hipe/cerl/erl_bif_types.erl
+++ b/lib/hipe/cerl/erl_bif_types.erl
@@ -678,8 +678,6 @@ type(erlang, check_old_code, 1, Xs) ->
type(erlang, check_process_code, 2, Xs) ->
strict(arg_types(erlang, check_process_code, 2), Xs,
fun (_) -> t_boolean() end);
-type(erlang, concat_binary, 1, Xs) ->
- strict(arg_types(erlang, concat_binary, 1), Xs, fun (_) -> t_binary() end);
type(erlang, crc32, 1, Xs) ->
strict(arg_types(erlang, crc32, 1), Xs, fun (_) -> t_crc32() end);
type(erlang, crc32, 2, Xs) ->
@@ -801,7 +799,8 @@ type(erlang, get_module_info, 2, Xs) ->
end
end);
type(erlang, get_stacktrace, 0, _) ->
- t_list(t_tuple([t_atom(), t_atom(), t_sup([t_arity(), t_list()])]));
+ t_list(t_tuple([t_atom(), t_atom(), t_sup([t_arity(), t_list()]),
+ t_list()]));
type(erlang, group_leader, 0, _) -> t_pid();
type(erlang, group_leader, 2, Xs) ->
strict(arg_types(erlang, group_leader, 2), Xs,
@@ -3446,8 +3445,6 @@ arg_types(erlang, check_old_code, 1) ->
[t_atom()];
arg_types(erlang, check_process_code, 2) ->
[t_pid(), t_atom()];
-arg_types(erlang, concat_binary, 1) ->
- [t_list(t_binary())];
arg_types(erlang, crc32, 1) ->
[t_iodata()];
arg_types(erlang, crc32, 2) ->
@@ -3763,7 +3760,10 @@ arg_types(erlang, purge_module, 1) ->
arg_types(erlang, put, 2) ->
[t_any(), t_any()];
arg_types(erlang, raise, 3) ->
- [t_raise_errorclass(), t_any(), type(erlang, get_stacktrace, 0, [])];
+ OldStyleType = t_list(t_tuple([t_atom(), t_atom(),
+ t_sup([t_arity(), t_list()])])),
+ NewStyleType = type(erlang, get_stacktrace, 0, []),
+ [t_raise_errorclass(), t_any(), t_sup(OldStyleType, NewStyleType)];
arg_types(erlang, read_timer, 1) ->
[t_reference()];
arg_types(erlang, ref_to_list, 1) ->
diff --git a/lib/hipe/doc/src/make.dep b/lib/hipe/doc/src/make.dep
deleted file mode 100644
index d5f5844c21..0000000000
--- a/lib/hipe/doc/src/make.dep
+++ /dev/null
@@ -1,13 +0,0 @@
-# ----------------------------------------------------
-# >>>> Do not edit this file <<<<
-# This file was automaticly generated by
-# /home/otp/bin/docdepend
-# ----------------------------------------------------
-
-
-# ----------------------------------------------------
-# TeX files that the DVI file depend on
-# ----------------------------------------------------
-
-book.dvi: book.tex
-
diff --git a/lib/hipe/icode/hipe_beam_to_icode.erl b/lib/hipe/icode/hipe_beam_to_icode.erl
index cfed410240..992f387bd5 100644
--- a/lib/hipe/icode/hipe_beam_to_icode.erl
+++ b/lib/hipe/icode/hipe_beam_to_icode.erl
@@ -31,7 +31,7 @@
-module(hipe_beam_to_icode).
--export([module/2, mfa/3]).
+-export([module/2]).
%%-----------------------------------------------------------------------
@@ -111,55 +111,6 @@ trans_beam_function_chunk(FunBeamCode, ClosureInfo) ->
{MFA,Icode}.
%%-----------------------------------------------------------------------
-%% @doc
-%% Translates the BEAM code of a single function into Icode.
-%% Returns a tuple whose first argument is list of {{M,F,A}, ICode}
-%% pairs, where the first entry is that of the given MFA, and the
-%% following (in undefined order) are those of the funs that are
-%% defined in the function, and recursively, in the funs. The
-%% second argument of the tuple is the HiPE compiler options
-%% contained in the file.
-%% @end
-%%-----------------------------------------------------------------------
-
--spec mfa(list(), mfa(), comp_options()) -> hipe_beam_to_icode_ret().
-
-mfa(BeamFuns, {M,F,A} = MFA, Options)
- when is_atom(M), is_atom(F), is_integer(A) ->
- BeamCode0 = [beam_disasm:function__code(Fn) || Fn <- BeamFuns],
- {ModCode, ClosureInfo} = preprocess_code(BeamCode0),
- mfa_loop([MFA], [], sets:new(), ModCode, ClosureInfo, Options).
-
-mfa_loop([{M,F,A} = MFA | MFAs], Acc, Seen, ModCode, ClosureInfo,
- Options) when is_atom(M), is_atom(F), is_integer(A) ->
- case sets:is_element(MFA, Seen) of
- true ->
- mfa_loop(MFAs, Acc, Seen, ModCode, ClosureInfo, Options);
- false ->
- {Icode, FunMFAs} = mfa_get(M, F, A, ModCode, ClosureInfo, Options),
- mfa_loop(FunMFAs ++ MFAs, [{MFA, Icode} | Acc],
- sets:add_element(MFA, Seen),
- ModCode, ClosureInfo, Options)
- end;
-mfa_loop([], Acc, _, _, _, _) ->
- lists:reverse(Acc).
-
-mfa_get(M, F, A, ModCode, ClosureInfo, Options) ->
- BeamCode = get_fun(ModCode, M,F,A),
- pp_beam([BeamCode], Options), % cheat by using a list
- Icode = trans_mfa_code(M,F,A, BeamCode, ClosureInfo),
- FunMFAs = get_fun_mfas(BeamCode),
- {Icode, FunMFAs}.
-
-get_fun_mfas([{patched_make_fun,{M,F,A} = MFA,_,_,_}|BeamCode])
- when is_atom(M), is_atom(F), is_integer(A) ->
- [MFA|get_fun_mfas(BeamCode)];
-get_fun_mfas([_|BeamCode]) ->
- get_fun_mfas(BeamCode);
-get_fun_mfas([]) ->
- [].
-
-%%-----------------------------------------------------------------------
%% The main translation function.
%%-----------------------------------------------------------------------
@@ -281,10 +232,14 @@ needs_redtest(Leafness) ->
%%-----------------------------------------------------------------------
%%--- label & func_info combo ---
+trans_fun([{label,_}=F,{func_info,_,_,_}=FI|Instructions], Env) ->
+ %% Handle old code without a line instruction.
+ trans_fun([F,{line,[]},FI|Instructions], Env);
trans_fun([{label,B},{label,_},
{func_info,M,F,A},{label,L}|Instructions], Env) ->
trans_fun([{label,B},{func_info,M,F,A},{label,L}|Instructions], Env);
trans_fun([{label,B},
+ {line,_},
{func_info,{atom,_M},{atom,_F},_A},
{label,L}|Instructions], Env) ->
%% Emit code to handle function_clause errors. The BEAM test instructions
@@ -1142,6 +1097,11 @@ trans_fun([{trim,N,NY}|Instructions], Env) ->
Moves = trans_trim(N, NY),
Moves ++ trans_fun(Instructions, Env);
%%--------------------------------------------------------------------
+%% New line/1 instruction in R15.
+%%--------------------------------------------------------------------
+trans_fun([{line,_}|Instructions], Env) ->
+ trans_fun(Instructions,Env);
+%%--------------------------------------------------------------------
%%--- ERROR HANDLING ---
%%--------------------------------------------------------------------
trans_fun([X|_], _) ->
@@ -1869,20 +1829,12 @@ patch_make_funs([], FunIndex, Acc) ->
find_mfa([{label,_}|Code]) ->
find_mfa(Code);
+find_mfa([{line,_}|Code]) ->
+ find_mfa(Code);
find_mfa([{func_info,{atom,M},{atom,F},A}|_])
when is_atom(M), is_atom(F), is_integer(A), 0 =< A, A =< 255 ->
{M, F, A}.
-%%-----------------------------------------------------------------------
-
-%% Localize a particular function in a module
-get_fun([[L, {func_info,{atom,M},{atom,F},A} | Is] | _], M,F,A) ->
- [L, {func_info,{atom,M},{atom,F},A} | Is];
-get_fun([[_L1,_L2, {func_info,{atom,M},{atom,F},A} = MFA| _Is] | _], M,F,A) ->
- ?WARNING_MSG("Consecutive labels found; please re-create the .beam file~n", []),
- [_L1,_L2, MFA | _Is];
-get_fun([_|Rest], M,F,A) ->
- get_fun(Rest, M,F,A).
%%-----------------------------------------------------------------------
%% Takes a list of arguments and returns the constants of them into
diff --git a/lib/hipe/icode/hipe_icode_coordinator.erl b/lib/hipe/icode/hipe_icode_coordinator.erl
index a71e143192..d2defa0c90 100644
--- a/lib/hipe/icode/hipe_icode_coordinator.erl
+++ b/lib/hipe/icode/hipe_icode_coordinator.erl
@@ -49,6 +49,12 @@ coordinate(CG, Escaping, NonEscaping, Mod) ->
fun (PM) -> last_action(PM, ServerPid, Mod, All) end,
coordinate({Clean,All}, CG, gb_trees:empty(), Restart, LastAction, ServerPid).
+-type mfalists() :: {[mfa()], [mfa()]}.
+
+-spec coordinate(mfalists(), hipe_digraph:hdg(), gb_tree(),
+ fun((mfalists(), gb_tree()) -> mfalists()),
+ fun((gb_tree()) -> 'ok'), pid()) -> no_return().
+
coordinate(MFALists, CG, PM, Restart, LastAction, ServerPid) ->
case MFALists of
{[], []} ->
@@ -106,8 +112,7 @@ last_action(PM, ServerPid, Mod, All) ->
receive
{done_rewrite, MFA} -> ok
end
- end, All),
- ok.
+ end, All).
restart_funs({Queue, Busy} = QB, PM, All, ServerPid) ->
case ?MAX_CONCURRENT - length(Busy) of
diff --git a/lib/hipe/icode/hipe_icode_mulret.erl b/lib/hipe/icode/hipe_icode_mulret.erl
index a6529c8519..0579867e2f 100644
--- a/lib/hipe/icode/hipe_icode_mulret.erl
+++ b/lib/hipe/icode/hipe_icode_mulret.erl
@@ -595,9 +595,9 @@ optimizeDefine([I|Code], Dsts, DstLst, Res) ->
[Ds] = Dsts,
case isCallPrimop(I, mktuple) andalso DstLst =:= [] of
true ->
- case (hipe_icode:call_dstlist(I) =:= Dsts) of
+ case hipe_icode:call_dstlist(I) =:= Dsts of
true ->
- case (hipe_icode:call_args(I) > 1) of
+ case length(hipe_icode:call_args(I)) > 1 of
true ->
optimizeDefine(Code, Dsts, hipe_icode:call_args(I), Res);
false ->
diff --git a/lib/hipe/icode/hipe_icode_pp.erl b/lib/hipe/icode/hipe_icode_pp.erl
index 575bbfe43d..575bbfe43d 100755..100644
--- a/lib/hipe/icode/hipe_icode_pp.erl
+++ b/lib/hipe/icode/hipe_icode_pp.erl
diff --git a/lib/hipe/icode/hipe_icode_ssa.erl b/lib/hipe/icode/hipe_icode_ssa.erl
index 719d5d8f45..719d5d8f45 100755..100644
--- a/lib/hipe/icode/hipe_icode_ssa.erl
+++ b/lib/hipe/icode/hipe_icode_ssa.erl
diff --git a/lib/hipe/main/hipe.erl b/lib/hipe/main/hipe.erl
index 570e4d9d17..7694b2fd95 100644
--- a/lib/hipe/main/hipe.erl
+++ b/lib/hipe/main/hipe.erl
@@ -47,9 +47,8 @@
%%
%% <h3>Using the direct interface - for advanced users only</h3>
%%
-%% To compile a module or a specific function to native code and
-%% automatically load the code into memory, call <a
-%% href="#c-1"><code>hipe:c(Module)</code></a> or <a
+%% To compile a module to native code and automatically load the code
+%% into memory, call <a href="#c-1"><code>hipe:c(Module)</code></a> or <a
%% href="#c-2"><code>hipe:c(Module, Options)</code></a>. Note that all
%% options are specific to the HiPE compiler. See the <a
%% href="#index">function index</a> for other compiler functions.
@@ -221,11 +220,10 @@
%%-------------------------------------------------------------------
-type mod() :: atom().
--type c_unit() :: mod() | mfa().
-type f_unit() :: mod() | binary().
-type ret_rtl() :: [_].
--type c_ret() :: {'ok', c_unit()} | {'error', term()} |
- {'ok', c_unit(), ret_rtl()}. %% The last for debugging only
+-type c_ret() :: {'ok', mod()} | {'error', term()} |
+ {'ok', mod(), ret_rtl()}. %% The last for debugging only
-type compile_file() :: atom() | string() | binary().
-type compile_ret() :: {hipe_architecture(), binary()} | list().
@@ -278,47 +276,44 @@ load(Mod, BeamFileName) when is_list(BeamFileName) ->
end.
%% @spec c(Name) -> {ok, Name} | {error, Reason}
-%% Name = mod() | mfa()
+%% Name = mod()
%% Reason = term()
%%
%% @equiv c(Name, [])
--spec c(c_unit()) -> c_ret().
+-spec c(mod()) -> c_ret().
c(Name) ->
c(Name, []).
%% @spec c(Name, options()) -> {ok, Name} | {error, Reason}
-%% Name = mod() | mfa()
+%% Name = mod()
%% options() = [option()]
%% option() = term()
%% Reason = term()
%%
-%% @type mfa() = {M::mod(),F::fun(),A::arity()}.
-%% A fully qualified function name.
-%%
%% @type fun() = atom(). A function identifier.
%%
%% @type arity() = integer(). A function arity; always nonnegative.
%%
%% @doc User-friendly native code compiler interface. Reads BEAM code
-%% from the corresponding "Module<code>.beam</code>" file in the system
-%% path, and compiles either a single function or the whole module to
-%% native code. By default, the compiled code is loaded directly. See
-%% above for documentation of options.
+%% from the corresponding "Module<code>.beam</code>" file in the
+%% system path, and compiles the whole module to native code. By
+%% default, the compiled code is loaded directly. See above for
+%% documentation of options.
%%
%% @see c/1
%% @see c/3
%% @see f/2
%% @see compile/2
--spec c(c_unit(), comp_options()) -> c_ret().
+-spec c(mod(), comp_options()) -> c_ret().
c(Name, Options) ->
c(Name, beam_file(Name), Options).
%% @spec c(Name, File, options()) -> {ok, Name} | {error, Reason}
-%% Name = mod() | mfa()
+%% Name = mod()
%% File = filename() | binary()
%% Reason = term()
%%
@@ -329,7 +324,6 @@ c(Name, Options) ->
%% @see f/2
c(Name, File, Opts) ->
- %% No server if only one function is compiled
Opts1 = user_compile_opts(Opts),
case compile(Name, File, Opts1) of
{ok, Res} ->
@@ -359,8 +353,7 @@ f(File) ->
%% Reason = term()
%%
%% @doc Like <code>c/3</code>, but takes the module name from the
-%% specified <code>File</code>. This always compiles the whole module;
-%% there is no possibility to compile just a single function.
+%% specified <code>File</code>.
%%
%% @see c/3
@@ -381,26 +374,26 @@ user_compile_opts(Opts) ->
%% @spec compile(Name) -> {ok, {Target,Binary}} | {error, Reason}
-%% Name = mod() | mfa()
+%% Name = mod()
%% Binary = binary()
%% Reason = term()
%%
%% @equiv compile(Name, [])
--spec compile(c_unit()) -> {'ok', compile_ret()} | {'error', term()}.
+-spec compile(mod()) -> {'ok', compile_ret()} | {'error', term()}.
compile(Name) ->
compile(Name, []).
%% @spec compile(Name, options()) -> {ok, {Target,Binary}} | {error, Reason}
-%% Name = mod() | mfa()
+%% Name = mod()
%% Binary = binary()
%% Reason = term()
%%
-%% @doc Direct compiler interface, for advanced use. This just compiles
-%% the named function or module, reading BEAM code from the
-%% corresponding "Module<code>.beam</code>" file in the system path.
-%% Returns <code>{ok, Binary}</code> if successful, or <code>{error,
+%% @doc Direct compiler interface, for advanced use. This just
+%% compiles the module, reading BEAM code from the corresponding
+%% "Module<code>.beam</code>" file in the system path. Returns
+%% <code>{ok, Binary}</code> if successful, or <code>{error,
%% Reason}</code> otherwise. By default, it does <em>not</em> load the
%% binary to memory (the <code>load</code> option can be used to
%% activate automatic loading). <code>File</code> can be either a file
@@ -412,15 +405,13 @@ compile(Name) ->
%% @see file/2
%% @see load/2
--spec compile(c_unit(), comp_options()) -> {'ok', compile_ret()} | {'error', _}.
+-spec compile(mod(), comp_options()) -> {'ok', compile_ret()} | {'error', _}.
compile(Name, Options) ->
compile(Name, beam_file(Name), Options).
--spec beam_file(mod() | mfa()) -> string().
+-spec beam_file(mod()) -> string().
-beam_file({M,F,A}) when is_atom(M), is_atom(F), is_integer(A), A >= 0 ->
- beam_file(M);
beam_file(Module) when is_atom(Module) ->
case code:which(Module) of
non_existing ->
@@ -432,7 +423,7 @@ beam_file(Module) when is_atom(Module) ->
%% @spec compile(Name, File, options()) ->
%% {ok, {Target, Binary}} | {error, Reason}
-%% Name = mod() | mfa()
+%% Name = mod()
%% File = filename() | binary()
%% Binary = binary()
%% Reason = term()
@@ -442,18 +433,11 @@ beam_file(Module) when is_atom(Module) ->
%%
%% @see compile/2
--spec compile(c_unit(), compile_file(), comp_options()) ->
+-spec compile(mod(), compile_file(), comp_options()) ->
{'ok', compile_ret()} | {'error', term()}.
-compile(Name, File, Opts0) ->
- Opts1 = expand_kt2(Opts0),
- Opts =
- case Name of
- {_Mod, _Fun, _Arity} ->
- [no_concurrent_comp|Opts1];
- _ ->
- Opts1
- end,
+compile(Name, File, Opts0) when is_atom(Name) ->
+ Opts = expand_kt2(Opts0),
case proplists:get_value(core, Opts) of
true when is_binary(File) ->
?error_msg("Cannot get Core Erlang code from BEAM binary.",[]),
@@ -486,23 +470,11 @@ compile(Name, File, Opts0) ->
?EXIT({cant_compile_source_code, Error})
end;
Other when Other =:= false; Other =:= undefined ->
- NewOpts =
- case proplists:get_value(use_callgraph, Opts) of
- No when No =:= false; No =:= undefined -> Opts;
- _ ->
- case Name of
- {_M,_F,_A} ->
- %% There is no point in using the callgraph or concurrent_comp
- %% when analyzing just one function.
- [no_use_callgraph, no_concurrent_comp|Opts];
- _ -> Opts
- end
- end,
DisasmFun = fun (_) -> disasm(File) end,
IcodeFun = fun (Code, Opts_) ->
get_beam_icode(Name, Code, File, Opts_)
end,
- run_compiler(Name, DisasmFun, IcodeFun, NewOpts)
+ run_compiler(Name, DisasmFun, IcodeFun, Opts)
end.
-spec compile_core(mod(), cerl:c_module(), compile_file(), comp_options()) ->
@@ -602,9 +574,13 @@ file(File, Options) when is_atom(File) ->
disasm(File) ->
case beam_disasm:file(File) of
#beam_file{labeled_exports = LabeledExports,
- compile_info = CompInfo,
+ compile_info = CompInfo0,
code = BeamCode} ->
- {options, CompOpts} = lists:keyfind(options, 1, CompInfo),
+ CompInfo = case CompInfo0 of
+ none -> [];
+ _ -> CompInfo0
+ end,
+ CompOpts = proplists:get_value(options, CompInfo, []),
HCompOpts = case lists:keyfind(hipe, 1, CompOpts) of
{hipe, L} when is_list(L) -> L;
{hipe, X} -> [X];
@@ -625,11 +601,6 @@ fix_beam_exports([{F,A,_}|BeamExports], Exports) ->
fix_beam_exports([], Exports) ->
Exports.
-get_beam_icode({M,_F,_A} = MFA, {BeamCode, Exports}, _File, Options) ->
- ?option_time({ok, Icode} =
- (catch {ok, hipe_beam_to_icode:mfa(BeamCode, MFA, Options)}),
- "BEAM-to-Icode", Options),
- {{M, Exports, Icode}, false};
get_beam_icode(Mod, {BeamCode, Exports}, File, Options) ->
?option_time({ok, Icode} =
(catch {ok, hipe_beam_to_icode:module(BeamCode, Options)}),
@@ -899,7 +870,8 @@ maybe_load(Mod, Bin, WholeModule, Opts) ->
do_load(Mod, Bin, WholeModule)
end.
-do_load(Mod, Bin, WholeModule) ->
+do_load(Mod, Bin, BeamBinOrPath) when is_binary(BeamBinOrPath);
+ is_list(BeamBinOrPath) ->
HostArch = get(hipe_host_arch),
TargetArch = get(hipe_target_arch),
%% Make sure we can do the load.
@@ -907,29 +879,22 @@ do_load(Mod, Bin, WholeModule) ->
?EXIT({host_and_target_arch_differ, HostArch, TargetArch});
true -> ok
end,
- case WholeModule of
+ case code:is_sticky(Mod) of
+ true ->
+ %% We unpack and repack the Beam binary as a workaround to
+ %% ensure that it is not compressed.
+ {ok, _, Chunks} = beam_lib:all_chunks(BeamBinOrPath),
+ {ok, Beam} = beam_lib:build_module(Chunks),
+ %% Don't purge or register sticky mods; just load native.
+ code:load_native_sticky(Mod, Bin, Beam);
false ->
- %% In this case, the emulated code for the module must be loaded.
- {module, Mod} = code:ensure_loaded(Mod),
- code:load_native_partial(Mod, Bin);
- BeamBinOrPath when is_binary(BeamBinOrPath) orelse is_list(BeamBinOrPath) ->
- case code:is_sticky(Mod) of
- true ->
- %% We unpack and repack the Beam binary as a workaround to
- %% ensure that it is not compressed.
- {ok, _, Chunks} = beam_lib:all_chunks(WholeModule),
- {ok, Beam} = beam_lib:build_module(Chunks),
- %% Don't purge or register sticky mods; just load native.
- code:load_native_sticky(Mod, Bin, Beam);
- false ->
- %% Normal loading of a whole module
- Architecture = erlang:system_info(hipe_architecture),
- ChunkName = hipe_unified_loader:chunk_name(Architecture),
- {ok, _, Chunks0} = beam_lib:all_chunks(WholeModule),
- Chunks = [{ChunkName, Bin}|lists:keydelete(ChunkName, 1, Chunks0)],
- {ok, BeamPlusNative} = beam_lib:build_module(Chunks),
- code:load_binary(Mod, code:which(Mod), BeamPlusNative)
- end
+ %% Normal loading of a whole module
+ Architecture = erlang:system_info(hipe_architecture),
+ ChunkName = hipe_unified_loader:chunk_name(Architecture),
+ {ok, _, Chunks0} = beam_lib:all_chunks(BeamBinOrPath),
+ Chunks = [{ChunkName, Bin}|lists:keydelete(ChunkName, 1, Chunks0)],
+ {ok, BeamPlusNative} = beam_lib:build_module(Chunks),
+ code:load_binary(Mod, code:which(Mod), BeamPlusNative)
end.
assemble(CompiledCode, Closures, Exports, Options) ->
diff --git a/lib/hipe/rtl/Makefile b/lib/hipe/rtl/Makefile
index 55d20af8af..690045b978 100644
--- a/lib/hipe/rtl/Makefile
+++ b/lib/hipe/rtl/Makefile
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2001-2010. All Rights Reserved.
+# Copyright Ericsson AB 2001-2011. All Rights Reserved.
#
# The contents of this file are subject to the Erlang Public License,
# Version 1.1, (the "License"); you may not use this file except in
@@ -108,10 +108,30 @@ release_spec: opt
release_docs_spec:
-HIPE_MKLITERALS=$(ERL_TOP)/bin/$(TARGET)/hipe_mkliterals
+ifeq ($(TYPE),debug)
+TYPE_STR=.debug
+else
+TYPE_STR=
+endif
+
+ifeq ($(FLAVOR),smp)
+FLAVOR_STR=.smp
+else
+FLAVOR_STR=
+endif
+
+ifeq ($(XCOMP),yes)
+MKLIT_FLAGS= -x
+else
+MKLIT_FLAGS=
+endif
+
+
+HIPE_MKLITERALS=$(ERL_TOP)/bin/$(TARGET)/hipe_mkliterals$(TYPE_STR)$(FLAVOR_STR)
+
hipe_literals.hrl: $(HIPE_MKLITERALS)
- $(HIPE_MKLITERALS) -e > hipe_literals.hrl
+ $(HIPE_MKLITERALS) $(MKLIT_FLAGS) -e > hipe_literals.hrl
# Need to generate hipe.hrl from one and only one target in one and only
# one makefile; otherwise, clearmake will force rebuilds of hipe over and
diff --git a/lib/hipe/rtl/hipe_rtl.erl b/lib/hipe/rtl/hipe_rtl.erl
index 29e9c8c8fe..4bf4eb6bd7 100644
--- a/lib/hipe/rtl/hipe_rtl.erl
+++ b/lib/hipe/rtl/hipe_rtl.erl
@@ -781,8 +781,11 @@ fstore_src_update(F, NewSrc) -> F#fstore{src=NewSrc}.
%% fp
%%
+
mk_fp(Dst, Src1, Op, Src2) ->
- #fp{dst=Dst, src1=Src1, op=Op, src2=Src2}.
+ [#fp{dst=Dst, src1=Src1, op=Op, src2=Src2}
+ | hipe_rtl_arch:mk_fp_check_result(Dst)].
+
fp_dst(#fp{dst=Dst}) -> Dst.
fp_dst_update(Fp, NewDst) -> Fp#fp{dst=NewDst}.
fp_src1(#fp{src1=Src1}) -> Src1.
diff --git a/lib/hipe/rtl/hipe_rtl_arch.erl b/lib/hipe/rtl/hipe_rtl_arch.erl
index 22cda57a3a..99eb80f3d1 100644
--- a/lib/hipe/rtl/hipe_rtl_arch.erl
+++ b/lib/hipe/rtl/hipe_rtl_arch.erl
@@ -65,7 +65,8 @@
%% alignment/0,
nr_of_return_regs/0,
log2_word_size/0,
- word_size/0
+ word_size/0,
+ mk_fp_check_result/1
]).
-include("hipe_literals.hrl").
@@ -558,6 +559,12 @@ eval_cond_bits(Cond, N, Z, V, C) ->
%%----------------------------------------------------------------------
fwait() ->
+ case ?ERTS_NO_FPE_SIGNALS of
+ 1 -> [];
+ 0 -> fwait_real()
+ end.
+
+fwait_real() ->
case get(hipe_target_arch) of
x86 -> [hipe_rtl:mk_call([], 'fwait', [], [], [], not_remote)];
amd64 -> [hipe_rtl:mk_call([], 'fwait', [], [], [], not_remote)];
@@ -573,6 +580,12 @@ fwait() ->
%% Returns RTL code to restore the FPU after a floating-point exception.
%% @end
handle_fp_exception() ->
+ case ?ERTS_NO_FPE_SIGNALS of
+ 1 -> [];
+ 0 -> handle_real_fp_exception()
+ end.
+
+handle_real_fp_exception() ->
case get(hipe_target_arch) of
x86 ->
ContLbl = hipe_rtl:mk_new_label(),
@@ -655,3 +668,15 @@ nr_of_return_regs() ->
1
%% hipe_amd64_registers:nr_rets();
end.
+
+
+mk_fp_check_result(Result) ->
+ case ?ERTS_NO_FPE_SIGNALS of
+ 0 ->
+ [];
+ 1 ->
+ [hipe_rtl:mk_fstore(proc_pointer(),
+ hipe_rtl:mk_imm(?P_FLOAT_RESULT),
+ Result),
+ hipe_rtl:mk_call([], emulate_fpe, [], [], [], not_remote)]
+ end.
diff --git a/lib/hipe/rtl/hipe_rtl_lcm.erl b/lib/hipe/rtl/hipe_rtl_lcm.erl
index 9224623c8b..262aedb409 100644
--- a/lib/hipe/rtl/hipe_rtl_lcm.erl
+++ b/lib/hipe/rtl/hipe_rtl_lcm.erl
@@ -486,7 +486,7 @@ lcm_precalc(CFG, Options) ->
?option_time(NodeInfo2 = calc_down_exp(CFG, ExprMap, NodeInfo1, Labels),
"RTL LCM calc_down_exp", Options),
?option_time(NodeInfo3 = calc_killed_expr(CFG, NodeInfo2, UseMap, AllExpr,
- Labels),
+ IdMap, Labels),
"RTL LCM calc_killed_exp", Options),
?option_time(NodeInfo4 = calc_avail(CFG, NodeInfo3),
"RTL LCM calc_avail", Options),
@@ -815,19 +815,19 @@ exp_kill_expr(Instr, [CheckedExpr|Exprs]) ->
%%=============================================================================
%% Calculates the killed expression sets for all given labels.
-calc_killed_expr(_, NodeInfo, _, _, []) ->
+calc_killed_expr(_, NodeInfo, _, _, _, []) ->
NodeInfo;
-calc_killed_expr(CFG, NodeInfo, UseMap, AllExpr, [Label|Labels]) ->
+calc_killed_expr(CFG, NodeInfo, UseMap, AllExpr, IdMap, [Label|Labels]) ->
Code = hipe_bb:code(hipe_rtl_cfg:bb(CFG, Label)),
- KilledExprs = calc_killed_expr_bb(Code, UseMap, AllExpr, ?SETS:new()),
+ KilledExprs = calc_killed_expr_bb(Code, UseMap, AllExpr, IdMap, ?SETS:new()),
NewNodeInfo = set_killed_expr(NodeInfo, Label, KilledExprs),
- calc_killed_expr(CFG, NewNodeInfo, UseMap, AllExpr, Labels).
+ calc_killed_expr(CFG, NewNodeInfo, UseMap, AllExpr, IdMap, Labels).
%%=============================================================================
%% Calculates the killed expressions set for one basic block.
-calc_killed_expr_bb([], _UseMap, _AllExpr, KilledExprs) ->
+calc_killed_expr_bb([], _UseMap, _AllExpr, _IdMap, KilledExprs) ->
KilledExprs;
-calc_killed_expr_bb([Instr|Instrs], UseMap, AllExpr, KilledExprs) ->
+calc_killed_expr_bb([Instr|Instrs], UseMap, AllExpr, IdMap, KilledExprs) ->
%% Calls, gctests and stores potentially clobber everything
case Instr of
#call{} -> AllExpr;
@@ -837,7 +837,8 @@ calc_killed_expr_bb([Instr|Instrs], UseMap, AllExpr, KilledExprs) ->
%% Kill all float expressions
%% FIXME: Make separate function is_fp_expr
?SETS:from_list
- (lists:foldl(fun(Expr, Fexprs) ->
+ (lists:foldl(fun(ExprId, Fexprs) ->
+ Expr = expr_id_map_get_expr(IdMap, ExprId),
[Define|_] = hipe_rtl:defines(Expr),
case hipe_rtl:is_fpreg(Define) of
true ->
@@ -849,10 +850,10 @@ calc_killed_expr_bb([Instr|Instrs], UseMap, AllExpr, KilledExprs) ->
_ ->
case hipe_rtl:defines(Instr) of
[] ->
- calc_killed_expr_bb(Instrs, UseMap, AllExpr, KilledExprs);
+ calc_killed_expr_bb(Instrs, UseMap, AllExpr, IdMap, KilledExprs);
[Define|_] ->
NewKilledExprs = use_map_get_expr_uses(UseMap, Define),
- calc_killed_expr_bb(Instrs, UseMap, AllExpr,
+ calc_killed_expr_bb(Instrs, UseMap, AllExpr, IdMap,
?SETS:union(NewKilledExprs, KilledExprs))
end
end.
diff --git a/lib/hipe/tools/Makefile b/lib/hipe/tools/Makefile
index 0eaa3a7b05..e9745a6767 100644
--- a/lib/hipe/tools/Makefile
+++ b/lib/hipe/tools/Makefile
@@ -42,7 +42,7 @@ RELSYSDIR = $(RELEASE_PATH)/lib/hipe-$(VSN)
# ----------------------------------------------------
# Target Specs
# ----------------------------------------------------
-MODULES = hipe_tool hipe_profile hipe_ceach hipe_jit
+MODULES = hipe_tool hipe_profile hipe_jit
# hipe_timer
HRL_FILES=
diff --git a/lib/hipe/tools/hipe_ceach.erl b/lib/hipe/tools/hipe_ceach.erl
deleted file mode 100644
index b29615e169..0000000000
--- a/lib/hipe/tools/hipe_ceach.erl
+++ /dev/null
@@ -1,74 +0,0 @@
-%% -*- erlang-indent-level: 2 -*-
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2002-2009. All Rights Reserved.
-%%
-%% The contents of this file are subject to the Erlang Public License,
-%% Version 1.1, (the "License"); you may not use this file except in
-%% compliance with the License. You should have received a copy of the
-%% Erlang Public License along with this software. If not, it can be
-%% retrieved online at http://www.erlang.org/.
-%%
-%% Software distributed under the License is distributed on an "AS IS"
-%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
-%% the License for the specific language governing rights and limitations
-%% under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% Copyright (c) 2001 by Erik Johansson. All Rights Reserved
-%% ====================================================================
-%% Module : hipe_ceach
-%% Purpose : Compile each function in a module, possibly applying a
-%% fun between each compilation. Useful for bug hunting by
-%% pinpointing a function that when compiled causes a bug.
-%% Notes :
-%% History : * 2001-12-11 Erik Johansson ([email protected]): Created.
-%% ====================================================================
-%% Exports :
-%%
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
--module(hipe_ceach).
-
--export([c/1, c/2, c/3]).
-
--include("../main/hipe.hrl").
-
-%%---------------------------------------------------------------------
-
--spec c(atom()) -> 'ok'.
-
-c(M) ->
- lists:foreach(fun({F,A}) -> comp(M, F, A) end,
- M:module_info(functions)).
-
--spec c(atom(), comp_options()) -> 'ok'.
-
-c(M, Opts) ->
- lists:foreach(fun({F,A}) -> comp(M, F, A, Opts) end,
- M:module_info(functions)).
-
--spec c(atom(), comp_options(), fun(() -> any())) -> 'ok'.
-
-c(M, Opts, Fn) ->
- lists:foreach(fun({F,A}) -> comp(M, F, A, Opts), Fn() end,
- M:module_info(functions)).
-
--spec comp(atom(), atom(), arity()) -> 'ok'.
-
-comp(M, F, A) ->
- io:format("~w:~w/~w... ", [M, F, A]),
- MFA = {M, F, A},
- {ok, MFA} = hipe:c(MFA),
- io:format("OK\n").
-
--spec comp(atom(), atom(), arity(), comp_options()) -> 'ok'.
-
-comp(M, F, A, Opts) ->
- io:format("~w:~w/~w... ", [M, F, A]),
- MFA = {M, F, A},
- {ok, MFA} = hipe:c(MFA, Opts),
- io:format("OK\n").
diff --git a/lib/hipe/util/hipe_dot.erl b/lib/hipe/util/hipe_dot.erl
index d6ef801c88..d6ef801c88 100755..100644
--- a/lib/hipe/util/hipe_dot.erl
+++ b/lib/hipe/util/hipe_dot.erl
diff --git a/lib/ic/c_src/Makefile.in b/lib/ic/c_src/Makefile.in
index 6eef7827b9..28040ca42d 100644
--- a/lib/ic/c_src/Makefile.in
+++ b/lib/ic/c_src/Makefile.in
@@ -125,13 +125,9 @@ docs:
# Special Build Targets
# ----------------------------------------------------
-$(OBJDIR):
- -mkdir -p $(OBJDIR)
+_create_dirs := $(shell mkdir -p $(OBJDIR) $(LIBDIR))
-$(LIBDIR):
- -mkdir -p $(LIBDIR)
-
-$(LIBRARY): $(OBJDIR) $(LIBDIR) $(OBJ_FILES)
+$(LIBRARY): $(OBJ_FILES)
-$(AR) $(AR_OUT) $@ $(OBJ_FILES)
-$(RANLIB) $@
diff --git a/lib/ic/doc/src/Makefile b/lib/ic/doc/src/Makefile
index 8eda436a24..1e93578cb1 100644
--- a/lib/ic/doc/src/Makefile
+++ b/lib/ic/doc/src/Makefile
@@ -26,13 +26,6 @@ include $(ERL_TOP)/make/$(TARGET)/otp.mk
include ../../vsn.mk
VSN=$(IC_VSN)
APPLICATION=ic
-# ----------------------------------------------------
-# Include dependency
-# ----------------------------------------------------
-
-ifndef DOCSUPPORT
-include make.dep
-endif
# ----------------------------------------------------
# Java specific
@@ -96,32 +89,10 @@ EXTRA_FILES = summary.html.src \
MAN3_FILES = $(XML_REF3_FILES:%.xml=$(MAN3DIR)/%.3)
-ifdef DOCSUPPORT
-
HTML_REF_MAN_FILE = $(HTMLDIR)/index.html
TOP_PDF_FILE = $(PDFDIR)/$(APPLICATION)-$(VSN).pdf
-else
-
-TEX_FILES_BOOK = \
- $(BOOK_FILES:%.xml=%.tex)
-TEX_FILES_REF_MAN = $(XML_REF3_FILES:%.xml=%.tex) \
- $(XML_APPLICATION_FILES:%.xml=%.tex)
-TEX_FILES_USERS_GUIDE = \
- $(XML_CHAPTER_FILES:%.xml=%.tex)
-
-TOP_PDF_FILE = $(APPLICATION)-$(VSN).pdf
-TOP_PS_FILE = $(APPLICATION)-$(VSN).ps
-
-$(TOP_PDF_FILE): book.dvi ../../vsn.mk
- $(DVI2PS) $(DVIPS_FLAGS) -f $< | $(DISTILL) $(DISTILL_FLAGS) > $@
-
-$(TOP_PS_FILE): book.dvi ../../vsn.mk
- $(DVI2PS) $(DVIPS_FLAGS) -f $< > $@
-
-endif
-
JAVA_SOURCE_FILES = \
Holder.java \
BooleanHolder.java \
@@ -209,8 +180,6 @@ JAVADOCFLAGS = \
$(HTMLDIR)/%.gif: %.gif
$(INSTALL_DATA) $< $@
-ifdef DOCSUPPORT
-
ifneq (,$(JAVA))
docs: pdf html man $(JAVADOC_GENERATED_FILES)
else
@@ -229,38 +198,11 @@ clean clean_docs:
rm -f $(TOP_PDF_FILE) $(TOP_PDF_FILE:%.pdf=%.fo)
rm -f errs core *~
-else
-
-ifeq ($(DOCTYPE),pdf)
-docs: pdf
-else
-ifeq ($(DOCTYPE),ps)
-docs: ps
-else
-docs: html $(JAVADOC_GENERATED_FILES) gifs man
-endif
-endif
-
-pdf: $(TOP_PDF_FILE)
-
-ps: $(TOP_PS_FILE)
+$(JAVADOC_GENERATED_FILES): JAVADOC-GENERATED
-html: $(HTML_FILES)
-
-clean clean_docs clean_tex:
- rm -f $(TEX_FILES_USERS_GUIDE) $(TEX_FILES_REF_MAN) $(TEX_FILES_BOOK)
- rm -f $(HTML_FILES) $(MAN3_FILES)
- rm -f $(TOP_PDF_FILE) $(TOP_PS_FILE)
- rm -f errs core *~ *xmls_output *xmls_errs $(LATEX_CLEAN)
- rm -rf $(JAVA_OUT_DIR)
-
-endif
-
-$(JAVA_OUT_DIR):
- mkdir $(JAVA_OUT_DIR)
-
-$(JAVADOC_GENERATED_FILES): $(JAVA_OUT_DIR)
+JAVADOC-GENERATED: $(JAVA_SOURCE_FILES:%=$(JAVA_SOURCE_DIR)/%)
@(cd ../../java_src; $(JAVADOC) $(JAVADOCFLAGS) com.ericsson.otp.ic)
+ >JAVADOC-GENERATED
man: $(MAN3_FILES)
@@ -277,8 +219,6 @@ debug opt:
# ----------------------------------------------------
include $(ERL_TOP)/make/otp_release_targets.mk
-ifdef DOCSUPPORT
-
release_docs_spec: docs
$(INSTALL_DIR) $(RELSYSDIR)/doc/pdf
$(INSTALL_DATA) $(TOP_PDF_FILE) $(RELSYSDIR)/doc/pdf
@@ -288,46 +228,4 @@ release_docs_spec: docs
$(INSTALL_DIR) $(RELEASE_PATH)/man/man3
$(INSTALL_DATA) $(MAN3_FILES) $(RELEASE_PATH)/man/man3
-else
-
-ifeq ($(DOCTYPE),pdf)
-release_docs_spec: pdf
- $(INSTALL_DIR) $(RELEASE_PATH)/pdf
- $(INSTALL_DATA) $(TOP_PDF_FILE) $(RELEASE_PATH)/pdf
-else
-ifeq ($(DOCTYPE),ps)
-release_docs_spec: ps
- $(INSTALL_DIR) $(RELEASE_PATH)/ps
- $(INSTALL_DATA) $(TOP_PS_FILE) $(RELEASE_PATH)/ps
-else
-release_docs_spec: docs
- $(INSTALL_DIR) $(RELSYSDIR)/doc/html
- $(INSTALL_DATA) $(GIF_FILES) $(EXTRA_FILES) $(HTML_FILES) \
- $(RELSYSDIR)/doc/html
- $(INSTALL_DATA) $(INFO_FILE) $(RELSYSDIR)
-ifneq (,$(JAVA))
- $(INSTALL_DIR) $(RELSYSDIR)/doc/html/java
- $(INSTALL_DIR) $(RELSYSDIR)/doc/html/java/resources
- $(INSTALL_DIR) $(RELSYSDIR)/doc/html/java/com
- $(INSTALL_DIR) $(RELSYSDIR)/doc/html/java/com/ericsson
- $(INSTALL_DIR) $(RELSYSDIR)/doc/html/java/com/ericsson/otp
- $(INSTALL_DIR) $(RELSYSDIR)/doc/html/java/com/ericsson/otp/ic
- $(INSTALL_DATA) $(JAVADOC_INDEX_HTML_FILES) \
- $(RELSYSDIR)/doc/html/java
- $(INSTALL_DATA) $(JD_GIF_FILES) \
- $(RELSYSDIR)/doc/html/java/resources
- $(INSTALL_DATA) $(JAVADOC_PACK_HTML_FILES) \
- $(RELSYSDIR)/doc/html/java/com/ericsson/otp/ic
-endif
- $(INSTALL_DIR) $(RELEASE_PATH)/man/man3
- $(INSTALL_DATA) $(MAN3_FILES) $(RELEASE_PATH)/man/man3
-
-endif
-endif
-
-endif
-
-
release_spec:
-
-
diff --git a/lib/ic/doc/src/make.dep b/lib/ic/doc/src/make.dep
deleted file mode 100644
index 64694ee85a..0000000000
--- a/lib/ic/doc/src/make.dep
+++ /dev/null
@@ -1,24 +0,0 @@
-# ----------------------------------------------------
-# >>>> Do not edit this file <<<<
-# This file was automaticly generated by
-# /home/otp/bin/docdepend
-# ----------------------------------------------------
-
-
-# ----------------------------------------------------
-# TeX files that the DVI file depend on
-# ----------------------------------------------------
-
-book.dvi: book.tex c-part.tex ch_basic_idl.tex ch_c_client.tex \
- ch_c_corba_env.tex ch_c_mapping.tex ch_c_server.tex \
- ch_erl_genserv.tex ch_erl_plain.tex ch_ic_protocol.tex \
- ch_introduction.tex ch_java.tex erl-part.tex \
- ic.tex ic_c_protocol.tex ic_clib.tex java-part.tex \
- ref_man.tex
-
-# ----------------------------------------------------
-# Source inlined when transforming from source to LaTeX
-# ----------------------------------------------------
-
-book.tex: ref_man.xml
-
diff --git a/lib/ic/doc/src/notes.xml b/lib/ic/doc/src/notes.xml
index de519d5f84..ff289bd76c 100644
--- a/lib/ic/doc/src/notes.xml
+++ b/lib/ic/doc/src/notes.xml
@@ -31,6 +31,22 @@
</header>
<section>
+ <title>IC 4.2.28</title>
+
+ <section>
+ <title>Fixed Bugs and Malfunctions</title>
+ <list type="bulleted">
+ <item>
+ <p>
+ Incorrect use of ets:match changed to ets:match_object.</p>
+ <p>
+ Own Id: OTP-9630 </p>
+ </item>
+ </list>
+ </section>
+ </section>
+
+ <section>
<title>IC 4.2.27</title>
<section>
diff --git a/lib/ic/examples/pre_post_condition/Makefile b/lib/ic/examples/pre_post_condition/Makefile
index 68e2168e1e..d57133c964 100644
--- a/lib/ic/examples/pre_post_condition/Makefile
+++ b/lib/ic/examples/pre_post_condition/Makefile
@@ -100,7 +100,7 @@ YRL_FLAGS =
debug opt: $(TARGET_FILES)
clean:
- rm -f $(TARGET_FILES) $(GEN_ERL_MODULES:%=%.erl) $(GEN_HRL_FILES) $(CLASS_FILES)
+ rm -f $(TARGET_FILES) $(GEN_ERL_MODULES:%=%.erl) $(GEN_HRL_FILES) $(CLASS_FILES) IDL-GENERATED
rm -f errs core *~
docs:
@@ -108,9 +108,14 @@ docs:
test: $(TEST_TARGET_FILES)
-$(GEN_ERL_MODULES:%=%.erl) $(GEN_HRL_FILES): ex.idl
+IDL-GENERATED: ex.idl
erlc $(ERL_LOCAL_FLAGS) +'{precond,{tracer,pre}}' \
+'{{postcond,"m::i::f"},{tracer,post}}' ex.idl
+ >IDL-GENERATED
+
+$(GEN_ERL_MODULES:%=%.erl) $(GEN_HRL_FILES): IDL-GENERATED
+
+$(TARGET_FILES): IDL-GENERATED
# ----------------------------------------------------
# Release Target
diff --git a/lib/ic/java_src/com/ericsson/otp/ic/ignore_config_record.inf b/lib/ic/java_src/com/ericsson/otp/ic/ignore_config_record.inf
deleted file mode 100644
index 34e5586175..0000000000
--- a/lib/ic/java_src/com/ericsson/otp/ic/ignore_config_record.inf
+++ /dev/null
@@ -1 +0,0 @@
-Dummy to speed up compilatio
diff --git a/lib/ic/src/ic_pragma.erl b/lib/ic/src/ic_pragma.erl
index 7f2216b9dc..beaa2852ab 100644
--- a/lib/ic/src/ic_pragma.erl
+++ b/lib/ic/src/ic_pragma.erl
@@ -1601,7 +1601,7 @@ remove_inheriters(S,RS,InheriterList) ->
ReducedInhList;
_Other ->
CleanList =
- ets:match(S, {inherits,'_','_'}),
+ ets:match_object(S, {inherits,'_','_'}),
% CodeOptList =
% [X || X <- EtsList, element(1,X) == codeopt],
NoInheriters =remove_inheriters2(S,ReducedInhList,CleanList),
@@ -1648,7 +1648,7 @@ remove_inh([X],[Y],List,EtsList) ->
%%%----------------------------------------------
remove_inherited(S,InheriterList) ->
CleanList =
- ets:match(S, {inherits, '_', '_'}),
+ ets:match_object(S, {inherits, '_', '_'}),
remove_inherited(S,InheriterList,CleanList).
@@ -1766,7 +1766,7 @@ inherits2(_X,Y,Z,EtsList) ->
%% false otherwise
%%
is_inherited_by(Interface1,Interface2,PragmaTab) ->
- InheritsList = ets:match(PragmaTab, {inherits, '_', '_'}),
+ InheritsList = ets:match_object(PragmaTab, {inherits, '_', '_'}),
inherits(Interface2,Interface1,InheritsList).
diff --git a/lib/ic/vsn.mk b/lib/ic/vsn.mk
index 6561ccd2a7..703c8d29eb 100644
--- a/lib/ic/vsn.mk
+++ b/lib/ic/vsn.mk
@@ -1 +1 @@
-IC_VSN = 4.2.27
+IC_VSN = 4.2.28
diff --git a/lib/inets/doc/archive/rfc3986.txt b/lib/inets/doc/archive/rfc3986.txt
new file mode 100644
index 0000000000..c56ed4eb70
--- /dev/null
+++ b/lib/inets/doc/archive/rfc3986.txt
@@ -0,0 +1,3419 @@
+
+
+
+
+
+
+Network Working Group T. Berners-Lee
+Request for Comments: 3986 W3C/MIT
+STD: 66 R. Fielding
+Updates: 1738 Day Software
+Obsoletes: 2732, 2396, 1808 L. Masinter
+Category: Standards Track Adobe Systems
+ January 2005
+
+
+ Uniform Resource Identifier (URI): Generic Syntax
+
+Status of This Memo
+
+ This document specifies an Internet standards track protocol for the
+ Internet community, and requests discussion and suggestions for
+ improvements. Please refer to the current edition of the "Internet
+ Official Protocol Standards" (STD 1) for the standardization state
+ and status of this protocol. Distribution of this memo is unlimited.
+
+Copyright Notice
+
+ Copyright (C) The Internet Society (2005).
+
+Abstract
+
+ A Uniform Resource Identifier (URI) is a compact sequence of
+ characters that identifies an abstract or physical resource. This
+ specification defines the generic URI syntax and a process for
+ resolving URI references that might be in relative form, along with
+ guidelines and security considerations for the use of URIs on the
+ Internet. The URI syntax defines a grammar that is a superset of all
+ valid URIs, allowing an implementation to parse the common components
+ of a URI reference without knowing the scheme-specific requirements
+ of every possible identifier. This specification does not define a
+ generative grammar for URIs; that task is performed by the individual
+ specifications of each URI scheme.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Berners-Lee, et al. Standards Track [Page 1]
+
+RFC 3986 URI Generic Syntax January 2005
+
+
+Table of Contents
+
+ 1. Introduction . . . . . . . . . . . . . . . . . . . . . . . . . 4
+ 1.1. Overview of URIs . . . . . . . . . . . . . . . . . . . . 4
+ 1.1.1. Generic Syntax . . . . . . . . . . . . . . . . . 6
+ 1.1.2. Examples . . . . . . . . . . . . . . . . . . . . 7
+ 1.1.3. URI, URL, and URN . . . . . . . . . . . . . . . 7
+ 1.2. Design Considerations . . . . . . . . . . . . . . . . . 8
+ 1.2.1. Transcription . . . . . . . . . . . . . . . . . 8
+ 1.2.2. Separating Identification from Interaction . . . 9
+ 1.2.3. Hierarchical Identifiers . . . . . . . . . . . . 10
+ 1.3. Syntax Notation . . . . . . . . . . . . . . . . . . . . 11
+ 2. Characters . . . . . . . . . . . . . . . . . . . . . . . . . . 11
+ 2.1. Percent-Encoding . . . . . . . . . . . . . . . . . . . . 12
+ 2.2. Reserved Characters . . . . . . . . . . . . . . . . . . 12
+ 2.3. Unreserved Characters . . . . . . . . . . . . . . . . . 13
+ 2.4. When to Encode or Decode . . . . . . . . . . . . . . . . 14
+ 2.5. Identifying Data . . . . . . . . . . . . . . . . . . . . 14
+ 3. Syntax Components . . . . . . . . . . . . . . . . . . . . . . 16
+ 3.1. Scheme . . . . . . . . . . . . . . . . . . . . . . . . . 17
+ 3.2. Authority . . . . . . . . . . . . . . . . . . . . . . . 17
+ 3.2.1. User Information . . . . . . . . . . . . . . . . 18
+ 3.2.2. Host . . . . . . . . . . . . . . . . . . . . . . 18
+ 3.2.3. Port . . . . . . . . . . . . . . . . . . . . . . 22
+ 3.3. Path . . . . . . . . . . . . . . . . . . . . . . . . . . 22
+ 3.4. Query . . . . . . . . . . . . . . . . . . . . . . . . . 23
+ 3.5. Fragment . . . . . . . . . . . . . . . . . . . . . . . . 24
+ 4. Usage . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25
+ 4.1. URI Reference . . . . . . . . . . . . . . . . . . . . . 25
+ 4.2. Relative Reference . . . . . . . . . . . . . . . . . . . 26
+ 4.3. Absolute URI . . . . . . . . . . . . . . . . . . . . . . 27
+ 4.4. Same-Document Reference . . . . . . . . . . . . . . . . 27
+ 4.5. Suffix Reference . . . . . . . . . . . . . . . . . . . . 27
+ 5. Reference Resolution . . . . . . . . . . . . . . . . . . . . . 28
+ 5.1. Establishing a Base URI . . . . . . . . . . . . . . . . 28
+ 5.1.1. Base URI Embedded in Content . . . . . . . . . . 29
+ 5.1.2. Base URI from the Encapsulating Entity . . . . . 29
+ 5.1.3. Base URI from the Retrieval URI . . . . . . . . 30
+ 5.1.4. Default Base URI . . . . . . . . . . . . . . . . 30
+ 5.2. Relative Resolution . . . . . . . . . . . . . . . . . . 30
+ 5.2.1. Pre-parse the Base URI . . . . . . . . . . . . . 31
+ 5.2.2. Transform References . . . . . . . . . . . . . . 31
+ 5.2.3. Merge Paths . . . . . . . . . . . . . . . . . . 32
+ 5.2.4. Remove Dot Segments . . . . . . . . . . . . . . 33
+ 5.3. Component Recomposition . . . . . . . . . . . . . . . . 35
+ 5.4. Reference Resolution Examples . . . . . . . . . . . . . 35
+ 5.4.1. Normal Examples . . . . . . . . . . . . . . . . 36
+ 5.4.2. Abnormal Examples . . . . . . . . . . . . . . . 36
+
+
+
+Berners-Lee, et al. Standards Track [Page 2]
+
+RFC 3986 URI Generic Syntax January 2005
+
+
+ 6. Normalization and Comparison . . . . . . . . . . . . . . . . . 38
+ 6.1. Equivalence . . . . . . . . . . . . . . . . . . . . . . 38
+ 6.2. Comparison Ladder . . . . . . . . . . . . . . . . . . . 39
+ 6.2.1. Simple String Comparison . . . . . . . . . . . . 39
+ 6.2.2. Syntax-Based Normalization . . . . . . . . . . . 40
+ 6.2.3. Scheme-Based Normalization . . . . . . . . . . . 41
+ 6.2.4. Protocol-Based Normalization . . . . . . . . . . 42
+ 7. Security Considerations . . . . . . . . . . . . . . . . . . . 43
+ 7.1. Reliability and Consistency . . . . . . . . . . . . . . 43
+ 7.2. Malicious Construction . . . . . . . . . . . . . . . . . 43
+ 7.3. Back-End Transcoding . . . . . . . . . . . . . . . . . . 44
+ 7.4. Rare IP Address Formats . . . . . . . . . . . . . . . . 45
+ 7.5. Sensitive Information . . . . . . . . . . . . . . . . . 45
+ 7.6. Semantic Attacks . . . . . . . . . . . . . . . . . . . . 45
+ 8. IANA Considerations . . . . . . . . . . . . . . . . . . . . . 46
+ 9. Acknowledgements . . . . . . . . . . . . . . . . . . . . . . . 46
+ 10. References . . . . . . . . . . . . . . . . . . . . . . . . . . 46
+ 10.1. Normative References . . . . . . . . . . . . . . . . . . 46
+ 10.2. Informative References . . . . . . . . . . . . . . . . . 47
+ A. Collected ABNF for URI . . . . . . . . . . . . . . . . . . . . 49
+ B. Parsing a URI Reference with a Regular Expression . . . . . . 50
+ C. Delimiting a URI in Context . . . . . . . . . . . . . . . . . 51
+ D. Changes from RFC 2396 . . . . . . . . . . . . . . . . . . . . 53
+ D.1. Additions . . . . . . . . . . . . . . . . . . . . . . . 53
+ D.2. Modifications . . . . . . . . . . . . . . . . . . . . . 53
+ Index . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 56
+ Authors' Addresses . . . . . . . . . . . . . . . . . . . . . . . . 60
+ Full Copyright Statement . . . . . . . . . . . . . . . . . . . . . 61
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Berners-Lee, et al. Standards Track [Page 3]
+
+RFC 3986 URI Generic Syntax January 2005
+
+
+1. Introduction
+
+ A Uniform Resource Identifier (URI) provides a simple and extensible
+ means for identifying a resource. This specification of URI syntax
+ and semantics is derived from concepts introduced by the World Wide
+ Web global information initiative, whose use of these identifiers
+ dates from 1990 and is described in "Universal Resource Identifiers
+ in WWW" [RFC1630]. The syntax is designed to meet the
+ recommendations laid out in "Functional Recommendations for Internet
+ Resource Locators" [RFC1736] and "Functional Requirements for Uniform
+ Resource Names" [RFC1737].
+
+ This document obsoletes [RFC2396], which merged "Uniform Resource
+ Locators" [RFC1738] and "Relative Uniform Resource Locators"
+ [RFC1808] in order to define a single, generic syntax for all URIs.
+ It obsoletes [RFC2732], which introduced syntax for an IPv6 address.
+ It excludes portions of RFC 1738 that defined the specific syntax of
+ individual URI schemes; those portions will be updated as separate
+ documents. The process for registration of new URI schemes is
+ defined separately by [BCP35]. Advice for designers of new URI
+ schemes can be found in [RFC2718]. All significant changes from RFC
+ 2396 are noted in Appendix D.
+
+ This specification uses the terms "character" and "coded character
+ set" in accordance with the definitions provided in [BCP19], and
+ "character encoding" in place of what [BCP19] refers to as a
+ "charset".
+
+1.1. Overview of URIs
+
+ URIs are characterized as follows:
+
+ Uniform
+
+ Uniformity provides several benefits. It allows different types
+ of resource identifiers to be used in the same context, even when
+ the mechanisms used to access those resources may differ. It
+ allows uniform semantic interpretation of common syntactic
+ conventions across different types of resource identifiers. It
+ allows introduction of new types of resource identifiers without
+ interfering with the way that existing identifiers are used. It
+ allows the identifiers to be reused in many different contexts,
+ thus permitting new applications or protocols to leverage a pre-
+ existing, large, and widely used set of resource identifiers.
+
+
+
+
+
+
+
+Berners-Lee, et al. Standards Track [Page 4]
+
+RFC 3986 URI Generic Syntax January 2005
+
+
+ Resource
+
+ This specification does not limit the scope of what might be a
+ resource; rather, the term "resource" is used in a general sense
+ for whatever might be identified by a URI. Familiar examples
+ include an electronic document, an image, a source of information
+ with a consistent purpose (e.g., "today's weather report for Los
+ Angeles"), a service (e.g., an HTTP-to-SMS gateway), and a
+ collection of other resources. A resource is not necessarily
+ accessible via the Internet; e.g., human beings, corporations, and
+ bound books in a library can also be resources. Likewise,
+ abstract concepts can be resources, such as the operators and
+ operands of a mathematical equation, the types of a relationship
+ (e.g., "parent" or "employee"), or numeric values (e.g., zero,
+ one, and infinity).
+
+ Identifier
+
+ An identifier embodies the information required to distinguish
+ what is being identified from all other things within its scope of
+ identification. Our use of the terms "identify" and "identifying"
+ refer to this purpose of distinguishing one resource from all
+ other resources, regardless of how that purpose is accomplished
+ (e.g., by name, address, or context). These terms should not be
+ mistaken as an assumption that an identifier defines or embodies
+ the identity of what is referenced, though that may be the case
+ for some identifiers. Nor should it be assumed that a system
+ using URIs will access the resource identified: in many cases,
+ URIs are used to denote resources without any intention that they
+ be accessed. Likewise, the "one" resource identified might not be
+ singular in nature (e.g., a resource might be a named set or a
+ mapping that varies over time).
+
+ A URI is an identifier consisting of a sequence of characters
+ matching the syntax rule named <URI> in Section 3. It enables
+ uniform identification of resources via a separately defined
+ extensible set of naming schemes (Section 3.1). How that
+ identification is accomplished, assigned, or enabled is delegated to
+ each scheme specification.
+
+ This specification does not place any limits on the nature of a
+ resource, the reasons why an application might seek to refer to a
+ resource, or the kinds of systems that might use URIs for the sake of
+ identifying resources. This specification does not require that a
+ URI persists in identifying the same resource over time, though that
+ is a common goal of all URI schemes. Nevertheless, nothing in this
+
+
+
+
+
+Berners-Lee, et al. Standards Track [Page 5]
+
+RFC 3986 URI Generic Syntax January 2005
+
+
+ specification prevents an application from limiting itself to
+ particular types of resources, or to a subset of URIs that maintains
+ characteristics desired by that application.
+
+ URIs have a global scope and are interpreted consistently regardless
+ of context, though the result of that interpretation may be in
+ relation to the end-user's context. For example, "http://localhost/"
+ has the same interpretation for every user of that reference, even
+ though the network interface corresponding to "localhost" may be
+ different for each end-user: interpretation is independent of access.
+ However, an action made on the basis of that reference will take
+ place in relation to the end-user's context, which implies that an
+ action intended to refer to a globally unique thing must use a URI
+ that distinguishes that resource from all other things. URIs that
+ identify in relation to the end-user's local context should only be
+ used when the context itself is a defining aspect of the resource,
+ such as when an on-line help manual refers to a file on the end-
+ user's file system (e.g., "file:///etc/hosts").
+
+1.1.1. Generic Syntax
+
+ Each URI begins with a scheme name, as defined in Section 3.1, that
+ refers to a specification for assigning identifiers within that
+ scheme. As such, the URI syntax is a federated and extensible naming
+ system wherein each scheme's specification may further restrict the
+ syntax and semantics of identifiers using that scheme.
+
+ This specification defines those elements of the URI syntax that are
+ required of all URI schemes or are common to many URI schemes. It
+ thus defines the syntax and semantics needed to implement a scheme-
+ independent parsing mechanism for URI references, by which the
+ scheme-dependent handling of a URI can be postponed until the
+ scheme-dependent semantics are needed. Likewise, protocols and data
+ formats that make use of URI references can refer to this
+ specification as a definition for the range of syntax allowed for all
+ URIs, including those schemes that have yet to be defined. This
+ decouples the evolution of identification schemes from the evolution
+ of protocols, data formats, and implementations that make use of
+ URIs.
+
+ A parser of the generic URI syntax can parse any URI reference into
+ its major components. Once the scheme is determined, further
+ scheme-specific parsing can be performed on the components. In other
+ words, the URI generic syntax is a superset of the syntax of all URI
+ schemes.
+
+
+
+
+
+
+Berners-Lee, et al. Standards Track [Page 6]
+
+RFC 3986 URI Generic Syntax January 2005
+
+
+1.1.2. Examples
+
+ The following example URIs illustrate several URI schemes and
+ variations in their common syntax components:
+
+ ftp://ftp.is.co.za/rfc/rfc1808.txt
+
+ http://www.ietf.org/rfc/rfc2396.txt
+
+ ldap://[2001:db8::7]/c=GB?objectClass?one
+
+
+ news:comp.infosystems.www.servers.unix
+
+ tel:+1-816-555-1212
+
+ telnet://192.0.2.16:80/
+
+ urn:oasis:names:specification:docbook:dtd:xml:4.1.2
+
+
+1.1.3. URI, URL, and URN
+
+ A URI can be further classified as a locator, a name, or both. The
+ term "Uniform Resource Locator" (URL) refers to the subset of URIs
+ that, in addition to identifying a resource, provide a means of
+ locating the resource by describing its primary access mechanism
+ (e.g., its network "location"). The term "Uniform Resource Name"
+ (URN) has been used historically to refer to both URIs under the
+ "urn" scheme [RFC2141], which are required to remain globally unique
+ and persistent even when the resource ceases to exist or becomes
+ unavailable, and to any other URI with the properties of a name.
+
+ An individual scheme does not have to be classified as being just one
+ of "name" or "locator". Instances of URIs from any given scheme may
+ have the characteristics of names or locators or both, often
+ depending on the persistence and care in the assignment of
+ identifiers by the naming authority, rather than on any quality of
+ the scheme. Future specifications and related documentation should
+ use the general term "URI" rather than the more restrictive terms
+ "URL" and "URN" [RFC3305].
+
+
+
+
+
+
+
+
+
+Berners-Lee, et al. Standards Track [Page 7]
+
+RFC 3986 URI Generic Syntax January 2005
+
+
+1.2. Design Considerations
+
+1.2.1. Transcription
+
+ The URI syntax has been designed with global transcription as one of
+ its main considerations. A URI is a sequence of characters from a
+ very limited set: the letters of the basic Latin alphabet, digits,
+ and a few special characters. A URI may be represented in a variety
+ of ways; e.g., ink on paper, pixels on a screen, or a sequence of
+ character encoding octets. The interpretation of a URI depends only
+ on the characters used and not on how those characters are
+ represented in a network protocol.
+
+ The goal of transcription can be described by a simple scenario.
+ Imagine two colleagues, Sam and Kim, sitting in a pub at an
+ international conference and exchanging research ideas. Sam asks Kim
+ for a location to get more information, so Kim writes the URI for the
+ research site on a napkin. Upon returning home, Sam takes out the
+ napkin and types the URI into a computer, which then retrieves the
+ information to which Kim referred.
+
+ There are several design considerations revealed by the scenario:
+
+ o A URI is a sequence of characters that is not always represented
+ as a sequence of octets.
+
+ o A URI might be transcribed from a non-network source and thus
+ should consist of characters that are most likely able to be
+ entered into a computer, within the constraints imposed by
+ keyboards (and related input devices) across languages and
+ locales.
+
+ o A URI often has to be remembered by people, and it is easier for
+ people to remember a URI when it consists of meaningful or
+ familiar components.
+
+ These design considerations are not always in alignment. For
+ example, it is often the case that the most meaningful name for a URI
+ component would require characters that cannot be typed into some
+ systems. The ability to transcribe a resource identifier from one
+ medium to another has been considered more important than having a
+ URI consist of the most meaningful of components.
+
+ In local or regional contexts and with improving technology, users
+ might benefit from being able to use a wider range of characters;
+ such use is not defined by this specification. Percent-encoded
+ octets (Section 2.1) may be used within a URI to represent characters
+ outside the range of the US-ASCII coded character set if this
+
+
+
+Berners-Lee, et al. Standards Track [Page 8]
+
+RFC 3986 URI Generic Syntax January 2005
+
+
+ representation is allowed by the scheme or by the protocol element in
+ which the URI is referenced. Such a definition should specify the
+ character encoding used to map those characters to octets prior to
+ being percent-encoded for the URI.
+
+1.2.2. Separating Identification from Interaction
+
+ A common misunderstanding of URIs is that they are only used to refer
+ to accessible resources. The URI itself only provides
+ identification; access to the resource is neither guaranteed nor
+ implied by the presence of a URI. Instead, any operation associated
+ with a URI reference is defined by the protocol element, data format
+ attribute, or natural language text in which it appears.
+
+ Given a URI, a system may attempt to perform a variety of operations
+ on the resource, as might be characterized by words such as "access",
+ "update", "replace", or "find attributes". Such operations are
+ defined by the protocols that make use of URIs, not by this
+ specification. However, we do use a few general terms for describing
+ common operations on URIs. URI "resolution" is the process of
+ determining an access mechanism and the appropriate parameters
+ necessary to dereference a URI; this resolution may require several
+ iterations. To use that access mechanism to perform an action on the
+ URI's resource is to "dereference" the URI.
+
+ When URIs are used within information retrieval systems to identify
+ sources of information, the most common form of URI dereference is
+ "retrieval": making use of a URI in order to retrieve a
+ representation of its associated resource. A "representation" is a
+ sequence of octets, along with representation metadata describing
+ those octets, that constitutes a record of the state of the resource
+ at the time when the representation is generated. Retrieval is
+ achieved by a process that might include using the URI as a cache key
+ to check for a locally cached representation, resolution of the URI
+ to determine an appropriate access mechanism (if any), and
+ dereference of the URI for the sake of applying a retrieval
+ operation. Depending on the protocols used to perform the retrieval,
+ additional information might be supplied about the resource (resource
+ metadata) and its relation to other resources.
+
+ URI references in information retrieval systems are designed to be
+ late-binding: the result of an access is generally determined when it
+ is accessed and may vary over time or due to other aspects of the
+ interaction. These references are created in order to be used in the
+ future: what is being identified is not some specific result that was
+ obtained in the past, but rather some characteristic that is expected
+ to be true for future results. In such cases, the resource referred
+ to by the URI is actually a sameness of characteristics as observed
+
+
+
+Berners-Lee, et al. Standards Track [Page 9]
+
+RFC 3986 URI Generic Syntax January 2005
+
+
+ over time, perhaps elucidated by additional comments or assertions
+ made by the resource provider.
+
+ Although many URI schemes are named after protocols, this does not
+ imply that use of these URIs will result in access to the resource
+ via the named protocol. URIs are often used simply for the sake of
+ identification. Even when a URI is used to retrieve a representation
+ of a resource, that access might be through gateways, proxies,
+ caches, and name resolution services that are independent of the
+ protocol associated with the scheme name. The resolution of some
+ URIs may require the use of more than one protocol (e.g., both DNS
+ and HTTP are typically used to access an "http" URI's origin server
+ when a representation isn't found in a local cache).
+
+1.2.3. Hierarchical Identifiers
+
+ The URI syntax is organized hierarchically, with components listed in
+ order of decreasing significance from left to right. For some URI
+ schemes, the visible hierarchy is limited to the scheme itself:
+ everything after the scheme component delimiter (":") is considered
+ opaque to URI processing. Other URI schemes make the hierarchy
+ explicit and visible to generic parsing algorithms.
+
+ The generic syntax uses the slash ("/"), question mark ("?"), and
+ number sign ("#") characters to delimit components that are
+ significant to the generic parser's hierarchical interpretation of an
+ identifier. In addition to aiding the readability of such
+ identifiers through the consistent use of familiar syntax, this
+ uniform representation of hierarchy across naming schemes allows
+ scheme-independent references to be made relative to that hierarchy.
+
+ It is often the case that a group or "tree" of documents has been
+ constructed to serve a common purpose, wherein the vast majority of
+ URI references in these documents point to resources within the tree
+ rather than outside it. Similarly, documents located at a particular
+ site are much more likely to refer to other resources at that site
+ than to resources at remote sites. Relative referencing of URIs
+ allows document trees to be partially independent of their location
+ and access scheme. For instance, it is possible for a single set of
+ hypertext documents to be simultaneously accessible and traversable
+ via each of the "file", "http", and "ftp" schemes if the documents
+ refer to each other with relative references. Furthermore, such
+ document trees can be moved, as a whole, without changing any of the
+ relative references.
+
+ A relative reference (Section 4.2) refers to a resource by describing
+ the difference within a hierarchical name space between the reference
+ context and the target URI. The reference resolution algorithm,
+
+
+
+Berners-Lee, et al. Standards Track [Page 10]
+
+RFC 3986 URI Generic Syntax January 2005
+
+
+ presented in Section 5, defines how such a reference is transformed
+ to the target URI. As relative references can only be used within
+ the context of a hierarchical URI, designers of new URI schemes
+ should use a syntax consistent with the generic syntax's hierarchical
+ components unless there are compelling reasons to forbid relative
+ referencing within that scheme.
+
+ NOTE: Previous specifications used the terms "partial URI" and
+ "relative URI" to denote a relative reference to a URI. As some
+ readers misunderstood those terms to mean that relative URIs are a
+ subset of URIs rather than a method of referencing URIs, this
+ specification simply refers to them as relative references.
+
+ All URI references are parsed by generic syntax parsers when used.
+ However, because hierarchical processing has no effect on an absolute
+ URI used in a reference unless it contains one or more dot-segments
+ (complete path segments of "." or "..", as described in Section 3.3),
+ URI scheme specifications can define opaque identifiers by
+ disallowing use of slash characters, question mark characters, and
+ the URIs "scheme:." and "scheme:..".
+
+1.3. Syntax Notation
+
+ This specification uses the Augmented Backus-Naur Form (ABNF)
+ notation of [RFC2234], including the following core ABNF syntax rules
+ defined by that specification: ALPHA (letters), CR (carriage return),
+ DIGIT (decimal digits), DQUOTE (double quote), HEXDIG (hexadecimal
+ digits), LF (line feed), and SP (space). The complete URI syntax is
+ collected in Appendix A.
+
+2. Characters
+
+ The URI syntax provides a method of encoding data, presumably for the
+ sake of identifying a resource, as a sequence of characters. The URI
+ characters are, in turn, frequently encoded as octets for transport
+ or presentation. This specification does not mandate any particular
+ character encoding for mapping between URI characters and the octets
+ used to store or transmit those characters. When a URI appears in a
+ protocol element, the character encoding is defined by that protocol;
+ without such a definition, a URI is assumed to be in the same
+ character encoding as the surrounding text.
+
+ The ABNF notation defines its terminal values to be non-negative
+ integers (codepoints) based on the US-ASCII coded character set
+ [ASCII]. Because a URI is a sequence of characters, we must invert
+ that relation in order to understand the URI syntax. Therefore, the
+
+
+
+
+
+Berners-Lee, et al. Standards Track [Page 11]
+
+RFC 3986 URI Generic Syntax January 2005
+
+
+ integer values used by the ABNF must be mapped back to their
+ corresponding characters via US-ASCII in order to complete the syntax
+ rules.
+
+ A URI is composed from a limited set of characters consisting of
+ digits, letters, and a few graphic symbols. A reserved subset of
+ those characters may be used to delimit syntax components within a
+ URI while the remaining characters, including both the unreserved set
+ and those reserved characters not acting as delimiters, define each
+ component's identifying data.
+
+2.1. Percent-Encoding
+
+ A percent-encoding mechanism is used to represent a data octet in a
+ component when that octet's corresponding character is outside the
+ allowed set or is being used as a delimiter of, or within, the
+ component. A percent-encoded octet is encoded as a character
+ triplet, consisting of the percent character "%" followed by the two
+ hexadecimal digits representing that octet's numeric value. For
+ example, "%20" is the percent-encoding for the binary octet
+ "00100000" (ABNF: %x20), which in US-ASCII corresponds to the space
+ character (SP). Section 2.4 describes when percent-encoding and
+ decoding is applied.
+
+ pct-encoded = "%" HEXDIG HEXDIG
+
+ The uppercase hexadecimal digits 'A' through 'F' are equivalent to
+ the lowercase digits 'a' through 'f', respectively. If two URIs
+ differ only in the case of hexadecimal digits used in percent-encoded
+ octets, they are equivalent. For consistency, URI producers and
+ normalizers should use uppercase hexadecimal digits for all percent-
+ encodings.
+
+2.2. Reserved Characters
+
+ URIs include components and subcomponents that are delimited by
+ characters in the "reserved" set. These characters are called
+ "reserved" because they may (or may not) be defined as delimiters by
+ the generic syntax, by each scheme-specific syntax, or by the
+ implementation-specific syntax of a URI's dereferencing algorithm.
+ If data for a URI component would conflict with a reserved
+ character's purpose as a delimiter, then the conflicting data must be
+ percent-encoded before the URI is formed.
+
+
+
+
+
+
+
+
+Berners-Lee, et al. Standards Track [Page 12]
+
+RFC 3986 URI Generic Syntax January 2005
+
+
+ reserved = gen-delims / sub-delims
+
+ gen-delims = ":" / "/" / "?" / "#" / "[" / "]" / "@"
+
+ sub-delims = "!" / "$" / "&" / "'" / "(" / ")"
+ / "*" / "+" / "," / ";" / "="
+
+ The purpose of reserved characters is to provide a set of delimiting
+ characters that are distinguishable from other data within a URI.
+ URIs that differ in the replacement of a reserved character with its
+ corresponding percent-encoded octet are not equivalent. Percent-
+ encoding a reserved character, or decoding a percent-encoded octet
+ that corresponds to a reserved character, will change how the URI is
+ interpreted by most applications. Thus, characters in the reserved
+ set are protected from normalization and are therefore safe to be
+ used by scheme-specific and producer-specific algorithms for
+ delimiting data subcomponents within a URI.
+
+ A subset of the reserved characters (gen-delims) is used as
+ delimiters of the generic URI components described in Section 3. A
+ component's ABNF syntax rule will not use the reserved or gen-delims
+ rule names directly; instead, each syntax rule lists the characters
+ allowed within that component (i.e., not delimiting it), and any of
+ those characters that are also in the reserved set are "reserved" for
+ use as subcomponent delimiters within the component. Only the most
+ common subcomponents are defined by this specification; other
+ subcomponents may be defined by a URI scheme's specification, or by
+ the implementation-specific syntax of a URI's dereferencing
+ algorithm, provided that such subcomponents are delimited by
+ characters in the reserved set allowed within that component.
+
+ URI producing applications should percent-encode data octets that
+ correspond to characters in the reserved set unless these characters
+ are specifically allowed by the URI scheme to represent data in that
+ component. If a reserved character is found in a URI component and
+ no delimiting role is known for that character, then it must be
+ interpreted as representing the data octet corresponding to that
+ character's encoding in US-ASCII.
+
+2.3. Unreserved Characters
+
+ Characters that are allowed in a URI but do not have a reserved
+ purpose are called unreserved. These include uppercase and lowercase
+ letters, decimal digits, hyphen, period, underscore, and tilde.
+
+ unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~"
+
+
+
+
+
+Berners-Lee, et al. Standards Track [Page 13]
+
+RFC 3986 URI Generic Syntax January 2005
+
+
+ URIs that differ in the replacement of an unreserved character with
+ its corresponding percent-encoded US-ASCII octet are equivalent: they
+ identify the same resource. However, URI comparison implementations
+ do not always perform normalization prior to comparison (see Section
+ 6). For consistency, percent-encoded octets in the ranges of ALPHA
+ (%41-%5A and %61-%7A), DIGIT (%30-%39), hyphen (%2D), period (%2E),
+ underscore (%5F), or tilde (%7E) should not be created by URI
+ producers and, when found in a URI, should be decoded to their
+ corresponding unreserved characters by URI normalizers.
+
+2.4. When to Encode or Decode
+
+ Under normal circumstances, the only time when octets within a URI
+ are percent-encoded is during the process of producing the URI from
+ its component parts. This is when an implementation determines which
+ of the reserved characters are to be used as subcomponent delimiters
+ and which can be safely used as data. Once produced, a URI is always
+ in its percent-encoded form.
+
+ When a URI is dereferenced, the components and subcomponents
+ significant to the scheme-specific dereferencing process (if any)
+ must be parsed and separated before the percent-encoded octets within
+ those components can be safely decoded, as otherwise the data may be
+ mistaken for component delimiters. The only exception is for
+ percent-encoded octets corresponding to characters in the unreserved
+ set, which can be decoded at any time. For example, the octet
+ corresponding to the tilde ("~") character is often encoded as "%7E"
+ by older URI processing implementations; the "%7E" can be replaced by
+ "~" without changing its interpretation.
+
+ Because the percent ("%") character serves as the indicator for
+ percent-encoded octets, it must be percent-encoded as "%25" for that
+ octet to be used as data within a URI. Implementations must not
+ percent-encode or decode the same string more than once, as decoding
+ an already decoded string might lead to misinterpreting a percent
+ data octet as the beginning of a percent-encoding, or vice versa in
+ the case of percent-encoding an already percent-encoded string.
+
+2.5. Identifying Data
+
+ URI characters provide identifying data for each of the URI
+ components, serving as an external interface for identification
+ between systems. Although the presence and nature of the URI
+ production interface is hidden from clients that use its URIs (and is
+ thus beyond the scope of the interoperability requirements defined by
+ this specification), it is a frequent source of confusion and errors
+ in the interpretation of URI character issues. Implementers have to
+ be aware that there are multiple character encodings involved in the
+
+
+
+Berners-Lee, et al. Standards Track [Page 14]
+
+RFC 3986 URI Generic Syntax January 2005
+
+
+ production and transmission of URIs: local name and data encoding,
+ public interface encoding, URI character encoding, data format
+ encoding, and protocol encoding.
+
+ Local names, such as file system names, are stored with a local
+ character encoding. URI producing applications (e.g., origin
+ servers) will typically use the local encoding as the basis for
+ producing meaningful names. The URI producer will transform the
+ local encoding to one that is suitable for a public interface and
+ then transform the public interface encoding into the restricted set
+ of URI characters (reserved, unreserved, and percent-encodings).
+ Those characters are, in turn, encoded as octets to be used as a
+ reference within a data format (e.g., a document charset), and such
+ data formats are often subsequently encoded for transmission over
+ Internet protocols.
+
+ For most systems, an unreserved character appearing within a URI
+ component is interpreted as representing the data octet corresponding
+ to that character's encoding in US-ASCII. Consumers of URIs assume
+ that the letter "X" corresponds to the octet "01011000", and even
+ when that assumption is incorrect, there is no harm in making it. A
+ system that internally provides identifiers in the form of a
+ different character encoding, such as EBCDIC, will generally perform
+ character translation of textual identifiers to UTF-8 [STD63] (or
+ some other superset of the US-ASCII character encoding) at an
+ internal interface, thereby providing more meaningful identifiers
+ than those resulting from simply percent-encoding the original
+ octets.
+
+ For example, consider an information service that provides data,
+ stored locally using an EBCDIC-based file system, to clients on the
+ Internet through an HTTP server. When an author creates a file with
+ the name "Laguna Beach" on that file system, the "http" URI
+ corresponding to that resource is expected to contain the meaningful
+ string "Laguna%20Beach". If, however, that server produces URIs by
+ using an overly simplistic raw octet mapping, then the result would
+ be a URI containing "%D3%81%87%A4%95%81@%C2%85%81%83%88". An
+ internal transcoding interface fixes this problem by transcoding the
+ local name to a superset of US-ASCII prior to producing the URI.
+ Naturally, proper interpretation of an incoming URI on such an
+ interface requires that percent-encoded octets be decoded (e.g.,
+ "%20" to SP) before the reverse transcoding is applied to obtain the
+ local name.
+
+ In some cases, the internal interface between a URI component and the
+ identifying data that it has been crafted to represent is much less
+ direct than a character encoding translation. For example, portions
+ of a URI might reflect a query on non-ASCII data, or numeric
+
+
+
+Berners-Lee, et al. Standards Track [Page 15]
+
+RFC 3986 URI Generic Syntax January 2005
+
+
+ coordinates on a map. Likewise, a URI scheme may define components
+ with additional encoding requirements that are applied prior to
+ forming the component and producing the URI.
+
+ When a new URI scheme defines a component that represents textual
+ data consisting of characters from the Universal Character Set [UCS],
+ the data should first be encoded as octets according to the UTF-8
+ character encoding [STD63]; then only those octets that do not
+ correspond to characters in the unreserved set should be percent-
+ encoded. For example, the character A would be represented as "A",
+ the character LATIN CAPITAL LETTER A WITH GRAVE would be represented
+ as "%C3%80", and the character KATAKANA LETTER A would be represented
+ as "%E3%82%A2".
+
+3. Syntax Components
+
+ The generic URI syntax consists of a hierarchical sequence of
+ components referred to as the scheme, authority, path, query, and
+ fragment.
+
+ URI = scheme ":" hier-part [ "?" query ] [ "#" fragment ]
+
+ hier-part = "//" authority path-abempty
+ / path-absolute
+ / path-rootless
+ / path-empty
+
+ The scheme and path components are required, though the path may be
+ empty (no characters). When authority is present, the path must
+ either be empty or begin with a slash ("/") character. When
+ authority is not present, the path cannot begin with two slash
+ characters ("//"). These restrictions result in five different ABNF
+ rules for a path (Section 3.3), only one of which will match any
+ given URI reference.
+
+ The following are two example URIs and their component parts:
+
+ foo://example.com:8042/over/there?name=ferret#nose
+ \_/ \______________/\_________/ \_________/ \__/
+ | | | | |
+ scheme authority path query fragment
+ | _____________________|__
+ / \ / \
+ urn:example:animal:ferret:nose
+
+
+
+
+
+
+
+Berners-Lee, et al. Standards Track [Page 16]
+
+RFC 3986 URI Generic Syntax January 2005
+
+
+3.1. Scheme
+
+ Each URI begins with a scheme name that refers to a specification for
+ assigning identifiers within that scheme. As such, the URI syntax is
+ a federated and extensible naming system wherein each scheme's
+ specification may further restrict the syntax and semantics of
+ identifiers using that scheme.
+
+ Scheme names consist of a sequence of characters beginning with a
+ letter and followed by any combination of letters, digits, plus
+ ("+"), period ("."), or hyphen ("-"). Although schemes are case-
+ insensitive, the canonical form is lowercase and documents that
+ specify schemes must do so with lowercase letters. An implementation
+ should accept uppercase letters as equivalent to lowercase in scheme
+ names (e.g., allow "HTTP" as well as "http") for the sake of
+ robustness but should only produce lowercase scheme names for
+ consistency.
+
+ scheme = ALPHA *( ALPHA / DIGIT / "+" / "-" / "." )
+
+ Individual schemes are not specified by this document. The process
+ for registration of new URI schemes is defined separately by [BCP35].
+ The scheme registry maintains the mapping between scheme names and
+ their specifications. Advice for designers of new URI schemes can be
+ found in [RFC2718]. URI scheme specifications must define their own
+ syntax so that all strings matching their scheme-specific syntax will
+ also match the <absolute-URI> grammar, as described in Section 4.3.
+
+ When presented with a URI that violates one or more scheme-specific
+ restrictions, the scheme-specific resolution process should flag the
+ reference as an error rather than ignore the unused parts; doing so
+ reduces the number of equivalent URIs and helps detect abuses of the
+ generic syntax, which might indicate that the URI has been
+ constructed to mislead the user (Section 7.6).
+
+3.2. Authority
+
+ Many URI schemes include a hierarchical element for a naming
+ authority so that governance of the name space defined by the
+ remainder of the URI is delegated to that authority (which may, in
+ turn, delegate it further). The generic syntax provides a common
+ means for distinguishing an authority based on a registered name or
+ server address, along with optional port and user information.
+
+ The authority component is preceded by a double slash ("//") and is
+ terminated by the next slash ("/"), question mark ("?"), or number
+ sign ("#") character, or by the end of the URI.
+
+
+
+
+Berners-Lee, et al. Standards Track [Page 17]
+
+RFC 3986 URI Generic Syntax January 2005
+
+
+ authority = [ userinfo "@" ] host [ ":" port ]
+
+ URI producers and normalizers should omit the ":" delimiter that
+ separates host from port if the port component is empty. Some
+ schemes do not allow the userinfo and/or port subcomponents.
+
+ If a URI contains an authority component, then the path component
+ must either be empty or begin with a slash ("/") character. Non-
+ validating parsers (those that merely separate a URI reference into
+ its major components) will often ignore the subcomponent structure of
+ authority, treating it as an opaque string from the double-slash to
+ the first terminating delimiter, until such time as the URI is
+ dereferenced.
+
+3.2.1. User Information
+
+ The userinfo subcomponent may consist of a user name and, optionally,
+ scheme-specific information about how to gain authorization to access
+ the resource. The user information, if present, is followed by a
+ commercial at-sign ("@") that delimits it from the host.
+
+ userinfo = *( unreserved / pct-encoded / sub-delims / ":" )
+
+ Use of the format "user:password" in the userinfo field is
+ deprecated. Applications should not render as clear text any data
+ after the first colon (":") character found within a userinfo
+ subcomponent unless the data after the colon is the empty string
+ (indicating no password). Applications may choose to ignore or
+ reject such data when it is received as part of a reference and
+ should reject the storage of such data in unencrypted form. The
+ passing of authentication information in clear text has proven to be
+ a security risk in almost every case where it has been used.
+
+ Applications that render a URI for the sake of user feedback, such as
+ in graphical hypertext browsing, should render userinfo in a way that
+ is distinguished from the rest of a URI, when feasible. Such
+ rendering will assist the user in cases where the userinfo has been
+ misleadingly crafted to look like a trusted domain name
+ (Section 7.6).
+
+3.2.2. Host
+
+ The host subcomponent of authority is identified by an IP literal
+ encapsulated within square brackets, an IPv4 address in dotted-
+ decimal form, or a registered name. The host subcomponent is case-
+ insensitive. The presence of a host subcomponent within a URI does
+ not imply that the scheme requires access to the given host on the
+ Internet. In many cases, the host syntax is used only for the sake
+
+
+
+Berners-Lee, et al. Standards Track [Page 18]
+
+RFC 3986 URI Generic Syntax January 2005
+
+
+ of reusing the existing registration process created and deployed for
+ DNS, thus obtaining a globally unique name without the cost of
+ deploying another registry. However, such use comes with its own
+ costs: domain name ownership may change over time for reasons not
+ anticipated by the URI producer. In other cases, the data within the
+ host component identifies a registered name that has nothing to do
+ with an Internet host. We use the name "host" for the ABNF rule
+ because that is its most common purpose, not its only purpose.
+
+ host = IP-literal / IPv4address / reg-name
+
+ The syntax rule for host is ambiguous because it does not completely
+ distinguish between an IPv4address and a reg-name. In order to
+ disambiguate the syntax, we apply the "first-match-wins" algorithm:
+ If host matches the rule for IPv4address, then it should be
+ considered an IPv4 address literal and not a reg-name. Although host
+ is case-insensitive, producers and normalizers should use lowercase
+ for registered names and hexadecimal addresses for the sake of
+ uniformity, while only using uppercase letters for percent-encodings.
+
+ A host identified by an Internet Protocol literal address, version 6
+ [RFC3513] or later, is distinguished by enclosing the IP literal
+ within square brackets ("[" and "]"). This is the only place where
+ square bracket characters are allowed in the URI syntax. In
+ anticipation of future, as-yet-undefined IP literal address formats,
+ an implementation may use an optional version flag to indicate such a
+ format explicitly rather than rely on heuristic determination.
+
+ IP-literal = "[" ( IPv6address / IPvFuture ) "]"
+
+ IPvFuture = "v" 1*HEXDIG "." 1*( unreserved / sub-delims / ":" )
+
+ The version flag does not indicate the IP version; rather, it
+ indicates future versions of the literal format. As such,
+ implementations must not provide the version flag for the existing
+ IPv4 and IPv6 literal address forms described below. If a URI
+ containing an IP-literal that starts with "v" (case-insensitive),
+ indicating that the version flag is present, is dereferenced by an
+ application that does not know the meaning of that version flag, then
+ the application should return an appropriate error for "address
+ mechanism not supported".
+
+ A host identified by an IPv6 literal address is represented inside
+ the square brackets without a preceding version flag. The ABNF
+ provided here is a translation of the text definition of an IPv6
+ literal address provided in [RFC3513]. This syntax does not support
+ IPv6 scoped addressing zone identifiers.
+
+
+
+
+Berners-Lee, et al. Standards Track [Page 19]
+
+RFC 3986 URI Generic Syntax January 2005
+
+
+ A 128-bit IPv6 address is divided into eight 16-bit pieces. Each
+ piece is represented numerically in case-insensitive hexadecimal,
+ using one to four hexadecimal digits (leading zeroes are permitted).
+ The eight encoded pieces are given most-significant first, separated
+ by colon characters. Optionally, the least-significant two pieces
+ may instead be represented in IPv4 address textual format. A
+ sequence of one or more consecutive zero-valued 16-bit pieces within
+ the address may be elided, omitting all their digits and leaving
+ exactly two consecutive colons in their place to mark the elision.
+
+ IPv6address = 6( h16 ":" ) ls32
+ / "::" 5( h16 ":" ) ls32
+ / [ h16 ] "::" 4( h16 ":" ) ls32
+ / [ *1( h16 ":" ) h16 ] "::" 3( h16 ":" ) ls32
+ / [ *2( h16 ":" ) h16 ] "::" 2( h16 ":" ) ls32
+ / [ *3( h16 ":" ) h16 ] "::" h16 ":" ls32
+ / [ *4( h16 ":" ) h16 ] "::" ls32
+ / [ *5( h16 ":" ) h16 ] "::" h16
+ / [ *6( h16 ":" ) h16 ] "::"
+
+ ls32 = ( h16 ":" h16 ) / IPv4address
+ ; least-significant 32 bits of address
+
+ h16 = 1*4HEXDIG
+ ; 16 bits of address represented in hexadecimal
+
+ A host identified by an IPv4 literal address is represented in
+ dotted-decimal notation (a sequence of four decimal numbers in the
+ range 0 to 255, separated by "."), as described in [RFC1123] by
+ reference to [RFC0952]. Note that other forms of dotted notation may
+ be interpreted on some platforms, as described in Section 7.4, but
+ only the dotted-decimal form of four octets is allowed by this
+ grammar.
+
+ IPv4address = dec-octet "." dec-octet "." dec-octet "." dec-octet
+
+ dec-octet = DIGIT ; 0-9
+ / %x31-39 DIGIT ; 10-99
+ / "1" 2DIGIT ; 100-199
+ / "2" %x30-34 DIGIT ; 200-249
+ / "25" %x30-35 ; 250-255
+
+ A host identified by a registered name is a sequence of characters
+ usually intended for lookup within a locally defined host or service
+ name registry, though the URI's scheme-specific semantics may require
+ that a specific registry (or fixed name table) be used instead. The
+ most common name registry mechanism is the Domain Name System (DNS).
+ A registered name intended for lookup in the DNS uses the syntax
+
+
+
+Berners-Lee, et al. Standards Track [Page 20]
+
+RFC 3986 URI Generic Syntax January 2005
+
+
+ defined in Section 3.5 of [RFC1034] and Section 2.1 of [RFC1123].
+ Such a name consists of a sequence of domain labels separated by ".",
+ each domain label starting and ending with an alphanumeric character
+ and possibly also containing "-" characters. The rightmost domain
+ label of a fully qualified domain name in DNS may be followed by a
+ single "." and should be if it is necessary to distinguish between
+ the complete domain name and some local domain.
+
+ reg-name = *( unreserved / pct-encoded / sub-delims )
+
+ If the URI scheme defines a default for host, then that default
+ applies when the host subcomponent is undefined or when the
+ registered name is empty (zero length). For example, the "file" URI
+ scheme is defined so that no authority, an empty host, and
+ "localhost" all mean the end-user's machine, whereas the "http"
+ scheme considers a missing authority or empty host invalid.
+
+ This specification does not mandate a particular registered name
+ lookup technology and therefore does not restrict the syntax of reg-
+ name beyond what is necessary for interoperability. Instead, it
+ delegates the issue of registered name syntax conformance to the
+ operating system of each application performing URI resolution, and
+ that operating system decides what it will allow for the purpose of
+ host identification. A URI resolution implementation might use DNS,
+ host tables, yellow pages, NetInfo, WINS, or any other system for
+ lookup of registered names. However, a globally scoped naming
+ system, such as DNS fully qualified domain names, is necessary for
+ URIs intended to have global scope. URI producers should use names
+ that conform to the DNS syntax, even when use of DNS is not
+ immediately apparent, and should limit these names to no more than
+ 255 characters in length.
+
+ The reg-name syntax allows percent-encoded octets in order to
+ represent non-ASCII registered names in a uniform way that is
+ independent of the underlying name resolution technology. Non-ASCII
+ characters must first be encoded according to UTF-8 [STD63], and then
+ each octet of the corresponding UTF-8 sequence must be percent-
+ encoded to be represented as URI characters. URI producing
+ applications must not use percent-encoding in host unless it is used
+ to represent a UTF-8 character sequence. When a non-ASCII registered
+ name represents an internationalized domain name intended for
+ resolution via the DNS, the name must be transformed to the IDNA
+ encoding [RFC3490] prior to name lookup. URI producers should
+ provide these registered names in the IDNA encoding, rather than a
+ percent-encoding, if they wish to maximize interoperability with
+ legacy URI resolvers.
+
+
+
+
+
+Berners-Lee, et al. Standards Track [Page 21]
+
+RFC 3986 URI Generic Syntax January 2005
+
+
+3.2.3. Port
+
+ The port subcomponent of authority is designated by an optional port
+ number in decimal following the host and delimited from it by a
+ single colon (":") character.
+
+ port = *DIGIT
+
+ A scheme may define a default port. For example, the "http" scheme
+ defines a default port of "80", corresponding to its reserved TCP
+ port number. The type of port designated by the port number (e.g.,
+ TCP, UDP, SCTP) is defined by the URI scheme. URI producers and
+ normalizers should omit the port component and its ":" delimiter if
+ port is empty or if its value would be the same as that of the
+ scheme's default.
+
+3.3. Path
+
+ The path component contains data, usually organized in hierarchical
+ form, that, along with data in the non-hierarchical query component
+ (Section 3.4), serves to identify a resource within the scope of the
+ URI's scheme and naming authority (if any). The path is terminated
+ by the first question mark ("?") or number sign ("#") character, or
+ by the end of the URI.
+
+ If a URI contains an authority component, then the path component
+ must either be empty or begin with a slash ("/") character. If a URI
+ does not contain an authority component, then the path cannot begin
+ with two slash characters ("//"). In addition, a URI reference
+ (Section 4.1) may be a relative-path reference, in which case the
+ first path segment cannot contain a colon (":") character. The ABNF
+ requires five separate rules to disambiguate these cases, only one of
+ which will match the path substring within a given URI reference. We
+ use the generic term "path component" to describe the URI substring
+ matched by the parser to one of these rules.
+
+ path = path-abempty ; begins with "/" or is empty
+ / path-absolute ; begins with "/" but not "//"
+ / path-noscheme ; begins with a non-colon segment
+ / path-rootless ; begins with a segment
+ / path-empty ; zero characters
+
+ path-abempty = *( "/" segment )
+ path-absolute = "/" [ segment-nz *( "/" segment ) ]
+ path-noscheme = segment-nz-nc *( "/" segment )
+ path-rootless = segment-nz *( "/" segment )
+ path-empty = 0<pchar>
+
+
+
+
+Berners-Lee, et al. Standards Track [Page 22]
+
+RFC 3986 URI Generic Syntax January 2005
+
+
+ segment = *pchar
+ segment-nz = 1*pchar
+ segment-nz-nc = 1*( unreserved / pct-encoded / sub-delims / "@" )
+ ; non-zero-length segment without any colon ":"
+
+ pchar = unreserved / pct-encoded / sub-delims / ":" / "@"
+
+ A path consists of a sequence of path segments separated by a slash
+ ("/") character. A path is always defined for a URI, though the
+ defined path may be empty (zero length). Use of the slash character
+ to indicate hierarchy is only required when a URI will be used as the
+ context for relative references. For example, the URI
+ <mailto:[email protected]> has a path of "[email protected]", whereas
+ the URI <foo://info.example.com?fred> has an empty path.
+
+ The path segments "." and "..", also known as dot-segments, are
+ defined for relative reference within the path name hierarchy. They
+ are intended for use at the beginning of a relative-path reference
+ (Section 4.2) to indicate relative position within the hierarchical
+ tree of names. This is similar to their role within some operating
+ systems' file directory structures to indicate the current directory
+ and parent directory, respectively. However, unlike in a file
+ system, these dot-segments are only interpreted within the URI path
+ hierarchy and are removed as part of the resolution process (Section
+ 5.2).
+
+ Aside from dot-segments in hierarchical paths, a path segment is
+ considered opaque by the generic syntax. URI producing applications
+ often use the reserved characters allowed in a segment to delimit
+ scheme-specific or dereference-handler-specific subcomponents. For
+ example, the semicolon (";") and equals ("=") reserved characters are
+ often used to delimit parameters and parameter values applicable to
+ that segment. The comma (",") reserved character is often used for
+ similar purposes. For example, one URI producer might use a segment
+ such as "name;v=1.1" to indicate a reference to version 1.1 of
+ "name", whereas another might use a segment such as "name,1.1" to
+ indicate the same. Parameter types may be defined by scheme-specific
+ semantics, but in most cases the syntax of a parameter is specific to
+ the implementation of the URI's dereferencing algorithm.
+
+3.4. Query
+
+ The query component contains non-hierarchical data that, along with
+ data in the path component (Section 3.3), serves to identify a
+ resource within the scope of the URI's scheme and naming authority
+ (if any). The query component is indicated by the first question
+ mark ("?") character and terminated by a number sign ("#") character
+ or by the end of the URI.
+
+
+
+Berners-Lee, et al. Standards Track [Page 23]
+
+RFC 3986 URI Generic Syntax January 2005
+
+
+ query = *( pchar / "/" / "?" )
+
+ The characters slash ("/") and question mark ("?") may represent data
+ within the query component. Beware that some older, erroneous
+ implementations may not handle such data correctly when it is used as
+ the base URI for relative references (Section 5.1), apparently
+ because they fail to distinguish query data from path data when
+ looking for hierarchical separators. However, as query components
+ are often used to carry identifying information in the form of
+ "key=value" pairs and one frequently used value is a reference to
+ another URI, it is sometimes better for usability to avoid percent-
+ encoding those characters.
+
+3.5. Fragment
+
+ The fragment identifier component of a URI allows indirect
+ identification of a secondary resource by reference to a primary
+ resource and additional identifying information. The identified
+ secondary resource may be some portion or subset of the primary
+ resource, some view on representations of the primary resource, or
+ some other resource defined or described by those representations. A
+ fragment identifier component is indicated by the presence of a
+ number sign ("#") character and terminated by the end of the URI.
+
+ fragment = *( pchar / "/" / "?" )
+
+ The semantics of a fragment identifier are defined by the set of
+ representations that might result from a retrieval action on the
+ primary resource. The fragment's format and resolution is therefore
+ dependent on the media type [RFC2046] of a potentially retrieved
+ representation, even though such a retrieval is only performed if the
+ URI is dereferenced. If no such representation exists, then the
+ semantics of the fragment are considered unknown and are effectively
+ unconstrained. Fragment identifier semantics are independent of the
+ URI scheme and thus cannot be redefined by scheme specifications.
+
+ Individual media types may define their own restrictions on or
+ structures within the fragment identifier syntax for specifying
+ different types of subsets, views, or external references that are
+ identifiable as secondary resources by that media type. If the
+ primary resource has multiple representations, as is often the case
+ for resources whose representation is selected based on attributes of
+ the retrieval request (a.k.a., content negotiation), then whatever is
+ identified by the fragment should be consistent across all of those
+ representations. Each representation should either define the
+ fragment so that it corresponds to the same secondary resource,
+ regardless of how it is represented, or should leave the fragment
+ undefined (i.e., not found).
+
+
+
+Berners-Lee, et al. Standards Track [Page 24]
+
+RFC 3986 URI Generic Syntax January 2005
+
+
+ As with any URI, use of a fragment identifier component does not
+ imply that a retrieval action will take place. A URI with a fragment
+ identifier may be used to refer to the secondary resource without any
+ implication that the primary resource is accessible or will ever be
+ accessed.
+
+ Fragment identifiers have a special role in information retrieval
+ systems as the primary form of client-side indirect referencing,
+ allowing an author to specifically identify aspects of an existing
+ resource that are only indirectly provided by the resource owner. As
+ such, the fragment identifier is not used in the scheme-specific
+ processing of a URI; instead, the fragment identifier is separated
+ from the rest of the URI prior to a dereference, and thus the
+ identifying information within the fragment itself is dereferenced
+ solely by the user agent, regardless of the URI scheme. Although
+ this separate handling is often perceived to be a loss of
+ information, particularly for accurate redirection of references as
+ resources move over time, it also serves to prevent information
+ providers from denying reference authors the right to refer to
+ information within a resource selectively. Indirect referencing also
+ provides additional flexibility and extensibility to systems that use
+ URIs, as new media types are easier to define and deploy than new
+ schemes of identification.
+
+ The characters slash ("/") and question mark ("?") are allowed to
+ represent data within the fragment identifier. Beware that some
+ older, erroneous implementations may not handle this data correctly
+ when it is used as the base URI for relative references (Section
+ 5.1).
+
+4. Usage
+
+ When applications make reference to a URI, they do not always use the
+ full form of reference defined by the "URI" syntax rule. To save
+ space and take advantage of hierarchical locality, many Internet
+ protocol elements and media type formats allow an abbreviation of a
+ URI, whereas others restrict the syntax to a particular form of URI.
+ We define the most common forms of reference syntax in this
+ specification because they impact and depend upon the design of the
+ generic syntax, requiring a uniform parsing algorithm in order to be
+ interpreted consistently.
+
+4.1. URI Reference
+
+ URI-reference is used to denote the most common usage of a resource
+ identifier.
+
+ URI-reference = URI / relative-ref
+
+
+
+Berners-Lee, et al. Standards Track [Page 25]
+
+RFC 3986 URI Generic Syntax January 2005
+
+
+ A URI-reference is either a URI or a relative reference. If the
+ URI-reference's prefix does not match the syntax of a scheme followed
+ by its colon separator, then the URI-reference is a relative
+ reference.
+
+ A URI-reference is typically parsed first into the five URI
+ components, in order to determine what components are present and
+ whether the reference is relative. Then, each component is parsed
+ for its subparts and their validation. The ABNF of URI-reference,
+ along with the "first-match-wins" disambiguation rule, is sufficient
+ to define a validating parser for the generic syntax. Readers
+ familiar with regular expressions should see Appendix B for an
+ example of a non-validating URI-reference parser that will take any
+ given string and extract the URI components.
+
+4.2. Relative Reference
+
+ A relative reference takes advantage of the hierarchical syntax
+ (Section 1.2.3) to express a URI reference relative to the name space
+ of another hierarchical URI.
+
+ relative-ref = relative-part [ "?" query ] [ "#" fragment ]
+
+ relative-part = "//" authority path-abempty
+ / path-absolute
+ / path-noscheme
+ / path-empty
+
+ The URI referred to by a relative reference, also known as the target
+ URI, is obtained by applying the reference resolution algorithm of
+ Section 5.
+
+ A relative reference that begins with two slash characters is termed
+ a network-path reference; such references are rarely used. A
+ relative reference that begins with a single slash character is
+ termed an absolute-path reference. A relative reference that does
+ not begin with a slash character is termed a relative-path reference.
+
+ A path segment that contains a colon character (e.g., "this:that")
+ cannot be used as the first segment of a relative-path reference, as
+ it would be mistaken for a scheme name. Such a segment must be
+ preceded by a dot-segment (e.g., "./this:that") to make a relative-
+ path reference.
+
+
+
+
+
+
+
+
+Berners-Lee, et al. Standards Track [Page 26]
+
+RFC 3986 URI Generic Syntax January 2005
+
+
+4.3. Absolute URI
+
+ Some protocol elements allow only the absolute form of a URI without
+ a fragment identifier. For example, defining a base URI for later
+ use by relative references calls for an absolute-URI syntax rule that
+ does not allow a fragment.
+
+ absolute-URI = scheme ":" hier-part [ "?" query ]
+
+ URI scheme specifications must define their own syntax so that all
+ strings matching their scheme-specific syntax will also match the
+ <absolute-URI> grammar. Scheme specifications will not define
+ fragment identifier syntax or usage, regardless of its applicability
+ to resources identifiable via that scheme, as fragment identification
+ is orthogonal to scheme definition. However, scheme specifications
+ are encouraged to include a wide range of examples, including
+ examples that show use of the scheme's URIs with fragment identifiers
+ when such usage is appropriate.
+
+4.4. Same-Document Reference
+
+ When a URI reference refers to a URI that is, aside from its fragment
+ component (if any), identical to the base URI (Section 5.1), that
+ reference is called a "same-document" reference. The most frequent
+ examples of same-document references are relative references that are
+ empty or include only the number sign ("#") separator followed by a
+ fragment identifier.
+
+ When a same-document reference is dereferenced for a retrieval
+ action, the target of that reference is defined to be within the same
+ entity (representation, document, or message) as the reference;
+ therefore, a dereference should not result in a new retrieval action.
+
+ Normalization of the base and target URIs prior to their comparison,
+ as described in Sections 6.2.2 and 6.2.3, is allowed but rarely
+ performed in practice. Normalization may increase the set of same-
+ document references, which may be of benefit to some caching
+ applications. As such, reference authors should not assume that a
+ slightly different, though equivalent, reference URI will (or will
+ not) be interpreted as a same-document reference by any given
+ application.
+
+4.5. Suffix Reference
+
+ The URI syntax is designed for unambiguous reference to resources and
+ extensibility via the URI scheme. However, as URI identification and
+ usage have become commonplace, traditional media (television, radio,
+ newspapers, billboards, etc.) have increasingly used a suffix of the
+
+
+
+Berners-Lee, et al. Standards Track [Page 27]
+
+RFC 3986 URI Generic Syntax January 2005
+
+
+ URI as a reference, consisting of only the authority and path
+ portions of the URI, such as
+
+ www.w3.org/Addressing/
+
+ or simply a DNS registered name on its own. Such references are
+ primarily intended for human interpretation rather than for machines,
+ with the assumption that context-based heuristics are sufficient to
+ complete the URI (e.g., most registered names beginning with "www"
+ are likely to have a URI prefix of "http://"). Although there is no
+ standard set of heuristics for disambiguating a URI suffix, many
+ client implementations allow them to be entered by the user and
+ heuristically resolved.
+
+ Although this practice of using suffix references is common, it
+ should be avoided whenever possible and should never be used in
+ situations where long-term references are expected. The heuristics
+ noted above will change over time, particularly when a new URI scheme
+ becomes popular, and are often incorrect when used out of context.
+ Furthermore, they can lead to security issues along the lines of
+ those described in [RFC1535].
+
+ As a URI suffix has the same syntax as a relative-path reference, a
+ suffix reference cannot be used in contexts where a relative
+ reference is expected. As a result, suffix references are limited to
+ places where there is no defined base URI, such as dialog boxes and
+ off-line advertisements.
+
+5. Reference Resolution
+
+ This section defines the process of resolving a URI reference within
+ a context that allows relative references so that the result is a
+ string matching the <URI> syntax rule of Section 3.
+
+5.1. Establishing a Base URI
+
+ The term "relative" implies that a "base URI" exists against which
+ the relative reference is applied. Aside from fragment-only
+ references (Section 4.4), relative references are only usable when a
+ base URI is known. A base URI must be established by the parser
+ prior to parsing URI references that might be relative. A base URI
+ must conform to the <absolute-URI> syntax rule (Section 4.3). If the
+ base URI is obtained from a URI reference, then that reference must
+ be converted to absolute form and stripped of any fragment component
+ prior to its use as a base URI.
+
+
+
+
+
+
+Berners-Lee, et al. Standards Track [Page 28]
+
+RFC 3986 URI Generic Syntax January 2005
+
+
+ The base URI of a reference can be established in one of four ways,
+ discussed below in order of precedence. The order of precedence can
+ be thought of in terms of layers, where the innermost defined base
+ URI has the highest precedence. This can be visualized graphically
+ as follows:
+
+ .----------------------------------------------------------.
+ | .----------------------------------------------------. |
+ | | .----------------------------------------------. | |
+ | | | .----------------------------------------. | | |
+ | | | | .----------------------------------. | | | |
+ | | | | | <relative-reference> | | | | |
+ | | | | `----------------------------------' | | | |
+ | | | | (5.1.1) Base URI embedded in content | | | |
+ | | | `----------------------------------------' | | |
+ | | | (5.1.2) Base URI of the encapsulating entity | | |
+ | | | (message, representation, or none) | | |
+ | | `----------------------------------------------' | |
+ | | (5.1.3) URI used to retrieve the entity | |
+ | `----------------------------------------------------' |
+ | (5.1.4) Default Base URI (application-dependent) |
+ `----------------------------------------------------------'
+
+5.1.1. Base URI Embedded in Content
+
+ Within certain media types, a base URI for relative references can be
+ embedded within the content itself so that it can be readily obtained
+ by a parser. This can be useful for descriptive documents, such as
+ tables of contents, which may be transmitted to others through
+ protocols other than their usual retrieval context (e.g., email or
+ USENET news).
+
+ It is beyond the scope of this specification to specify how, for each
+ media type, a base URI can be embedded. The appropriate syntax, when
+ available, is described by the data format specification associated
+ with each media type.
+
+5.1.2. Base URI from the Encapsulating Entity
+
+ If no base URI is embedded, the base URI is defined by the
+ representation's retrieval context. For a document that is enclosed
+ within another entity, such as a message or archive, the retrieval
+ context is that entity. Thus, the default base URI of a
+ representation is the base URI of the entity in which the
+ representation is encapsulated.
+
+
+
+
+
+
+Berners-Lee, et al. Standards Track [Page 29]
+
+RFC 3986 URI Generic Syntax January 2005
+
+
+ A mechanism for embedding a base URI within MIME container types
+ (e.g., the message and multipart types) is defined by MHTML
+ [RFC2557]. Protocols that do not use the MIME message header syntax,
+ but that do allow some form of tagged metadata to be included within
+ messages, may define their own syntax for defining a base URI as part
+ of a message.
+
+5.1.3. Base URI from the Retrieval URI
+
+ If no base URI is embedded and the representation is not encapsulated
+ within some other entity, then, if a URI was used to retrieve the
+ representation, that URI shall be considered the base URI. Note that
+ if the retrieval was the result of a redirected request, the last URI
+ used (i.e., the URI that resulted in the actual retrieval of the
+ representation) is the base URI.
+
+5.1.4. Default Base URI
+
+ If none of the conditions described above apply, then the base URI is
+ defined by the context of the application. As this definition is
+ necessarily application-dependent, failing to define a base URI by
+ using one of the other methods may result in the same content being
+ interpreted differently by different types of applications.
+
+ A sender of a representation containing relative references is
+ responsible for ensuring that a base URI for those references can be
+ established. Aside from fragment-only references, relative
+ references can only be used reliably in situations where the base URI
+ is well defined.
+
+5.2. Relative Resolution
+
+ This section describes an algorithm for converting a URI reference
+ that might be relative to a given base URI into the parsed components
+ of the reference's target. The components can then be recomposed, as
+ described in Section 5.3, to form the target URI. This algorithm
+ provides definitive results that can be used to test the output of
+ other implementations. Applications may implement relative reference
+ resolution by using some other algorithm, provided that the results
+ match what would be given by this one.
+
+
+
+
+
+
+
+
+
+
+
+Berners-Lee, et al. Standards Track [Page 30]
+
+RFC 3986 URI Generic Syntax January 2005
+
+
+5.2.1. Pre-parse the Base URI
+
+ The base URI (Base) is established according to the procedure of
+ Section 5.1 and parsed into the five main components described in
+ Section 3. Note that only the scheme component is required to be
+ present in a base URI; the other components may be empty or
+ undefined. A component is undefined if its associated delimiter does
+ not appear in the URI reference; the path component is never
+ undefined, though it may be empty.
+
+ Normalization of the base URI, as described in Sections 6.2.2 and
+ 6.2.3, is optional. A URI reference must be transformed to its
+ target URI before it can be normalized.
+
+5.2.2. Transform References
+
+ For each URI reference (R), the following pseudocode describes an
+ algorithm for transforming R into its target URI (T):
+
+ -- The URI reference is parsed into the five URI components
+ --
+ (R.scheme, R.authority, R.path, R.query, R.fragment) = parse(R);
+
+ -- A non-strict parser may ignore a scheme in the reference
+ -- if it is identical to the base URI's scheme.
+ --
+ if ((not strict) and (R.scheme == Base.scheme)) then
+ undefine(R.scheme);
+ endif;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Berners-Lee, et al. Standards Track [Page 31]
+
+RFC 3986 URI Generic Syntax January 2005
+
+
+ if defined(R.scheme) then
+ T.scheme = R.scheme;
+ T.authority = R.authority;
+ T.path = remove_dot_segments(R.path);
+ T.query = R.query;
+ else
+ if defined(R.authority) then
+ T.authority = R.authority;
+ T.path = remove_dot_segments(R.path);
+ T.query = R.query;
+ else
+ if (R.path == "") then
+ T.path = Base.path;
+ if defined(R.query) then
+ T.query = R.query;
+ else
+ T.query = Base.query;
+ endif;
+ else
+ if (R.path starts-with "/") then
+ T.path = remove_dot_segments(R.path);
+ else
+ T.path = merge(Base.path, R.path);
+ T.path = remove_dot_segments(T.path);
+ endif;
+ T.query = R.query;
+ endif;
+ T.authority = Base.authority;
+ endif;
+ T.scheme = Base.scheme;
+ endif;
+
+ T.fragment = R.fragment;
+
+5.2.3. Merge Paths
+
+ The pseudocode above refers to a "merge" routine for merging a
+ relative-path reference with the path of the base URI. This is
+ accomplished as follows:
+
+ o If the base URI has a defined authority component and an empty
+ path, then return a string consisting of "/" concatenated with the
+ reference's path; otherwise,
+
+
+
+
+
+
+
+
+Berners-Lee, et al. Standards Track [Page 32]
+
+RFC 3986 URI Generic Syntax January 2005
+
+
+ o return a string consisting of the reference's path component
+ appended to all but the last segment of the base URI's path (i.e.,
+ excluding any characters after the right-most "/" in the base URI
+ path, or excluding the entire base URI path if it does not contain
+ any "/" characters).
+
+5.2.4. Remove Dot Segments
+
+ The pseudocode also refers to a "remove_dot_segments" routine for
+ interpreting and removing the special "." and ".." complete path
+ segments from a referenced path. This is done after the path is
+ extracted from a reference, whether or not the path was relative, in
+ order to remove any invalid or extraneous dot-segments prior to
+ forming the target URI. Although there are many ways to accomplish
+ this removal process, we describe a simple method using two string
+ buffers.
+
+ 1. The input buffer is initialized with the now-appended path
+ components and the output buffer is initialized to the empty
+ string.
+
+ 2. While the input buffer is not empty, loop as follows:
+
+ A. If the input buffer begins with a prefix of "../" or "./",
+ then remove that prefix from the input buffer; otherwise,
+
+ B. if the input buffer begins with a prefix of "/./" or "/.",
+ where "." is a complete path segment, then replace that
+ prefix with "/" in the input buffer; otherwise,
+
+ C. if the input buffer begins with a prefix of "/../" or "/..",
+ where ".." is a complete path segment, then replace that
+ prefix with "/" in the input buffer and remove the last
+ segment and its preceding "/" (if any) from the output
+ buffer; otherwise,
+
+ D. if the input buffer consists only of "." or "..", then remove
+ that from the input buffer; otherwise,
+
+ E. move the first path segment in the input buffer to the end of
+ the output buffer, including the initial "/" character (if
+ any) and any subsequent characters up to, but not including,
+ the next "/" character or the end of the input buffer.
+
+ 3. Finally, the output buffer is returned as the result of
+ remove_dot_segments.
+
+
+
+
+
+Berners-Lee, et al. Standards Track [Page 33]
+
+RFC 3986 URI Generic Syntax January 2005
+
+
+ Note that dot-segments are intended for use in URI references to
+ express an identifier relative to the hierarchy of names in the base
+ URI. The remove_dot_segments algorithm respects that hierarchy by
+ removing extra dot-segments rather than treat them as an error or
+ leaving them to be misinterpreted by dereference implementations.
+
+ The following illustrates how the above steps are applied for two
+ examples of merged paths, showing the state of the two buffers after
+ each step.
+
+ STEP OUTPUT BUFFER INPUT BUFFER
+
+ 1 : /a/b/c/./../../g
+ 2E: /a /b/c/./../../g
+ 2E: /a/b /c/./../../g
+ 2E: /a/b/c /./../../g
+ 2B: /a/b/c /../../g
+ 2C: /a/b /../g
+ 2C: /a /g
+ 2E: /a/g
+
+ STEP OUTPUT BUFFER INPUT BUFFER
+
+ 1 : mid/content=5/../6
+ 2E: mid /content=5/../6
+ 2E: mid/content=5 /../6
+ 2C: mid /6
+ 2E: mid/6
+
+ Some applications may find it more efficient to implement the
+ remove_dot_segments algorithm by using two segment stacks rather than
+ strings.
+
+ Note: Beware that some older, erroneous implementations will fail
+ to separate a reference's query component from its path component
+ prior to merging the base and reference paths, resulting in an
+ interoperability failure if the query component contains the
+ strings "/../" or "/./".
+
+
+
+
+
+
+
+
+
+
+
+
+
+Berners-Lee, et al. Standards Track [Page 34]
+
+RFC 3986 URI Generic Syntax January 2005
+
+
+5.3. Component Recomposition
+
+ Parsed URI components can be recomposed to obtain the corresponding
+ URI reference string. Using pseudocode, this would be:
+
+ result = ""
+
+ if defined(scheme) then
+ append scheme to result;
+ append ":" to result;
+ endif;
+
+ if defined(authority) then
+ append "//" to result;
+ append authority to result;
+ endif;
+
+ append path to result;
+
+ if defined(query) then
+ append "?" to result;
+ append query to result;
+ endif;
+
+ if defined(fragment) then
+ append "#" to result;
+ append fragment to result;
+ endif;
+
+ return result;
+
+ Note that we are careful to preserve the distinction between a
+ component that is undefined, meaning that its separator was not
+ present in the reference, and a component that is empty, meaning that
+ the separator was present and was immediately followed by the next
+ component separator or the end of the reference.
+
+5.4. Reference Resolution Examples
+
+ Within a representation with a well defined base URI of
+
+ http://a/b/c/d;p?q
+
+ a relative reference is transformed to its target URI as follows.
+
+
+
+
+
+
+
+Berners-Lee, et al. Standards Track [Page 35]
+
+RFC 3986 URI Generic Syntax January 2005
+
+
+5.4.1. Normal Examples
+
+ "g:h" = "g:h"
+ "g" = "http://a/b/c/g"
+ "./g" = "http://a/b/c/g"
+ "g/" = "http://a/b/c/g/"
+ "/g" = "http://a/g"
+ "//g" = "http://g"
+ "?y" = "http://a/b/c/d;p?y"
+ "g?y" = "http://a/b/c/g?y"
+ "#s" = "http://a/b/c/d;p?q#s"
+ "g#s" = "http://a/b/c/g#s"
+ "g?y#s" = "http://a/b/c/g?y#s"
+ ";x" = "http://a/b/c/;x"
+ "g;x" = "http://a/b/c/g;x"
+ "g;x?y#s" = "http://a/b/c/g;x?y#s"
+ "" = "http://a/b/c/d;p?q"
+ "." = "http://a/b/c/"
+ "./" = "http://a/b/c/"
+ ".." = "http://a/b/"
+ "../" = "http://a/b/"
+ "../g" = "http://a/b/g"
+ "../.." = "http://a/"
+ "../../" = "http://a/"
+ "../../g" = "http://a/g"
+
+5.4.2. Abnormal Examples
+
+ Although the following abnormal examples are unlikely to occur in
+ normal practice, all URI parsers should be capable of resolving them
+ consistently. Each example uses the same base as that above.
+
+ Parsers must be careful in handling cases where there are more ".."
+ segments in a relative-path reference than there are hierarchical
+ levels in the base URI's path. Note that the ".." syntax cannot be
+ used to change the authority component of a URI.
+
+ "../../../g" = "http://a/g"
+ "../../../../g" = "http://a/g"
+
+
+
+
+
+
+
+
+
+
+
+
+Berners-Lee, et al. Standards Track [Page 36]
+
+RFC 3986 URI Generic Syntax January 2005
+
+
+ Similarly, parsers must remove the dot-segments "." and ".." when
+ they are complete components of a path, but not when they are only
+ part of a segment.
+
+ "/./g" = "http://a/g"
+ "/../g" = "http://a/g"
+ "g." = "http://a/b/c/g."
+ ".g" = "http://a/b/c/.g"
+ "g.." = "http://a/b/c/g.."
+ "..g" = "http://a/b/c/..g"
+
+ Less likely are cases where the relative reference uses unnecessary
+ or nonsensical forms of the "." and ".." complete path segments.
+
+ "./../g" = "http://a/b/g"
+ "./g/." = "http://a/b/c/g/"
+ "g/./h" = "http://a/b/c/g/h"
+ "g/../h" = "http://a/b/c/h"
+ "g;x=1/./y" = "http://a/b/c/g;x=1/y"
+ "g;x=1/../y" = "http://a/b/c/y"
+
+ Some applications fail to separate the reference's query and/or
+ fragment components from the path component before merging it with
+ the base path and removing dot-segments. This error is rarely
+ noticed, as typical usage of a fragment never includes the hierarchy
+ ("/") character and the query component is not normally used within
+ relative references.
+
+ "g?y/./x" = "http://a/b/c/g?y/./x"
+ "g?y/../x" = "http://a/b/c/g?y/../x"
+ "g#s/./x" = "http://a/b/c/g#s/./x"
+ "g#s/../x" = "http://a/b/c/g#s/../x"
+
+ Some parsers allow the scheme name to be present in a relative
+ reference if it is the same as the base URI scheme. This is
+ considered to be a loophole in prior specifications of partial URI
+ [RFC1630]. Its use should be avoided but is allowed for backward
+ compatibility.
+
+ "http:g" = "http:g" ; for strict parsers
+ / "http://a/b/c/g" ; for backward compatibility
+
+
+
+
+
+
+
+
+
+
+Berners-Lee, et al. Standards Track [Page 37]
+
+RFC 3986 URI Generic Syntax January 2005
+
+
+6. Normalization and Comparison
+
+ One of the most common operations on URIs is simple comparison:
+ determining whether two URIs are equivalent without using the URIs to
+ access their respective resource(s). A comparison is performed every
+ time a response cache is accessed, a browser checks its history to
+ color a link, or an XML parser processes tags within a namespace.
+ Extensive normalization prior to comparison of URIs is often used by
+ spiders and indexing engines to prune a search space or to reduce
+ duplication of request actions and response storage.
+
+ URI comparison is performed for some particular purpose. Protocols
+ or implementations that compare URIs for different purposes will
+ often be subject to differing design trade-offs in regards to how
+ much effort should be spent in reducing aliased identifiers. This
+ section describes various methods that may be used to compare URIs,
+ the trade-offs between them, and the types of applications that might
+ use them.
+
+6.1. Equivalence
+
+ Because URIs exist to identify resources, presumably they should be
+ considered equivalent when they identify the same resource. However,
+ this definition of equivalence is not of much practical use, as there
+ is no way for an implementation to compare two resources unless it
+ has full knowledge or control of them. For this reason,
+ determination of equivalence or difference of URIs is based on string
+ comparison, perhaps augmented by reference to additional rules
+ provided by URI scheme definitions. We use the terms "different" and
+ "equivalent" to describe the possible outcomes of such comparisons,
+ but there are many application-dependent versions of equivalence.
+
+ Even though it is possible to determine that two URIs are equivalent,
+ URI comparison is not sufficient to determine whether two URIs
+ identify different resources. For example, an owner of two different
+ domain names could decide to serve the same resource from both,
+ resulting in two different URIs. Therefore, comparison methods are
+ designed to minimize false negatives while strictly avoiding false
+ positives.
+
+ In testing for equivalence, applications should not directly compare
+ relative references; the references should be converted to their
+ respective target URIs before comparison. When URIs are compared to
+ select (or avoid) a network action, such as retrieval of a
+ representation, fragment components (if any) should be excluded from
+ the comparison.
+
+
+
+
+
+Berners-Lee, et al. Standards Track [Page 38]
+
+RFC 3986 URI Generic Syntax January 2005
+
+
+6.2. Comparison Ladder
+
+ A variety of methods are used in practice to test URI equivalence.
+ These methods fall into a range, distinguished by the amount of
+ processing required and the degree to which the probability of false
+ negatives is reduced. As noted above, false negatives cannot be
+ eliminated. In practice, their probability can be reduced, but this
+ reduction requires more processing and is not cost-effective for all
+ applications.
+
+ If this range of comparison practices is considered as a ladder, the
+ following discussion will climb the ladder, starting with practices
+ that are cheap but have a relatively higher chance of producing false
+ negatives, and proceeding to those that have higher computational
+ cost and lower risk of false negatives.
+
+6.2.1. Simple String Comparison
+
+ If two URIs, when considered as character strings, are identical,
+ then it is safe to conclude that they are equivalent. This type of
+ equivalence test has very low computational cost and is in wide use
+ in a variety of applications, particularly in the domain of parsing.
+
+ Testing strings for equivalence requires some basic precautions.
+ This procedure is often referred to as "bit-for-bit" or
+ "byte-for-byte" comparison, which is potentially misleading. Testing
+ strings for equality is normally based on pair comparison of the
+ characters that make up the strings, starting from the first and
+ proceeding until both strings are exhausted and all characters are
+ found to be equal, until a pair of characters compares unequal, or
+ until one of the strings is exhausted before the other.
+
+ This character comparison requires that each pair of characters be
+ put in comparable form. For example, should one URI be stored in a
+ byte array in EBCDIC encoding and the second in a Java String object
+ (UTF-16), bit-for-bit comparisons applied naively will produce
+ errors. It is better to speak of equality on a character-for-
+ character basis rather than on a byte-for-byte or bit-for-bit basis.
+ In practical terms, character-by-character comparisons should be done
+ codepoint-by-codepoint after conversion to a common character
+ encoding.
+
+ False negatives are caused by the production and use of URI aliases.
+ Unnecessary aliases can be reduced, regardless of the comparison
+ method, by consistently providing URI references in an already-
+ normalized form (i.e., a form identical to what would be produced
+ after normalization is applied, as described below).
+
+
+
+
+Berners-Lee, et al. Standards Track [Page 39]
+
+RFC 3986 URI Generic Syntax January 2005
+
+
+ Protocols and data formats often limit some URI comparisons to simple
+ string comparison, based on the theory that people and
+ implementations will, in their own best interest, be consistent in
+ providing URI references, or at least consistent enough to negate any
+ efficiency that might be obtained from further normalization.
+
+6.2.2. Syntax-Based Normalization
+
+ Implementations may use logic based on the definitions provided by
+ this specification to reduce the probability of false negatives.
+ This processing is moderately higher in cost than character-for-
+ character string comparison. For example, an application using this
+ approach could reasonably consider the following two URIs equivalent:
+
+ example://a/b/c/%7Bfoo%7D
+ eXAMPLE://a/./b/../b/%63/%7bfoo%7d
+
+ Web user agents, such as browsers, typically apply this type of URI
+ normalization when determining whether a cached response is
+ available. Syntax-based normalization includes such techniques as
+ case normalization, percent-encoding normalization, and removal of
+ dot-segments.
+
+6.2.2.1. Case Normalization
+
+ For all URIs, the hexadecimal digits within a percent-encoding
+ triplet (e.g., "%3a" versus "%3A") are case-insensitive and therefore
+ should be normalized to use uppercase letters for the digits A-F.
+
+ When a URI uses components of the generic syntax, the component
+ syntax equivalence rules always apply; namely, that the scheme and
+ host are case-insensitive and therefore should be normalized to
+ lowercase. For example, the URI <HTTP://www.EXAMPLE.com/> is
+ equivalent to <http://www.example.com/>. The other generic syntax
+ components are assumed to be case-sensitive unless specifically
+ defined otherwise by the scheme (see Section 6.2.3).
+
+6.2.2.2. Percent-Encoding Normalization
+
+ The percent-encoding mechanism (Section 2.1) is a frequent source of
+ variance among otherwise identical URIs. In addition to the case
+ normalization issue noted above, some URI producers percent-encode
+ octets that do not require percent-encoding, resulting in URIs that
+ are equivalent to their non-encoded counterparts. These URIs should
+ be normalized by decoding any percent-encoded octet that corresponds
+ to an unreserved character, as described in Section 2.3.
+
+
+
+
+
+Berners-Lee, et al. Standards Track [Page 40]
+
+RFC 3986 URI Generic Syntax January 2005
+
+
+6.2.2.3. Path Segment Normalization
+
+ The complete path segments "." and ".." are intended only for use
+ within relative references (Section 4.1) and are removed as part of
+ the reference resolution process (Section 5.2). However, some
+ deployed implementations incorrectly assume that reference resolution
+ is not necessary when the reference is already a URI and thus fail to
+ remove dot-segments when they occur in non-relative paths. URI
+ normalizers should remove dot-segments by applying the
+ remove_dot_segments algorithm to the path, as described in
+ Section 5.2.4.
+
+6.2.3. Scheme-Based Normalization
+
+ The syntax and semantics of URIs vary from scheme to scheme, as
+ described by the defining specification for each scheme.
+ Implementations may use scheme-specific rules, at further processing
+ cost, to reduce the probability of false negatives. For example,
+ because the "http" scheme makes use of an authority component, has a
+ default port of "80", and defines an empty path to be equivalent to
+ "/", the following four URIs are equivalent:
+
+ http://example.com
+ http://example.com/
+ http://example.com:/
+ http://example.com:80/
+
+ In general, a URI that uses the generic syntax for authority with an
+ empty path should be normalized to a path of "/". Likewise, an
+ explicit ":port", for which the port is empty or the default for the
+ scheme, is equivalent to one where the port and its ":" delimiter are
+ elided and thus should be removed by scheme-based normalization. For
+ example, the second URI above is the normal form for the "http"
+ scheme.
+
+ Another case where normalization varies by scheme is in the handling
+ of an empty authority component or empty host subcomponent. For many
+ scheme specifications, an empty authority or host is considered an
+ error; for others, it is considered equivalent to "localhost" or the
+ end-user's host. When a scheme defines a default for authority and a
+ URI reference to that default is desired, the reference should be
+ normalized to an empty authority for the sake of uniformity, brevity,
+ and internationalization. If, however, either the userinfo or port
+ subcomponents are non-empty, then the host should be given explicitly
+ even if it matches the default.
+
+ Normalization should not remove delimiters when their associated
+ component is empty unless licensed to do so by the scheme
+
+
+
+Berners-Lee, et al. Standards Track [Page 41]
+
+RFC 3986 URI Generic Syntax January 2005
+
+
+ specification. For example, the URI "http://example.com/?" cannot be
+ assumed to be equivalent to any of the examples above. Likewise, the
+ presence or absence of delimiters within a userinfo subcomponent is
+ usually significant to its interpretation. The fragment component is
+ not subject to any scheme-based normalization; thus, two URIs that
+ differ only by the suffix "#" are considered different regardless of
+ the scheme.
+
+ Some schemes define additional subcomponents that consist of case-
+ insensitive data, giving an implicit license to normalizers to
+ convert this data to a common case (e.g., all lowercase). For
+ example, URI schemes that define a subcomponent of path to contain an
+ Internet hostname, such as the "mailto" URI scheme, cause that
+ subcomponent to be case-insensitive and thus subject to case
+ normalization (e.g., "mailto:[email protected]" is equivalent to
+ "mailto:[email protected]", even though the generic syntax considers
+ the path component to be case-sensitive).
+
+ Other scheme-specific normalizations are possible.
+
+6.2.4. Protocol-Based Normalization
+
+ Substantial effort to reduce the incidence of false negatives is
+ often cost-effective for web spiders. Therefore, they implement even
+ more aggressive techniques in URI comparison. For example, if they
+ observe that a URI such as
+
+ http://example.com/data
+
+ redirects to a URI differing only in the trailing slash
+
+ http://example.com/data/
+
+ they will likely regard the two as equivalent in the future. This
+ kind of technique is only appropriate when equivalence is clearly
+ indicated by both the result of accessing the resources and the
+ common conventions of their scheme's dereference algorithm (in this
+ case, use of redirection by HTTP origin servers to avoid problems
+ with relative references).
+
+
+
+
+
+
+
+
+
+
+
+
+Berners-Lee, et al. Standards Track [Page 42]
+
+RFC 3986 URI Generic Syntax January 2005
+
+
+7. Security Considerations
+
+ A URI does not in itself pose a security threat. However, as URIs
+ are often used to provide a compact set of instructions for access to
+ network resources, care must be taken to properly interpret the data
+ within a URI, to prevent that data from causing unintended access,
+ and to avoid including data that should not be revealed in plain
+ text.
+
+7.1. Reliability and Consistency
+
+ There is no guarantee that once a URI has been used to retrieve
+ information, the same information will be retrievable by that URI in
+ the future. Nor is there any guarantee that the information
+ retrievable via that URI in the future will be observably similar to
+ that retrieved in the past. The URI syntax does not constrain how a
+ given scheme or authority apportions its namespace or maintains it
+ over time. Such guarantees can only be obtained from the person(s)
+ controlling that namespace and the resource in question. A specific
+ URI scheme may define additional semantics, such as name persistence,
+ if those semantics are required of all naming authorities for that
+ scheme.
+
+7.2. Malicious Construction
+
+ It is sometimes possible to construct a URI so that an attempt to
+ perform a seemingly harmless, idempotent operation, such as the
+ retrieval of a representation, will in fact cause a possibly damaging
+ remote operation. The unsafe URI is typically constructed by
+ specifying a port number other than that reserved for the network
+ protocol in question. The client unwittingly contacts a site running
+ a different protocol service, and data within the URI contains
+ instructions that, when interpreted according to this other protocol,
+ cause an unexpected operation. A frequent example of such abuse has
+ been the use of a protocol-based scheme with a port component of
+ "25", thereby fooling user agent software into sending an unintended
+ or impersonating message via an SMTP server.
+
+ Applications should prevent dereference of a URI that specifies a TCP
+ port number within the "well-known port" range (0 - 1023) unless the
+ protocol being used to dereference that URI is compatible with the
+ protocol expected on that well-known port. Although IANA maintains a
+ registry of well-known ports, applications should make such
+ restrictions user-configurable to avoid preventing the deployment of
+ new services.
+
+
+
+
+
+
+Berners-Lee, et al. Standards Track [Page 43]
+
+RFC 3986 URI Generic Syntax January 2005
+
+
+ When a URI contains percent-encoded octets that match the delimiters
+ for a given resolution or dereference protocol (for example, CR and
+ LF characters for the TELNET protocol), these percent-encodings must
+ not be decoded before transmission across that protocol. Transfer of
+ the percent-encoding, which might violate the protocol, is less
+ harmful than allowing decoded octets to be interpreted as additional
+ operations or parameters, perhaps triggering an unexpected and
+ possibly harmful remote operation.
+
+7.3. Back-End Transcoding
+
+ When a URI is dereferenced, the data within it is often parsed by
+ both the user agent and one or more servers. In HTTP, for example, a
+ typical user agent will parse a URI into its five major components,
+ access the authority's server, and send it the data within the
+ authority, path, and query components. A typical server will take
+ that information, parse the path into segments and the query into
+ key/value pairs, and then invoke implementation-specific handlers to
+ respond to the request. As a result, a common security concern for
+ server implementations that handle a URI, either as a whole or split
+ into separate components, is proper interpretation of the octet data
+ represented by the characters and percent-encodings within that URI.
+
+ Percent-encoded octets must be decoded at some point during the
+ dereference process. Applications must split the URI into its
+ components and subcomponents prior to decoding the octets, as
+ otherwise the decoded octets might be mistaken for delimiters.
+ Security checks of the data within a URI should be applied after
+ decoding the octets. Note, however, that the "%00" percent-encoding
+ (NUL) may require special handling and should be rejected if the
+ application is not expecting to receive raw data within a component.
+
+ Special care should be taken when the URI path interpretation process
+ involves the use of a back-end file system or related system
+ functions. File systems typically assign an operational meaning to
+ special characters, such as the "/", "\", ":", "[", and "]"
+ characters, and to special device names like ".", "..", "...", "aux",
+ "lpt", etc. In some cases, merely testing for the existence of such
+ a name will cause the operating system to pause or invoke unrelated
+ system calls, leading to significant security concerns regarding
+ denial of service and unintended data transfer. It would be
+ impossible for this specification to list all such significant
+ characters and device names. Implementers should research the
+ reserved names and characters for the types of storage device that
+ may be attached to their applications and restrict the use of data
+ obtained from URI components accordingly.
+
+
+
+
+
+Berners-Lee, et al. Standards Track [Page 44]
+
+RFC 3986 URI Generic Syntax January 2005
+
+
+7.4. Rare IP Address Formats
+
+ Although the URI syntax for IPv4address only allows the common
+ dotted-decimal form of IPv4 address literal, many implementations
+ that process URIs make use of platform-dependent system routines,
+ such as gethostbyname() and inet_aton(), to translate the string
+ literal to an actual IP address. Unfortunately, such system routines
+ often allow and process a much larger set of formats than those
+ described in Section 3.2.2.
+
+ For example, many implementations allow dotted forms of three
+ numbers, wherein the last part is interpreted as a 16-bit quantity
+ and placed in the right-most two bytes of the network address (e.g.,
+ a Class B network). Likewise, a dotted form of two numbers means
+ that the last part is interpreted as a 24-bit quantity and placed in
+ the right-most three bytes of the network address (Class A), and a
+ single number (without dots) is interpreted as a 32-bit quantity and
+ stored directly in the network address. Adding further to the
+ confusion, some implementations allow each dotted part to be
+ interpreted as decimal, octal, or hexadecimal, as specified in the C
+ language (i.e., a leading 0x or 0X implies hexadecimal; a leading 0
+ implies octal; otherwise, the number is interpreted as decimal).
+
+ These additional IP address formats are not allowed in the URI syntax
+ due to differences between platform implementations. However, they
+ can become a security concern if an application attempts to filter
+ access to resources based on the IP address in string literal format.
+ If this filtering is performed, literals should be converted to
+ numeric form and filtered based on the numeric value, and not on a
+ prefix or suffix of the string form.
+
+7.5. Sensitive Information
+
+ URI producers should not provide a URI that contains a username or
+ password that is intended to be secret. URIs are frequently
+ displayed by browsers, stored in clear text bookmarks, and logged by
+ user agent history and intermediary applications (proxies). A
+ password appearing within the userinfo component is deprecated and
+ should be considered an error (or simply ignored) except in those
+ rare cases where the 'password' parameter is intended to be public.
+
+7.6. Semantic Attacks
+
+ Because the userinfo subcomponent is rarely used and appears before
+ the host in the authority component, it can be used to construct a
+ URI intended to mislead a human user by appearing to identify one
+ (trusted) naming authority while actually identifying a different
+ authority hidden behind the noise. For example
+
+
+
+Berners-Lee, et al. Standards Track [Page 45]
+
+RFC 3986 URI Generic Syntax January 2005
+
+
+ ftp://cnn.example.com&[email protected]/top_story.htm
+
+ might lead a human user to assume that the host is 'cnn.example.com',
+ whereas it is actually '10.0.0.1'. Note that a misleading userinfo
+ subcomponent could be much longer than the example above.
+
+ A misleading URI, such as that above, is an attack on the user's
+ preconceived notions about the meaning of a URI rather than an attack
+ on the software itself. User agents may be able to reduce the impact
+ of such attacks by distinguishing the various components of the URI
+ when they are rendered, such as by using a different color or tone to
+ render userinfo if any is present, though there is no panacea. More
+ information on URI-based semantic attacks can be found in [Siedzik].
+
+8. IANA Considerations
+
+ URI scheme names, as defined by <scheme> in Section 3.1, form a
+ registered namespace that is managed by IANA according to the
+ procedures defined in [BCP35]. No IANA actions are required by this
+ document.
+
+9. Acknowledgements
+
+ This specification is derived from RFC 2396 [RFC2396], RFC 1808
+ [RFC1808], and RFC 1738 [RFC1738]; the acknowledgements in those
+ documents still apply. It also incorporates the update (with
+ corrections) for IPv6 literals in the host syntax, as defined by
+ Robert M. Hinden, Brian E. Carpenter, and Larry Masinter in
+ [RFC2732]. In addition, contributions by Gisle Aas, Reese Anschultz,
+ Daniel Barclay, Tim Bray, Mike Brown, Rob Cameron, Jeremy Carroll,
+ Dan Connolly, Adam M. Costello, John Cowan, Jason Diamond, Martin
+ Duerst, Stefan Eissing, Clive D.W. Feather, Al Gilman, Tony Hammond,
+ Elliotte Harold, Pat Hayes, Henry Holtzman, Ian B. Jacobs, Michael
+ Kay, John C. Klensin, Graham Klyne, Dan Kohn, Bruce Lilly, Andrew
+ Main, Dave McAlpin, Ira McDonald, Michael Mealling, Ray Merkert,
+ Stephen Pollei, Julian Reschke, Tomas Rokicki, Miles Sabin, Kai
+ Schaetzl, Mark Thomson, Ronald Tschalaer, Norm Walsh, Marc Warne,
+ Stuart Williams, and Henry Zongaro are gratefully acknowledged.
+
+10. References
+
+10.1. Normative References
+
+ [ASCII] American National Standards Institute, "Coded Character
+ Set -- 7-bit American Standard Code for Information
+ Interchange", ANSI X3.4, 1986.
+
+
+
+
+
+Berners-Lee, et al. Standards Track [Page 46]
+
+RFC 3986 URI Generic Syntax January 2005
+
+
+ [RFC2234] Crocker, D. and P. Overell, "Augmented BNF for Syntax
+ Specifications: ABNF", RFC 2234, November 1997.
+
+ [STD63] Yergeau, F., "UTF-8, a transformation format of
+ ISO 10646", STD 63, RFC 3629, November 2003.
+
+ [UCS] International Organization for Standardization,
+ "Information Technology - Universal Multiple-Octet Coded
+ Character Set (UCS)", ISO/IEC 10646:2003, December 2003.
+
+10.2. Informative References
+
+ [BCP19] Freed, N. and J. Postel, "IANA Charset Registration
+ Procedures", BCP 19, RFC 2978, October 2000.
+
+ [BCP35] Petke, R. and I. King, "Registration Procedures for URL
+ Scheme Names", BCP 35, RFC 2717, November 1999.
+
+ [RFC0952] Harrenstien, K., Stahl, M., and E. Feinler, "DoD Internet
+ host table specification", RFC 952, October 1985.
+
+ [RFC1034] Mockapetris, P., "Domain names - concepts and facilities",
+ STD 13, RFC 1034, November 1987.
+
+ [RFC1123] Braden, R., "Requirements for Internet Hosts - Application
+ and Support", STD 3, RFC 1123, October 1989.
+
+ [RFC1535] Gavron, E., "A Security Problem and Proposed Correction
+ With Widely Deployed DNS Software", RFC 1535,
+ October 1993.
+
+ [RFC1630] Berners-Lee, T., "Universal Resource Identifiers in WWW: A
+ Unifying Syntax for the Expression of Names and Addresses
+ of Objects on the Network as used in the World-Wide Web",
+ RFC 1630, June 1994.
+
+ [RFC1736] Kunze, J., "Functional Recommendations for Internet
+ Resource Locators", RFC 1736, February 1995.
+
+ [RFC1737] Sollins, K. and L. Masinter, "Functional Requirements for
+ Uniform Resource Names", RFC 1737, December 1994.
+
+ [RFC1738] Berners-Lee, T., Masinter, L., and M. McCahill, "Uniform
+ Resource Locators (URL)", RFC 1738, December 1994.
+
+ [RFC1808] Fielding, R., "Relative Uniform Resource Locators",
+ RFC 1808, June 1995.
+
+
+
+
+Berners-Lee, et al. Standards Track [Page 47]
+
+RFC 3986 URI Generic Syntax January 2005
+
+
+ [RFC2046] Freed, N. and N. Borenstein, "Multipurpose Internet Mail
+ Extensions (MIME) Part Two: Media Types", RFC 2046,
+ November 1996.
+
+ [RFC2141] Moats, R., "URN Syntax", RFC 2141, May 1997.
+
+ [RFC2396] Berners-Lee, T., Fielding, R., and L. Masinter, "Uniform
+ Resource Identifiers (URI): Generic Syntax", RFC 2396,
+ August 1998.
+
+ [RFC2518] Goland, Y., Whitehead, E., Faizi, A., Carter, S., and D.
+ Jensen, "HTTP Extensions for Distributed Authoring --
+ WEBDAV", RFC 2518, February 1999.
+
+ [RFC2557] Palme, J., Hopmann, A., and N. Shelness, "MIME
+ Encapsulation of Aggregate Documents, such as HTML
+ (MHTML)", RFC 2557, March 1999.
+
+ [RFC2718] Masinter, L., Alvestrand, H., Zigmond, D., and R. Petke,
+ "Guidelines for new URL Schemes", RFC 2718, November 1999.
+
+ [RFC2732] Hinden, R., Carpenter, B., and L. Masinter, "Format for
+ Literal IPv6 Addresses in URL's", RFC 2732, December 1999.
+
+ [RFC3305] Mealling, M. and R. Denenberg, "Report from the Joint
+ W3C/IETF URI Planning Interest Group: Uniform Resource
+ Identifiers (URIs), URLs, and Uniform Resource Names
+ (URNs): Clarifications and Recommendations", RFC 3305,
+ August 2002.
+
+ [RFC3490] Faltstrom, P., Hoffman, P., and A. Costello,
+ "Internationalizing Domain Names in Applications (IDNA)",
+ RFC 3490, March 2003.
+
+ [RFC3513] Hinden, R. and S. Deering, "Internet Protocol Version 6
+ (IPv6) Addressing Architecture", RFC 3513, April 2003.
+
+ [Siedzik] Siedzik, R., "Semantic Attacks: What's in a URL?",
+ April 2001, <http://www.giac.org/practical/gsec/
+ Richard_Siedzik_GSEC.pdf>.
+
+
+
+
+
+
+
+
+
+
+
+Berners-Lee, et al. Standards Track [Page 48]
+
+RFC 3986 URI Generic Syntax January 2005
+
+
+Appendix A. Collected ABNF for URI
+
+ URI = scheme ":" hier-part [ "?" query ] [ "#" fragment ]
+
+ hier-part = "//" authority path-abempty
+ / path-absolute
+ / path-rootless
+ / path-empty
+
+ URI-reference = URI / relative-ref
+
+ absolute-URI = scheme ":" hier-part [ "?" query ]
+
+ relative-ref = relative-part [ "?" query ] [ "#" fragment ]
+
+ relative-part = "//" authority path-abempty
+ / path-absolute
+ / path-noscheme
+ / path-empty
+
+ scheme = ALPHA *( ALPHA / DIGIT / "+" / "-" / "." )
+
+ authority = [ userinfo "@" ] host [ ":" port ]
+ userinfo = *( unreserved / pct-encoded / sub-delims / ":" )
+ host = IP-literal / IPv4address / reg-name
+ port = *DIGIT
+
+ IP-literal = "[" ( IPv6address / IPvFuture ) "]"
+
+ IPvFuture = "v" 1*HEXDIG "." 1*( unreserved / sub-delims / ":" )
+
+ IPv6address = 6( h16 ":" ) ls32
+ / "::" 5( h16 ":" ) ls32
+ / [ h16 ] "::" 4( h16 ":" ) ls32
+ / [ *1( h16 ":" ) h16 ] "::" 3( h16 ":" ) ls32
+ / [ *2( h16 ":" ) h16 ] "::" 2( h16 ":" ) ls32
+ / [ *3( h16 ":" ) h16 ] "::" h16 ":" ls32
+ / [ *4( h16 ":" ) h16 ] "::" ls32
+ / [ *5( h16 ":" ) h16 ] "::" h16
+ / [ *6( h16 ":" ) h16 ] "::"
+
+ h16 = 1*4HEXDIG
+ ls32 = ( h16 ":" h16 ) / IPv4address
+ IPv4address = dec-octet "." dec-octet "." dec-octet "." dec-octet
+
+
+
+
+
+
+
+Berners-Lee, et al. Standards Track [Page 49]
+
+RFC 3986 URI Generic Syntax January 2005
+
+
+ dec-octet = DIGIT ; 0-9
+ / %x31-39 DIGIT ; 10-99
+ / "1" 2DIGIT ; 100-199
+ / "2" %x30-34 DIGIT ; 200-249
+ / "25" %x30-35 ; 250-255
+
+ reg-name = *( unreserved / pct-encoded / sub-delims )
+
+ path = path-abempty ; begins with "/" or is empty
+ / path-absolute ; begins with "/" but not "//"
+ / path-noscheme ; begins with a non-colon segment
+ / path-rootless ; begins with a segment
+ / path-empty ; zero characters
+
+ path-abempty = *( "/" segment )
+ path-absolute = "/" [ segment-nz *( "/" segment ) ]
+ path-noscheme = segment-nz-nc *( "/" segment )
+ path-rootless = segment-nz *( "/" segment )
+ path-empty = 0<pchar>
+
+ segment = *pchar
+ segment-nz = 1*pchar
+ segment-nz-nc = 1*( unreserved / pct-encoded / sub-delims / "@" )
+ ; non-zero-length segment without any colon ":"
+
+ pchar = unreserved / pct-encoded / sub-delims / ":" / "@"
+
+ query = *( pchar / "/" / "?" )
+
+ fragment = *( pchar / "/" / "?" )
+
+ pct-encoded = "%" HEXDIG HEXDIG
+
+ unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~"
+ reserved = gen-delims / sub-delims
+ gen-delims = ":" / "/" / "?" / "#" / "[" / "]" / "@"
+ sub-delims = "!" / "$" / "&" / "'" / "(" / ")"
+ / "*" / "+" / "," / ";" / "="
+
+Appendix B. Parsing a URI Reference with a Regular Expression
+
+ As the "first-match-wins" algorithm is identical to the "greedy"
+ disambiguation method used by POSIX regular expressions, it is
+ natural and commonplace to use a regular expression for parsing the
+ potential five components of a URI reference.
+
+ The following line is the regular expression for breaking-down a
+ well-formed URI reference into its components.
+
+
+
+Berners-Lee, et al. Standards Track [Page 50]
+
+RFC 3986 URI Generic Syntax January 2005
+
+
+ ^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?
+ 12 3 4 5 6 7 8 9
+
+ The numbers in the second line above are only to assist readability;
+ they indicate the reference points for each subexpression (i.e., each
+ paired parenthesis). We refer to the value matched for subexpression
+ <n> as $<n>. For example, matching the above expression to
+
+ http://www.ics.uci.edu/pub/ietf/uri/#Related
+
+ results in the following subexpression matches:
+
+ $1 = http:
+ $2 = http
+ $3 = //www.ics.uci.edu
+ $4 = www.ics.uci.edu
+ $5 = /pub/ietf/uri/
+ $6 = <undefined>
+ $7 = <undefined>
+ $8 = #Related
+ $9 = Related
+
+ where <undefined> indicates that the component is not present, as is
+ the case for the query component in the above example. Therefore, we
+ can determine the value of the five components as
+
+ scheme = $2
+ authority = $4
+ path = $5
+ query = $7
+ fragment = $9
+
+ Going in the opposite direction, we can recreate a URI reference from
+ its components by using the algorithm of Section 5.3.
+
+Appendix C. Delimiting a URI in Context
+
+ URIs are often transmitted through formats that do not provide a
+ clear context for their interpretation. For example, there are many
+ occasions when a URI is included in plain text; examples include text
+ sent in email, USENET news, and on printed paper. In such cases, it
+ is important to be able to delimit the URI from the rest of the text,
+ and in particular from punctuation marks that might be mistaken for
+ part of the URI.
+
+ In practice, URIs are delimited in a variety of ways, but usually
+ within double-quotes "http://example.com/", angle brackets
+ <http://example.com/>, or just by using whitespace:
+
+
+
+Berners-Lee, et al. Standards Track [Page 51]
+
+RFC 3986 URI Generic Syntax January 2005
+
+
+ http://example.com/
+
+ These wrappers do not form part of the URI.
+
+ In some cases, extra whitespace (spaces, line-breaks, tabs, etc.) may
+ have to be added to break a long URI across lines. The whitespace
+ should be ignored when the URI is extracted.
+
+ No whitespace should be introduced after a hyphen ("-") character.
+ Because some typesetters and printers may (erroneously) introduce a
+ hyphen at the end of line when breaking it, the interpreter of a URI
+ containing a line break immediately after a hyphen should ignore all
+ whitespace around the line break and should be aware that the hyphen
+ may or may not actually be part of the URI.
+
+ Using <> angle brackets around each URI is especially recommended as
+ a delimiting style for a reference that contains embedded whitespace.
+
+ The prefix "URL:" (with or without a trailing space) was formerly
+ recommended as a way to help distinguish a URI from other bracketed
+ designators, though it is not commonly used in practice and is no
+ longer recommended.
+
+ For robustness, software that accepts user-typed URI should attempt
+ to recognize and strip both delimiters and embedded whitespace.
+
+ For example, the text
+
+ Yes, Jim, I found it under "http://www.w3.org/Addressing/",
+ but you can probably pick it up from <ftp://foo.example.
+ com/rfc/>. Note the warning in <http://www.ics.uci.edu/pub/
+ ietf/uri/historical.html#WARNING>.
+
+ contains the URI references
+
+ http://www.w3.org/Addressing/
+ ftp://foo.example.com/rfc/
+ http://www.ics.uci.edu/pub/ietf/uri/historical.html#WARNING
+
+
+
+
+
+
+
+
+
+
+
+
+
+Berners-Lee, et al. Standards Track [Page 52]
+
+RFC 3986 URI Generic Syntax January 2005
+
+
+Appendix D. Changes from RFC 2396
+
+D.1. Additions
+
+ An ABNF rule for URI has been introduced to correspond to one common
+ usage of the term: an absolute URI with optional fragment.
+
+ IPv6 (and later) literals have been added to the list of possible
+ identifiers for the host portion of an authority component, as
+ described by [RFC2732], with the addition of "[" and "]" to the
+ reserved set and a version flag to anticipate future versions of IP
+ literals. Square brackets are now specified as reserved within the
+ authority component and are not allowed outside their use as
+ delimiters for an IP literal within host. In order to make this
+ change without changing the technical definition of the path, query,
+ and fragment components, those rules were redefined to directly
+ specify the characters allowed.
+
+ As [RFC2732] defers to [RFC3513] for definition of an IPv6 literal
+ address, which, unfortunately, lacks an ABNF description of
+ IPv6address, we created a new ABNF rule for IPv6address that matches
+ the text representations defined by Section 2.2 of [RFC3513].
+ Likewise, the definition of IPv4address has been improved in order to
+ limit each decimal octet to the range 0-255.
+
+ Section 6, on URI normalization and comparison, has been completely
+ rewritten and extended by using input from Tim Bray and discussion
+ within the W3C Technical Architecture Group.
+
+D.2. Modifications
+
+ The ad-hoc BNF syntax of RFC 2396 has been replaced with the ABNF of
+ [RFC2234]. This change required all rule names that formerly
+ included underscore characters to be renamed with a dash instead. In
+ addition, a number of syntax rules have been eliminated or simplified
+ to make the overall grammar more comprehensible. Specifications that
+ refer to the obsolete grammar rules may be understood by replacing
+ those rules according to the following table:
+
+
+
+
+
+
+
+
+
+
+
+
+
+Berners-Lee, et al. Standards Track [Page 53]
+
+RFC 3986 URI Generic Syntax January 2005
+
+
+ +----------------+--------------------------------------------------+
+ | obsolete rule | translation |
+ +----------------+--------------------------------------------------+
+ | absoluteURI | absolute-URI |
+ | relativeURI | relative-part [ "?" query ] |
+ | hier_part | ( "//" authority path-abempty / |
+ | | path-absolute ) [ "?" query ] |
+ | | |
+ | opaque_part | path-rootless [ "?" query ] |
+ | net_path | "//" authority path-abempty |
+ | abs_path | path-absolute |
+ | rel_path | path-rootless |
+ | rel_segment | segment-nz-nc |
+ | reg_name | reg-name |
+ | server | authority |
+ | hostport | host [ ":" port ] |
+ | hostname | reg-name |
+ | path_segments | path-abempty |
+ | param | *<pchar excluding ";"> |
+ | | |
+ | uric | unreserved / pct-encoded / ";" / "?" / ":" |
+ | | / "@" / "&" / "=" / "+" / "$" / "," / "/" |
+ | | |
+ | uric_no_slash | unreserved / pct-encoded / ";" / "?" / ":" |
+ | | / "@" / "&" / "=" / "+" / "$" / "," |
+ | | |
+ | mark | "-" / "_" / "." / "!" / "~" / "*" / "'" |
+ | | / "(" / ")" |
+ | | |
+ | escaped | pct-encoded |
+ | hex | HEXDIG |
+ | alphanum | ALPHA / DIGIT |
+ +----------------+--------------------------------------------------+
+
+ Use of the above obsolete rules for the definition of scheme-specific
+ syntax is deprecated.
+
+ Section 2, on characters, has been rewritten to explain what
+ characters are reserved, when they are reserved, and why they are
+ reserved, even when they are not used as delimiters by the generic
+ syntax. The mark characters that are typically unsafe to decode,
+ including the exclamation mark ("!"), asterisk ("*"), single-quote
+ ("'"), and open and close parentheses ("(" and ")"), have been moved
+ to the reserved set in order to clarify the distinction between
+ reserved and unreserved and, hopefully, to answer the most common
+ question of scheme designers. Likewise, the section on
+ percent-encoded characters has been rewritten, and URI normalizers
+ are now given license to decode any percent-encoded octets
+
+
+
+Berners-Lee, et al. Standards Track [Page 54]
+
+RFC 3986 URI Generic Syntax January 2005
+
+
+ corresponding to unreserved characters. In general, the terms
+ "escaped" and "unescaped" have been replaced with "percent-encoded"
+ and "decoded", respectively, to reduce confusion with other forms of
+ escape mechanisms.
+
+ The ABNF for URI and URI-reference has been redesigned to make them
+ more friendly to LALR parsers and to reduce complexity. As a result,
+ the layout form of syntax description has been removed, along with
+ the uric, uric_no_slash, opaque_part, net_path, abs_path, rel_path,
+ path_segments, rel_segment, and mark rules. All references to
+ "opaque" URIs have been replaced with a better description of how the
+ path component may be opaque to hierarchy. The relativeURI rule has
+ been replaced with relative-ref to avoid unnecessary confusion over
+ whether they are a subset of URI. The ambiguity regarding the
+ parsing of URI-reference as a URI or a relative-ref with a colon in
+ the first segment has been eliminated through the use of five
+ separate path matching rules.
+
+ The fragment identifier has been moved back into the section on
+ generic syntax components and within the URI and relative-ref rules,
+ though it remains excluded from absolute-URI. The number sign ("#")
+ character has been moved back to the reserved set as a result of
+ reintegrating the fragment syntax.
+
+ The ABNF has been corrected to allow the path component to be empty.
+ This also allows an absolute-URI to consist of nothing after the
+ "scheme:", as is present in practice with the "dav:" namespace
+ [RFC2518] and with the "about:" scheme used internally by many WWW
+ browser implementations. The ambiguity regarding the boundary
+ between authority and path has been eliminated through the use of
+ five separate path matching rules.
+
+ Registry-based naming authorities that use the generic syntax are now
+ defined within the host rule. This change allows current
+ implementations, where whatever name provided is simply fed to the
+ local name resolution mechanism, to be consistent with the
+ specification. It also removes the need to re-specify DNS name
+ formats here. Furthermore, it allows the host component to contain
+ percent-encoded octets, which is necessary to enable
+ internationalized domain names to be provided in URIs, processed in
+ their native character encodings at the application layers above URI
+ processing, and passed to an IDNA library as a registered name in the
+ UTF-8 character encoding. The server, hostport, hostname,
+ domainlabel, toplabel, and alphanum rules have been removed.
+
+ The resolving relative references algorithm of [RFC2396] has been
+ rewritten with pseudocode for this revision to improve clarity and
+ fix the following issues:
+
+
+
+Berners-Lee, et al. Standards Track [Page 55]
+
+RFC 3986 URI Generic Syntax January 2005
+
+
+ o [RFC2396] section 5.2, step 6a, failed to account for a base URI
+ with no path.
+
+ o Restored the behavior of [RFC1808] where, if the reference
+ contains an empty path and a defined query component, the target
+ URI inherits the base URI's path component.
+
+ o The determination of whether a URI reference is a same-document
+ reference has been decoupled from the URI parser, simplifying the
+ URI processing interface within applications in a way consistent
+ with the internal architecture of deployed URI processing
+ implementations. The determination is now based on comparison to
+ the base URI after transforming a reference to absolute form,
+ rather than on the format of the reference itself. This change
+ may result in more references being considered "same-document"
+ under this specification than there would be under the rules given
+ in RFC 2396, especially when normalization is used to reduce
+ aliases. However, it does not change the status of existing
+ same-document references.
+
+ o Separated the path merge routine into two routines: merge, for
+ describing combination of the base URI path with a relative-path
+ reference, and remove_dot_segments, for describing how to remove
+ the special "." and ".." segments from a composed path. The
+ remove_dot_segments algorithm is now applied to all URI reference
+ paths in order to match common implementations and to improve the
+ normalization of URIs in practice. This change only impacts the
+ parsing of abnormal references and same-scheme references wherein
+ the base URI has a non-hierarchical path.
+
+Index
+
+ A
+ ABNF 11
+ absolute 27
+ absolute-path 26
+ absolute-URI 27
+ access 9
+ authority 17, 18
+
+ B
+ base URI 28
+
+ C
+ character encoding 4
+ character 4
+ characters 8, 11
+ coded character set 4
+
+
+
+Berners-Lee, et al. Standards Track [Page 56]
+
+RFC 3986 URI Generic Syntax January 2005
+
+
+ D
+ dec-octet 20
+ dereference 9
+ dot-segments 23
+
+ F
+ fragment 16, 24
+
+ G
+ gen-delims 13
+ generic syntax 6
+
+ H
+ h16 20
+ hier-part 16
+ hierarchical 10
+ host 18
+
+ I
+ identifier 5
+ IP-literal 19
+ IPv4 20
+ IPv4address 19, 20
+ IPv6 19
+ IPv6address 19, 20
+ IPvFuture 19
+
+ L
+ locator 7
+ ls32 20
+
+ M
+ merge 32
+
+ N
+ name 7
+ network-path 26
+
+ P
+ path 16, 22, 26
+ path-abempty 22
+ path-absolute 22
+ path-empty 22
+ path-noscheme 22
+ path-rootless 22
+ path-abempty 16, 22, 26
+ path-absolute 16, 22, 26
+ path-empty 16, 22, 26
+
+
+
+Berners-Lee, et al. Standards Track [Page 57]
+
+RFC 3986 URI Generic Syntax January 2005
+
+
+ path-rootless 16, 22
+ pchar 23
+ pct-encoded 12
+ percent-encoding 12
+ port 22
+
+ Q
+ query 16, 23
+
+ R
+ reg-name 21
+ registered name 20
+ relative 10, 28
+ relative-path 26
+ relative-ref 26
+ remove_dot_segments 33
+ representation 9
+ reserved 12
+ resolution 9, 28
+ resource 5
+ retrieval 9
+
+ S
+ same-document 27
+ sameness 9
+ scheme 16, 17
+ segment 22, 23
+ segment-nz 23
+ segment-nz-nc 23
+ sub-delims 13
+ suffix 27
+
+ T
+ transcription 8
+
+ U
+ uniform 4
+ unreserved 13
+ URI grammar
+ absolute-URI 27
+ ALPHA 11
+ authority 18
+ CR 11
+ dec-octet 20
+ DIGIT 11
+ DQUOTE 11
+ fragment 24
+ gen-delims 13
+
+
+
+Berners-Lee, et al. Standards Track [Page 58]
+
+RFC 3986 URI Generic Syntax January 2005
+
+
+ h16 20
+ HEXDIG 11
+ hier-part 16
+ host 19
+ IP-literal 19
+ IPv4address 20
+ IPv6address 20
+ IPvFuture 19
+ LF 11
+ ls32 20
+ OCTET 11
+ path 22
+ path-abempty 22
+ path-absolute 22
+ path-empty 22
+ path-noscheme 22
+ path-rootless 22
+ pchar 23
+ pct-encoded 12
+ port 22
+ query 24
+ reg-name 21
+ relative-ref 26
+ reserved 13
+ scheme 17
+ segment 23
+ segment-nz 23
+ segment-nz-nc 23
+ SP 11
+ sub-delims 13
+ unreserved 13
+ URI 16
+ URI-reference 25
+ userinfo 18
+ URI 16
+ URI-reference 25
+ URL 7
+ URN 7
+ userinfo 18
+
+
+
+
+
+
+
+
+
+
+
+
+Berners-Lee, et al. Standards Track [Page 59]
+
+RFC 3986 URI Generic Syntax January 2005
+
+
+Authors' Addresses
+
+ Tim Berners-Lee
+ World Wide Web Consortium
+ Massachusetts Institute of Technology
+ 77 Massachusetts Avenue
+ Cambridge, MA 02139
+ USA
+
+ Phone: +1-617-253-5702
+ Fax: +1-617-258-5999
+ URI: http://www.w3.org/People/Berners-Lee/
+
+
+ Roy T. Fielding
+ Day Software
+ 5251 California Ave., Suite 110
+ Irvine, CA 92617
+ USA
+
+ Phone: +1-949-679-2960
+ Fax: +1-949-679-2972
+ URI: http://roy.gbiv.com/
+
+
+ Larry Masinter
+ Adobe Systems Incorporated
+ 345 Park Ave
+ San Jose, CA 95110
+ USA
+
+ Phone: +1-408-536-3024
+ URI: http://larry.masinter.net/
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Berners-Lee, et al. Standards Track [Page 60]
+
+RFC 3986 URI Generic Syntax January 2005
+
+
+Full Copyright Statement
+
+ Copyright (C) The Internet Society (2005).
+
+ This document is subject to the rights, licenses and restrictions
+ contained in BCP 78, and except as set forth therein, the authors
+ retain all their rights.
+
+ This document and the information contained herein are provided on an
+ "AS IS" basis and THE CONTRIBUTOR, THE ORGANIZATION HE/SHE REPRESENTS
+ OR IS SPONSORED BY (IF ANY), THE INTERNET SOCIETY AND THE INTERNET
+ ENGINEERING TASK FORCE DISCLAIM ALL WARRANTIES, EXPRESS OR IMPLIED,
+ INCLUDING BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE
+ INFORMATION HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED
+ WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+
+Intellectual Property
+
+ The IETF takes no position regarding the validity or scope of any
+ Intellectual Property Rights or other rights that might be claimed to
+ pertain to the implementation or use of the technology described in
+ this document or the extent to which any license under such rights
+ might or might not be available; nor does it represent that it has
+ made any independent effort to identify any such rights. Information
+ on the IETF's procedures with respect to rights in IETF Documents can
+ be found in BCP 78 and BCP 79.
+
+ Copies of IPR disclosures made to the IETF Secretariat and any
+ assurances of licenses to be made available, or the result of an
+ attempt made to obtain a general license or permission for the use of
+ such proprietary rights by implementers or users of this
+ specification can be obtained from the IETF on-line IPR repository at
+ http://www.ietf.org/ipr.
+
+ The IETF invites any interested party to bring to its attention any
+ copyrights, patents or patent applications, or other proprietary
+ rights that may cover technology that may be required to implement
+ this standard. Please address the information to the IETF at ietf-
+
+
+Acknowledgement
+
+ Funding for the RFC Editor function is currently provided by the
+ Internet Society.
+
+
+
+
+
+
+Berners-Lee, et al. Standards Track [Page 61]
+
diff --git a/lib/inets/doc/src/Makefile b/lib/inets/doc/src/Makefile
index e4cb0c4e48..82f2a5829f 100644
--- a/lib/inets/doc/src/Makefile
+++ b/lib/inets/doc/src/Makefile
@@ -26,16 +26,6 @@ include $(ERL_TOP)/make/$(TARGET)/otp.mk
include ../../vsn.mk
VSN=$(INETS_VSN)
-
-# ----------------------------------------------------
-# Include dependency
-# ----------------------------------------------------
-
-ifndef DOCSUPPORT
-include make.dep
-endif
-
-
# ----------------------------------------------------
# Release directory specification
# ----------------------------------------------------
@@ -98,37 +88,10 @@ EXTRA_FILES = summary.html.src \
MAN3_FILES = $(XML_REF3_FILES:%.xml=$(MAN3DIR)/%.3)
-ifdef DOCSUPPORT
-
HTML_REF_MAN_FILE = $(HTMLDIR)/index.html
TOP_PDF_FILE = $(PDFDIR)/$(APPLICATION)-$(VSN).pdf
-else
-
-TEX_FILES_BOOK = \
- $(BOOK_FILES:%.xml=%.tex)
-TEX_FILES_REF_MAN = \
- $(XML_PART_FILES:%.xml=%.tex) \
- $(XML_REF3_FILES:%.xml=%.tex) \
- $(XML_REF6_FILES:%.xml=%.tex) \
- $(XML_APPLICATION_FILES:%.xml=%.tex)
-TEX_FILES_USERS_GUIDE = \
- $(XML_CHAPTER_FILES:%.xml=%.tex)
-
-TOP_PDF_FILE = $(APPLICATION)-$(VSN).pdf
-TOP_PS_FILE = $(APPLICATION)-$(VSN).ps
-
-$(TOP_PDF_FILE): book.dvi ../../vsn.mk
- $(DVI2PS) $(DVIPS_FLAGS) -f $< | $(DISTILL) $(DISTILL_FLAGS) > $@
-
-$(TOP_PS_FILE): book.dvi ../../vsn.mk
- $(DVI2PS) $(DVIPS_FLAGS) -f $< > $@
-
-TOP_HTML_FILES =
-
-endif
-
# ----------------------------------------------------
# FLAGS
# ----------------------------------------------------
@@ -141,8 +104,6 @@ DVIPS_FLAGS +=
$(HTMLDIR)/%.gif: %.gif
$(INSTALL_DATA) $< $@
-ifdef DOCSUPPORT
-
docs: pdf html man
ldocs: local_docs
@@ -156,33 +117,6 @@ html: gifs $(HTML_REF_MAN_FILE)
clean clean_docs: clean_html clean_man clean_pdf
rm -f errs core *~
-else
-
-ifeq ($(DOCTYPE),pdf)
-docs: pdf
-else
-ifeq ($(DOCTYPE),ps)
-docs: ps
-else
-docs: html man
-endif
-endif
-
-pdf: $(TOP_PDF_FILE)
-
-ps: $(TOP_PS_FILE)
-
-html: $(HTML_FILES) $(TOP_HTML_FILES) gifs
-
-clean_tex:
- rm -f $(TEX_FILES_USERS_GUIDE) $(TEX_FILES_REF_MAN) $(TEX_FILES_BOOK)
-
-clean: clean_tex clean_html clean_man
- rm -f *.xmls_output *.xmls_errs
- rm -f $(TOP_PDF_FILE)
- rm -f errs core *~
-endif
-
man: $(MAN3_FILES)
gifs: $(GIF_FILES:%=$(HTMLDIR)/%)
@@ -204,10 +138,7 @@ clean_man:
# ----------------------------------------------------
include $(ERL_TOP)/make/otp_release_targets.mk
-ifdef DOCSUPPORT
-
release_docs_spec: docs
- @echo "release_docs_spec(docs) when DOCSUPPORT=$DOCSUPPORT"
$(INSTALL_DIR) $(RELSYSDIR)/doc/pdf
$(INSTALL_DATA) $(TOP_PDF_FILE) $(RELSYSDIR)/doc/pdf
$(INSTALL_DIR) $(RELSYSDIR)/doc/html
@@ -215,33 +146,6 @@ release_docs_spec: docs
$(INSTALL_DATA) $(INFO_FILE) $(RELSYSDIR)
$(INSTALL_DIR) $(RELEASE_PATH)/man/man3
$(INSTALL_DATA) $(MAN3DIR)/* $(RELEASE_PATH)/man/man3
-else
-
-ifeq ($(DOCTYPE),pdf)
-release_docs_spec: pdf
- @echo "release_docs_spec(pdf)"
- $(INSTALL_DIR) $(RELEASE_PATH)/pdf
- $(INSTALL_DATA) $(TOP_PDF_FILE) $(RELEASE_PATH)/pdf
-else
-ifeq ($(DOCTYPE),ps)
-release_docs_spec: ps
- @echo "release_docs_spec(ps)"
- $(INSTALL_DIR) $(RELEASE_PATH)/ps
- $(INSTALL_DATA) $(TOP_PS_FILE) $(RELEASE_PATH)/ps
-else
-release_docs_spec: docs
- @echo "release_docs_spec(docs)"
- $(INSTALL_DIR) $(RELSYSDIR)/doc/html
- $(INSTALL_DATA) $(GIF_FILES) $(EXTRA_FILES) $(HTML_FILES) \
- $(RELSYSDIR)/doc/html
- $(INSTALL_DATA) $(INFO_FILE) $(RELSYSDIR)
- $(INSTALL_DIR) $(RELEASE_PATH)/man/man3
- $(INSTALL_DATA) $(MAN3_FILES) $(RELEASE_PATH)/man/man3
-
-endif
-endif
-
-endif
release_spec:
diff --git a/lib/inets/doc/src/ftp.xml b/lib/inets/doc/src/ftp.xml
index ca902d8d9d..f8f11ec705 100644
--- a/lib/inets/doc/src/ftp.xml
+++ b/lib/inets/doc/src/ftp.xml
@@ -1,10 +1,10 @@
-<?xml version="1.0" encoding="latin1" ?>
+<?xml version="1.0" encoding="iso-8859-1" ?>
<!DOCTYPE erlref SYSTEM "erlref.dtd">
<erlref>
<header>
<copyright>
- <year>1997</year><year>2010</year>
+ <year>1997</year><year>2011</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -141,11 +141,21 @@
<tag>{timeout, Timeout}</tag>
<item>
<marker id="timeout"></marker>
- <p>Timeout = <c>integer() >= 0</c> </p>
+ <p>Timeout = <c>non_neg_integer()</c> </p>
<p>Connection timeout. </p>
<p>Default is 60000 (milliseconds). </p>
</item>
+ <tag>{dtimeout, DTimeout}</tag>
+ <item>
+ <marker id="dtimeout"></marker>
+ <p>DTimeout = <c>non_neg_integer() | infinity</c> </p>
+ <p>Data Connect timeout.
+ The time the client will wait for the server to connect to the
+ data socket. </p>
+ <p>Default is infinity. </p>
+ </item>
+
<tag>{progress, Progress}</tag>
<item>
<marker id="progress"></marker>
@@ -542,11 +552,12 @@
<v>verbose() = boolean() (defaults to false)</v>
<v>debug() = disable | debug | trace (defaults to disable)</v>
<!-- <v>open_options() = [open_option()]</v> -->
- <v>open_option() = {ipfamily, ipfamily()} | {port, port()} | {mode, mode()} | {timeout, timeout()} | {progress, progress()}</v>
+ <v>open_option() = {ipfamily, ipfamily()} | {port, port()} | {mode, mode()} | {timeout, timeout()} | {dtimeout, dtimeout()} | {progress, progress()}</v>
<v>ipfamily() = inet | inet6 | inet6fb4 (defaults to inet)</v>
<v>port() = integer() > 0 (defaults to 21)</v>
<v>mode() = active | passive (defaults to passive)</v>
- <v>timeout() = integer() >= 0 (defaults to 60000 milliseconds)</v>
+ <v>timeout() = integer() > 0 (defaults to 60000 milliseconds)</v>
+ <v>dtimeout() = integer() > 0 | infinity (defaults to infinity)</v>
<v>pogress() = ignore | {module(), function(), initial_data()} (defaults to ignore)</v>
<v>module() = atom()</v>
<v>function() = atom()</v>
diff --git a/lib/inets/doc/src/httpc.xml b/lib/inets/doc/src/httpc.xml
index d1671ac9bd..b1f964ae69 100644
--- a/lib/inets/doc/src/httpc.xml
+++ b/lib/inets/doc/src/httpc.xml
@@ -28,8 +28,10 @@
<date></date>
<rev></rev>
</header>
+
<module>httpc</module>
<modulesummary>An HTTP/1.1 client </modulesummary>
+
<description>
<p>This module provides the API to a HTTP/1.1 compatible client according
to RFC 2616, caching is currently not supported.</p>
@@ -167,7 +169,6 @@ filename() = string()
<v>http_option() = {timeout, timeout()} |
{connect_timeout, timeout()} |
{ssl, ssloptions()} |
- {ossl, ssloptions()} |
{essl, ssloptions()} |
{autoredirect, boolean()} |
{proxy_auth, {userstring(), passwordstring()}} |
@@ -206,6 +207,7 @@ filename() = string()
to the <c>receiver</c> depending on that value. </p>
<p>Http option (<c>http_option()</c>) details: </p>
+ <marker id="request2_http_options"></marker>
<taglist>
<tag><c><![CDATA[timeout]]></c></tag>
<item>
@@ -231,16 +233,9 @@ filename() = string()
<p>Defaults to <c>[]</c>. </p>
</item>
- <tag><c><![CDATA[ossl]]></c></tag>
- <item>
- <p>If using the OpenSSL based (old) implementation of SSL,
- these SSL-specific options are used. </p>
- <p>Defaults to <c>[]</c>. </p>
- </item>
-
<tag><c><![CDATA[essl]]></c></tag>
<item>
- <p>If using the Erlang based (new) implementation of SSL,
+ <p>If using the Erlang based implementation of SSL,
these SSL-specific options are used. </p>
<p>Defaults to <c>[]</c>. </p>
</item>
diff --git a/lib/inets/doc/src/httpd.xml b/lib/inets/doc/src/httpd.xml
index edacb73b65..f88099a82e 100644
--- a/lib/inets/doc/src/httpd.xml
+++ b/lib/inets/doc/src/httpd.xml
@@ -148,13 +148,11 @@
in the apache like configuration file.
</item>
- <tag>{socket_type, ip_comm | ssl | ossl | essl}</tag>
+ <tag>{socket_type, ip_comm | ssl | essl}</tag>
<item>
- <p>When using ssl, there are several alternatives.
- <c>ossl</c> specifically uses the OpenSSL based (old) SSL.
- <c>essl</c> specifically uses the Erlang based (new) SSL.
- When using <c>ssl</c> it <em>currently</em> defaults to
- <c>essl</c>. </p>
+ <p>When using ssl, there are currently only one alternative.
+ <c>essl</c> specifically uses the Erlang based SSL.
+ <c>ssl</c> defaults to <c>essl</c>. </p>
<p>Defaults to <c>ip_comm</c>. </p>
</item>
@@ -162,7 +160,7 @@
<item>
<p>Defaults to <c>inet6fb4. </c> </p>
<p>Note that this option is only used when the option
- <c>socket_type</c> has the value <c>ip_comm</c>. </p>
+ <c>socket_type</c> has the value <c>ip_comm</c>. </p>
</item>
</taglist>
diff --git a/lib/inets/doc/src/make.dep b/lib/inets/doc/src/make.dep
deleted file mode 100644
index 8deb7e7a5a..0000000000
--- a/lib/inets/doc/src/make.dep
+++ /dev/null
@@ -1,47 +0,0 @@
-#
-# %CopyrightBegin%
-#
-# Copyright Ericsson AB 1999-2010. All Rights Reserved.
-#
-# The contents of this file are subject to the Erlang Public License,
-# Version 1.1, (the "License"); you may not use this file except in
-# compliance with the License. You should have received a copy of the
-# Erlang Public License along with this software. If not, it can be
-# retrieved online at http://www.erlang.org/.
-#
-# Software distributed under the License is distributed on an "AS IS"
-# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
-# the License for the specific language governing rights and limitations
-# under the License.
-#
-# %CopyrightEnd%
-#
-#
-
-# ----------------------------------------------------
-# >>>> Do not edit this file <<<<
-# This file was automaticly generated by
-# /home/otp/bin/docdepend
-# ----------------------------------------------------
-
-
-# ----------------------------------------------------
-# TeX files that the DVI file depend on
-# ----------------------------------------------------
-
-book.dvi: book.tex ftp.tex ftp_client.tex httpc.tex http_client.tex \
- http_server.tex httpd.tex httpd_conf.tex httpd_socket.tex \
- httpd_util.tex inets.tex inets_services.tex \
- mod_alias.tex mod_auth.tex mod_esi.tex mod_security.tex \
- part.tex ref_man.tex tftp.tex
-
-# ----------------------------------------------------
-# Source inlined when transforming from source to LaTeX
-# ----------------------------------------------------
-
-book.tex: ref_man.xml
-
-ftp.tex: ../../../../system/doc/definitions/term.defs
-
-inets_services.tex: ../../../../system/doc/definitions/term.defs
-
diff --git a/lib/inets/doc/src/notes.xml b/lib/inets/doc/src/notes.xml
index 5b5dfdde21..7f0f61148c 100644
--- a/lib/inets/doc/src/notes.xml
+++ b/lib/inets/doc/src/notes.xml
@@ -32,9 +32,74 @@
<file>notes.xml</file>
</header>
- <section><title>Inets 5.7.1</title>
+ <section><title>Inets 5.8</title>
<section><title>Improvements and New Features</title>
+<!--
+ <p>-</p>
+-->
+
+ <list>
+ <item>
+ <p>[ftpc] Add a config option to specify a
+ <seealso marker="ftp#dtimeout">data connect timeout</seealso>.
+ That is how long the ftp client will wait for the server to connect
+ to the data socket. If this timeout occurs, an error will be
+ returned to the caller and the ftp client process will be
+ terminated. </p>
+ <p>Own Id: OTP-9545</p>
+ </item>
+
+ </list>
+
+ </section>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+<!--
+ <p>-</p>
+-->
+
+ <list>
+ <item>
+ <p>[httpd] Fix logging of content length in mod_log. </p>
+ <p>Garrett Smith</p>
+ <p>Own Id: OTP-9715</p>
+ </item>
+
+ </list>
+
+ </section>
+
+ <section>
+ <title>Incompatibilities</title>
+<!--
+ <p>-</p>
+-->
+
+ <list>
+ <item>
+ <p>[httpc] Deprecated interface module <c>http</c> has been removed.
+ It has (long) been replaced by http client interface module
+ <seealso marker="httpc#">httpc</seealso>. </p>
+ <p>Own Id: OTP-9359</p>
+ </item>
+
+ <item>
+ <p>[httpc|httpd] The old ssl implementation (based on OpenSSL),
+ has been deprecated. The config option that specified usage of
+ this version of the ssl app, <c>ossl</c>, has been removed. </p>
+ <p>Own Id: OTP-9522</p>
+ </item>
+
+ </list>
+
+ </section>
+
+ </section> <!-- 5.8 -->
+
+
+ <section><title>Inets 5.7.2</title>
+ <section><title>Improvements and New Features</title>
<p>-</p>
<!--
@@ -49,6 +114,73 @@
</section>
+ <section>
+ <title>Incompatibilities</title>
+<!--
+ <p>-</p>
+-->
+
+ <list>
+ <item>
+ <p>[httpc] Deprecated interface module <c>http</c> has been removed.
+ It has (long) been replaced by http client interface module
+ <seealso marker="httpc#">httpc</seealso>. </p>
+ <p>Own Id: OTP-9359</p>
+ </item>
+
+ <item>
+ <p>[httpc|httpd] The old ssl implementation (based on OpenSSL),
+ has been deprecated. The config option that specified usage of
+ this version of the ssl app, <c>ossl</c>, has been removed. </p>
+ <p>Own Id: OTP-9522</p>
+ </item>
+
+ </list>
+
+ </section>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+<!--
+ <p>-</p>
+-->
+
+ <list>
+ <item>
+ <p>[httpd] XSS prevention did not work for hex-encoded URL's. </p>
+ <p>Own Id: OTP-9655</p>
+ </item>
+
+ <item>
+ <p>[httpd] GET request with malformed header date caused
+ server crash (non-fatal) with no reply to client. Will
+ now result in a reply with status code 400. </p>
+ <p>Own Id: OTP-9674</p>
+ <p>Aux Id: seq11936</p>
+ </item>
+
+ </list>
+ </section>
+
+ </section> <!-- 5.7.2 -->
+
+
+ <section><title>Inets 5.7.1</title>
+
+ <section><title>Improvements and New Features</title>
+ <p>-</p>
+
+<!--
+ <list>
+ <item>
+ <p>[httpc|httpd] Added support for IPv6 with ssl. </p>
+ <p>Own Id: OTP-5566</p>
+ </item>
+
+ </list>
+-->
+
+ </section>
+
<section><title>Fixed Bugs and Malfunctions</title>
<!--
<p>-</p>
@@ -57,24 +189,24 @@
<list>
<item>
<p>[httpc] Parsing of a cookie expire date should be more forgiving.
- That is, if the parsing fails, the date should be ignored.
- Also added support for (yet another) date format:
- "Tue Jan 01 08:00:01 2036 GMT". </p>
- <p>Own Id: OTP-9433</p>
+ That is, if the parsing fails, the date should be ignored.
+ Also added support for (yet another) date format:
+ "Tue Jan 01 08:00:01 2036 GMT". </p>
+ <p>Own Id: OTP-9433</p>
</item>
<item>
<p>[httpc] Rewrote cookie parsing. Among other things solving
- cookie processing from www.expedia.com. </p>
- <p>Own Id: OTP-9434</p>
+ cookie processing from www.expedia.com. </p>
+ <p>Own Id: OTP-9434</p>
</item>
<item>
<p>[httpd] Fix httpd directory traversal on Windows.
- Directory traversal was possible on Windows where
- backward slash is used as directory separator. </p>
- <p>Andr�s Veres-Szentkir�lyi.</p>
- <p>Own Id: OTP-9561</p>
+ Directory traversal was possible on Windows where
+ backward slash is used as directory separator. </p>
+ <p>Andr�s Veres-Szentkir�lyi.</p>
+ <p>Own Id: OTP-9561</p>
</item>
</list>
@@ -1095,570 +1227,11 @@
</section> <!-- 5.1 -->
+ <!--
+ <p>For information about older versions see
+ <url href="part_notes_history_frame.html">release notes history</url>.</p>
+ -->
- <section><title>Inets 5.0.14</title>
-
- <section><title>Improvements and New Features</title>
- <list>
- <item>
- <p>
- [tftp] The callback watchdog has been removed, as it
- turned out to be counter productive when the disk was
- overloaded. Earlier a connection was aborted when a
- callback (which performs the file access in the TFTP
- server) took too long time.</p>
- <p>
- [tftp] The error message "Too many connections" has been
- reclassified to be a warning.</p>
- <p>
- Own Id: OTP-7888</p>
- </item>
- </list>
- </section>
-
-
- <section><title>Fixed Bugs and Malfunctions</title>
- <list>
- <item>
- <p>[httpc] - Incorrect http version option check. </p>
- <p>Mats Cronqvist</p>
- <p>Own Id: OTP-7882</p>
- </item>
-
- <item>
- <p>[httpc] - Unnecessary error report when client
- terminating as a result of the server closed the
- socket unexpectedly. </p>
- <p>Own Id: OTP-7883</p>
- </item>
-
- <item>
- <p>[httpc] - Failed transforming a relative URI to
- an absolute URI. </p>
- <p>Own Id: OTP-7950</p>
- </item>
-
- <item>
- <p>[httpd] - The HTTP server did not handle the config
- option ssl_ca_certificate_file. </p>
- <p>Own Id: OTP-7976</p>
- </item>
-
- </list>
- </section>
-
- </section> <!-- 5.0.14 -->
-
-
- <section><title>Inets 5.0.13</title>
-
- <section><title>Fixed Bugs and Malfunctions</title>
- <list>
- <item>
- <p>
- Ssl did not work correctly with the use of new style
- configuration due to sn old internal format that was not
- changed correctly in all places.</p>
- <p>
- Own Id: OTP-7723 Aux Id: seq11143 </p>
- </item>
- <item>
- <p>
- [httpc] - Now streams 200 and 206 results and not only
- 200 results.</p>
- <p>
- Own Id: OTP-7857</p>
- </item>
- </list>
- </section>
-
-
- <section><title>Improvements and New Features</title>
- <list>
- <item>
- <p>
- [httpc] - The inets http client will now use persistent
- connections without pipelining as default and if a
- pipeline timeout is set it will pipeline the requests on
- the persistent connections.</p>
- <p>
- *** POTENTIAL INCOMPATIBILITY ***</p>
- <p>
- Own Id: OTP-7463</p>
- </item>
- <item>
- <p>
- [httpd] - added option ssl_password_callback_arguments.</p>
- <p>
- Own Id: OTP-7724 Aux Id: seq11151 </p>
- </item>
- <item>
- <p>
- Changed the socket use so that it will become more robust
- to non-functional ipv6 and fallback on ipv4. This changes
- may for very special os-configurations cause a problem
- when used with erts-versions pre R13.</p>
- <p>
- Own Id: OTP-7726</p>
- </item>
- <item>
- <p>
- Removed deprecated function httpd_util:key1search/[2,3]</p>
- <p>
- Own Id: OTP-7815</p>
- </item>
- </list>
- </section>
-
- </section>
-
- <section><title>Inets 5.0.12</title>
-
- <section><title>Improvements and New Features</title>
- <list>
- <item>
- <p>
- [httpd] - Updated inets so that it not uses the deprecated
- function ssl:accept/[2,3].</p>
- <p>
- Own Id: OTP-7636 Aux Id: seq11086 </p>
- </item>
- </list>
- </section>
-
- </section>
-
-
- <section><title>Inets 5.0.11</title>
-
- <section><title>Fixed Bugs and Malfunctions</title>
- <list>
- <item>
- <p>
- Transient bug related to hot code swap of the TFTP server is
- now fixed. It could happen that the first TFTP server that was
- started after a code upgrade to Inets-5.0.6 crashed with a
- function clause error in tftp_engine:service_init/2.</p>
- <p> Own Id: OTP-7574 Aux Id: seq11069 </p>
- </item>
- <item>
- <p>
- [httpd] - Validation of ssl_password_callback_module was
- incorrect.</p>
- <p>
- Own Id: OTP-7597 Aux Id: seq11074 </p>
- </item>
- <item>
- <p>
- [httpd] - Misspelling in old apachelike configuration
- directive TransferDiskLogSize has been corrected.</p>
- <p> Own Id: OTP-7598 Aux Id: seq11059 </p>
- </item>
- <item>
- <p>
- Minor problems found by dialyzer has been fixed.</p>
- <p>
- Own Id: OTP-7605</p>
- </item>
- </list>
- </section>
-
- </section>
-
-<section><title>Inets 5.0.10</title>
-
- <section><title>Fixed Bugs and Malfunctions</title>
- <list>
- <item>
- <p>
- Enhanched an info report.</p>
- <p>
- Own Id: OTP-7450</p>
- </item>
- </list>
- </section>
-
-
- <section><title>Improvements and New Features</title>
- <list>
- <item>
- <p>
- Changed errro message from
- {wrong_type,{document_root,"/tmp/htdocs"}} to
- {invalid_option,{non_existing,
- document_root,"/tmp/htdocs"}}.</p>
- <p>
- Own Id: OTP-7454</p>
- </item>
- <item>
- <p>
- Relative paths in directory authentication did not work
- as intended, this has now been fixed.</p>
- <p>
- Own Id: OTP-7490</p>
- </item>
- <item>
- <p>
- The query-string passed to the callback function was not
- compliant with the documentation, it is now.</p>
- <p>
- Own Id: OTP-7512</p>
- </item>
- </list>
- </section>
-
-</section>
-
- <section><title>Inets 5.0.9</title>
-
- <section><title>Fixed Bugs and Malfunctions</title>
- <list>
- <item>
- <p>
- Parameters to error_logger:error_report/1 has been
- corrected.</p>
- <p>
- Own Id: OTP-7257 Aux Id: OTP-7294, OTP-7258 </p>
- </item>
- <item>
- <p>
- [httpd] - If a Module/Function request matching an
- erl_script_alias registration does not exist as a function in
- the module registered a 404 error will now be issued instead of a
- 500 error.</p>
- <p>
- Own Id: OTP-7323</p>
- </item>
- <item>
- <p>
- [httpd] -The option auth_type for mod_auth is no longer
- mandatory, for backward-compatibility reasons.</p>
- <p>
- Own Id: OTP-7341</p>
- </item>
- </list>
- </section>
-
- </section>
-
- <section><title>Inets 5.0.8</title>
-
- <section><title>Fixed Bugs and Malfunctions</title>
- <list>
- <item>
- <p>
- [httpd] - Spelling error caused client connection header
- to be ignored.</p>
- <p>
- Own Id: OTP-7315 Aux Id: seq10951 </p>
- </item>
- <item>
- <p>
- [httpd] - Call to the function
- mod_get:get_modification_date/1 was made too early
- resulting in that httpd did not send the 404 file missing
- response.</p>
- <p>
- Own Id: OTP-7321</p>
- </item>
- </list>
- </section>
-
- </section>
-
- <section><title>Inets 5.0.7</title>
-
- <section><title>Improvements and New Features</title>
- <list>
- <item>
- <p>
- [httpc, httpd] - Now follows the recommendation regarding
- line terminators in section 19.3 in RFC 2616 e.i: "The
- line terminator for message-header fields is the sequence
- CRLF. However, we recommend that applications, when
- parsing such headers, recognize a single LF as a line
- terminator and ignore the leading CR".</p>
- <p>
- Own Id: OTP-7304 Aux Id: seq10944 </p>
- </item>
- </list>
- </section>
-
- </section>
-
- <section><title>Inets 5.0.6</title>
-
- <section><title>Improvements and New Features</title>
- <list>
- <item>
- <p>
- [tftp] If a callback (which performs the file access in
- the TFTP server) takes too long time (more than the
- double TFTP timeout), the server will abort the
- connection and send an error reply to the client. This
- implies that the server will release resources attached
- to the connection faster than before. The server simply
- assumes that the client has given up.</p>
- <p>
- [tftp] If the TFTP server receives yet another request
- from the same client (same host and port) while it
- already has an active connection to the client, it will
- simply ignore the new request if the request is equal
- with the first one (same filename and options). This
- implies that the (new) client will be served by the
- already ongoing connection on the server side. By not
- setting up yet another connection, in parallel with the
- ongoing one, the server will consumer lesser resources.</p>
- <p>
- [tftp] netascii mode is now supported when the
- client/server has native ascii support (Windows). The new
- optional parameter native_ascii in the tftp_binary and
- tftp_file callback modules can be used to override the
- default behavior.</p>
- <p>
- [tftp] Yet another callback module has been added in
- order to allow customized handling of error, warning and
- info messages. See the new configuration parameter,
- logger.</p>
- <p>
- [tftp] Yet another configuration parameter, max_retries,
- has been added in order to control the number of times a
- packet can be resent. The default is 5.</p>
- <p>
- [tftp] tftp:info/1 and tftp:change_config/2 can now be
- applied to all daemons or all servers in one command
- without bothering about their process identifiers.</p>
- <p>
- External TR HI89527.</p>
- <p>
- Own Id: OTP-7266</p>
- </item>
- </list>
- </section>
-
-</section>
-
-<section><title>Inets 5.0.5</title>
-
- <section><title>Improvements and New Features</title>
- <list>
- <item>
- <p>
- [tftp] Blocks with too low block numbers are silently
- discarded. For example if a server receives block #5 when
- it expects block #7 it will discard the block without
- interrupting the file transfer. Too high block numbers
- does still imply an error. External TR HI96072.</p>
- <p>
- Own Id: OTP-7220</p>
- </item>
- <item>
- <p>
- [tftp] The problem with occasional case_clause errors in
- tftp_engine:common_read/7 has been fixed. External TR
- HI97362.</p>
- <p>
- Own Id: OTP-7221</p>
- </item>
- </list>
- </section>
-
-</section>
-
- <section><title>Inets 5.0.4</title>
-
- <section><title>Improvements and New Features</title>
- <list>
- <item>
- <p>
- Changed calls to file open to concur with the API and not
- use deprecated syntax.</p>
- <p>
- Own Id: OTP-7172</p>
- </item>
- <item>
- <p>
- [tftp] Server lost the first packet when the client timed
- out</p>
- <p>
- Own Id: OTP-7173</p>
- </item>
- </list>
- </section>
-
- </section>
-
- <section><title>Inets 5.0.3</title>
-
- <section><title>Improvements and New Features</title>
- <list>
- <item>
- <p>
- Updated copyright headers and fixed backwards
- compatibility for an undocumented feature, for now. This
- feature will later be removed and a new and documented
- option will take its place.</p>
- <p>
- Own Id: OTP-7144</p>
- </item>
- </list>
- </section>
-
- </section>
-
- <section><title>Inets 5.0.2</title>
-
- <section><title>Improvements and New Features</title>
- <list>
- <item>
- <p>
- [httpd] - Error logs now has a pretty and a compact
- format and access logs can be written on the common log
- format or the extended common log format.</p>
- <p>
- Own Id: OTP-6661 Aux Id: Seq 7764 </p>
- </item>
- <item>
- <p>
- [httpc] - Added acceptance of missing reason phrase to
- the relaxed mode.</p>
- <p>
- Own Id: OTP-7024</p>
- </item>
- <item>
- <p>
- [httpc] - A new option has been added to enable the
- client to act as lower version clients, by default the
- client is an HTTP/1.1 client.</p>
- <p>
- Own Id: OTP-7043</p>
- </item>
- </list>
- </section>
-
- </section>
-
- <section><title>Inets 5.0.1</title>
-
- <section><title>Fixed Bugs and Malfunctions</title>
- <list>
- <item>
- <p>
- [httpd] - Deprecated function httpd:start/1 did not
- accept all inputs that it had done previously. This
- should now work again.</p>
- <p>
- Own Id: OTP-7040</p>
- </item>
- </list>
- </section>
-
- <section><title>Improvements and New Features</title>
- <list>
- <item>
- <p>
- [httpd] - Changed validity check on bind_address so that
- it uses inet:getaddr instead of inet:gethostbyaddr as the
- former puts a too hard restriction on the bind_address.</p>
- <p>
- Own Id: OTP-7041 Aux Id: seq10829 </p>
- </item>
- <item>
- <p>
- [httpc] - Internal process now does try-catch and
- terminates normally in case of HTTP parse errors.
- Semantical the client works just as before returning an
- error message to the client, even if the error massage
- has been enhanced, but there is no supervisor report in
- the shell of a internal process crashing. (Which was the
- expected behavior and not a fault.)</p>
- <p>
- Own Id: OTP-7042</p>
- </item>
- </list>
- </section>
-
- </section>
-
- <section><title>Inets 5.0</title>
-
- <section><title>Improvements and New Features</title>
- <list>
- <item>
- <p>
- [httpd, httpc] - Deprecated base64 decode/encode
- functions have been removed. Inets uses base64 in STDLIB
- instead.</p>
- <p>
- *** POTENTIAL INCOMPATIBILITY ***</p>
- <p>
- Own Id: OTP-6485</p>
- </item>
- <item>
- <p>
- [httpd] - It is now possible to restrict the length of
- acceptable URI:s in the HTTP server.</p>
- <p>
- Own Id: OTP-6572</p>
- </item>
- <item>
- <p>
- [httpc] - Profiles are now supported i.e. the options
- available in set_options/1 can be set locally for a
- certain profile and do not have to affect all
- HTTP-requests issued in the Erlang node. Calls to the
- HTTP client API functions not using the profile argument
- will use the default profile.</p>
- <p>
- Own Id: OTP-6690</p>
- </item>
- <item>
- <p>
- A new uniform Inets interface provides a flexible way to
- start/stop Inets services and get information about
- running services. See inets(3). This also means that
- inflexibilities in the HTTP server has been removed and
- more default values has been added.</p>
- <p>
- Own Id: OTP-6705</p>
- </item>
- <item>
- <p>
- [tftp] Logged errors have been changed to be logged
- warnings.</p>
- <p>
- Own Id: OTP-6916 Aux Id: seq10737 </p>
- </item>
- <item>
- <p>
- [httpc] - The client will now return the proper value
- when receiving a HTTP 204 code instead of hanging.</p>
- <p>
- Own Id: OTP-6982</p>
- </item>
- <item>
- <p>
- The Inets application now has to be explicitly started
- and stopped i.e. it will not automatically be started as
- a temporary application as it did before. Although a
- practical feature when testing things in the shell it is
- not desirable that people take advantage of this and not
- start the Inets application in a correct way in their
- products. Added functions to the Inets API that call
- application:start/stop.</p>
- <p>
- *** POTENTIAL INCOMPATIBILITY ***</p>
- <p>
- Own Id: OTP-6993</p>
- </item>
- </list>
- </section>
-
- <!-- p>For information about older versions see
- <url href="part_notes_history_frame.html">release notes history</url>.</p -->
- </section>
</chapter>
diff --git a/lib/inets/src/ftp/ftp.erl b/lib/inets/src/ftp/ftp.erl
index ac72963347..b6da92947c 100644
--- a/lib/inets/src/ftp/ftp.erl
+++ b/lib/inets/src/ftp/ftp.erl
@@ -55,9 +55,10 @@
-include("ftp_internal.hrl").
%% Constante used in internal state definition
--define(CONNECTION_TIMEOUT, 60*1000).
--define(DEFAULT_MODE, passive).
--define(PROGRESS_DEFAULT, ignore).
+-define(CONNECTION_TIMEOUT, 60*1000).
+-define(DATA_ACCEPT_TIMEOUT, infinity).
+-define(DEFAULT_MODE, passive).
+-define(PROGRESS_DEFAULT, ignore).
%% Internal Constants
-define(FTP_PORT, 21).
@@ -88,7 +89,8 @@
%% data needed further on.
caller = undefined, % term()
ipfamily, % inet | inet6 | inet6fb4
- progress = ignore % ignore | pid()
+ progress = ignore, % ignore | pid()
+ dtimeout = ?DATA_ACCEPT_TIMEOUT % non_neg_integer() | infinity
}).
@@ -847,6 +849,7 @@ start_options(Options) ->
%% host
%% port
%% timeout
+%% dtimeout
%% progress
open_options(Options) ->
?fcrt("open_options", [{options, Options}]),
@@ -875,7 +878,12 @@ open_options(Options) ->
(_) -> false
end,
ValidateTimeout =
- fun(Timeout) when is_integer(Timeout) andalso (Timeout > 0) -> true;
+ fun(Timeout) when is_integer(Timeout) andalso (Timeout >= 0) -> true;
+ (_) -> false
+ end,
+ ValidateDTimeout =
+ fun(DTimeout) when is_integer(DTimeout) andalso (DTimeout >= 0) -> true;
+ (infinity) -> true;
(_) -> false
end,
ValidateProgress =
@@ -893,6 +901,7 @@ open_options(Options) ->
{port, ValidatePort, false, ?FTP_PORT},
{ipfamily, ValidateIpFamily, false, inet},
{timeout, ValidateTimeout, false, ?CONNECTION_TIMEOUT},
+ {dtimeout, ValidateDTimeout, false, ?DATA_ACCEPT_TIMEOUT},
{progress, ValidateProgress, false, ?PROGRESS_DEFAULT}],
validate_options(Options, ValidOptions, []).
@@ -1037,13 +1046,15 @@ handle_call({_, {open, ip_comm, Opts}}, From, State) ->
Mode = key_search(mode, Opts, ?DEFAULT_MODE),
Port = key_search(port, Opts, ?FTP_PORT),
Timeout = key_search(timeout, Opts, ?CONNECTION_TIMEOUT),
+ DTimeout = key_search(dtimeout, Opts, ?DATA_ACCEPT_TIMEOUT),
Progress = key_search(progress, Opts, ignore),
IpFamily = key_search(ipfamily, Opts, inet),
-
+
State2 = State#state{client = From,
mode = Mode,
progress = progress(Progress),
- ipfamily = IpFamily},
+ ipfamily = IpFamily,
+ dtimeout = DTimeout},
?fcrd("handle_call(open) -> setup ctrl connection with",
[{host, Host}, {port, Port}, {timeout, Timeout}]),
@@ -1064,11 +1075,13 @@ handle_call({_, {open, ip_comm, Host, Opts}}, From, State) ->
Mode = key_search(mode, Opts, ?DEFAULT_MODE),
Port = key_search(port, Opts, ?FTP_PORT),
Timeout = key_search(timeout, Opts, ?CONNECTION_TIMEOUT),
+ DTimeout = key_search(dtimeout, Opts, ?DATA_ACCEPT_TIMEOUT),
Progress = key_search(progress, Opts, ignore),
State2 = State#state{client = From,
mode = Mode,
- progress = progress(Progress)},
+ progress = progress(Progress),
+ dtimeout = DTimeout},
case setup_ctrl_connection(Host, Port, Timeout, State2) of
{ok, State3, WaitTimeout} ->
@@ -1657,9 +1670,19 @@ handle_ctrl_result({pos_compl, Lines},
%%--------------------------------------------------------------------------
%% Directory listing
handle_ctrl_result({pos_prel, _}, #state{caller = {dir, Dir}} = State) ->
- NewState = accept_data_connection(State),
- activate_data_connection(NewState),
- {noreply, NewState#state{caller = {handle_dir_result, Dir}}};
+ case accept_data_connection(State) of
+ {ok, NewState} ->
+ activate_data_connection(NewState),
+ {noreply, NewState#state{caller = {handle_dir_result, Dir}}};
+ {error, _Reason} = ERROR ->
+ case State#state.client of
+ undefined ->
+ {stop, ERROR, State};
+ From ->
+ gen_server:reply(From, ERROR),
+ {stop, normal, State#state{client = undefined}}
+ end
+ end;
handle_ctrl_result({pos_compl, _}, #state{caller = {handle_dir_result, Dir,
Data}, client = From}
@@ -1756,9 +1779,19 @@ handle_ctrl_result({Status, _},
%%--------------------------------------------------------------------------
%% File handling - recv_bin
handle_ctrl_result({pos_prel, _}, #state{caller = recv_bin} = State) ->
- NewState = accept_data_connection(State),
- activate_data_connection(NewState),
- {noreply, NewState};
+ case accept_data_connection(State) of
+ {ok, NewState} ->
+ activate_data_connection(NewState),
+ {noreply, NewState};
+ {error, _Reason} = ERROR ->
+ case State#state.client of
+ undefined ->
+ {stop, ERROR, State};
+ From ->
+ gen_server:reply(From, ERROR),
+ {stop, normal, State#state{client = undefined}}
+ end
+ end;
handle_ctrl_result({pos_compl, _}, #state{caller = {recv_bin, Data},
client = From} = State) ->
@@ -1780,16 +1813,37 @@ handle_ctrl_result({Status, _}, #state{caller = {recv_bin, _}} = State) ->
handle_ctrl_result({pos_prel, _}, #state{client = From,
caller = start_chunk_transfer}
= State) ->
- NewState = accept_data_connection(State),
- gen_server:reply(From, ok),
- {noreply, NewState#state{chunk = true, client = undefined,
- caller = undefined}};
+ case accept_data_connection(State) of
+ {ok, NewState} ->
+ gen_server:reply(From, ok),
+ {noreply, NewState#state{chunk = true, client = undefined,
+ caller = undefined}};
+ {error, _Reason} = ERROR ->
+ case State#state.client of
+ undefined ->
+ {stop, ERROR, State};
+ From ->
+ gen_server:reply(From, ERROR),
+ {stop, normal, State#state{client = undefined}}
+ end
+ end;
+
%%--------------------------------------------------------------------------
%% File handling - recv_file
handle_ctrl_result({pos_prel, _}, #state{caller = {recv_file, _}} = State) ->
- NewState = accept_data_connection(State),
- activate_data_connection(NewState),
- {noreply, NewState};
+ case accept_data_connection(State) of
+ {ok, NewState} ->
+ activate_data_connection(NewState),
+ {noreply, NewState};
+ {error, _Reason} = ERROR ->
+ case State#state.client of
+ undefined ->
+ {stop, ERROR, State};
+ From ->
+ gen_server:reply(From, ERROR),
+ {stop, normal, State#state{client = undefined}}
+ end
+ end;
handle_ctrl_result({Status, _}, #state{caller = {recv_file, Fd}} = State) ->
file_close(Fd),
@@ -1800,17 +1854,38 @@ handle_ctrl_result({Status, _}, #state{caller = {recv_file, Fd}} = State) ->
%% File handling - transfer_*
handle_ctrl_result({pos_prel, _}, #state{caller = {transfer_file, Fd}}
= State) ->
- NewState = accept_data_connection(State),
- send_file(Fd, NewState);
+ case accept_data_connection(State) of
+ {ok, NewState} ->
+ send_file(Fd, NewState);
+ {error, _Reason} = ERROR ->
+ case State#state.client of
+ undefined ->
+ {stop, ERROR, State};
+ From ->
+ gen_server:reply(From, ERROR),
+ {stop, normal, State#state{client = undefined}}
+ end
+ end;
handle_ctrl_result({pos_prel, _}, #state{caller = {transfer_data, Bin}}
= State) ->
- NewState = accept_data_connection(State),
- send_data_message(NewState, Bin),
- close_data_connection(NewState),
- activate_ctrl_connection(NewState),
- {noreply, NewState#state{caller = transfer_data_second_phase,
- dsock = undefined}};
+ case accept_data_connection(State) of
+ {ok, NewState} ->
+ send_data_message(NewState, Bin),
+ close_data_connection(NewState),
+ activate_ctrl_connection(NewState),
+ {noreply, NewState#state{caller = transfer_data_second_phase,
+ dsock = undefined}};
+ {error, _Reason} = ERROR ->
+ case State#state.client of
+ undefined ->
+ {stop, ERROR, State};
+ From ->
+ gen_server:reply(From, ERROR),
+ {stop, normal, State#state{client = undefined}}
+ end
+ end;
+
%%--------------------------------------------------------------------------
%% Default
handle_ctrl_result({Status, Lines}, #state{client = From} = State)
@@ -2009,16 +2084,20 @@ connect2(Host, Port, IpFam, Timeout) ->
Error
end.
-
-accept_data_connection(#state{mode = active,
- dsock = {lsock, LSock}} = State) ->
- {ok, Socket} = gen_tcp:accept(LSock),
- gen_tcp:close(LSock),
- State#state{dsock = Socket};
+accept_data_connection(#state{mode = active,
+ dtimeout = DTimeout,
+ dsock = {lsock, LSock}} = State) ->
+ case gen_tcp:accept(LSock, DTimeout) of
+ {ok, Socket} ->
+ gen_tcp:close(LSock),
+ {ok, State#state{dsock = Socket}};
+ {error, Reason} ->
+ {error, {data_connect_failed, Reason}}
+ end;
accept_data_connection(#state{mode = passive} = State) ->
- State.
+ {ok, State}.
send_ctrl_message(#state{csock = Socket, verbose = Verbose}, Message) ->
%% io:format("send control message: ~n~p~n", [lists:flatten(Message)]),
diff --git a/lib/inets/src/http_client/Makefile b/lib/inets/src/http_client/Makefile
index 0397b48ab2..3960c36d00 100644
--- a/lib/inets/src/http_client/Makefile
+++ b/lib/inets/src/http_client/Makefile
@@ -41,7 +41,6 @@ RELSYSDIR = $(RELEASE_PATH)/lib/$(APPLICATION)-$(VSN)
# Target Specs
# ----------------------------------------------------
MODULES = \
- http \
httpc \
httpc_cookie \
httpc_handler \
diff --git a/lib/inets/src/http_client/http.erl b/lib/inets/src/http_client/http.erl
deleted file mode 100644
index bbe2fec267..0000000000
--- a/lib/inets/src/http_client/http.erl
+++ /dev/null
@@ -1,132 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2002-2010. All Rights Reserved.
-%%
-%% The contents of this file are subject to the Erlang Public License,
-%% Version 1.1, (the "License"); you may not use this file except in
-%% compliance with the License. You should have received a copy of the
-%% Erlang Public License along with this software. If not, it can be
-%% retrieved online at http://www.erlang.org/.
-%%
-%% Software distributed under the License is distributed on an "AS IS"
-%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
-%% the License for the specific language governing rights and limitations
-%% under the License.
-%%
-%% %CopyrightEnd%
-%%
-%%
-
-%%% Description: OLD API MODULE - USE httpc INSTEAD
-
--module(http).
-
--deprecated({request, 1, next_major_release}).
--deprecated({request, 2, next_major_release}).
--deprecated({request, 4, next_major_release}).
--deprecated({request, 5, next_major_release}).
--deprecated({cancel_request, 1, next_major_release}).
--deprecated({cancel_request, 2, next_major_release}).
--deprecated({set_option, 2, next_major_release}).
--deprecated({set_option, 3, next_major_release}).
--deprecated({set_options, 1, next_major_release}).
--deprecated({set_options, 2, next_major_release}).
--deprecated({verify_cookies, 2, next_major_release}).
--deprecated({verify_cookies, 3, next_major_release}).
--deprecated({cookie_header, 1, next_major_release}).
--deprecated({cookie_header, 2, next_major_release}).
--deprecated({stream_next, 1, next_major_release}).
--deprecated({default_profile, 0, next_major_release}).
-
-%% Deprecated
--export([
- request/1, request/2, request/4, request/5,
- cancel_request/1, cancel_request/2,
- set_option/2, set_option/3,
- set_options/1, set_options/2,
- verify_cookies/2, verify_cookies/3,
- cookie_header/1, cookie_header/2,
- stream_next/1,
- default_profile/0
- ]).
-
-
-%%%=========================================================================
-%%% API
-%%%=========================================================================
-
-%%--------------------------------------------------------------------------
-%% request(Url [, Profile]) ->
-%% request(Method, Request, HTTPOptions, Options [, Profile])
-%%--------------------------------------------------------------------------
-
-request(Url) -> httpc:request(Url).
-request(Url, Profile) -> httpc:request(Url, Profile).
-
-request(Method, Request, HttpOptions, Options) ->
- httpc:request(Method, Request, HttpOptions, Options).
-request(Method, Request, HttpOptions, Options, Profile) ->
- httpc:request(Method, Request, HttpOptions, Options, Profile).
-
-
-%%--------------------------------------------------------------------------
-%% cancel_request(RequestId [, Profile])
-%%-------------------------------------------------------------------------
-
-cancel_request(RequestId) ->
- httpc:cancel_request(RequestId).
-cancel_request(RequestId, Profile) ->
- httpc:cancel_request(RequestId, Profile).
-
-
-%%--------------------------------------------------------------------------
-%% set_options(Options [, Profile])
-%% set_option(Key, Value [, Profile])
-%%-------------------------------------------------------------------------
-
-set_options(Options) ->
- httpc:set_options(Options).
-set_options(Options, Profile) ->
- httpc:set_options(Options, Profile).
-
-set_option(Key, Value) ->
- httpc:set_option(Key, Value).
-set_option(Key, Value, Profile) ->
- httpc:set_option(Key, Value, Profile).
-
-
-%%--------------------------------------------------------------------------
-%% verify_cookies(SetCookieHeaders, Url [, Profile])
-%%-------------------------------------------------------------------------
-
-verify_cookies(SetCookieHeaders, Url) ->
- httpc:store_cookies(SetCookieHeaders, Url).
-verify_cookies(SetCookieHeaders, Url, Profile) ->
- httpc:store_cookies(SetCookieHeaders, Url, Profile).
-
-
-%%--------------------------------------------------------------------------
-%% cookie_header(Url [, Profile])
-%%-------------------------------------------------------------------------
-
-cookie_header(Url) ->
- httpc:cookie_header(Url).
-cookie_header(Url, Profile) ->
- httpc:cookie_header(Url, Profile).
-
-
-%%--------------------------------------------------------------------------
-%% stream_next(Pid)
-%%-------------------------------------------------------------------------
-
-stream_next(Pid) ->
- httpc:stream_next(Pid).
-
-
-%%--------------------------------------------------------------------------
-%% default_profile()
-%%-------------------------------------------------------------------------
-
-default_profile() ->
- httpc:default_profile().
diff --git a/lib/inets/src/http_client/httpc.erl b/lib/inets/src/http_client/httpc.erl
index fe8e93af1f..d72c34fa6b 100644
--- a/lib/inets/src/http_client/httpc.erl
+++ b/lib/inets/src/http_client/httpc.erl
@@ -105,7 +105,6 @@ request(Url, Profile) ->
%% {ssl, SSLOptions} | {proxy_auth, {User, Password}}
%% Ssloptions = ssl_options() |
%% {ssl, ssl_options()} |
-%% {ossl, ssl_options()} |
%% {essl, ssl_options()}
%% ssl_options() = [ssl_option()]
%% ssl_option() = {verify, code()} |
@@ -142,7 +141,9 @@ request(Url, Profile) ->
request(Method, Request, HttpOptions, Options) ->
request(Method, Request, HttpOptions, Options, default_profile()).
-request(Method, {Url, Headers}, HTTPOptions, Options, Profile)
+request(Method,
+ {Url, Headers},
+ HTTPOptions, Options, Profile)
when (Method =:= options) orelse
(Method =:= get) orelse
(Method =:= head) orelse
@@ -155,15 +156,17 @@ request(Method, {Url, Headers}, HTTPOptions, Options, Profile)
{http_options, HTTPOptions},
{options, Options},
{profile, Profile}]),
- case http_uri:parse(Url) of
+ case http_uri:parse(Url, Options) of
{error, Reason} ->
{error, Reason};
- ParsedUrl ->
+ {ok, ParsedUrl} ->
handle_request(Method, Url, ParsedUrl, Headers, [], [],
HTTPOptions, Options, Profile)
end;
-request(Method, {Url,Headers,ContentType,Body}, HTTPOptions, Options, Profile)
+request(Method,
+ {Url, Headers, ContentType, Body},
+ HTTPOptions, Options, Profile)
when ((Method =:= post) orelse (Method =:= put)) andalso
(is_atom(Profile) orelse is_pid(Profile)) ->
?hcrt("request", [{method, Method},
@@ -174,10 +177,10 @@ request(Method, {Url,Headers,ContentType,Body}, HTTPOptions, Options, Profile)
{http_options, HTTPOptions},
{options, Options},
{profile, Profile}]),
- case http_uri:parse(Url) of
+ case http_uri:parse(Url, Options) of
{error, Reason} ->
{error, Reason};
- ParsedUrl ->
+ {ok, ParsedUrl} ->
handle_request(Method, Url,
ParsedUrl, Headers, ContentType, Body,
HTTPOptions, Options, Profile)
@@ -268,7 +271,10 @@ store_cookies(SetCookieHeaders, Url, Profile)
{profile, Profile}]),
try
begin
- {_, _, Host, Port, Path, _} = http_uri:parse(Url),
+ %% Since the Address part is not actually used
+ %% by the manager when storing cookies, we dont
+ %% care about ipv6-host-with-brackets.
+ {ok, {_, _, Host, Port, Path, _}} = http_uri:parse(Url),
Address = {Host, Port},
ProfileName = profile_name(Profile),
Cookies = httpc_cookie:cookies(SetCookieHeaders, Path, Host),
@@ -465,6 +471,8 @@ handle_request(Method, Url,
HeadersRecord = header_record(NewHeaders, Host2, HTTPOptions),
Receiver = proplists:get_value(receiver, Options),
SocketOpts = proplists:get_value(socket_opts, Options),
+ BracketedHost = proplists:get_value(ipv6_host_with_brackets,
+ Options),
MaybeEscPath = maybe_encode_uri(HTTPOptions, Path),
MaybeEscQuery = maybe_encode_uri(HTTPOptions, Query),
AbsUri = maybe_encode_uri(HTTPOptions, Url),
@@ -483,7 +491,8 @@ handle_request(Method, Url,
stream = Stream,
headers_as_is = headers_as_is(Headers0, Options),
socket_opts = SocketOpts,
- started = Started},
+ started = Started,
+ ipv6_host_with_brackets = BracketedHost},
case httpc_manager:request(Request, profile_name(Profile)) of
{ok, RequestId} ->
@@ -644,8 +653,6 @@ http_options_default() ->
{ok, {?HTTP_DEFAULT_SSL_KIND, Value}};
({ssl, SslOptions}) when is_list(SslOptions) ->
{ok, {?HTTP_DEFAULT_SSL_KIND, SslOptions}};
- ({ossl, SslOptions}) when is_list(SslOptions) ->
- {ok, {ossl, SslOptions}};
({essl, SslOptions}) when is_list(SslOptions) ->
{ok, {essl, SslOptions}};
(_) ->
@@ -742,14 +749,17 @@ request_options_defaults() ->
error
end,
+ VerifyBrackets = VerifyBoolean,
+
[
- {sync, true, VerifySync},
- {stream, none, VerifyStream},
- {body_format, string, VerifyBodyFormat},
- {full_result, true, VerifyFullResult},
- {headers_as_is, false, VerifyHeaderAsIs},
- {receiver, self(), VerifyReceiver},
- {socket_opts, undefined, VerifySocketOpts}
+ {sync, true, VerifySync},
+ {stream, none, VerifyStream},
+ {body_format, string, VerifyBodyFormat},
+ {full_result, true, VerifyFullResult},
+ {headers_as_is, false, VerifyHeaderAsIs},
+ {receiver, self(), VerifyReceiver},
+ {socket_opts, undefined, VerifySocketOpts},
+ {ipv6_host_with_brackets, false, VerifyBrackets}
].
request_options(Options) ->
diff --git a/lib/inets/src/http_client/httpc_internal.hrl b/lib/inets/src/http_client/httpc_internal.hrl
index 1d8a5b6a92..e4127d992d 100644
--- a/lib/inets/src/http_client/httpc_internal.hrl
+++ b/lib/inets/src/http_client/httpc_internal.hrl
@@ -90,25 +90,28 @@
%%% All data associated to a specific HTTP request
-record(request,
{
- id, % ref() - Request Id
- from, % pid() - Caller
- redircount = 0,% Number of redirects made for this request
- scheme, % http | https
- address, % ({Host,Port}) Destination Host and Port
- path, % string() - Path of parsed URL
- pquery, % string() - Rest of parsed URL
- method, % atom() - HTTP request Method
- headers, % #http_request_h{}
- content, % {ContentType, Body} - Current HTTP request
- settings, % #http_options{} - User defined settings
- abs_uri, % string() ex: "http://www.erlang.org"
- userinfo, % string() - optinal "<userinfo>@<host>:<port>"
- stream, % Boolean() - stream async reply?
- headers_as_is, % Boolean() - workaround for servers that does
- % not honor the http standard, can also be used for testing purposes.
- started, % integer() > 0 - When we started processing the request
- timer, % undefined | ref()
- socket_opts % undefined | [socket_option()]
+ id, % ref() - Request Id
+ from, % pid() - Caller
+ redircount = 0,% Number of redirects made for this request
+ scheme, % http | https
+ address, % ({Host,Port}) Destination Host and Port
+ path, % string() - Path of parsed URL
+ pquery, % string() - Rest of parsed URL
+ method, % atom() - HTTP request Method
+ headers, % #http_request_h{}
+ content, % {ContentType, Body} - Current HTTP request
+ settings, % #http_options{} - User defined settings
+ abs_uri, % string() ex: "http://www.erlang.org"
+ userinfo, % string() - optinal "<userinfo>@<host>:<port>"
+ stream, % boolean() - stream async reply?
+ headers_as_is, % boolean() - workaround for servers that does
+ % not honor the http standard, can also be used
+ % for testing purposes.
+ started, % integer() > 0 - When we started processing the
+ % request
+ timer, % undefined | ref()
+ socket_opts, % undefined | [socket_option()]
+ ipv6_host_with_brackets % boolean()
}
).
diff --git a/lib/inets/src/http_client/httpc_manager.erl b/lib/inets/src/http_client/httpc_manager.erl
index 9015bf1ce2..ab575d867e 100644
--- a/lib/inets/src/http_client/httpc_manager.erl
+++ b/lib/inets/src/http_client/httpc_manager.erl
@@ -256,19 +256,27 @@ reset_cookies(ProfileName) ->
%%--------------------------------------------------------------------
-%% Function: which_cookies(Url, ProfileName) -> [cookie()]
+%% Function: which_cookies(ProfileName) -> [cookie()]
+%% which_cookies(Url, ProfileName) -> [cookie()]
+%% which_cookies(Url, Options, ProfileName) -> [cookie()]
%%
%% Url = string()
+%% Options = [option()]
%% ProfileName = atom()
+%% option() = {ipv6_host_with_brackets, boolean()}
%%
%% Description: Retrieves the cookies that would be sent when
%% requesting <Url>.
%%--------------------------------------------------------------------
-which_cookies(ProfileName) ->
+which_cookies(ProfileName) when is_atom(ProfileName) ->
call(ProfileName, which_cookies).
-which_cookies(Url, ProfileName) ->
- call(ProfileName, {which_cookies, Url}).
+which_cookies(Url, ProfileName)
+ when is_list(Url) andalso is_atom(ProfileName) ->
+ call(ProfileName, {which_cookies, Url, []}).
+which_cookies(Url, Options, ProfileName)
+ when is_list(Url) andalso is_list(Options) andalso is_atom(ProfileName) ->
+ call(ProfileName, {which_cookies, Url, Options}).
%%--------------------------------------------------------------------
@@ -395,15 +403,16 @@ handle_call(which_cookies, _, #state{cookie_db = CookieDb} = State) ->
CookieHeaders = httpc_cookie:which_cookies(CookieDb),
{reply, CookieHeaders, State};
-handle_call({which_cookies, Url}, _, #state{cookie_db = CookieDb} = State) ->
- ?hcrv("which cookies", [{url, Url}]),
- case http_uri:parse(Url) of
- {Scheme, _, Host, Port, Path, _} ->
+handle_call({which_cookies, Url, Options}, _,
+ #state{cookie_db = CookieDb} = State) ->
+ ?hcrv("which cookies", [{url, Url}, {options, Options}]),
+ case http_uri:parse(Url, Options) of
+ {ok, {Scheme, _, Host, Port, Path, _}} ->
CookieHeaders =
httpc_cookie:header(CookieDb, Scheme, {Host, Port}, Path),
{reply, CookieHeaders, State};
- Msg ->
- {reply, Msg, State}
+ {error, _} = ERROR ->
+ {reply, ERROR, State}
end;
handle_call(info, _, State) ->
diff --git a/lib/inets/src/http_client/httpc_response.erl b/lib/inets/src/http_client/httpc_response.erl
index 207b96271c..2414ed0911 100644
--- a/lib/inets/src/http_client/httpc_response.erl
+++ b/lib/inets/src/http_client/httpc_response.erl
@@ -340,7 +340,9 @@ redirect(Response = {StatusLine, Headers, Body}, Request) ->
undefined ->
transparent(Response, Request);
RedirUrl ->
- case http_uri:parse(RedirUrl) of
+ UrlParseOpts = [{ipv6_host_with_brackets,
+ Request#request.ipv6_host_with_brackets}],
+ case http_uri:parse(RedirUrl, UrlParseOpts) of
{error, no_scheme} when
(Request#request.settings)#http_options.relaxed ->
NewLocation = fix_relative_uri(Request, RedirUrl),
@@ -350,10 +352,9 @@ redirect(Response = {StatusLine, Headers, Body}, Request) ->
{error, Reason} ->
{ok, error(Request, Reason), Data};
%% Automatic redirection
- {Scheme, _, Host, Port, Path, Query} ->
+ {ok, {Scheme, _, Host, Port, Path, Query}} ->
NewHeaders =
- (Request#request.headers)#http_request_h{host =
- Host},
+ (Request#request.headers)#http_request_h{host = Host},
NewRequest =
Request#request{redircount =
Request#request.redircount+1,
diff --git a/lib/inets/src/http_lib/http_internal.hrl b/lib/inets/src/http_lib/http_internal.hrl
index 2e924667c6..97cf474ab9 100644
--- a/lib/inets/src/http_lib/http_internal.hrl
+++ b/lib/inets/src/http_lib/http_internal.hrl
@@ -28,7 +28,6 @@
-define(HTTP_MAX_URI_SIZE, nolimit).
-ifndef(HTTP_DEFAULT_SSL_KIND).
-%% -define(HTTP_DEFAULT_SSL_KIND, ossl).
-define(HTTP_DEFAULT_SSL_KIND, essl).
-endif. % -ifdef(HTTP_DEFAULT_SSL_KIND).
diff --git a/lib/inets/src/http_lib/http_transport.erl b/lib/inets/src/http_lib/http_transport.erl
index 9b8190ebed..5eb827032f 100644
--- a/lib/inets/src/http_lib/http_transport.erl
+++ b/lib/inets/src/http_lib/http_transport.erl
@@ -62,8 +62,6 @@ start(ip_comm) ->
%% This is just for backward compatibillity
start({ssl, _}) ->
do_start_ssl();
-start({ossl, _}) ->
- do_start_ssl();
start({essl, _}) ->
do_start_ssl().
@@ -126,22 +124,6 @@ connect(ip_comm = _SocketType, {Host, Port}, Opts0, Timeout)
connect({ssl, SslConfig}, Address, Opts, Timeout) ->
connect({?HTTP_DEFAULT_SSL_KIND, SslConfig}, Address, Opts, Timeout);
-connect({ossl, SslConfig}, {Host, Port}, _, Timeout) ->
- Opts = [binary, {active, false}, {ssl_imp, old}] ++ SslConfig,
- ?hlrt("connect using ossl",
- [{host, Host},
- {port, Port},
- {ssl_config, SslConfig},
- {timeout, Timeout}]),
- case (catch ssl:connect(Host, Port, Opts, Timeout)) of
- {'EXIT', Reason} ->
- {error, {eoptions, Reason}};
- {ok, _} = OK ->
- OK;
- {error, _} = ERROR ->
- ERROR
- end;
-
connect({essl, SslConfig}, {Host, Port}, Opts0, Timeout) ->
Opts = [binary, {active, false}, {ssl_imp, new} | Opts0] ++ SslConfig,
?hlrt("connect using essl",
@@ -187,13 +169,6 @@ listen({ssl, SSLConfig}, Addr, Port) ->
{ssl_config, SSLConfig}]),
listen({?HTTP_DEFAULT_SSL_KIND, SSLConfig}, Addr, Port);
-listen({ossl, SSLConfig}, Addr, Port) ->
- ?hlrt("listen (ossl)",
- [{addr, Addr},
- {port, Port},
- {ssl_config, SSLConfig}]),
- listen_ssl(Addr, Port, [{ssl_imp, old} | SSLConfig]);
-
listen({essl, SSLConfig}, Addr, Port) ->
?hlrt("listen (essl)",
[{addr, Addr},
@@ -353,8 +328,6 @@ accept(ip_comm, ListenSocket, Timeout) ->
accept({ssl, SSLConfig}, ListenSocket, Timeout) ->
accept({?HTTP_DEFAULT_SSL_KIND, SSLConfig}, ListenSocket, Timeout);
-accept({ossl, _SSLConfig}, ListenSocket, Timeout) ->
- ssl:transport_accept(ListenSocket, Timeout);
accept({essl, _SSLConfig}, ListenSocket, Timeout) ->
ssl:transport_accept(ListenSocket, Timeout).
@@ -374,9 +347,6 @@ controlling_process(ip_comm, Socket, NewOwner) ->
controlling_process({ssl, SSLConfig}, Socket, NewOwner) ->
controlling_process({?HTTP_DEFAULT_SSL_KIND, SSLConfig}, Socket, NewOwner);
-controlling_process({ossl, _}, Socket, NewOwner) ->
- ssl:controlling_process(Socket, NewOwner);
-
controlling_process({essl, _}, Socket, NewOwner) ->
ssl:controlling_process(Socket, NewOwner).
@@ -397,13 +367,6 @@ setopts(ip_comm, Socket, Options) ->
setopts({ssl, SSLConfig}, Socket, Options) ->
setopts({?HTTP_DEFAULT_SSL_KIND, SSLConfig}, Socket, Options);
-setopts({ossl, _}, Socket, Options) ->
- ?hlrt("[o]ssl setopts", [{socket, Socket}, {options, Options}]),
- Reason = (catch ssl:setopts(Socket, Options)),
- ?hlrt("[o]ssl setopts result", [{reason, Reason}]),
- Reason;
-
-
setopts({essl, _}, Socket, Options) ->
?hlrt("[e]ssl setopts", [{socket, Socket}, {options, Options}]),
Reason = (catch ssl:setopts(Socket, Options)),
@@ -435,10 +398,6 @@ getopts(ip_comm, Socket, Options) ->
getopts({ssl, SSLConfig}, Socket, Options) ->
getopts({?HTTP_DEFAULT_SSL_KIND, SSLConfig}, Socket, Options);
-getopts({ossl, _}, Socket, Options) ->
- ?hlrt("ssl getopts", [{socket, Socket}, {options, Options}]),
- getopts_ssl(Socket, Options);
-
getopts({essl, _}, Socket, Options) ->
?hlrt("essl getopts", [{socket, Socket}, {options, Options}]),
getopts_ssl(Socket, Options).
@@ -472,9 +431,6 @@ getstat(ip_comm = _SocketType, Socket) ->
getstat({ssl, SSLConfig}, Socket) ->
getstat({?HTTP_DEFAULT_SSL_KIND, SSLConfig}, Socket);
-getstat({ossl, _} = _SocketType, _Socket) ->
- [];
-
getstat({essl, _} = _SocketType, _Socket) ->
[].
@@ -493,9 +449,6 @@ send(ip_comm, Socket, Message) ->
send({ssl, SSLConfig}, Socket, Message) ->
send({?HTTP_DEFAULT_SSL_KIND, SSLConfig}, Socket, Message);
-send({ossl, _}, Socket, Message) ->
- ssl:send(Socket, Message);
-
send({essl, _}, Socket, Message) ->
ssl:send(Socket, Message).
@@ -514,9 +467,6 @@ close(ip_comm, Socket) ->
close({ssl, SSLConfig}, Socket) ->
close({?HTTP_DEFAULT_SSL_KIND, SSLConfig}, Socket);
-close({ossl, _}, Socket) ->
- ssl:close(Socket);
-
close({essl, _}, Socket) ->
ssl:close(Socket).
@@ -538,9 +488,6 @@ peername(ip_comm, Socket) ->
peername({ssl, SSLConfig}, Socket) ->
peername({?HTTP_DEFAULT_SSL_KIND, SSLConfig}, Socket);
-peername({ossl, _}, Socket) ->
- do_peername(ssl:peername(Socket));
-
peername({essl, _}, Socket) ->
do_peername(ssl:peername(Socket)).
@@ -573,9 +520,6 @@ sockname(ip_comm, Socket) ->
sockname({ssl, SSLConfig}, Socket) ->
sockname({?HTTP_DEFAULT_SSL_KIND, SSLConfig}, Socket);
-sockname({ossl, _}, Socket) ->
- do_sockname(ssl:sockname(Socket));
-
sockname({essl, _}, Socket) ->
do_sockname(ssl:sockname(Socket)).
@@ -651,9 +595,6 @@ negotiate(ip_comm,_,_) ->
negotiate({ssl, SSLConfig}, Socket, Timeout) ->
?hlrt("negotiate(ssl)", []),
negotiate({?HTTP_DEFAULT_SSL_KIND, SSLConfig}, Socket, Timeout);
-negotiate({ossl, _}, Socket, Timeout) ->
- ?hlrt("negotiate(ossl)", []),
- negotiate_ssl(Socket, Timeout);
negotiate({essl, _}, Socket, Timeout) ->
?hlrt("negotiate(essl)", []),
negotiate_ssl(Socket, Timeout).
diff --git a/lib/inets/src/http_lib/http_uri.erl b/lib/inets/src/http_lib/http_uri.erl
index 44b9face0b..32c6305a79 100644
--- a/lib/inets/src/http_lib/http_uri.erl
+++ b/lib/inets/src/http_lib/http_uri.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2006-2010. All Rights Reserved.
+%% Copyright Ericsson AB 2006-2011. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -16,23 +16,30 @@
%%
%% %CopyrightEnd%
%%
-%%
+%%
+%% RFC 3986
+%%
-module(http_uri).
--export([parse/1, encode/1, decode/1]).
+-export([parse/1, parse/2,
+ encode/1, decode/1]).
+
%%%=========================================================================
%%% API
%%%=========================================================================
parse(AbsURI) ->
+ parse(AbsURI, []).
+
+parse(AbsURI, Opts) ->
case parse_scheme(AbsURI) of
{error, Reason} ->
{error, Reason};
{Scheme, Rest} ->
- case (catch parse_uri_rest(Scheme, Rest)) of
+ case (catch parse_uri_rest(Scheme, Rest, Opts)) of
{UserInfo, Host, Port, Path, Query} ->
- {Scheme, UserInfo, Host, Port, Path, Query};
+ {ok, {Scheme, UserInfo, Host, Port, Path, Query}};
_ ->
{error, {malformed_url, AbsURI}}
end
@@ -42,35 +49,38 @@ encode(URI) ->
Reserved = sets:from_list([$;, $:, $@, $&, $=, $+, $,, $/, $?,
$#, $[, $], $<, $>, $\", ${, $}, $|,
$\\, $', $^, $%, $ ]),
- lists:append(lists:map(fun(Char) ->
- uri_encode(Char, Reserved)
- end, URI)).
-
-decode([$%,Hex1,Hex2|Rest]) ->
- [hex2dec(Hex1)*16+hex2dec(Hex2)|decode(Rest)];
-decode([First|Rest]) ->
- [First|decode(Rest)];
-decode([]) ->
+ %% lists:append(lists:map(fun(Char) -> uri_encode(Char, Reserved) end, URI)).
+ lists:append([uri_encode(Char, Reserved) || Char <- URI]).
+
+decode(String) ->
+ do_decode(String).
+
+do_decode([$%,Hex1,Hex2|Rest]) ->
+ [hex2dec(Hex1)*16+hex2dec(Hex2)|do_decode(Rest)];
+do_decode([First|Rest]) ->
+ [First|do_decode(Rest)];
+do_decode([]) ->
[].
+
%%%========================================================================
%%% Internal functions
%%%========================================================================
+
parse_scheme(AbsURI) ->
case split_uri(AbsURI, ":", {error, no_scheme}, 1, 1) of
{error, no_scheme} ->
{error, no_scheme};
{StrScheme, Rest} ->
case list_to_atom(http_util:to_lower(StrScheme)) of
- Scheme when Scheme == http; Scheme == https ->
+ Scheme when (Scheme =:= http) orelse (Scheme =:= https) ->
{Scheme, Rest};
Scheme ->
{error, {not_supported_scheme, Scheme}}
end
end.
-parse_uri_rest(Scheme, "//" ++ URIPart) ->
-
+parse_uri_rest(Scheme, "//" ++ URIPart, Opts) ->
{Authority, PathQuery} =
case split_uri(URIPart, "/", URIPart, 1, 0) of
Split = {_, _} ->
@@ -85,8 +95,8 @@ parse_uri_rest(Scheme, "//" ++ URIPart) ->
end,
{UserInfo, HostPort} = split_uri(Authority, "@", {"", Authority}, 1, 1),
- {Host, Port} = parse_host_port(Scheme, HostPort),
- {Path, Query} = parse_path_query(PathQuery),
+ {Host, Port} = parse_host_port(Scheme, HostPort, Opts),
+ {Path, Query} = parse_path_query(PathQuery),
{UserInfo, Host, Port, Path, Query}.
@@ -94,13 +104,14 @@ parse_path_query(PathQuery) ->
{Path, Query} = split_uri(PathQuery, "\\?", {PathQuery, ""}, 1, 0),
{path(Path), Query}.
-parse_host_port(Scheme,"[" ++ HostPort) -> %ipv6
+parse_host_port(Scheme,"[" ++ HostPort, Opts) -> %ipv6
DefaultPort = default_port(Scheme),
{Host, ColonPort} = split_uri(HostPort, "\\]", {HostPort, ""}, 1, 1),
+ Host2 = maybe_ipv6_host_with_brackets(Host, Opts),
{_, Port} = split_uri(ColonPort, ":", {"", DefaultPort}, 0, 1),
- {Host, int_port(Port)};
+ {Host2, int_port(Port)};
-parse_host_port(Scheme, HostPort) ->
+parse_host_port(Scheme, HostPort, _Opts) ->
DefaultPort = default_port(Scheme),
{Host, Port} = split_uri(HostPort, ":", {HostPort, DefaultPort}, 1, 1),
{Host, int_port(Port)}.
@@ -114,6 +125,14 @@ split_uri(UriPart, SplitChar, NoMatchResult, SkipLeft, SkipRight) ->
NoMatchResult
end.
+maybe_ipv6_host_with_brackets(Host, Opts) ->
+ case lists:keysearch(ipv6_host_with_brackets, 1, Opts) of
+ {value, {ipv6_host_with_brackets, true}} ->
+ "[" ++ Host ++ "]";
+ _ ->
+ Host
+ end.
+
default_port(http) ->
80;
default_port(https) ->
diff --git a/lib/inets/src/http_lib/http_util.erl b/lib/inets/src/http_lib/http_util.erl
index 973600d7be..5b21170b78 100644
--- a/lib/inets/src/http_lib/http_util.erl
+++ b/lib/inets/src/http_lib/http_util.erl
@@ -206,9 +206,7 @@ timeout(Timeout, Started) ->
html_encode(Chars) ->
Reserved = sets:from_list([$&, $<, $>, $\", $', $/]),
- lists:append(lists:map(fun(Char) ->
- char_to_html_entity(Char, Reserved)
- end, Chars)).
+ lists:append([char_to_html_entity(Char, Reserved) || Char <- Chars]).
%%%========================================================================
diff --git a/lib/inets/src/http_server/httpd_conf.erl b/lib/inets/src/http_server/httpd_conf.erl
index 5352eb8bb9..7646300409 100644
--- a/lib/inets/src/http_server/httpd_conf.erl
+++ b/lib/inets/src/http_server/httpd_conf.erl
@@ -219,9 +219,8 @@ load("ServerName " ++ ServerName, []) ->
load("SocketType " ++ SocketType, []) ->
%% ssl is the same as HTTP_DEFAULT_SSL_KIND
- %% ossl is ssl based on OpenSSL (the "old" ssl)
%% essl is the pure Erlang-based ssl (the "new" ssl)
- case check_enum(clean(SocketType), ["ssl", "ossl", "essl", "ip_comm"]) of
+ case check_enum(clean(SocketType), ["ssl", "essl", "ip_comm"]) of
{ok, ValidSocketType} ->
{ok, [], {socket_type, ValidSocketType}};
{error,_} ->
@@ -541,7 +540,6 @@ validate_config_params([{server_name, Value} | _]) ->
validate_config_params([{socket_type, Value} | Rest])
when (Value =:= ip_comm) orelse
(Value =:= ssl) orelse
- (Value =:= ossl) orelse
(Value =:= essl) ->
validate_config_params(Rest);
validate_config_params([{socket_type, Value} | _]) ->
@@ -811,7 +809,7 @@ lookup_socket_type(ConfigDB) ->
case httpd_util:lookup(ConfigDB, socket_type, ip_comm) of
ip_comm ->
ip_comm;
- SSL when (SSL =:= ssl) orelse (SSL =:= ossl) orelse (SSL =:= essl) ->
+ SSL when (SSL =:= ssl) orelse (SSL =:= essl) ->
SSLTag =
if
(SSL =:= ssl) ->
diff --git a/lib/inets/src/http_server/httpd_file.erl b/lib/inets/src/http_server/httpd_file.erl
index e8a8ab6411..f2ba33099e 100644
--- a/lib/inets/src/http_server/httpd_file.erl
+++ b/lib/inets/src/http_server/httpd_file.erl
@@ -36,9 +36,9 @@ handle_error(emfile, Op, _ModData, Path) ->
handle_error(500, Op, none, Path, ": Too many open files");
handle_error({enfile,_}, Op, _ModData, Path) ->
handle_error(500, Op, none, Path, ": File table overflow");
-handle_error(_Reason, Op, ModData, Path) ->
- handle_error(404, Op, ModData, Path, ": File not found").
-
+handle_error(_Reason, Op, _ModData, Path) ->
+ handle_error(500, Op, none, Path, "").
+
handle_error(StatusCode, Op, none, Path, Reason) ->
{StatusCode, none, ?NICE("Can't " ++ Op ++ " " ++ Path ++ Reason)};
handle_error(StatusCode, Op, ModData, Path, Reason) ->
diff --git a/lib/inets/src/http_server/httpd_request.erl b/lib/inets/src/http_server/httpd_request.erl
index a04bcc2778..5ba79b2706 100644
--- a/lib/inets/src/http_server/httpd_request.erl
+++ b/lib/inets/src/http_server/httpd_request.erl
@@ -309,12 +309,12 @@ validate_uri(RequestURI) ->
(catch http_uri:decode(string:left(RequestURI, Ndx)))
end,
case UriNoQueryNoHex of
- {'EXIT',_Reason} ->
+ {'EXIT', _Reason} ->
{error, {bad_request, {malformed_syntax, RequestURI}}};
_ ->
Path = format_request_uri(UriNoQueryNoHex),
- Path2 = [X||X<-string:tokens(Path, "/\\"),X=/="."],
- validate_path( Path2,0, RequestURI)
+ Path2 = [X||X<-string:tokens(Path, "/"),X=/="."], %% OTP-5938
+ validate_path(Path2, 0, RequestURI)
end.
validate_path([], _, _) ->
diff --git a/lib/inets/src/http_server/httpd_request_handler.erl b/lib/inets/src/http_server/httpd_request_handler.erl
index c3b47ce390..d2f22fce93 100644
--- a/lib/inets/src/http_server/httpd_request_handler.erl
+++ b/lib/inets/src/http_server/httpd_request_handler.erl
@@ -1,8 +1,8 @@
%%
%% %CopyrightBegin%
-%%
+%%
%% Copyright Ericsson AB 1997-2011. All Rights Reserved.
-%%
+%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
%% compliance with the License. You should have received a copy of the
@@ -355,7 +355,7 @@ handle_http_msg({Method, Uri, Version, {RecordHeaders, Headers}, Body},
Reason = io_lib:format("Forbidden URI: ~p~n", [URI]),
error_log(Reason, ModData),
{stop, normal, State#state{response_sent = true}};
- {error,{bad_request, {malformed_syntax, URI}}} ->
+ {error, {bad_request, {malformed_syntax, URI}}} ->
?hdrd("validation failed: bad request - malformed syntax",
[{uri, URI}]),
httpd_response:send_status(ModData#mod{http_version = Version},
diff --git a/lib/inets/src/http_server/httpd_response.erl b/lib/inets/src/http_server/httpd_response.erl
index ea9cfbf4f2..dd7223876e 100644
--- a/lib/inets/src/http_server/httpd_response.erl
+++ b/lib/inets/src/http_server/httpd_response.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2009. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2011. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -78,6 +78,7 @@ traverse_modules(ModData,[Module|Rest]) ->
[Module, Reason])),
report_error(mod_log, ModData#mod.config_db, String),
report_error(mod_disk_log, ModData#mod.config_db, String),
+ send_status(ModData, 500, none),
done;
done ->
?hdrt("traverse modules - done", []),
@@ -100,12 +101,19 @@ send_status(#mod{socket_type = SocketType,
socket = Socket,
config_db = ConfigDB} = ModData, StatusCode, PhraseArgs) ->
+ ?hdrd("send status", [{status_code, StatusCode},
+ {phrase_args, PhraseArgs}]),
+
ReasonPhrase = httpd_util:reason_phrase(StatusCode),
Message = httpd_util:message(StatusCode, PhraseArgs, ConfigDB),
Body = get_body(ReasonPhrase, Message),
- send_header(ModData, StatusCode, [{content_type, "text/html"},
- {content_length, integer_to_list(length(Body))}]),
+ ?hdrt("send status - header", [{reason_phrase, ReasonPhrase},
+ {message, Message}]),
+ send_header(ModData, StatusCode,
+ [{content_type, "text/html"},
+ {content_length, integer_to_list(length(Body))}]),
+
httpd_socket:deliver(SocketType, Socket, Body).
@@ -345,8 +353,9 @@ transform({Field, Value}) when is_list(Field) ->
%% Leave this method and go on to the newer form of response
%% OTP-4408
%%----------------------------------------------------------------------
-send_response_old(#mod{method = "HEAD"} = ModData,
+send_response_old(#mod{method = "HEAD"} = ModData,
StatusCode, Response) ->
+
NewResponse = lists:flatten(Response),
case httpd_util:split(NewResponse, [?CR, ?LF, ?CR, ?LF],2) of
diff --git a/lib/inets/src/http_server/httpd_util.erl b/lib/inets/src/http_server/httpd_util.erl
index c051422529..b0b18b9c3d 100644
--- a/lib/inets/src/http_server/httpd_util.erl
+++ b/lib/inets/src/http_server/httpd_util.erl
@@ -178,11 +178,12 @@ message(301,URL,_) ->
"The document has moved <A HREF=\""++ maybe_encode(URL) ++"\">here</A>.";
message(304, _URL,_) ->
"The document has not been changed.";
-message(400,none,_) ->
- "Your browser sent a query that this server could not understand.";
-message(400,Msg,_) ->
- "Your browser sent a query that this server could not understand. "++ http_util:html_encode(Msg);
-message(401,none,_) ->
+message(400, none, _) ->
+ "Your browser sent a query that this server could not understand. ";
+message(400, Msg, _) ->
+ "Your browser sent a query that this server could not understand. " ++
+ html_encode(Msg);
+message(401, none, _) ->
"This server could not verify that you
are authorized to access the document you
requested. Either you supplied the wrong
@@ -190,40 +191,49 @@ credentials (e.g., bad password), or your
browser doesn't understand how to supply
the credentials required.";
message(403,RequestURI,_) ->
- "You don't have permission to access "++ http_util:html_encode(RequestURI) ++" on this server.";
+ "You don't have permission to access " ++
+ html_encode(RequestURI) ++
+ " on this server.";
message(404,RequestURI,_) ->
- "The requested URL " ++ http_util:html_encode(RequestURI) ++ " was not found on this server.";
+ "The requested URL " ++
+ html_encode(RequestURI) ++
+ " was not found on this server.";
message(408, Timeout, _) ->
Timeout;
message(412,none,_) ->
"The requested preconditions were false";
message(413, Reason,_) ->
- "Entity: " ++ http_util:html_encode(Reason);
+ "Entity: " ++ html_encode(Reason);
message(414,ReasonPhrase,_) ->
- "Message "++ http_util:html_encode(ReasonPhrase) ++".";
+ "Message " ++ html_encode(ReasonPhrase) ++ ".";
message(416,ReasonPhrase,_) ->
- http_util:html_encode(ReasonPhrase);
+ html_encode(ReasonPhrase);
message(500,_,ConfigDB) ->
ServerAdmin=lookup(ConfigDB,server_admin,"unknown@unknown"),
"The server encountered an internal error or "
"misconfiguration and was unable to complete "
"your request.<P>Please contact the server administrator "
- ++ http_util:html_encode(ServerAdmin) ++ ", and inform them of the time the error occurred "
+ ++ html_encode(ServerAdmin) ++
+ ", and inform them of the time the error occurred "
"and anything you might have done that may have caused the error.";
message(501,{Method, RequestURI, HTTPVersion}, _ConfigDB) ->
if
is_atom(Method) ->
- http_util:html_encode(atom_to_list(Method))++
- " to "++ http_util:html_encode(RequestURI)++" ("++ http_util:html_encode(HTTPVersion)++") not supported.";
+ atom_to_list(Method) ++
+ " to " ++
+ html_encode(RequestURI) ++
+ " (" ++ HTTPVersion ++ ") not supported.";
is_list(Method) ->
- http_util:html_encode(Method)++
- " to "++ http_util:html_encode(RequestURI)++" ("++ http_util:html_encode(HTTPVersion)++") not supported."
+ Method ++
+ " to " ++
+ html_encode(RequestURI) ++
+ " (" ++ HTTPVersion ++ ") not supported."
end;
message(503, String, _ConfigDB) ->
- "This service in unavailable due to: "++ http_util:html_encode(String).
+ "This service in unavailable due to: " ++ html_encode(String).
maybe_encode(URI) ->
Decoded = try http_uri:decode(URI) of
@@ -233,6 +243,15 @@ maybe_encode(URI) ->
end,
http_uri:encode(Decoded).
+html_encode(String) ->
+ try http_uri:decode(String) of
+ Decoded when is_list(Decoded) ->
+ http_util:html_encode(Decoded)
+ catch
+ _:_ ->
+ http_util:html_encode(String)
+ end.
+
%%convert_rfc_date(Date)->{{YYYY,MM,DD},{HH,MIN,SEC}}
convert_request_date([D,A,Y,DateType| Rest])->
@@ -245,7 +264,7 @@ convert_request_date([D,A,Y,DateType| Rest])->
fun convert_rfc850_date/1
end,
case catch Func([D,A,Y,DateType| Rest]) of
- {ok,Date} ->
+ {ok, Date} ->
Date;
_Error->
bad_date
diff --git a/lib/inets/src/http_server/mod_log.erl b/lib/inets/src/http_server/mod_log.erl
index c8a2ec0dc4..62faa285df 100644
--- a/lib/inets/src/http_server/mod_log.erl
+++ b/lib/inets/src/http_server/mod_log.erl
@@ -100,7 +100,7 @@ do(Info) ->
transfer_log(Info,"-",AuthUser,Date,StatusCode,Size),
{proceed,Info#mod.data};
{response, Head, _Body} ->
- Size = proplists:get_value(content_length,Head,unknown),
+ Size = content_length(Head),
Code = proplists:get_value(code,Head,unknown),
transfer_log(Info, "-", AuthUser, Date, Code, Size),
{proceed, Info#mod.data};
@@ -254,4 +254,10 @@ auth_user(Data) ->
RemoteUser
end.
-
+content_length(Head) ->
+ case proplists:get_value(content_length, Head) of
+ undefined ->
+ unknown;
+ Size ->
+ list_to_integer(Size)
+ end.
diff --git a/lib/inets/src/http_server/mod_responsecontrol.erl b/lib/inets/src/http_server/mod_responsecontrol.erl
index 5d5b60cdbd..989f45db20 100644
--- a/lib/inets/src/http_server/mod_responsecontrol.erl
+++ b/lib/inets/src/http_server/mod_responsecontrol.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2001-2010. All Rights Reserved.
+%% Copyright Ericsson AB 2001-2011. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -209,14 +209,14 @@ compare_etags(Tag,Etags) ->
nomatch
end.
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% %%
-%%Control if the file is modificated %%
-%% %%
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% %%
+%% Control if the file is modificated %%
+%% %%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%----------------------------------------------------------------------
-%%Control the If-Modified-Since and If-Not-Modified-Since header fields
+%% Control the If-Modified-Since and If-Not-Modified-Since header fields
%%----------------------------------------------------------------------
control_modification(Path,Info,FileInfo)->
?DEBUG("control_modification() -> entry",[]),
@@ -227,6 +227,8 @@ control_modification(Path,Info,FileInfo)->
continue;
unmodified->
{304, Info, Path};
+ {bad_date, _} = BadDate->
+ {400, Info, BadDate};
undefined ->
case control_modification_data(Info,
FileInfo#file_info.mtime,
@@ -253,21 +255,27 @@ control_modification_data(Info, ModificationTime, HeaderField)->
undefined->
undefined;
LastModified0 ->
- LastModified = calendar:universal_time_to_local_time(
- httpd_util:convert_request_date(LastModified0)),
- ?DEBUG("control_modification_data() -> "
- "~n Request-Field: ~s"
- "~n FileLastModified: ~p"
- "~n FieldValue: ~p",
- [HeaderField, ModificationTime, LastModified]),
- FileTime =
- calendar:datetime_to_gregorian_seconds(ModificationTime),
- FieldTime = calendar:datetime_to_gregorian_seconds(LastModified),
- if
- FileTime =< FieldTime ->
- ?DEBUG("File unmodified~n", []), unmodified;
- FileTime >= FieldTime ->
- ?DEBUG("File modified~n", []), modified
+ case httpd_util:convert_request_date(LastModified0) of
+ bad_date ->
+ {bad_date, LastModified0};
+ ConvertedReqDate ->
+ LastModified =
+ calendar:universal_time_to_local_time(ConvertedReqDate),
+ ?DEBUG("control_modification_data() -> "
+ "~n Request-Field: ~s"
+ "~n FileLastModified: ~p"
+ "~n FieldValue: ~p",
+ [HeaderField, ModificationTime, LastModified]),
+ FileTime =
+ calendar:datetime_to_gregorian_seconds(ModificationTime),
+ FieldTime =
+ calendar:datetime_to_gregorian_seconds(LastModified),
+ if
+ FileTime =< FieldTime ->
+ ?DEBUG("File unmodified~n", []), unmodified;
+ FileTime >= FieldTime ->
+ ?DEBUG("File modified~n", []), modified
+ end
end
end.
@@ -285,6 +293,9 @@ strip_date([C | Rest]) ->
send_return_value({412,_,_}, _FileInfo)->
{status,{412,none,"Precondition Failed"}};
+send_return_value({400,_, {bad_date, BadDate}}, _FileInfo)->
+ {status, {400, none, "Bad date: " ++ BadDate}};
+
send_return_value({304,Info,Path}, FileInfo)->
Suffix = httpd_util:suffix(Path),
MimeType = httpd_util:lookup_mime_default(Info#mod.config_db,Suffix,
diff --git a/lib/inets/src/inets_app/Makefile b/lib/inets/src/inets_app/Makefile
index 20e22917e2..63ab0a5bae 100644
--- a/lib/inets/src/inets_app/Makefile
+++ b/lib/inets/src/inets_app/Makefile
@@ -30,6 +30,7 @@ include ../../vsn.mk
VSN = $(INETS_VSN)
+
# ----------------------------------------------------
# Release directory specification
# ----------------------------------------------------
@@ -41,8 +42,8 @@ RELSYSDIR = $(RELEASE_PATH)/lib/$(APPLICATION)-$(VSN)
# ----------------------------------------------------
MODULES = \
- inets_service \
inets \
+ inets_service \
inets_app \
inets_sup \
inets_regexp
diff --git a/lib/inets/src/inets_app/inets.app.src b/lib/inets/src/inets_app/inets.app.src
index cb036157a5..4d0defb329 100644
--- a/lib/inets/src/inets_app/inets.app.src
+++ b/lib/inets/src/inets_app/inets.app.src
@@ -34,8 +34,7 @@
ftp_sup,
%% HTTP client:
- http, %% Old client API module
- httpc, %% New client API module
+ httpc,
httpc_handler,
httpc_handler_sup,
httpc_manager,
diff --git a/lib/inets/src/inets_app/inets.appup.src b/lib/inets/src/inets_app/inets.appup.src
index d5fdf86a60..779dd8e439 100644
--- a/lib/inets/src/inets_app/inets.appup.src
+++ b/lib/inets/src/inets_app/inets.appup.src
@@ -18,85 +18,47 @@
{"%VSN%",
[
- {"5.7",
- [
- {load_module, httpd_request, soft_purge, soft_purge, []},
- {load_module, httpc_cookie, soft_purge, soft_purge, [http_util]},
- {load_module, http_util, soft_purge, soft_purge, []}
- ]
- },
- {"5.6",
- [
- {load_module, httpd_request, soft_purge, soft_purge, []},
- {load_module, httpc, soft_purge, soft_purge, [httpc_manager]},
- {load_module, http_transport, soft_purge, soft_purge, [http_transport]},
- {load_module, httpc_cookie, soft_purge, soft_purge, [http_util]},
- {load_module, http_util, soft_purge, soft_purge, []},
- {update, httpc_handler, soft, soft_purge, soft_purge, []},
- {update, httpc_manager, soft, soft_purge, soft_purge, [httpc_handler]},
- {update, ftp, soft, soft_purge, soft_purge, []}
- ]
- },
- {"5.5.2",
+ {"5.7.2",
[
{restart_application, inets}
]
},
- {"5.5.1",
+ {"5.7.1",
[
{restart_application, inets}
]
},
- {"5.5",
+ {"5.7",
[
{restart_application, inets}
]
},
- {"5.4",
+ {"5.6",
[
{restart_application, inets}
]
}
],
[
- {"5.7",
- [
- {load_module, httpd_request, soft_purge, soft_purge, []},
- {load_module, httpc_cookie, soft_purge, soft_purge, [http_util]},
- {load_module, http_util, soft_purge, soft_purge, []}
- ]
- },
- {"5.6",
- [
- {load_module, httpd_request, soft_purge, soft_purge, []},
- {load_module, httpc, soft_purge, soft_purge, [httpc_manager]},
- {load_module, http_transport, soft_purge, soft_purge, [http_transport]},
- {load_module, httpc_cookie, soft_purge, soft_purge, [http_util]},
- {load_module, http_util, soft_purge, soft_purge, []},
- {update, httpc_handler, soft, soft_purge, soft_purge, []},
- {update, httpc_manager, soft, soft_purge, soft_purge, [httpc_handler]},
- {update, ftp, soft, soft_purge, soft_purge, []}
- ]
- },
- {"5.5.2",
+ {"5.7.2",
[
{restart_application, inets}
]
- },
- {"5.5.1",
+ },
+ {"5.7.1",
[
{restart_application, inets}
]
},
- {"5.5",
+ {"5.7",
[
{restart_application, inets}
]
- },
- {"5.4",
+ },
+ {"5.6",
[
{restart_application, inets}
]
- }
+ }
]
}.
diff --git a/lib/inets/src/inets_app/inets.mk b/lib/inets/src/inets_app/inets.mk
index b6e9fe1d96..35fb0d7eca 100644
--- a/lib/inets/src/inets_app/inets.mk
+++ b/lib/inets/src/inets_app/inets.mk
@@ -33,6 +33,10 @@ ifeq ($(WARN_UNUSED_WARS), true)
ERL_COMPILE_FLAGS += +warn_unused_vars
endif
+ifeq ($(shell erl -noshell -eval 'io:format("~4s", [erlang:system_info(otp_release)])' -s init stop), R14B)
+INETS_ERL_COMPILE_FLAGS += -D'OTP-R14B-COMPILER'
+endif
+
INETS_APP_VSN_COMPILE_FLAGS = \
+'{parse_transform,sys_pre_attributes}' \
+'{attribute,insert,app_vsn,$(APP_VSN)}'
diff --git a/lib/inets/src/inets_app/inets_service.erl b/lib/inets/src/inets_app/inets_service.erl
index e9eb9892f2..a057a51e2c 100644
--- a/lib/inets/src/inets_app/inets_service.erl
+++ b/lib/inets/src/inets_app/inets_service.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2007-2010. All Rights Reserved.
+%% Copyright Ericsson AB 2007-2011. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -20,24 +20,35 @@
-module(inets_service).
+-ifdef('OTP-R14B-COMPILER').
+
-export([behaviour_info/1]).
behaviour_info(callbacks) ->
- [{start_standalone, 1},
- {start_service, 1},
- {stop_service, 1},
- {services, 0},
- {service_info, 1}];
+ [{start_standalone, 1},
+ {start_service, 1},
+ {stop_service, 1},
+ {services, 0},
+ {service_info, 1}];
behaviour_info(_) ->
- undefined.
+ undefined.
+
+-else.
%% Starts service stand-alone
%% start_standalone(Config) -> % {ok, Pid} | {error, Reason}
%% <service>:start_link(Config).
+-callback start_standalone(Config :: term()) ->
+ {ok, pid()} | {error, Reason :: term()}.
+
%% Starts service as part of inets
%% start_service(Config) -> % {ok, Pid} | {error, Reason}
%% <service_sup>:start_child(Config).
+
+-callback start_service(Config :: term()) ->
+ {ok, pid()} | {error, Reason :: term()}.
+
%% Stop service
%% stop_service(Pid) -> % ok | {error, Reason}
%% <service_sup>:stop_child(maybe_map_pid_to_other_ref(Pid)).
@@ -51,6 +62,9 @@ behaviour_info(_) ->
%% Error
%% end.
+-callback stop_service(Service :: term()) ->
+ ok | {error, Reason :: term()}.
+
%% Returns list of running services. Services started as stand alone
%% are not listed
%% services() -> % [{Service, Pid}]
@@ -59,7 +73,14 @@ behaviour_info(_) ->
%% [{httpc, Pid} || {_, Pid, _, _} <-
%% supervisor:which_children(httpc_profile_sup)].
+-callback services() ->
+ [{Service :: term(), pid()}].
-%% service_info() -> [{Property, Value}] | {error, Reason}
+%% service_info() -> {ok, [{Property, Value}]} | {error, Reason}
%% ex: httpc:service_info() -> [{profile, ProfileName}]
%% httpd:service_info() -> [{host, Host}, {port, Port}]
+
+-callback service_info(Service :: term()) ->
+ {ok, [{Property :: term(), Value :: term()}]} | {error, Reason :: term()}.
+
+-endif.
diff --git a/lib/inets/src/tftp/tftp.erl b/lib/inets/src/tftp/tftp.erl
index bfdb4c0030..8d8fce388d 100644
--- a/lib/inets/src/tftp/tftp.erl
+++ b/lib/inets/src/tftp/tftp.erl
@@ -215,8 +215,6 @@
start/0
]).
--export([behaviour_info/1]).
-
%% Application local functions
-export([
start_standalone/1,
@@ -226,14 +224,67 @@
service_info/1
]).
+-ifdef('OTP-R14B-COMPILER').
+
+-export([behaviour_info/1]).
behaviour_info(callbacks) ->
- [{prepare, 6}, {open, 6}, {read, 1}, {write, 2}, {abort, 3}];
+ [{prepare, 6},
+ {open, 6},
+ {read, 1},
+ {write, 2},
+ {abort, 3}];
behaviour_info(_) ->
undefined.
+-else.
+
+-type peer() :: {PeerType :: inet | inet6,
+ PeerHost :: inet:ip_address(),
+ PeerPort :: port()}.
+
+-type access() :: read | write.
+
+-type options() :: [{Key :: string(), Value :: string()}].
+
+-type error_code() :: undef | enoent | eacces | enospc |
+ badop | eexist | baduser | badopt |
+ integer().
+
+-callback prepare(Peer :: peer(),
+ Access :: access(),
+ Filename :: file:name(),
+ Mode :: string(),
+ SuggestedOptions :: options(),
+ InitialState :: [] | [{root_dir, string()}]) ->
+ {ok, AcceptedOptions :: options(), NewState :: term()} |
+ {error, {Code :: error_code(), string()}}.
+
+-callback open(Peer :: peer(),
+ Access :: access(),
+ Filename :: file:name(),
+ Mode :: string(),
+ SuggestedOptions :: options(),
+ State :: [] | [{root_dir, string()}] | term()) ->
+ {ok, AcceptedOptions :: options(), NewState :: term()} |
+ {error, {Code :: error_code(), string()}}.
+
+-callback read(State :: term()) -> {more, binary(), NewState :: term()} |
+ {last, binary(), integer()} |
+ {error, {Code :: error_code(), string()}}.
+
+-callback write(binary(), State :: term()) ->
+ {more, NewState :: term()} |
+ {last, FileSize :: integer()} |
+ {error, {Code :: error_code(), string()}}.
+
+-callback abort(Code :: error_code(), string(), State :: term()) -> 'ok'.
+
+-endif.
+
-include("tftp.hrl").
+
%%-------------------------------------------------------------------
%% read_file(RemoteFilename, LocalFilename, Options) ->
%% {ok, LastCallbackState} | {error, Reason}
diff --git a/lib/inets/test/ftp_suite_lib.erl b/lib/inets/test/ftp_suite_lib.erl
index 3ebd02229e..ffb58c91b6 100644
--- a/lib/inets/test/ftp_suite_lib.erl
+++ b/lib/inets/test/ftp_suite_lib.erl
@@ -196,7 +196,9 @@ test_filenames() ->
%% variable, but should NOT alter/remove any existing entries.
%%--------------------------------------------------------------------
init_per_testcase(Case, Config)
- when (Case =:= open) orelse (Case =:= open_port) ->
+ when (Case =:= open) orelse
+ (Case =:= open_port) ->
+ put(ftp_testcase, Case),
io:format(user, "~n~n*** INIT ~w:~w ***~n~n", [?MODULE, Case]),
inets:start(),
NewConfig = data_dir(Config),
@@ -266,7 +268,7 @@ do_init_per_testcase(Case, Config) ->
end,
Opts2 =
case string:tokens(atom_to_list(Case), [$_]) of
- [_, "active" | _] ->
+ ["active" | _] ->
[{mode, active} | Opts1];
_ ->
[{mode, passive} | Opts1]
@@ -367,8 +369,11 @@ open(Config) when is_list(Config) ->
tc_open(Host) ->
+ p("tc_open -> entry with"
+ "~n Host: ~p", [Host]),
{ok, Pid} = ?ftp_open(Host, []),
ok = ftp:close(Pid),
+ p("tc_open -> try (ok) open 1"),
{ok, Pid1} =
ftp:open({option_list, [{host,Host},
{port, ?FTP_PORT},
@@ -376,11 +381,13 @@ tc_open(Host) ->
{timeout, 30000}]}),
ok = ftp:close(Pid1),
+ p("tc_open -> try (fail) open 2"),
{error, ehost} =
ftp:open({option_list, [{port, ?FTP_PORT}, {flags, [verbose]}]}),
{ok, Pid2} = ftp:open(Host),
ok = ftp:close(Pid2),
+ p("tc_open -> try (ok) open 3"),
{ok, NewHost} = inet:getaddr(Host, inet),
{ok, Pid3} = ftp:open(NewHost),
ftp:user(Pid3, ?FTP_USER, ?FTP_PASS),
@@ -392,33 +399,68 @@ tc_open(Host) ->
%% Bad input that has default values are ignored and the defult
%% is used.
+ p("tc_open -> try (ok) open 4"),
{ok, Pid4} =
- ftp:open({option_list, [{host, Host}, {port, badarg},
- {flags, [verbose]},
+ ftp:open({option_list, [{host, Host},
+ {port, badarg},
+ {flags, [verbose]},
{timeout, 30000}]}),
test_server:sleep(100),
ok = ftp:close(Pid4),
+
+ p("tc_open -> try (ok) open 5"),
{ok, Pid5} =
- ftp:open({option_list, [{host, Host}, {port, ?FTP_PORT},
- {flags, [verbose]},
+ ftp:open({option_list, [{host, Host},
+ {port, ?FTP_PORT},
+ {flags, [verbose]},
{timeout, -42}]}),
test_server:sleep(100),
ok = ftp:close(Pid5),
+
+ p("tc_open -> try (ok) open 6"),
{ok, Pid6} =
- ftp:open({option_list, [{host, Host}, {port, ?FTP_PORT},
+ ftp:open({option_list, [{host, Host},
+ {port, ?FTP_PORT},
{flags, [verbose]},
- {mode, cool}]}),
+ {mode, cool}]}),
test_server:sleep(100),
ok = ftp:close(Pid6),
+ p("tc_open -> try (ok) open 7"),
{ok, Pid7} =
ftp:open(Host, [{port, ?FTP_PORT}, {verbose, true}, {timeout, 30000}]),
ok = ftp:close(Pid7),
+ p("tc_open -> try (ok) open 8"),
{ok, Pid8} =
ftp:open(Host, ?FTP_PORT),
ok = ftp:close(Pid8),
+ p("tc_open -> try (ok) open 9"),
+ {ok, Pid9} =
+ ftp:open(Host, [{port, ?FTP_PORT},
+ {verbose, true},
+ {timeout, 30000},
+ {dtimeout, -99}]),
+ ok = ftp:close(Pid9),
+
+ p("tc_open -> try (ok) open 10"),
+ {ok, Pid10} =
+ ftp:open(Host, [{port, ?FTP_PORT},
+ {verbose, true},
+ {timeout, 30000},
+ {dtimeout, "foobar"}]),
+ ok = ftp:close(Pid10),
+
+ p("tc_open -> try (ok) open 11"),
+ {ok, Pid11} =
+ ftp:open(Host, [{port, ?FTP_PORT},
+ {verbose, true},
+ {timeout, 30000},
+ {dtimeout, 1}]),
+ ok = ftp:close(Pid11),
+
+ p("tc_open -> done"),
ok.
@@ -445,7 +487,7 @@ passive_user(suite) ->
[];
passive_user(Config) when is_list(Config) ->
Pid = ?config(ftp, Config),
- io:format("Pid: ~p~n",[Pid]),
+ p("Pid: ~p",[Pid]),
do_user(Pid).
@@ -967,13 +1009,13 @@ api_missuse(doc)->
["Test that behaviour of the ftp process if the api is abused"];
api_missuse(suite) -> [];
api_missuse(Config) when is_list(Config) ->
- io:format("api_missuse -> entry~n", []),
+ p("api_missuse -> entry"),
Flag = process_flag(trap_exit, true),
Pid = ?config(ftp, Config),
Host = ftp_host(Config),
%% Serious programming fault, connetion will be shut down
- io:format("api_missuse -> verify bad call termination (~p)~n", [Pid]),
+ p("api_missuse -> verify bad call termination (~p)", [Pid]),
case (catch gen_server:call(Pid, {self(), foobar, 10}, infinity)) of
{error, {connection_terminated, 'API_violation'}} ->
ok;
@@ -983,23 +1025,23 @@ api_missuse(Config) when is_list(Config) ->
test_server:sleep(500),
undefined = process_info(Pid, status),
- io:format("api_missuse -> start new client~n", []),
+ p("api_missuse -> start new client"),
{ok, Pid2} = ?ftp_open(Host, []),
%% Serious programming fault, connetion will be shut down
- io:format("api_missuse -> verify bad cast termination~n", []),
+ p("api_missuse -> verify bad cast termination"),
gen_server:cast(Pid2, {self(), foobar, 10}),
test_server:sleep(500),
undefined = process_info(Pid2, status),
- io:format("api_missuse -> start new client~n", []),
+ p("api_missuse -> start new client"),
{ok, Pid3} = ?ftp_open(Host, []),
%% Could be an innocent misstake the connection lives.
- io:format("api_missuse -> verify bad bang~n", []),
+ p("api_missuse -> verify bad bang"),
Pid3 ! foobar,
test_server:sleep(500),
{status, _} = process_info(Pid3, status),
process_flag(trap_exit, Flag),
- io:format("api_missuse -> done~n", []),
+ p("api_missuse -> done"),
ok.
@@ -1567,9 +1609,9 @@ split([], I, Is) ->
lists:reverse([lists:reverse(I)| Is]).
do_ftp_open(Host, Opts) ->
- io:format("do_ftp_open -> entry with"
- "~n Host: ~p"
- "~n Opts: ~p", [Host, Opts]),
+ p("do_ftp_open -> entry with"
+ "~n Host: ~p"
+ "~n Opts: ~p", [Host, Opts]),
case ftp:open(Host, Opts) of
{ok, _} = OK ->
OK;
@@ -1595,7 +1637,7 @@ passwd() ->
ftpd_hosts(Config) ->
DataDir = ?config(data_dir, Config),
FileName = filename:join([DataDir, "../ftp_SUITE_data/", ftpd_hosts]),
- io:format("FileName: ~p~n", [FileName]),
+ p("FileName: ~p", [FileName]),
case file:consult(FileName) of
{ok, [Hosts]} when is_list(Hosts) ->
Hosts;
diff --git a/lib/inets/test/ftp_windows_2003_server_test.erl b/lib/inets/test/ftp_windows_2003_server_test.erl
index 57f1ae8358..32f25713f8 100644
--- a/lib/inets/test/ftp_windows_2003_server_test.erl
+++ b/lib/inets/test/ftp_windows_2003_server_test.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2005-2010. All Rights Reserved.
+%% Copyright Ericsson AB 2005-2011. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -87,14 +87,22 @@ end_per_testcase(Case, Config) ->
%% Description: Returns a list of all test cases in this test suite
%%--------------------------------------------------------------------
all() ->
- [open, open_port, {group, passive}, {group, active},
- api_missuse, not_owner, {group, progress_report}].
+ [
+ open,
+ open_port,
+ {group, passive},
+ {group, active},
+ api_missuse,
+ not_owner,
+ {group, progress_report}
+ ].
groups() ->
- [{passive, [], ftp_suite_lib:passive(suite)},
- {active, [], ftp_suite_lib:active(suite)},
- {progress_report, [],
- ftp_suite_lib:progress_report(suite)}].
+ [
+ {passive, [], ftp_suite_lib:passive(suite)},
+ {active, [], ftp_suite_lib:active(suite)},
+ {progress_report, [], ftp_suite_lib:progress_report(suite)}
+ ].
init_per_group(_GroupName, Config) ->
Config.
diff --git a/lib/inets/test/httpc_SUITE.erl b/lib/inets/test/httpc_SUITE.erl
index 6edd5371af..d86e52f3d5 100644
--- a/lib/inets/test/httpc_SUITE.erl
+++ b/lib/inets/test/httpc_SUITE.erl
@@ -113,13 +113,10 @@ groups() ->
proxy_page_does_not_exist,
proxy_https_not_supported]},
{ssl, [], [ssl_head,
- ossl_head,
essl_head,
ssl_get,
- ossl_get,
essl_get,
ssl_trace,
- ossl_trace,
essl_trace]},
{stream, [], [http_stream,
http_stream_once,
@@ -253,10 +250,10 @@ init_per_testcase(Case, Config) ->
init_per_testcase(Case, 2, Config).
init_per_testcase(Case, Timeout, Config) ->
- io:format(user, "~n~n*** INIT ~w:~w[~w] ***~n~n",
- [?MODULE, Case, Timeout]),
- PrivDir = ?config(priv_dir, Config),
- tsp("init_per_testcase -> stop inets"),
+ io:format(user,
+ "~n~n*** INIT ~w:~w[~w] ***"
+ "~n~n", [?MODULE, Case, Timeout]),
+ PrivDir = ?config(priv_dir, Config),
application:stop(inets),
Dog = test_server:timetrap(inets_test_lib:minutes(Timeout)),
TmpConfig = lists:keydelete(watchdog, 1, Config),
@@ -273,10 +270,6 @@ init_per_testcase(Case, Timeout, Config) ->
init_per_testcase_ssl(ssl, PrivDir, SslConfFile,
[{watchdog, Dog} | TmpConfig]);
- [$o, $s, $s, $l | _] ->
- init_per_testcase_ssl(ossl, PrivDir, SslConfFile,
- [{watchdog, Dog} | TmpConfig]);
-
[$e, $s, $s, $l | _] ->
init_per_testcase_ssl(essl, PrivDir, SslConfFile,
[{watchdog, Dog} | TmpConfig]);
@@ -296,12 +289,12 @@ init_per_testcase(Case, Timeout, Config) ->
throw:{error, {failed_starting, App, _}} ->
SkipString =
"Could not start " ++ atom_to_list(App),
- {skip, SkipString};
- _:X ->
+ skip(SkipString);
+ _:X ->
SkipString =
lists:flatten(
io_lib:format("Failed starting apps: ~p", [X])),
- {skip, SkipString}
+ skip(SkipString)
end;
_ ->
@@ -330,14 +323,14 @@ init_per_testcase(Case, Timeout, Config) ->
],
case lists:member(Rest, BadCases) of
true ->
- [{skip, "TC and server not compatible"}|
+ [skip("TC and server not compatible") |
TmpConfig];
false ->
inets:start(),
[{watchdog, Dog} | TmpConfig]
end;
false ->
- [{skip, "proxy not responding"} | TmpConfig]
+ [skip("proxy not responding") | TmpConfig]
end
end;
@@ -367,20 +360,19 @@ init_per_testcase(Case, Timeout, Config) ->
io_lib:format("Failed starting apps: ~p", [X])),
{skip, SkipString}
end;
+
_ ->
TmpConfig2 = lists:keydelete(local_server, 1, TmpConfig),
- Server =
- %% Will start inets
- inets_test_lib:start_http_server(
- filename:join(PrivDir, IpConfFile)),
+ %% Will start inets
+ Server = start_http_server(PrivDir, IpConfFile),
[{watchdog, Dog}, {local_server, Server} | TmpConfig2]
end,
%% This will fail for the ipv6_ - cases (but that is ok)
- httpc:set_options([{proxy, {{?PROXY, ?PROXY_PORT},
- ["localhost", ?IPV6_LOCAL_HOST]}},
- {ipfamily, inet6fb4}]),
-
+ ProxyExceptions = ["localhost", ?IPV6_LOCAL_HOST],
+ http:set_options([{proxy, {{?PROXY, ?PROXY_PORT}, ProxyExceptions}}]),
+ inets:enable_trace(max, io, httpc),
+ %% inets:enable_trace(max, io, all),
%% snmp:set_trace([gen_tcp]),
NewConfig.
@@ -397,7 +389,10 @@ init_per_testcase_ssl(Tag, PrivDir, SslConfFile, Config) ->
tsp("init_per_testcase(~w) -> Server: ~p", [Tag, Server]),
[{local_ssl_server, Server} | Config2].
-
+start_http_server(ConfDir, ConfFile) ->
+ inets_test_lib:start_http_server( filename:join(ConfDir, ConfFile) ).
+
+
%%--------------------------------------------------------------------
%% Function: end_per_testcase(Case, Config) -> _
%% Case - atom()
@@ -733,7 +728,7 @@ test_pipeline(URL) ->
p("test_pipeline -> received reply for (async) request 2"),
ok;
{http, Msg1} ->
- test_server:fail(Msg1)
+ tsf(Msg1)
end;
{http, {RequestId2, {{_, 200, _}, _, _}}} ->
io:format("test_pipeline -> received reply for (async) request 2 - now wait for 1"),
@@ -742,14 +737,14 @@ test_pipeline(URL) ->
io:format("test_pipeline -> received reply for (async) request 1"),
ok;
{http, Msg2} ->
- test_server:fail(Msg2)
+ tsf(Msg2)
end;
{http, Msg3} ->
- test_server:fail(Msg3)
+ tsf(Msg3)
after 60000 ->
receive Any1 ->
tsp("received crap after timeout: ~n ~p", [Any1]),
- test_server:fail({error, {timeout, Any1}})
+ tsf({error, {timeout, Any1}})
end
end,
@@ -774,7 +769,7 @@ test_pipeline(URL) ->
p("test_pipeline -> expect *no* reply for cancelled (async) request 4 (for 3 secs)"),
receive
{http, {RequestId3, _}} ->
- test_server:fail(http_cancel_request_failed)
+ tsf(http_cancel_request_failed)
after 3000 ->
ok
end,
@@ -787,11 +782,11 @@ test_pipeline(URL) ->
tsp("Receive : ~p", [Res]),
BinBody4;
{http, Msg4} ->
- test_server:fail(Msg4)
+ tsf(Msg4)
after 60000 ->
receive Any2 ->
tsp("received crap after timeout: ~n ~p", [Any2]),
- test_server:fail({error, {timeout, Any2}})
+ tsf({error, {timeout, Any2}})
end
end,
@@ -801,7 +796,7 @@ test_pipeline(URL) ->
p("test_pipeline -> ensure no unexpected incomming"),
receive
{http, Any} ->
- test_server:fail({unexpected_message, Any})
+ tsf({unexpected_message, Any})
after 500 ->
ok
end,
@@ -823,11 +818,11 @@ http_trace(Config) when is_list(Config) ->
{ok, {{_,200,_}, [_ | _], "TRACE /dummy.html" ++ _}} ->
ok;
{ok, {{_,200,_}, [_ | _], WrongBody}} ->
- test_server:fail({wrong_body, WrongBody});
+ tsf({wrong_body, WrongBody});
{ok, WrongReply} ->
- test_server:fail({wrong_reply, WrongReply});
+ tsf({wrong_reply, WrongReply});
Error ->
- test_server:fail({failed, Error})
+ tsf({failed, Error})
end;
_ ->
{skip, "Failed to start local http-server"}
@@ -850,7 +845,7 @@ http_async(Config) when is_list(Config) ->
{http, {RequestId, {{_, 200, _}, _, BinBody}}} ->
BinBody;
{http, Msg} ->
- test_server:fail(Msg)
+ tsf(Msg)
end,
inets_test_lib:check_body(binary_to_list(Body)),
@@ -860,7 +855,7 @@ http_async(Config) when is_list(Config) ->
ok = httpc:cancel_request(NewRequestId),
receive
{http, {NewRequestId, _NewResult}} ->
- test_server:fail(http_cancel_request_failed)
+ tsf(http_cancel_request_failed)
after 3000 ->
ok
end;
@@ -909,7 +904,7 @@ http_save_to_file_async(Config) when is_list(Config) ->
{http, {RequestId, saved_to_file}} ->
ok;
{http, Msg} ->
- test_server:fail(Msg)
+ tsf(Msg)
end,
{ok, Bin} = file:read_file(FilePath),
@@ -1076,13 +1071,6 @@ ssl_head(suite) ->
ssl_head(Config) when is_list(Config) ->
ssl_head(ssl, Config).
-ossl_head(doc) ->
- ["Same as http_head/1 but over ssl sockets."];
-ossl_head(suite) ->
- [];
-ossl_head(Config) when is_list(Config) ->
- ssl_head(ossl, Config).
-
essl_head(doc) ->
["Same as http_head/1 but over ssl sockets."];
essl_head(suite) ->
@@ -1105,8 +1093,6 @@ ssl_head(SslTag, Config) ->
case SslTag of
ssl ->
SSLOptions;
- ossl ->
- {ossl, SSLOptions};
essl ->
{essl, SSLOptions}
end,
@@ -1131,13 +1117,6 @@ ssl_get(suite) ->
ssl_get(Config) when is_list(Config) ->
ssl_get(ssl, Config).
-ossl_get(doc) ->
- ["Same as http_get/1 but over ssl sockets."];
-ossl_get(suite) ->
- [];
-ossl_get(Config) when is_list(Config) ->
- ssl_get(ossl, Config).
-
essl_get(doc) ->
["Same as http_get/1 but over ssl sockets."];
essl_get(suite) ->
@@ -1157,8 +1136,6 @@ ssl_get(SslTag, Config) when is_list(Config) ->
case SslTag of
ssl ->
SSLOptions;
- ossl ->
- {ossl, SSLOptions};
essl ->
{essl, SSLOptions}
end,
@@ -1184,13 +1161,6 @@ ssl_trace(suite) ->
ssl_trace(Config) when is_list(Config) ->
ssl_trace(ssl, Config).
-ossl_trace(doc) ->
- ["Same as http_trace/1 but over ssl sockets."];
-ossl_trace(suite) ->
- [];
-ossl_trace(Config) when is_list(Config) ->
- ssl_trace(ossl, Config).
-
essl_trace(doc) ->
["Same as http_trace/1 but over ssl sockets."];
essl_trace(suite) ->
@@ -1210,8 +1180,6 @@ ssl_trace(SslTag, Config) when is_list(Config) ->
case SslTag of
ssl ->
SSLOptions;
- ossl ->
- {ossl, SSLOptions};
essl ->
{essl, SSLOptions}
end,
@@ -1482,10 +1450,10 @@ proxy_options(Config) when is_list(Config) ->
{value, {"allow", _}} ->
ok;
_ ->
- test_server:fail(http_options_request_failed)
+ tsf(http_options_request_failed)
end;
Unexpected ->
- test_server:fail({unexpected_result, Unexpected})
+ tsf({unexpected_result, Unexpected})
end;
Reason ->
{skip, Reason}
@@ -1506,7 +1474,7 @@ proxy_head(Config) when is_list(Config) ->
{ok, {{_,200, _}, [_ | _], []}} ->
ok;
Unexpected ->
- test_server:fail({unexpected_result, Unexpected})
+ tsf({unexpected_result, Unexpected})
end;
Reason ->
{skip, Reason}
@@ -1525,7 +1493,7 @@ proxy_get(Config) when is_list(Config) ->
{ok, {{_,200,_}, [_ | _], Body = [_ | _]}} ->
inets_test_lib:check_body(Body);
Unexpected ->
- test_server:fail({unexpected_result, Unexpected})
+ tsf({unexpected_result, Unexpected})
end;
Reason ->
{skip, Reason}
@@ -1604,7 +1572,7 @@ proxy_post(Config) when is_list(Config) ->
{ok, {{_,405,_}, [_ | _], [_ | _]}} ->
ok;
Unexpected ->
- test_server:fail({unexpected_result, Unexpected})
+ tsf({unexpected_result, Unexpected})
end;
Reason ->
{skip, Reason}
@@ -1629,7 +1597,7 @@ proxy_put(Config) when is_list(Config) ->
{ok, {{_,405,_}, [_ | _], [_ | _]}} ->
ok;
Unexpected ->
- test_server:fail({unexpected_result, Unexpected})
+ tsf({unexpected_result, Unexpected})
end;
Reason ->
{skip, Reason}
@@ -1654,7 +1622,7 @@ proxy_delete(Config) when is_list(Config) ->
{ok, {{_,404,_}, [_ | _], [_ | _]}} ->
ok;
Unexpected ->
- test_server:fail({unexpected_result, Unexpected})
+ tsf({unexpected_result, Unexpected})
end;
Reason ->
{skip, Reason}
@@ -1710,7 +1678,7 @@ proxy_auth(Config) when is_list(Config) ->
{ok, {{_,200, _}, [_ | _], [_|_]}} ->
ok;
Unexpected ->
- test_server:fail({unexpected_result, Unexpected})
+ tsf({unexpected_result, Unexpected})
end;
Reason ->
{skip, Reason}
@@ -1796,7 +1764,7 @@ http_stream(Config) when is_list(Config) ->
{http, {RequestId, stream_start, _Headers}} ->
ok;
{http, Msg} ->
- test_server:fail(Msg)
+ tsf(Msg)
end,
StreamedBody = receive_streamed_body(RequestId, <<>>),
@@ -1851,7 +1819,7 @@ once(URL) ->
[RequestId, Pid]),
Pid;
{http, Msg} ->
- test_server:fail(Msg)
+ tsf(Msg)
end,
tsp("once -> request handler: ~p", [NewPid]),
@@ -1894,7 +1862,7 @@ proxy_stream(Config) when is_list(Config) ->
{http, {RequestId, stream_start, _Headers}} ->
ok;
{http, Msg} ->
- test_server:fail(Msg)
+ tsf(Msg)
end,
StreamedBody = receive_streamed_body(RequestId, <<>>),
@@ -1912,22 +1880,31 @@ parse_url(suite) ->
[];
parse_url(Config) when is_list(Config) ->
%% ipv6
- {http,[],"2010:836B:4179::836B:4179",80,"/foobar.html",[]}
- = http_uri:parse("http://[2010:836B:4179::836B:4179]/foobar.html"),
+ {ok, {http,[],"2010:836B:4179::836B:4179",80,"/foobar.html",[]}} =
+ http_uri:parse("http://[2010:836B:4179::836B:4179]/foobar.html"),
+ {ok, {http,[],"[2010:836B:4179::836B:4179]",80,"/foobar.html",[]}} =
+ http_uri:parse("http://[2010:836B:4179::836B:4179]/foobar.html",
+ [{ipv6_host_with_brackets, true}]),
+ {ok, {http,[],"2010:836B:4179::836B:4179",80,"/foobar.html",[]}} =
+ http_uri:parse("http://[2010:836B:4179::836B:4179]/foobar.html",
+ [{ipv6_host_with_brackets, false}]),
+ {ok, {http,[],"2010:836B:4179::836B:4179",80,"/foobar.html",[]}} =
+ http_uri:parse("http://[2010:836B:4179::836B:4179]/foobar.html",
+ [{foo, false}]),
{error,
{malformed_url,"http://2010:836B:4179::836B:4179/foobar.html"}} =
http_uri:parse("http://2010:836B:4179::836B:4179/foobar.html"),
%% ipv4
- {http,[],"127.0.0.1",80,"/foobar.html",[]} =
+ {ok, {http,[],"127.0.0.1",80,"/foobar.html",[]}} =
http_uri:parse("http://127.0.0.1/foobar.html"),
%% host
- {http,[],"localhost",8888,"/foobar.html",[]} =
+ {ok, {http,[],"localhost",8888,"/foobar.html",[]}} =
http_uri:parse("http://localhost:8888/foobar.html"),
%% Userinfo
- {http,"nisse:foobar","localhost",8888,"/foobar.html",[]} =
+ {ok, {http,"nisse:foobar","localhost",8888,"/foobar.html",[]}} =
http_uri:parse("http://nisse:foobar@localhost:8888/foobar.html"),
%% Scheme error
@@ -1936,18 +1913,20 @@ parse_url(Config) when is_list(Config) ->
http_uri:parse("localhost:8888/foobar.html"),
%% Query
- {http,[],"localhost",8888,"/foobar.html","?foo=bar&foobar=42"} =
+ {ok, {http,[],"localhost",8888,"/foobar.html","?foo=bar&foobar=42"}} =
http_uri:parse("http://localhost:8888/foobar.html?foo=bar&foobar=42"),
%% Esc chars
- {http,[],"www.somedomain.com",80,"/%2Eabc",[]} =
+ {ok, {http,[],"www.somedomain.com",80,"/%2Eabc",[]}} =
http_uri:parse("http://www.somedomain.com/%2Eabc"),
- {http,[],"www.somedomain.com",80,"/%252Eabc",[]} =
+ {ok, {http,[],"www.somedomain.com",80,"/%252Eabc",[]}} =
http_uri:parse("http://www.somedomain.com/%252Eabc"),
- {http,[],"www.somedomain.com",80,"/%25abc",[]} =
+ {ok, {http,[],"www.somedomain.com",80,"/%25abc",[]}} =
http_uri:parse("http://www.somedomain.com/%25abc"),
- {http,[],"www.somedomain.com",80,"/%25abc", "?foo=bar"} =
+ {ok, {http,[],"www.somedomain.com",80,"/%25abc", "?foo=bar"}} =
http_uri:parse("http://www.somedomain.com/%25abc?foo=bar"),
+
+
ok.
@@ -2092,12 +2071,14 @@ http_invalid_http(Config) when is_list(Config) ->
%%-------------------------------------------------------------------------
+-define(GOOGLE, "www.google.com").
+
hexed_query_otp_6191(doc) ->
[];
hexed_query_otp_6191(suite) ->
[];
hexed_query_otp_6191(Config) when is_list(Config) ->
- Google = "www.google.com",
+ Google = ?GOOGLE,
GoogleSearch = "http://" ++ Google ++ "/search",
Search1 = "?hl=en&q=a%D1%85%D1%83%D0%B9&btnG=Google+Search",
URI1 = GoogleSearch ++ Search1,
@@ -2106,11 +2087,32 @@ hexed_query_otp_6191(Config) when is_list(Config) ->
Search3 = "?hl=en&q=%foo",
URI3 = GoogleSearch ++ Search3,
- {http, [], Google, 80, "/search", _} = http_uri:parse(URI1),
- {http, [], Google, 80, "/search", _} = http_uri:parse(URI2),
- {http, [], Google, 80, "/search", _} = http_uri:parse(URI3),
+ Verify1 =
+ fun({http, [], ?GOOGLE, 80, "/search", _}) -> ok;
+ (_) -> error
+ end,
+ Verify2 = Verify1,
+ Verify3 = Verify1,
+ verify_uri(URI1, Verify1),
+ verify_uri(URI2, Verify2),
+ verify_uri(URI3, Verify3),
ok.
+verify_uri(URI, Verify) ->
+ case http_uri:parse(URI) of
+ {ok, ParsedURI} ->
+ case Verify(ParsedURI) of
+ ok ->
+ ok;
+ error ->
+ Reason = {unexpected_parse_result, URI, ParsedURI},
+ ERROR = {error, Reason},
+ throw(ERROR)
+ end;
+ {error, _} = ERROR ->
+ throw(ERROR)
+ end.
+
%%-------------------------------------------------------------------------
@@ -2979,7 +2981,7 @@ receive_streamed_body(RequestId, Body) ->
{http, {RequestId, stream_end, _Headers}} ->
Body;
{http, Msg} ->
- test_server:fail(Msg)
+ tsf(Msg)
end.
receive_streamed_body(RequestId, Body, Pid) ->
@@ -2993,7 +2995,7 @@ receive_streamed_body(RequestId, Body, Pid) ->
{http, {RequestId, stream_end, _Headers}} ->
Body;
{http, Msg} ->
- test_server:fail(Msg)
+ tsf(Msg)
end.
%% Perform a synchronous stop
@@ -3038,10 +3040,6 @@ dummy_server_init(Caller, essl, IpV, SSLOptions) ->
BaseOpts = [{ssl_imp, new},
{backlog, 128}, binary, {reuseaddr,true}, {active, false} |
SSLOptions],
- dummy_ssl_server_init(Caller, BaseOpts, IpV);
-dummy_server_init(Caller, ossl, IpV, SSLOptions) ->
- BaseOpts = [{ssl_imp, old},
- {backlog, 128}, binary, {active, false} | SSLOptions],
dummy_ssl_server_init(Caller, BaseOpts, IpV).
dummy_ssl_server_init(Caller, BaseOpts, IpV) ->
@@ -3455,7 +3453,7 @@ handle_auth("Basic " ++ UserInfo, Challange, DefaultResponse) ->
end.
check_cookie([]) ->
- test_server:fail(no_cookie_header);
+ tsf(no_cookie_header);
check_cookie(["cookie:" ++ _Value | _]) ->
ok;
check_cookie([_Head | Tail]) ->
@@ -3513,9 +3511,9 @@ p(F, A) ->
io:format("~p ~w:" ++ F ++ "~n", [self(), ?MODULE | A]).
tsp(F) ->
- tsp(F, []).
+ inets_test_lib:tsp(F).
tsp(F, A) ->
- test_server:format("~p ~p:" ++ F ++ "~n", [self(), ?MODULE | A]).
+ inets_test_lib:tsp(F, A).
tsf(Reason) ->
test_server:fail(Reason).
@@ -3570,3 +3568,6 @@ ensure_started(App) when is_atom(App) ->
throw({error, {failed_starting, App, Error}})
end.
+
+skip(Reason) ->
+ {skip, Reason}.
diff --git a/lib/inets/test/httpc_cookie_SUITE.erl b/lib/inets/test/httpc_cookie_SUITE.erl
index 866fa9d525..93dbc270c5 100644
--- a/lib/inets/test/httpc_cookie_SUITE.erl
+++ b/lib/inets/test/httpc_cookie_SUITE.erl
@@ -55,7 +55,7 @@ init_per_testcase(session_cookies_only = Case, Config0) ->
"~n Config0: ~p", [Case, Config0]),
Config = init_workdir(Case, Config0),
application:start(inets),
- http:set_options([{cookies, verify}]),
+ httpc:set_options([{cookies, verify}]),
watch_dog(Config);
init_per_testcase(Case, Config0) ->
@@ -66,7 +66,7 @@ init_per_testcase(Case, Config0) ->
application:load(inets),
application:set_env(inets, services, [{httpc, {default, CaseDir}}]),
application:start(inets),
- http:set_options([{cookies, verify}]),
+ httpc:set_options([{cookies, verify}]),
watch_dog(Config).
watch_dog(Config) ->
@@ -160,12 +160,12 @@ session_cookies_only(Config) when is_list(Config) ->
SetCookieHeaders = [{"set-cookie", "test_cookie=true; path=/;"
";max-age=60000"}],
- http:verify_cookies(SetCookieHeaders, ?URL),
- {"cookie","$Version=0; test_cookie=true; $Path=/"}
- = http:cookie_header(?URL),
+ httpc:store_cookies(SetCookieHeaders, ?URL),
+ {"cookie", "$Version=0; test_cookie=true; $Path=/"} =
+ httpc:cookie_header(?URL),
application:stop(inets),
application:start(inets),
- {"cookie",""} = http:cookie_header(?URL),
+ {"cookie", ""} = httpc:cookie_header(?URL),
tsp("session_cookies_only -> Cookies 2: ~p", [httpc:which_cookies()]),
ok.
@@ -180,9 +180,9 @@ netscape_cookies(Config) when is_list(Config) ->
Expires = future_netscape_date(),
SetCookieHeaders = [{"set-cookie", "test_cookie=true; path=/; "
"expires=" ++ Expires}],
- http:verify_cookies(SetCookieHeaders, ?URL),
- {"cookie","$Version=0; test_cookie=true; $Path=/"} =
- http:cookie_header(?URL),
+ httpc:store_cookies(SetCookieHeaders, ?URL),
+ {"cookie", "$Version=0; test_cookie=true; $Path=/"} =
+ httpc:cookie_header(?URL),
tsp("netscape_cookies -> Cookies 2: ~p", [httpc:which_cookies()]),
ok.
@@ -197,13 +197,13 @@ cookie_cancel(Config) when is_list(Config) ->
SetCookieHeaders = [{"set-cookie", "test_cookie=true; path=/;"
"max-age=60000"}],
- http:verify_cookies(SetCookieHeaders, ?URL),
- {"cookie","$Version=0; test_cookie=true; $Path=/"}
- = http:cookie_header(?URL),
- NewSetCookieHeaders = [{"set-cookie", "test_cookie=true; path=/;"
- "max-age=0"}],
- http:verify_cookies(NewSetCookieHeaders, ?URL),
- {"cookie", ""} = http:cookie_header(?URL),
+ httpc:store_cookies(SetCookieHeaders, ?URL),
+ {"cookie", "$Version=0; test_cookie=true; $Path=/"} =
+ httpc:cookie_header(?URL),
+ NewSetCookieHeaders =
+ [{"set-cookie", "test_cookie=true; path=/;max-age=0"}],
+ httpc:store_cookies(NewSetCookieHeaders, ?URL),
+ {"cookie", ""} = httpc:cookie_header(?URL),
tsp("cookie_cancel -> Cookies 2: ~p", [httpc:which_cookies()]),
ok.
@@ -217,11 +217,11 @@ cookie_expires(Config) when is_list(Config) ->
SetCookieHeaders = [{"set-cookie", "test_cookie=true; path=/;"
"max-age=5"}],
- http:verify_cookies(SetCookieHeaders, ?URL),
- {"cookie","$Version=0; test_cookie=true; $Path=/"}
- = http:cookie_header(?URL),
+ httpc:store_cookies(SetCookieHeaders, ?URL),
+ {"cookie", "$Version=0; test_cookie=true; $Path=/"} =
+ httpc:cookie_header(?URL),
test_server:sleep(10000),
- {"cookie", ""} = http:cookie_header(?URL),
+ {"cookie", ""} = httpc:cookie_header(?URL),
tsp("cookie_expires -> Cookies 2: ~p", [httpc:which_cookies()]),
ok.
@@ -235,16 +235,16 @@ persistent_cookie(Config) when is_list(Config)->
SetCookieHeaders = [{"set-cookie", "test_cookie=true; path=/;"
"max-age=60000"}],
- http:verify_cookies(SetCookieHeaders, ?URL),
- {"cookie","$Version=0; test_cookie=true; $Path=/"} =
- http:cookie_header(?URL),
+ httpc:store_cookies(SetCookieHeaders, ?URL),
+ {"cookie", "$Version=0; test_cookie=true; $Path=/"} =
+ httpc:cookie_header(?URL),
CaseDir = ?config(case_top_dir, Config),
application:stop(inets),
application:load(inets),
application:set_env(inets, services, [{httpc, {default, CaseDir}}]),
application:start(inets),
- http:set_options([{cookies, enabled}]),
- {"cookie","$Version=0; test_cookie=true; $Path=/"} = http:cookie_header(?URL),
+ httpc:set_options([{cookies, enabled}]),
+ {"cookie","$Version=0; test_cookie=true; $Path=/"} = httpc:cookie_header(?URL),
tsp("persistent_cookie -> Cookies 2: ~p", [httpc:which_cookies()]),
ok.
@@ -259,10 +259,10 @@ domain_cookie(Config) when is_list(Config) ->
SetCookieHeaders = [{"set-cookie", "test_cookie=true; path=/;"
"domain=.cookie.test.org"}],
- http:verify_cookies(SetCookieHeaders, ?URL),
+ httpc:store_cookies(SetCookieHeaders, ?URL),
{"cookie","$Version=0; test_cookie=true; $Path=/; "
"$Domain=.cookie.test.org"} =
- http:cookie_header(?URL_DOMAIN),
+ httpc:cookie_header(?URL_DOMAIN),
tsp("domain_cookie -> Cookies 2: ~p", [httpc:which_cookies()]),
ok.
@@ -283,8 +283,8 @@ secure_cookie(Config) when is_list(Config) ->
tsp("secure_cookie -> Cookies 1: ~p", [httpc:which_cookies()]),
SetCookieHeaders = [{"set-cookie", "test_cookie=true; path=/; secure"}],
- tsp("secure_cookie -> verify cookies (1)"),
- ok = http:verify_cookies(SetCookieHeaders, ?URL),
+ tsp("secure_cookie -> store cookies (1)"),
+ ok = httpc:store_cookies(SetCookieHeaders, ?URL),
tsp("secure_cookie -> Cookies 2: ~p", [httpc:which_cookies()]),
@@ -294,9 +294,9 @@ secure_cookie(Config) when is_list(Config) ->
tsp("secure_cookie -> check cookie (plain)"),
check_cookie("", ?URL),
- tsp("secure_cookie -> verify cookies (2)"),
+ tsp("secure_cookie -> store cookies (2)"),
SetCookieHeaders1 = [{"set-cookie", "test1_cookie=true; path=/; secure"}],
- ok = http:verify_cookies(SetCookieHeaders1, ?URL),
+ ok = httpc:store_cookies(SetCookieHeaders1, ?URL),
tsp("secure_cookie -> Cookies 3: ~p", [httpc:which_cookies()]),
@@ -305,7 +305,7 @@ secure_cookie(Config) when is_list(Config) ->
"test1_cookie=true; $Path=/",
?URL_SECURE),
%% {"cookie","$Version=0; test_cookie=true; $Path=/; "
-%% "test1_cookie=true; $Path=/"} = http:cookie_header(?URL_SECURE),
+%% "test1_cookie=true; $Path=/"} = httpc:cookie_header(?URL_SECURE),
tsp("secure_cookie -> Cookies 4: ~p", [httpc:which_cookies()]),
@@ -411,8 +411,8 @@ cookie_attributes(Config) when is_list(Config) ->
"comment=foobar; "%% Comment
"foo=bar;" %% Nonsense should be ignored
"max-age=60000"}],
- http:verify_cookies(SetCookieHeaders, ?URL),
- {"cookie","$Version=1; test_cookie=true"} = http:cookie_header(?URL),
+ httpc:store_cookies(SetCookieHeaders, ?URL),
+ {"cookie","$Version=1; test_cookie=true"} = httpc:cookie_header(?URL),
ok.
@@ -421,7 +421,7 @@ cookie_attributes(Config) when is_list(Config) ->
%%--------------------------------------------------------------------
check_cookie(Expect, URL) ->
- case http:cookie_header(URL) of
+ case httpc:cookie_header(URL) of
{"cookie", Expect} ->
ok;
{"cookie", Unexpected} ->
diff --git a/lib/inets/test/httpd_1_1.erl b/lib/inets/test/httpd_1_1.erl
index 2a6110e3ea..07d94ea97a 100644
--- a/lib/inets/test/httpd_1_1.erl
+++ b/lib/inets/test/httpd_1_1.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2005-2010. All Rights Reserved.
+%% Copyright Ericsson AB 2005-2011. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -19,7 +19,6 @@
%%
-module(httpd_1_1).
--author('[email protected]').
-include("test_server.hrl").
-include("test_server_line.hrl").
@@ -159,70 +158,79 @@ if_test(Type, Port, Host, Node, DocRoot)->
calendar:datetime_to_gregorian_seconds(FileInfo#file_info.mtime),
Mod = httpd_util:rfc1123_date(calendar:gregorian_seconds_to_datetime(
- CreatedSec-1)),
-
+ CreatedSec-1)),
+
%% Test that we get the data when the file is modified
ok = httpd_test_lib:verify_request(Type, Host, Port, Node,
- "GET / HTTP/1.1\r\nHost:" ++ Host ++
- "\r\nIf-Modified-Since:" ++
- Mod ++ "\r\n\r\n",
- [{statuscode, 200}]),
- Mod1 = httpd_util:rfc1123_date(calendar:gregorian_seconds_to_datetime(
- CreatedSec+100)),
- ok = httpd_test_lib:verify_request(Type,Host,Port,Node,
- "GET / HTTP/1.1\r\nHost:"
- ++ Host ++"\r\nIf-Modified-Since:"
- ++ Mod1 ++"\r\n\r\n",
- [{statuscode, 304}]),
+ "GET / HTTP/1.1\r\nHost:" ++ Host ++
+ "\r\nIf-Modified-Since:" ++
+ Mod ++ "\r\n\r\n",
+ [{statuscode, 200}]),
+ Mod1 = httpd_util:rfc1123_date(calendar:gregorian_seconds_to_datetime(
+ CreatedSec+100)),
+ ok = httpd_test_lib:verify_request(Type,Host,Port,Node,
+ "GET / HTTP/1.1\r\nHost:"
+ ++ Host ++"\r\nIf-Modified-Since:"
+ ++ Mod1 ++"\r\n\r\n",
+ [{statuscode, 304}]),
+
+ ok = httpd_test_lib:verify_request(Type, Host, Port, Node,
+ "GET / HTTP/1.1\r\nHost:" ++ Host ++
+ "\r\nIf-Modified-Since:" ++
+ "AAA[...]AAAA" ++ "\r\n\r\n",
+ [{statuscode, 400}]),
+
+
Mod2 = httpd_util:rfc1123_date(calendar:gregorian_seconds_to_datetime(
- CreatedSec+1)),
+ CreatedSec+1)),
%% Control that the If-Unmodified-Header lmits the response
ok = httpd_test_lib:verify_request(Type,Host,Port,Node,
- "GET / HTTP/1.1\r\nHost:"
- ++ Host ++
- "\r\nIf-Unmodified-Since:" ++ Mod2
- ++ "\r\n\r\n",
- [{statuscode, 200}]),
+ "GET / HTTP/1.1\r\nHost:"
+ ++ Host ++
+ "\r\nIf-Unmodified-Since:" ++ Mod2
+ ++ "\r\n\r\n",
+ [{statuscode, 200}]),
Mod3 = httpd_util:rfc1123_date(calendar:gregorian_seconds_to_datetime(
- CreatedSec-1)),
+ CreatedSec-1)),
ok = httpd_test_lib:verify_request(Type, Host, Port, Node,
- "GET / HTTP/1.1\r\nHost:"
- ++ Host ++
- "\r\nIf-Unmodified-Since:"++ Mod3
- ++"\r\n\r\n",
- [{statuscode, 412}]),
-
+ "GET / HTTP/1.1\r\nHost:"
+ ++ Host ++
+ "\r\nIf-Unmodified-Since:"++ Mod3
+ ++"\r\n\r\n",
+ [{statuscode, 412}]),
+
%% Control that we get the body when the etag match
ok = httpd_test_lib:verify_request(Type, Host, Port, Node,
- "GET / HTTP/1.1\r\nHost:" ++ Host
- ++"\r\n"++
- "If-Match:"++
- httpd_util:create_etag(FileInfo)++
- "\r\n\r\n",
- [{statuscode, 200}]),
+ "GET / HTTP/1.1\r\nHost:" ++ Host
+ ++"\r\n"++
+ "If-Match:"++
+ httpd_util:create_etag(FileInfo)++
+ "\r\n\r\n",
+ [{statuscode, 200}]),
ok = httpd_test_lib:verify_request(Type, Host, Port, Node,
- "GET / HTTP/1.1\r\nHost:" ++
- Host ++ "\r\n"++
- "If-Match:NotEtag\r\n\r\n",
- [{statuscode, 412}]),
+ "GET / HTTP/1.1\r\nHost:" ++
+ Host ++ "\r\n"++
+ "If-Match:NotEtag\r\n\r\n",
+ [{statuscode, 412}]),
%% Control the response when the if-none-match header is there
ok = httpd_test_lib:verify_request(Type, Host, Port, Node,
- "GET / HTTP/1.1\r\nHost:"
- ++ Host ++"\r\n"++
- "If-None-Match:NoTaag," ++
- httpd_util:create_etag(FileInfo) ++
- "\r\n\r\n",
- [{statuscode, 304}]),
-
+ "GET / HTTP/1.1\r\nHost:"
+ ++ Host ++"\r\n"++
+ "If-None-Match:NoTaag," ++
+ httpd_util:create_etag(FileInfo) ++
+ "\r\n\r\n",
+ [{statuscode, 304}]),
+
ok = httpd_test_lib:verify_request(Type, Host, Port, Node,
- "GET / HTTP/1.1\r\nHost:"
- ++ Host ++ "\r\n"++
- "If-None-Match:NotEtag,"
- "NeihterEtag\r\n\r\n",
- [{statuscode,200}]).
+ "GET / HTTP/1.1\r\nHost:"
+ ++ Host ++ "\r\n"++
+ "If-None-Match:NotEtag,"
+ "NeihterEtag\r\n\r\n",
+ [{statuscode,200}]),
+ ok.
http_trace(Type, Port, Host, Node)->
ok = httpd_test_lib:verify_request(Type, Host, Port, Node,
diff --git a/lib/inets/test/httpd_SUITE.erl b/lib/inets/test/httpd_SUITE.erl
index 1112208295..ba31788ccc 100644
--- a/lib/inets/test/httpd_SUITE.erl
+++ b/lib/inets/test/httpd_SUITE.erl
@@ -68,127 +68,96 @@
-export([
pssl_mod_alias/1,
- ossl_mod_alias/1,
essl_mod_alias/1,
pssl_mod_actions/1,
- ossl_mod_actions/1,
essl_mod_actions/1,
pssl_mod_security/1,
- ossl_mod_security/1,
essl_mod_security/1,
pssl_mod_auth/1,
- ossl_mod_auth/1,
essl_mod_auth/1,
pssl_mod_auth_api/1,
- ossl_mod_auth_api/1,
essl_mod_auth_api/1,
pssl_mod_auth_mnesia_api/1,
- ossl_mod_auth_mnesia_api/1,
essl_mod_auth_mnesia_api/1,
pssl_mod_htaccess/1,
- ossl_mod_htaccess/1,
essl_mod_htaccess/1,
pssl_mod_cgi/1,
- ossl_mod_cgi/1,
essl_mod_cgi/1,
pssl_mod_esi/1,
- ossl_mod_esi/1,
essl_mod_esi/1,
pssl_mod_get/1,
- ossl_mod_get/1,
essl_mod_get/1,
pssl_mod_head/1,
- ossl_mod_head/1,
essl_mod_head/1,
pssl_mod_all/1,
- ossl_mod_all/1,
essl_mod_all/1,
pssl_load_light/1,
- ossl_load_light/1,
essl_load_light/1,
pssl_load_medium/1,
- ossl_load_medium/1,
essl_load_medium/1,
pssl_load_heavy/1,
- ossl_load_heavy/1,
essl_load_heavy/1,
pssl_dos_hostname/1,
- ossl_dos_hostname/1,
essl_dos_hostname/1,
pssl_time_test/1,
- ossl_time_test/1,
essl_time_test/1,
pssl_restart_no_block/1,
- ossl_restart_no_block/1,
essl_restart_no_block/1,
pssl_restart_disturbing_block/1,
- ossl_restart_disturbing_block/1,
essl_restart_disturbing_block/1,
pssl_restart_non_disturbing_block/1,
- ossl_restart_non_disturbing_block/1,
essl_restart_non_disturbing_block/1,
pssl_block_disturbing_idle/1,
- ossl_block_disturbing_idle/1,
essl_block_disturbing_idle/1,
pssl_block_non_disturbing_idle/1,
- ossl_block_non_disturbing_idle/1,
essl_block_non_disturbing_idle/1,
pssl_block_503/1,
- ossl_block_503/1,
essl_block_503/1,
pssl_block_disturbing_active/1,
- ossl_block_disturbing_active/1,
essl_block_disturbing_active/1,
pssl_block_non_disturbing_active/1,
- ossl_block_non_disturbing_active/1,
essl_block_non_disturbing_active/1,
pssl_block_disturbing_active_timeout_not_released/1,
- ossl_block_disturbing_active_timeout_not_released/1,
essl_block_disturbing_active_timeout_not_released/1,
pssl_block_disturbing_active_timeout_released/1,
- ossl_block_disturbing_active_timeout_released/1,
essl_block_disturbing_active_timeout_released/1,
pssl_block_non_disturbing_active_timeout_not_released/1,
- ossl_block_non_disturbing_active_timeout_not_released/1,
essl_block_non_disturbing_active_timeout_not_released/1,
pssl_block_non_disturbing_active_timeout_released/1,
- ossl_block_non_disturbing_active_timeout_released/1,
essl_block_non_disturbing_active_timeout_released/1,
pssl_block_disturbing_blocker_dies/1,
- ossl_block_disturbing_blocker_dies/1,
essl_block_disturbing_blocker_dies/1,
pssl_block_non_disturbing_blocker_dies/1,
- ossl_block_non_disturbing_blocker_dies/1,
essl_block_non_disturbing_blocker_dies/1
]).
@@ -272,8 +241,7 @@ groups() ->
ip_block_non_disturbing_active_timeout_released,
ip_block_disturbing_blocker_dies,
ip_block_non_disturbing_blocker_dies]},
- {ssl, [],
- [{group, pssl}, {group, ossl}, {group, essl}]},
+ {ssl, [], [{group, pssl}, {group, essl}]},
{pssl, [],
[pssl_mod_alias, pssl_mod_actions, pssl_mod_security,
pssl_mod_auth, pssl_mod_auth_api,
@@ -293,25 +261,6 @@ groups() ->
pssl_block_non_disturbing_active_timeout_released,
pssl_block_disturbing_blocker_dies,
pssl_block_non_disturbing_blocker_dies]},
- {ossl, [],
- [ossl_mod_alias, ossl_mod_actions, ossl_mod_security,
- ossl_mod_auth, ossl_mod_auth_api,
- ossl_mod_auth_mnesia_api, ossl_mod_htaccess,
- ossl_mod_cgi, ossl_mod_esi, ossl_mod_get, ossl_mod_head,
- ossl_mod_all, ossl_load_light, ossl_load_medium,
- ossl_load_heavy, ossl_dos_hostname, ossl_time_test,
- ossl_restart_no_block, ossl_restart_disturbing_block,
- ossl_restart_non_disturbing_block,
- ossl_block_disturbing_idle,
- ossl_block_non_disturbing_idle, ossl_block_503,
- ossl_block_disturbing_active,
- ossl_block_non_disturbing_active,
- ossl_block_disturbing_active_timeout_not_released,
- ossl_block_disturbing_active_timeout_released,
- ossl_block_non_disturbing_active_timeout_not_released,
- ossl_block_non_disturbing_active_timeout_released,
- ossl_block_disturbing_blocker_dies,
- ossl_block_non_disturbing_blocker_dies]},
{essl, [],
[essl_mod_alias, essl_mod_actions, essl_mod_security,
essl_mod_auth, essl_mod_auth_api,
@@ -493,7 +442,6 @@ init_per_testcase2(Case, Config) ->
[X, $s, $s, $l | _] ->
case X of
$p -> ssl;
- $o -> ossl;
$e -> essl
end;
_ ->
@@ -636,7 +584,6 @@ init_per_testcase3(Case, Config) ->
SslTag =
case X of
$p -> ssl; % plain
- $o -> ossl; % OpenSSL based ssl
$e -> essl % Erlang based ssl
end,
case inets_test_lib:start_http_server_ssl(
@@ -653,7 +600,6 @@ init_per_testcase3(Case, Config) ->
SslTag =
case X of
$p -> ssl;
- $o -> ossl;
$e -> essl
end,
case inets_test_lib:start_http_server_ssl(
@@ -740,6 +686,19 @@ end_per_testcase2(Case, Config) ->
%%-------------------------------------------------------------------------
+http_1_1_ip(doc) ->
+ ["HTTP/1.1"];
+http_1_1_ip(suite) ->
+ [
+ ip_host,
+ ip_chunked,
+ ip_expect,
+ ip_range,
+ ip_if_test,
+ ip_http_trace,
+ ip_http1_1_head,
+ ip_mod_cgi_chunked_encoding_test
+ ].
%%-------------------------------------------------------------------------
@@ -1158,13 +1117,6 @@ pssl_mod_alias(suite) ->
pssl_mod_alias(Config) when is_list(Config) ->
ssl_mod_alias(ssl, Config).
-ossl_mod_alias(doc) ->
- ["Module test: mod_alias - using new of configure old SSL"];
-ossl_mod_alias(suite) ->
- [];
-ossl_mod_alias(Config) when is_list(Config) ->
- ssl_mod_alias(ossl, Config).
-
essl_mod_alias(doc) ->
["Module test: mod_alias - using new of configure new SSL"];
essl_mod_alias(suite) ->
@@ -1188,13 +1140,6 @@ pssl_mod_actions(suite) ->
pssl_mod_actions(Config) when is_list(Config) ->
ssl_mod_actions(ssl, Config).
-ossl_mod_actions(doc) ->
- ["Module test: mod_actions - using new of configure old SSL"];
-ossl_mod_actions(suite) ->
- [];
-ossl_mod_actions(Config) when is_list(Config) ->
- ssl_mod_actions(ossl, Config).
-
essl_mod_actions(doc) ->
["Module test: mod_actions - using new of configure new SSL"];
essl_mod_actions(suite) ->
@@ -1220,13 +1165,6 @@ pssl_mod_security(suite) ->
pssl_mod_security(Config) when is_list(Config) ->
ssl_mod_security(ssl, Config).
-ossl_mod_security(doc) ->
- ["Module test: mod_security - using new of configure old SSL"];
-ossl_mod_security(suite) ->
- [];
-ossl_mod_security(Config) when is_list(Config) ->
- ssl_mod_security(ossl, Config).
-
essl_mod_security(doc) ->
["Module test: mod_security - using new of configure new SSL"];
essl_mod_security(suite) ->
@@ -1253,13 +1191,6 @@ pssl_mod_auth(suite) ->
pssl_mod_auth(Config) when is_list(Config) ->
ssl_mod_auth(ssl, Config).
-ossl_mod_auth(doc) ->
- ["Module test: mod_auth - using new of configure old SSL"];
-ossl_mod_auth(suite) ->
- [];
-ossl_mod_auth(Config) when is_list(Config) ->
- ssl_mod_auth(ossl, Config).
-
essl_mod_auth(doc) ->
["Module test: mod_auth - using new of configure new SSL"];
essl_mod_auth(suite) ->
@@ -1284,13 +1215,6 @@ pssl_mod_auth_api(suite) ->
pssl_mod_auth_api(Config) when is_list(Config) ->
ssl_mod_auth_api(ssl, Config).
-ossl_mod_auth_api(doc) ->
- ["Module test: mod_auth - using new of configure old SSL"];
-ossl_mod_auth_api(suite) ->
- [];
-ossl_mod_auth_api(Config) when is_list(Config) ->
- ssl_mod_auth_api(ossl, Config).
-
essl_mod_auth_api(doc) ->
["Module test: mod_auth - using new of configure new SSL"];
essl_mod_auth_api(suite) ->
@@ -1317,13 +1241,6 @@ pssl_mod_auth_mnesia_api(suite) ->
pssl_mod_auth_mnesia_api(Config) when is_list(Config) ->
ssl_mod_auth_mnesia_api(ssl, Config).
-ossl_mod_auth_mnesia_api(doc) ->
- ["Module test: mod_auth_mnesia_api - using new of configure old SSL"];
-ossl_mod_auth_mnesia_api(suite) ->
- [];
-ossl_mod_auth_mnesia_api(Config) when is_list(Config) ->
- ssl_mod_auth_mnesia_api(ossl, Config).
-
essl_mod_auth_mnesia_api(doc) ->
["Module test: mod_auth_mnesia_api - using new of configure new SSL"];
essl_mod_auth_mnesia_api(suite) ->
@@ -1348,13 +1265,6 @@ pssl_mod_htaccess(suite) ->
pssl_mod_htaccess(Config) when is_list(Config) ->
ssl_mod_htaccess(ssl, Config).
-ossl_mod_htaccess(doc) ->
- ["Module test: mod_htaccess - using new of configure old SSL"];
-ossl_mod_htaccess(suite) ->
- [];
-ossl_mod_htaccess(Config) when is_list(Config) ->
- ssl_mod_htaccess(ossl, Config).
-
essl_mod_htaccess(doc) ->
["Module test: mod_htaccess - using new of configure new SSL"];
essl_mod_htaccess(suite) ->
@@ -1379,13 +1289,6 @@ pssl_mod_cgi(suite) ->
pssl_mod_cgi(Config) when is_list(Config) ->
ssl_mod_cgi(ssl, Config).
-ossl_mod_cgi(doc) ->
- ["Module test: mod_cgi - using new of configure old SSL"];
-ossl_mod_cgi(suite) ->
- [];
-ossl_mod_cgi(Config) when is_list(Config) ->
- ssl_mod_cgi(ossl, Config).
-
essl_mod_cgi(doc) ->
["Module test: mod_cgi - using new of configure new SSL"];
essl_mod_cgi(suite) ->
@@ -1415,13 +1318,6 @@ pssl_mod_esi(suite) ->
pssl_mod_esi(Config) when is_list(Config) ->
ssl_mod_esi(ssl, Config).
-ossl_mod_esi(doc) ->
- ["Module test: mod_esi - using new of configure old SSL"];
-ossl_mod_esi(suite) ->
- [];
-ossl_mod_esi(Config) when is_list(Config) ->
- ssl_mod_esi(ossl, Config).
-
essl_mod_esi(doc) ->
["Module test: mod_esi - using new of configure new SSL"];
essl_mod_esi(suite) ->
@@ -1446,13 +1342,6 @@ pssl_mod_get(suite) ->
pssl_mod_get(Config) when is_list(Config) ->
ssl_mod_get(ssl, Config).
-ossl_mod_get(doc) ->
- ["Module test: mod_get - using new of configure old SSL"];
-ossl_mod_get(suite) ->
- [];
-ossl_mod_get(Config) when is_list(Config) ->
- ssl_mod_get(ossl, Config).
-
essl_mod_get(doc) ->
["Module test: mod_get - using new of configure new SSL"];
essl_mod_get(suite) ->
@@ -1477,13 +1366,6 @@ pssl_mod_head(suite) ->
pssl_mod_head(Config) when is_list(Config) ->
ssl_mod_head(ssl, Config).
-ossl_mod_head(doc) ->
- ["Module test: mod_head - using new of configure old SSL"];
-ossl_mod_head(suite) ->
- [];
-ossl_mod_head(Config) when is_list(Config) ->
- ssl_mod_head(ossl, Config).
-
essl_mod_head(doc) ->
["Module test: mod_head - using new of configure new SSL"];
essl_mod_head(suite) ->
@@ -1508,13 +1390,6 @@ pssl_mod_all(suite) ->
pssl_mod_all(Config) when is_list(Config) ->
ssl_mod_all(ssl, Config).
-ossl_mod_all(doc) ->
- ["All modules test - using new of configure old SSL"];
-ossl_mod_all(suite) ->
- [];
-ossl_mod_all(Config) when is_list(Config) ->
- ssl_mod_all(ossl, Config).
-
essl_mod_all(doc) ->
["All modules test - using new of configure new SSL"];
essl_mod_all(suite) ->
@@ -1539,13 +1414,6 @@ pssl_load_light(suite) ->
pssl_load_light(Config) when is_list(Config) ->
ssl_load_light(ssl, Config).
-ossl_load_light(doc) ->
- ["Test light load - using new of configure old SSL"];
-ossl_load_light(suite) ->
- [];
-ossl_load_light(Config) when is_list(Config) ->
- ssl_load_light(ossl, Config).
-
essl_load_light(doc) ->
["Test light load - using new of configure new SSL"];
essl_load_light(suite) ->
@@ -1571,13 +1439,6 @@ pssl_load_medium(suite) ->
pssl_load_medium(Config) when is_list(Config) ->
ssl_load_medium(ssl, Config).
-ossl_load_medium(doc) ->
- ["Test medium load - using new of configure old SSL"];
-ossl_load_medium(suite) ->
- [];
-ossl_load_medium(Config) when is_list(Config) ->
- ssl_load_medium(ossl, Config).
-
essl_load_medium(doc) ->
["Test medium load - using new of configure new SSL"];
essl_load_medium(suite) ->
@@ -1609,13 +1470,6 @@ pssl_load_heavy(suite) ->
pssl_load_heavy(Config) when is_list(Config) ->
ssl_load_heavy(ssl, Config).
-ossl_load_heavy(doc) ->
- ["Test heavy load - using new of configure old SSL"];
-ossl_load_heavy(suite) ->
- [];
-ossl_load_heavy(Config) when is_list(Config) ->
- ssl_load_heavy(ossl, Config).
-
essl_load_heavy(doc) ->
["Test heavy load - using new of configure new SSL"];
essl_load_heavy(suite) ->
@@ -1647,13 +1501,6 @@ pssl_dos_hostname(suite) ->
pssl_dos_hostname(Config) when is_list(Config) ->
ssl_dos_hostname(ssl, Config).
-ossl_dos_hostname(doc) ->
- ["Denial Of Service (DOS) attack test case - using new of configure old SSL"];
-ossl_dos_hostname(suite) ->
- [];
-ossl_dos_hostname(Config) when is_list(Config) ->
- ssl_dos_hostname(ossl, Config).
-
essl_dos_hostname(doc) ->
["Denial Of Service (DOS) attack test case - using new of configure new SSL"];
essl_dos_hostname(suite) ->
@@ -1679,13 +1526,6 @@ pssl_time_test(suite) ->
pssl_time_test(Config) when is_list(Config) ->
ssl_time_test(ssl, Config).
-ossl_time_test(doc) ->
- ["using new of configure old SSL"];
-ossl_time_test(suite) ->
- [];
-ossl_time_test(Config) when is_list(Config) ->
- ssl_time_test(ossl, Config).
-
essl_time_test(doc) ->
["using new of configure new SSL"];
essl_time_test(suite) ->
@@ -1725,14 +1565,6 @@ pssl_block_503(suite) ->
pssl_block_503(Config) when is_list(Config) ->
ssl_block_503(ssl, Config).
-ossl_block_503(doc) ->
- ["Check that you will receive status code 503 when the server"
- " is blocked and 200 when its not blocked - using new of configure old SSL."];
-ossl_block_503(suite) ->
- [];
-ossl_block_503(Config) when is_list(Config) ->
- ssl_block_503(ossl, Config).
-
essl_block_503(doc) ->
["Check that you will receive status code 503 when the server"
" is blocked and 200 when its not blocked - using new of configure new SSL."];
@@ -1760,15 +1592,6 @@ pssl_block_disturbing_idle(suite) ->
pssl_block_disturbing_idle(Config) when is_list(Config) ->
ssl_block_disturbing_idle(ssl, Config).
-ossl_block_disturbing_idle(doc) ->
- ["Check that you can block/unblock an idle server. The strategy "
- "distribing does not really make a difference in this case."
- "Using new of configure old SSL"];
-ossl_block_disturbing_idle(suite) ->
- [];
-ossl_block_disturbing_idle(Config) when is_list(Config) ->
- ssl_block_disturbing_idle(ossl, Config).
-
essl_block_disturbing_idle(doc) ->
["Check that you can block/unblock an idle server. The strategy "
"distribing does not really make a difference in this case."
@@ -1797,15 +1620,6 @@ pssl_block_non_disturbing_idle(suite) ->
pssl_block_non_disturbing_idle(Config) when is_list(Config) ->
ssl_block_non_disturbing_idle(ssl, Config).
-ossl_block_non_disturbing_idle(doc) ->
- ["Check that you can block/unblock an idle server. The strategy "
- "non distribing does not really make a difference in this case."
- "Using new of configure old SSL"];
-ossl_block_non_disturbing_idle(suite) ->
- [];
-ossl_block_non_disturbing_idle(Config) when is_list(Config) ->
- ssl_block_non_disturbing_idle(ossl, Config).
-
essl_block_non_disturbing_idle(doc) ->
["Check that you can block/unblock an idle server. The strategy "
"non distribing does not really make a difference in this case."
@@ -1834,15 +1648,6 @@ pssl_block_disturbing_active(suite) ->
pssl_block_disturbing_active(Config) when is_list(Config) ->
ssl_block_disturbing_active(ssl, Config).
-ossl_block_disturbing_active(doc) ->
- ["Check that you can block/unblock an active server. The strategy "
- "distribing means ongoing requests should be terminated."
- "Using new of configure old SSL"];
-ossl_block_disturbing_active(suite) ->
- [];
-ossl_block_disturbing_active(Config) when is_list(Config) ->
- ssl_block_disturbing_active(ossl, Config).
-
essl_block_disturbing_active(doc) ->
["Check that you can block/unblock an active server. The strategy "
"distribing means ongoing requests should be terminated."
@@ -1871,15 +1676,6 @@ pssl_block_non_disturbing_active(suite) ->
pssl_block_non_disturbing_active(Config) when is_list(Config) ->
ssl_block_non_disturbing_active(ssl, Config).
-ossl_block_non_disturbing_active(doc) ->
- ["Check that you can block/unblock an idle server. The strategy "
- "non distribing means the ongoing requests should be compleated."
- "Using new of configure old SSL"];
-ossl_block_non_disturbing_active(suite) ->
- [];
-ossl_block_non_disturbing_active(Config) when is_list(Config) ->
- ssl_block_non_disturbing_active(ossl, Config).
-
essl_block_non_disturbing_active(doc) ->
["Check that you can block/unblock an idle server. The strategy "
"non distribing means the ongoing requests should be compleated."
@@ -1910,17 +1706,6 @@ pssl_block_disturbing_active_timeout_not_released(Config)
when is_list(Config) ->
ssl_block_disturbing_active_timeout_not_released(ssl, Config).
-ossl_block_disturbing_active_timeout_not_released(doc) ->
- ["Check that you can block an active server. The strategy "
- "distribing means ongoing requests should be compleated"
- "if the timeout does not occur."
- "Using new of configure old SSL"];
-ossl_block_disturbing_active_timeout_not_released(suite) ->
- [];
-ossl_block_disturbing_active_timeout_not_released(Config)
- when is_list(Config) ->
- ssl_block_disturbing_active_timeout_not_released(ossl, Config).
-
essl_block_disturbing_active_timeout_not_released(doc) ->
["Check that you can block an active server. The strategy "
"distribing means ongoing requests should be compleated"
@@ -1954,17 +1739,6 @@ pssl_block_disturbing_active_timeout_released(Config)
when is_list(Config) ->
ssl_block_disturbing_active_timeout_released(ssl, Config).
-ossl_block_disturbing_active_timeout_released(doc) ->
- ["Check that you can block an active server. The strategy "
- "distribing means ongoing requests should be terminated when"
- "the timeout occurs."
- "Using new of configure old SSL"];
-ossl_block_disturbing_active_timeout_released(suite) ->
- [];
-ossl_block_disturbing_active_timeout_released(Config)
- when is_list(Config) ->
- ssl_block_disturbing_active_timeout_released(ossl, Config).
-
essl_block_disturbing_active_timeout_released(doc) ->
["Check that you can block an active server. The strategy "
"distribing means ongoing requests should be terminated when"
@@ -1999,16 +1773,6 @@ pssl_block_non_disturbing_active_timeout_not_released(Config)
when is_list(Config) ->
ssl_block_non_disturbing_active_timeout_not_released(ssl, Config).
-ossl_block_non_disturbing_active_timeout_not_released(doc) ->
- ["Check that you can block an active server. The strategy "
- "non non distribing means ongoing requests should be completed."
- "Using new of configure old SSL"];
-ossl_block_non_disturbing_active_timeout_not_released(suite) ->
- [];
-ossl_block_non_disturbing_active_timeout_not_released(Config)
- when is_list(Config) ->
- ssl_block_non_disturbing_active_timeout_not_released(ossl, Config).
-
essl_block_non_disturbing_active_timeout_not_released(doc) ->
["Check that you can block an active server. The strategy "
"non non distribing means ongoing requests should be completed."
@@ -2043,17 +1807,6 @@ pssl_block_non_disturbing_active_timeout_released(Config)
when is_list(Config) ->
ssl_block_non_disturbing_active_timeout_released(ssl, Config).
-ossl_block_non_disturbing_active_timeout_released(doc) ->
- ["Check that you can block an active server. The strategy "
- "non distribing means ongoing requests should be completed. "
- "When the timeout occurs the block operation sohould be canceled."
- "Using new of configure old SSL"];
-ossl_block_non_disturbing_active_timeout_released(suite) ->
- [];
-ossl_block_non_disturbing_active_timeout_released(Config)
- when is_list(Config) ->
- ssl_block_non_disturbing_active_timeout_released(ossl, Config).
-
essl_block_non_disturbing_active_timeout_released(doc) ->
["Check that you can block an active server. The strategy "
"non distribing means ongoing requests should be completed. "
@@ -2087,13 +1840,6 @@ pssl_block_disturbing_blocker_dies(suite) ->
pssl_block_disturbing_blocker_dies(Config) when is_list(Config) ->
ssl_block_disturbing_blocker_dies(ssl, Config).
-ossl_block_disturbing_blocker_dies(doc) ->
- ["using new of configure old SSL"];
-ossl_block_disturbing_blocker_dies(suite) ->
- [];
-ossl_block_disturbing_blocker_dies(Config) when is_list(Config) ->
- ssl_block_disturbing_blocker_dies(ossl, Config).
-
essl_block_disturbing_blocker_dies(doc) ->
["using new of configure new SSL"];
essl_block_disturbing_blocker_dies(suite) ->
@@ -2118,13 +1864,6 @@ pssl_block_non_disturbing_blocker_dies(suite) ->
pssl_block_non_disturbing_blocker_dies(Config) when is_list(Config) ->
ssl_block_non_disturbing_blocker_dies(ssl, Config).
-ossl_block_non_disturbing_blocker_dies(doc) ->
- ["using new of configure old SSL"];
-ossl_block_non_disturbing_blocker_dies(suite) ->
- [];
-ossl_block_non_disturbing_blocker_dies(Config) when is_list(Config) ->
- ssl_block_non_disturbing_blocker_dies(ossl, Config).
-
essl_block_non_disturbing_blocker_dies(doc) ->
["using new of configure new SSL"];
essl_block_non_disturbing_blocker_dies(suite) ->
@@ -2149,13 +1888,6 @@ pssl_restart_no_block(suite) ->
pssl_restart_no_block(Config) when is_list(Config) ->
ssl_restart_no_block(ssl, Config).
-ossl_restart_no_block(doc) ->
- ["using new of configure old SSL"];
-ossl_restart_no_block(suite) ->
- [];
-ossl_restart_no_block(Config) when is_list(Config) ->
- ssl_restart_no_block(ossl, Config).
-
essl_restart_no_block(doc) ->
["using new of configure new SSL"];
essl_restart_no_block(suite) ->
@@ -2180,13 +1912,6 @@ pssl_restart_disturbing_block(suite) ->
pssl_restart_disturbing_block(Config) when is_list(Config) ->
ssl_restart_disturbing_block(ssl, Config).
-ossl_restart_disturbing_block(doc) ->
- ["using new of configure old SSL"];
-ossl_restart_disturbing_block(suite) ->
- [];
-ossl_restart_disturbing_block(Config) when is_list(Config) ->
- ssl_restart_disturbing_block(ossl, Config).
-
essl_restart_disturbing_block(doc) ->
["using new of configure new SSL"];
essl_restart_disturbing_block(suite) ->
@@ -2244,13 +1969,6 @@ pssl_restart_non_disturbing_block(suite) ->
pssl_restart_non_disturbing_block(Config) when is_list(Config) ->
ssl_restart_non_disturbing_block(ssl, Config).
-ossl_restart_non_disturbing_block(doc) ->
- ["using new of configure old SSL"];
-ossl_restart_non_disturbing_block(suite) ->
- [];
-ossl_restart_non_disturbing_block(Config) when is_list(Config) ->
- ssl_restart_non_disturbing_block(ossl, Config).
-
essl_restart_non_disturbing_block(doc) ->
["using new of configure new SSL"];
essl_restart_non_disturbing_block(suite) ->
@@ -2571,24 +2289,24 @@ ticket_5913(doc) ->
["Tests that a header without last-modified is handled"];
ticket_5913(suite) -> [];
ticket_5913(Config) ->
- ok=httpd_test_lib:verify_request(ip_comm, ?config(host, Config),
- ?IP_PORT, ?config(node, Config),
+ ok = httpd_test_lib:verify_request(ip_comm, ?config(host, Config),
+ ?IP_PORT, ?config(node, Config),
"GET /cgi-bin/erl/httpd_example:get_bin "
"HTTP/1.0\r\n\r\n",
[{statuscode, 200},
- {version, "HTTP/1.0"}]),
+ {version, "HTTP/1.0"}]),
ok.
ticket_6003(doc) ->
["Tests that a URI with a bad hexadecimal code is handled"];
ticket_6003(suite) -> [];
ticket_6003(Config) ->
- ok=httpd_test_lib:verify_request(ip_comm, ?config(host, Config),
- ?IP_PORT, ?config(node, Config),
- "GET http://www.erlang.org/%skalle "
- "HTTP/1.0\r\n\r\n",
- [{statuscode, 400},
- {version, "HTTP/1.0"}]),
+ ok = httpd_test_lib:verify_request(ip_comm, ?config(host, Config),
+ ?IP_PORT, ?config(node, Config),
+ "GET http://www.erlang.org/%skalle "
+ "HTTP/1.0\r\n\r\n",
+ [{statuscode, 400},
+ {version, "HTTP/1.0"}]),
ok.
ticket_7304(doc) ->
@@ -2646,7 +2364,6 @@ create_config(Config, Access, FileName) ->
SSL =
if
(Type =:= ssl) orelse
- (Type =:= ossl) orelse
(Type =:= essl) ->
[cline(["SSLCertificateFile ",
filename:join(ServerRoot, "ssl/ssl_server.pem")]),
@@ -3041,7 +2758,6 @@ create_ipv6_config(Config, FileName, Ipv6Address) ->
SSL =
if
(SockType =:= ssl) orelse
- (SockType =:= ossl) orelse
(SockType =:= essl) ->
[cline(["SSLCertificateFile ",
filename:join(ServerRoot, "ssl/ssl_server.pem")]),
diff --git a/lib/inets/test/httpd_basic_SUITE.erl b/lib/inets/test/httpd_basic_SUITE.erl
index f23d0b4765..4cd38f2ec4 100644
--- a/lib/inets/test/httpd_basic_SUITE.erl
+++ b/lib/inets/test/httpd_basic_SUITE.erl
@@ -59,9 +59,28 @@ init_per_suite(Config) ->
"~n Config: ~p", [Config]),
ok = inets:start(),
PrivDir = ?config(priv_dir, Config),
- HttpdConf = [{port, 0}, {ipfamily, inet},
- {server_name, "httpd_test"}, {server_root, PrivDir},
- {document_root, PrivDir}, {bind_address, "localhost"}],
+
+ Dummy =
+"<HTML>
+<HEAD>
+<TITLE>/index.html</TITLE>
+</HEAD>
+<BODY>
+DUMMY
+</BODY>
+</HTML>",
+
+ DummyFile = filename:join([PrivDir,"dummy.html"]),
+ {ok, Fd} = file:open(DummyFile, [write]),
+ ok = file:write(Fd, Dummy),
+ ok = file:close(Fd),
+ HttpdConf = [{port, 0},
+ {ipfamily, inet},
+ {server_name, "httpd_test"},
+ {server_root, PrivDir},
+ {document_root, PrivDir},
+ {bind_address, "localhost"}],
+
[{httpd_conf, HttpdConf} | Config].
%%--------------------------------------------------------------------
@@ -133,6 +152,10 @@ uri_too_long_414(Config) when is_list(Config) ->
{version, "HTTP/0.9"}]),
inets:stop(httpd, Pid).
+
+%%-------------------------------------------------------------------------
+%%-------------------------------------------------------------------------
+
header_too_long_413(doc) ->
["Test that too long headers's get 413 HTTP code"];
header_too_long_413(suite) ->
@@ -152,34 +175,92 @@ header_too_long_413(Config) when is_list(Config) ->
{version, "HTTP/1.1"}]),
inets:stop(httpd, Pid).
+
+%%-------------------------------------------------------------------------
+%%-------------------------------------------------------------------------
+
escaped_url_in_error_body(doc) ->
["Test Url-encoding see OTP-8940"];
escaped_url_in_error_body(suite) ->
[];
escaped_url_in_error_body(Config) when is_list(Config) ->
- tsp("escaped_url_in_error_body -> entry with"
- "~n Config: ~p", [Config]),
- HttpdConf = ?config(httpd_conf, Config),
- {ok, Pid} = inets:start(httpd, [{port, 0} | HttpdConf]),
- Info = httpd:info(Pid),
- Port = proplists:get_value(port, Info),
- _Address = proplists:get_value(bind_address, Info),
- Path = "/<b>this_is_bold</b>",
- URL = ?URL_START ++ integer_to_list(Port) ++ Path,
- EscapedPath = http_uri:encode(Path),
- {ok, {404, Body1}} = httpc:request(get, {URL, []},
- [{url_encode, true},
- {version, "HTTP/1.0"}],
- [{full_result, false}]),
- EscapedPath = find_URL_path(string:tokens(Body1, " ")),
- {ok, {404, Body2}} = httpc:request(get, {URL, []},
- [{url_encode, false},
- {version, "HTTP/1.0"}],
- [{full_result, false}]),
+ tsp("escaped_url_in_error_body -> entry"),
+ HttpdConf = ?config(httpd_conf, Config),
+ {ok, Pid} = inets:start(httpd, [{port, 0} | HttpdConf]),
+ Info = httpd:info(Pid),
+ Port = proplists:get_value(port, Info),
+ _Address = proplists:get_value(bind_address, Info),
+
+ %% Request 1
+ tsp("escaped_url_in_error_body -> request 1"),
+ URL1 = ?URL_START ++ integer_to_list(Port),
+ %% Make sure the server is ok, by making a request for a valid page
+ case httpc:request(get, {URL1 ++ "/dummy.html", []},
+ [{url_encode, false},
+ {version, "HTTP/1.0"}],
+ [{full_result, false}]) of
+ {ok, {200, _}} ->
+ %% Don't care about the the body, just that we get a ok response
+ ok;
+ {ok, UnexpectedOK1} ->
+ tsf({unexpected_ok_1, UnexpectedOK1})
+ end,
+
+ %% Request 2
+ tsp("escaped_url_in_error_body -> request 2"),
+ %% Make sure the server is ok, by making a request for a valid page
+ case httpc:request(get, {URL1 ++ "/dummy.html", []},
+ [{url_encode, true},
+ {version, "HTTP/1.0"}],
+ [{full_result, false}]) of
+ {ok, {200, _}} ->
+ %% Don't care about the the body, just that we get a ok response
+ ok;
+ {ok, UnexpectedOK2} ->
+ tsf({unexpected_ok_2, UnexpectedOK2})
+ end,
+
+ %% Request 3
+ tsp("escaped_url_in_error_body -> request 3"),
+ %% Ask for a non-existing page(1)
+ Path = "/<b>this_is_bold<b>",
HTMLEncodedPath = http_util:html_encode(Path),
- HTMLEncodedPath = find_URL_path(string:tokens(Body2, " ")),
+ URL2 = URL1 ++ Path,
+ case httpc:request(get, {URL2, []},
+ [{url_encode, true},
+ {version, "HTTP/1.0"}],
+ [{full_result, false}]) of
+ {ok, {404, Body3}} ->
+ case find_URL_path(string:tokens(Body3, " ")) of
+ HTMLEncodedPath ->
+ ok;
+ BadPath3 ->
+ tsf({unexpected_path_3, HTMLEncodedPath, BadPath3})
+ end;
+ {ok, UnexpectedOK3} ->
+ tsf({unexpected_ok_1, UnexpectedOK3})
+ end,
+
+ %% Request 4
+ tsp("escaped_url_in_error_body -> request 4"),
+ %% Ask for a non-existing page(2)
+ case httpc:request(get, {URL2, []},
+ [{url_encode, false},
+ {version, "HTTP/1.0"}],
+ [{full_result, false}]) of
+ {ok, {404, Body4}} ->
+ case find_URL_path(string:tokens(Body4, " ")) of
+ HTMLEncodedPath ->
+ ok;
+ BadPath4 ->
+ tsf({unexpected_path_2, HTMLEncodedPath, BadPath4})
+ end;
+ {ok, UnexpectedOK4} ->
+ tsf({unexpected_ok_4, UnexpectedOK4})
+ end,
+ tsp("escaped_url_in_error_body -> stop inets"),
inets:stop(httpd, Pid),
- tsp("escaped_url_in_error_body -> done"),
+ tsp("escaped_url_in_error_body -> done"),
ok.
find_URL_path([]) ->
@@ -191,7 +272,14 @@ find_URL_path([_ | Rest]) ->
tsp(F) ->
- tsp(F, []).
+ inets_test_lib:tsp(F).
tsp(F, A) ->
- test_server:format("~p ~p:" ++ F ++ "~n", [self(), ?MODULE | A]).
+ inets_test_lib:tsp(F, A).
+
+tsf(Reason) ->
+ test_server:fail(Reason).
+
+
+skip(Reason) ->
+ {skip, Reason}.
diff --git a/lib/inets/test/httpd_mod.erl b/lib/inets/test/httpd_mod.erl
index 1754cec7bc..5016cdb9e6 100644
--- a/lib/inets/test/httpd_mod.erl
+++ b/lib/inets/test/httpd_mod.erl
@@ -1,8 +1,8 @@
%%
%% %CopyrightBegin%
-%%
+%%
%% Copyright Ericsson AB 2005-2011. All Rights Reserved.
-%%
+%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
%% compliance with the License. You should have received a copy of the
@@ -88,13 +88,13 @@ actions(Type, Port, Host, Node) ->
%%-------------------------------------------------------------------------
security(ServerRoot, Type, Port, Host, Node) ->
-%% io:format(user, "~w:security -> entry with"
-%% "~n ServerRoot: ~p"
-%% "~n Type: ~p"
-%% "~n Port: ~p"
-%% "~n Host: ~p"
-%% "~n Node: ~p"
-%% "~n", [?MODULE, ServerRoot, Type, Port, Host, Node]),
+ %% io:format(user, "~w:security -> entry with"
+ %% "~n ServerRoot: ~p"
+ %% "~n Type: ~p"
+ %% "~n Port: ~p"
+ %% "~n Host: ~p"
+ %% "~n Node: ~p"
+ %% "~n", [?MODULE, ServerRoot, Type, Port, Host, Node]),
%% io:format(user, "~w:security -> register~n", [?MODULE]),
global:register_name(mod_security_test, self()), % Receive events
@@ -175,8 +175,8 @@ security(ServerRoot, Type, Port, Host, Node) ->
[{"one",_, Port, OpenDir,_}] ->
ok;
Blocked ->
- io:format(user, "~w:security -> Blocked: ~p"
- "~n", [?MODULE, Blocked]),
+ %% io:format(user, "~w:security -> Blocked: ~p"
+ %% "~n", [?MODULE, Blocked]),
exit({unexpected_blocked, Blocked})
end,
@@ -917,11 +917,11 @@ list_users(Node, Root, _Host, Port, Dir) ->
receive_security_event(Event, Node, Port) ->
-%% io:format(user, "~w:receive_security_event -> entry with"
-%% "~n Event: ~p"
-%% "~n Node: ~p"
-%% "~n Port: ~p"
-%% "~n", [?MODULE, Event, Node, Port]),
+ %% io:format(user, "~w:receive_security_event -> entry with"
+ %% "~n Event: ~p"
+ %% "~n Node: ~p"
+ %% "~n Port: ~p"
+ %% "~n", [?MODULE, Event, Node, Port]),
receive
Event ->
ok;
diff --git a/lib/inets/test/httpd_test_lib.erl b/lib/inets/test/httpd_test_lib.erl
index 581461fe03..1c7bb512cc 100644
--- a/lib/inets/test/httpd_test_lib.erl
+++ b/lib/inets/test/httpd_test_lib.erl
@@ -1,8 +1,8 @@
%%
%% %CopyrightBegin%
-%%
+%%
%% Copyright Ericsson AB 2001-2011. All Rights Reserved.
-%%
+%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
%% compliance with the License. You should have received a copy of the
@@ -140,6 +140,9 @@ request(#state{mfa = {Module, Function, Args},
HeadRequest = lists:sublist(RequestStr, 1, 4),
receive
{tcp, Socket, Data} ->
+ io:format("~p ~w[~w]request -> received (tcp) data"
+ "~n Data: ~p"
+ "~n", [self(), ?MODULE, ?LINE, Data]),
print(tcp, Data, State),
case Module:Function([Data | Args]) of
{ok, Parsed} ->
@@ -150,11 +153,19 @@ request(#state{mfa = {Module, Function, Args},
request(State#state{mfa = NewMFA}, TimeOut)
end;
{tcp_closed, Socket} when Function =:= whole_body ->
+ io:format("~p ~w[~w]request -> "
+ "received (tcp) closed when whole_body"
+ "~n", [self(), ?MODULE, ?LINE]),
print(tcp, "closed", State),
State#state{body = hd(Args)};
{tcp_closed, Socket} ->
+ io:format("~p ~w[~w]request -> received (tcp) closed"
+ "~n", [self(), ?MODULE, ?LINE]),
test_server:fail(connection_closed);
{tcp_error, Socket, Reason} ->
+ io:format("~p ~w[~w]request -> received (tcp) error"
+ "~n Reason: ~p"
+ "~n", [self(), ?MODULE, ?LINE, Reason]),
test_server:fail({tcp_error, Reason});
{ssl, Socket, Data} ->
print(ssl, Data, State),
@@ -174,11 +185,21 @@ request(#state{mfa = {Module, Function, Args},
{ssl_error, Socket, Reason} ->
test_server:fail({ssl_error, Reason})
after TimeOut ->
+ io:format("~p ~w[~w]request -> timeout"
+ "~n", [self(), ?MODULE, ?LINE]),
test_server:fail(connection_timed_out)
end.
handle_http_msg({Version, StatusCode, ReasonPharse, Headers, Body},
State = #state{request = RequestStr}) ->
+ io:format("~p ~w[~w]handle_http_msg -> entry with"
+ "~n Version: ~p"
+ "~n StatusCode: ~p"
+ "~n ReasonPharse: ~p"
+ "~n Headers: ~p"
+ "~n Body: ~p"
+ "~n", [self(), ?MODULE, ?LINE,
+ Version, StatusCode, ReasonPharse, Headers, Body]),
case is_expect(RequestStr) of
true ->
State#state{status_line = {Version,
@@ -235,13 +256,14 @@ handle_http_body(Body, State = #state{headers = Headers,
end.
validate(RequestStr, #state{status_line = {Version, StatusCode, _},
- headers = Headers,
- body = Body}, Options, N, P) ->
+ headers = Headers,
+ body = Body}, Options, N, P) ->
%% tsp("validate -> entry with"
%% "~n StatusCode: ~p"
%% "~n Headers: ~p"
%% "~n Body: ~p", [StatusCode, Headers, Body]),
+
check_version(Version, Options),
case lists:keysearch(statuscode, 1, Options) of
{value, _} ->
@@ -255,6 +277,7 @@ validate(RequestStr, #state{status_line = {Version, StatusCode, _},
list_to_integer(Headers#http_response_h.'content-length'),
Body).
+
%%--------------------------------------------------------------------
%% Internal functions
%%------------------------------------------------------------------
@@ -263,21 +286,20 @@ check_version(Version, Options) ->
{value, {version, Version}} ->
ok;
{value, {version, Ver}} ->
- test_server:fail({wrong_version, [{got, Version},
- {expected, Ver}]});
+ tsf({wrong_version, [{got, Version},
+ {expected, Ver}]});
_ ->
case Version of
"HTTP/1.1" ->
ok;
_ ->
- test_server:fail({wrong_version, [{got, Version},
- {expected, "HTTP/1.1"}]})
+ tsf({wrong_version, [{got, Version},
+ {expected, "HTTP/1.1"}]})
end
end.
check_status_code(StatusCode, [], Options) ->
- test_server:fail({wrong_status_code, [{got, StatusCode},
- {expected, Options}]});
+ tsf({wrong_status_code, [{got, StatusCode}, {expected, Options}]});
check_status_code(StatusCode, Current = [_ | Rest], Options) ->
case lists:keysearch(statuscode, 1, Current) of
{value, {statuscode, StatusCode}} ->
@@ -285,8 +307,7 @@ check_status_code(StatusCode, Current = [_ | Rest], Options) ->
{value, {statuscode, _OtherStatus}} ->
check_status_code(StatusCode, Rest, Options);
false ->
- test_server:fail({wrong_status_code, [{got, StatusCode},
- {expected, Options}]})
+ tsf({wrong_status_code, [{got, StatusCode}, {expected, Options}]})
end.
do_validate(_, [], _, _) ->
@@ -317,8 +338,7 @@ do_validate(Header, [{header, HeaderField, Value}|Rest],N,P) ->
Header})
end,
do_validate(Header, Rest, N, P);
-do_validate(Header,[{no_last_modified,HeaderField}|Rest],N,P) ->
-% io:format("Header: ~p~nHeaderField: ~p~n",[Header,HeaderField]),
+do_validate(Header,[{no_last_modified, HeaderField}|Rest],N,P) ->
case lists:keysearch(HeaderField,1,Header) of
{value,_} ->
test_server:fail({wrong_header_field_value, HeaderField,
@@ -331,7 +351,6 @@ do_validate(Header, [_Unknown | Rest], N, P) ->
do_validate(Header, Rest, N, P).
is_expect(RequestStr) ->
-
case inets_regexp:match(RequestStr, "xpect:100-continue") of
{match, _, _}->
true;
@@ -340,15 +359,15 @@ is_expect(RequestStr) ->
end.
%% OTP-5775, content-length
-check_body("GET /cgi-bin/erl/httpd_example:get_bin HTTP/1.0\r\n\r\n", 200, "text/html", Length, _Body) when Length /= 274->
- test_server:fail(content_length_error);
+check_body("GET /cgi-bin/erl/httpd_example:get_bin HTTP/1.0\r\n\r\n", 200, "text/html", Length, _Body) when (Length =/= 274) ->
+ tsf(content_length_error);
check_body("GET /cgi-bin/cgi_echo HTTP/1.0\r\n\r\n", 200, "text/plain",
_, Body) ->
case size(Body) of
100 ->
ok;
_ ->
- test_server:fail(content_length_error)
+ tsf(content_length_error)
end;
check_body(RequestStr, 200, "text/html", _, Body) ->
diff --git a/lib/inets/test/httpd_time_test.erl b/lib/inets/test/httpd_time_test.erl
index f39f9faff0..c54674be36 100644
--- a/lib/inets/test/httpd_time_test.erl
+++ b/lib/inets/test/httpd_time_test.erl
@@ -19,7 +19,7 @@
%%
-module(httpd_time_test).
--export([t/3, t1/2, t2/2, t3/2, t4/2]).
+-export([t/3, t1/2, t2/2, t4/2]).
-export([do/1, do/2, do/3, do/4, do/5]).
@@ -45,10 +45,6 @@ t2(Host, Port) ->
t(ssl, Host, Port).
-t3(Host, Port) ->
- t(ossl, Host, Port).
-
-
t4(Host, Port) ->
t(essl, Host, Port).
diff --git a/lib/inets/test/inets_test_lib.erl b/lib/inets/test/inets_test_lib.erl
index 2e19c41f16..ddb1a49394 100644
--- a/lib/inets/test/inets_test_lib.erl
+++ b/lib/inets/test/inets_test_lib.erl
@@ -340,9 +340,6 @@ connect_bin(SockType, Host, Port) ->
connect_bin(ssl, Host, Port, Opts0) ->
Opts = [binary, {packet,0} | Opts0],
connect(ssl, Host, Port, Opts);
-connect_bin(ossl, Host, Port, Opts0) ->
- Opts = [{ssl_imp, old}, binary, {packet,0} | Opts0],
- connect(ssl, Host, Port, Opts);
connect_bin(essl, Host, Port, Opts0) ->
Opts = [{ssl_imp, new}, binary, {packet,0}, {reuseaddr, true} | Opts0],
connect(ssl, Host, Port, Opts);
@@ -357,9 +354,6 @@ connect_byte(SockType, Host, Port) ->
connect_byte(ssl, Host, Port, Opts0) ->
Opts = [{packet,0} | Opts0],
connect(ssl, Host, Port, Opts);
-connect_byte(ossl, Host, Port, Opts0) ->
- Opts = [{ssl_imp, old}, {packet,0} | Opts0],
- connect(ssl, Host, Port, Opts);
connect_byte(essl, Host, Port, Opts0) ->
Opts = [{ssl_imp, new}, {packet,0} | Opts0],
connect(ssl, Host, Port, Opts);
@@ -421,8 +415,6 @@ connect(ip_comm, Host, Port, Opts) ->
send(ssl, Socket, Data) ->
ssl:send(Socket, Data);
-send(ossl, Socket, Data) ->
- ssl:send(Socket, Data);
send(essl, Socket, Data) ->
ssl:send(Socket, Data);
send(ip_comm,Socket,Data) ->
@@ -431,8 +423,6 @@ send(ip_comm,Socket,Data) ->
close(ssl,Socket) ->
catch ssl:close(Socket);
-close(ossl,Socket) ->
- catch ssl:close(Socket);
close(essl,Socket) ->
catch ssl:close(Socket);
close(ip_comm,Socket) ->
diff --git a/lib/inets/vsn.mk b/lib/inets/vsn.mk
index 0e77bf913d..1df4558e45 100644
--- a/lib/inets/vsn.mk
+++ b/lib/inets/vsn.mk
@@ -18,7 +18,7 @@
# %CopyrightEnd%
APPLICATION = inets
-INETS_VSN = 5.7.1
+INETS_VSN = 5.8
PRE_VSN =
APP_VSN = "$(APPLICATION)-$(INETS_VSN)$(PRE_VSN)"
diff --git a/lib/inviso/doc/src/make.dep b/lib/inviso/doc/src/make.dep
deleted file mode 100644
index 9459f74e6d..0000000000
--- a/lib/inviso/doc/src/make.dep
+++ /dev/null
@@ -1,27 +0,0 @@
-# ----------------------------------------------------
-# >>>> Do not edit this file <<<<
-# This file was automaticly generated by
-# /home/otp/bin/docdepend
-# ----------------------------------------------------
-
-
-# ----------------------------------------------------
-# TeX files that the DVI file depend on
-# ----------------------------------------------------
-
-book.dvi: book.tex inviso.tex inviso_as_lib.tex inviso_chapter.tex \
- inviso_lfm.tex inviso_lfm_tpfreader.tex inviso_rt.tex \
- inviso_rt_meta.tex part.tex ref_man.tex
-
-# ----------------------------------------------------
-# Source inlined when transforming from source to LaTeX
-# ----------------------------------------------------
-
-book.tex: ref_man.xml
-
-# ----------------------------------------------------
-# Pictures that the DVI file depend on
-# ----------------------------------------------------
-
-book.dvi: inviso_users_guide_pic1.ps
-
diff --git a/lib/inviso/src/inviso_tool_lib.erl b/lib/inviso/src/inviso_tool_lib.erl
index 7953acedd6..f221c4b6de 100644
--- a/lib/inviso/src/inviso_tool_lib.erl
+++ b/lib/inviso/src/inviso_tool_lib.erl
@@ -19,7 +19,7 @@
%% Support module to the inviso tool.
%%
%% Authors:
-%% Lennart �hman, [email protected]
+%% Lennart Öhman, [email protected]
%% -----------------------------------------------------------------------------
-module(inviso_tool_lib).
@@ -145,10 +145,10 @@ expand_module_names_2(Nodes,DirStr,ModStr,Opts) ->
%% Always returns a regexp or {error,Reason}.
expand_module_names_special_regexp(Str) ->
StrLen=length(Str),
- case regexp:first_match(Str,"[0-9a-zA-Z_/]*") of
- {match,1,StrLen} -> % Ok, it is the special case.
+ case re:run(Str,"[0-9a-zA-Z_/]*") of
+ {match,[{0,StrLen}]} -> % Ok, it is the special case.
{ok,".*"++Str++".*"}; % Convert it to a proper regexp.
- {match,_,_} ->
+ {match,_} ->
{ok,Str}; % Keep it and hope it is a regexp.
nomatch ->
{ok,Str}; % Keep it and hope it is a regexp.
diff --git a/lib/jinterface/doc/src/make.dep b/lib/jinterface/doc/src/make.dep
deleted file mode 100644
index a1b3c322c6..0000000000
--- a/lib/jinterface/doc/src/make.dep
+++ /dev/null
@@ -1,20 +0,0 @@
-# ----------------------------------------------------
-# >>>> Do not edit this file <<<<
-# This file was automaticly generated by
-# /home/otp/bin/docdepend
-# ----------------------------------------------------
-
-
-# ----------------------------------------------------
-# TeX files that the DVI file depend on
-# ----------------------------------------------------
-
-book.dvi: book.tex jinterface.tex jinterface_users_guide.tex \
- part.tex ref_man.tex
-
-# ----------------------------------------------------
-# Source inlined when transforming from source to LaTeX
-# ----------------------------------------------------
-
-book.tex: ref_man.xml
-
diff --git a/lib/jinterface/java_src/Makefile b/lib/jinterface/java_src/Makefile
index 755ef46a8b..19f99831eb 100644
--- a/lib/jinterface/java_src/Makefile
+++ b/lib/jinterface/java_src/Makefile
@@ -29,9 +29,7 @@ VSN=$(JINTERFACE_VSN)
# Common Macros
# ----------------------------------------------------
-# call recursive make explicitly below
-# due to separate makefiles for Ronja & OTP
-# SUB_DIRECTORIES = com/ericsson/otp/erlang
+SUB_DIRECTORIES = com/ericsson/otp/erlang
SPECIAL_TARGETS =
@@ -51,15 +49,5 @@ POM_SRC= $(POM_FILE).src
$(POM_TARGET): $(POM_SRC) ../vsn.mk
sed -e 's;%VSN%;$(VSN);' $< > $@
-# ----------------------------------------------------
-# Default Subdir Targets
-# ----------------------------------------------------
-
-.PHONY: debug opt instr release docs release_docs tests release_tests clean depend
-
-debug opt instr release docs release_docs tests release_tests clean depend: $(TARGET_FILES)
- set -e; set -x; \
- case "$(MAKE)" in *clearmake*) tflag="-T";; *) tflag="";; esac; \
- if test -f com/ericsson/otp/erlang/ignore_config_record.inf; then xflag=$$tflag; fi; \
- (cd com/ericsson/otp/erlang && $(MAKE) -f Makefile.otp $$xflag $@)
+include $(ERL_TOP)/make/otp_subdir.mk
diff --git a/lib/jinterface/java_src/com/ericsson/otp/erlang/Makefile.otp b/lib/jinterface/java_src/com/ericsson/otp/erlang/Makefile
index d0ff9cda34..e772a2b0a5 100644
--- a/lib/jinterface/java_src/com/ericsson/otp/erlang/Makefile.otp
+++ b/lib/jinterface/java_src/com/ericsson/otp/erlang/Makefile
@@ -96,7 +96,7 @@ docs:
# include $(ERL_TOP)/make/otp_release_targets.mk
release release_docs release_tests release_html:
- $(MAKE) -f Makefile.otp $(MFLAGS) RELEASE_PATH=$(RELEASE_PATH) $(TARGET_MAKEFILE) $@_spec
+ $(MAKE) $(MFLAGS) RELEASE_PATH=$(RELEASE_PATH) $(TARGET_MAKEFILE) $@_spec
release_spec: opt
$(INSTALL_DIR) $(RELSYSDIR)/java_src/com/ericsson/otp/erlang
diff --git a/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpErlangString.java b/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpErlangString.java
index 19ee92e0d0..23734bf83b 100644
--- a/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpErlangString.java
+++ b/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpErlangString.java
@@ -166,7 +166,7 @@ public class OtpErlangString extends OtpErlangObject implements Serializable,
/**
* Validate a code point according to Erlang definition; Unicode 3.0.
* That is; valid in the range U+0..U+10FFFF, but not in the range
- * U+D800..U+DFFF (surrogat pairs), nor U+FFFE..U+FFFF (non-characters).
+ * U+D800..U+DFFF (surrogat pairs).
*
* @param cp
* the code point value to validate
@@ -179,8 +179,7 @@ public class OtpErlangString extends OtpErlangObject implements Serializable,
// Erlang definition of valid Unicode code points;
// Unicode 3.0, XML, et.al.
return (cp>>>16) <= 0x10 // in 0..10FFFF; Unicode range
- && (cp & ~0x7FF) != 0xD800 // not in D800..DFFF; surrogate range
- && (cp & ~1) != 0xFFFE; // not in FFFE..FFFF; non-characters
+ && (cp & ~0x7FF) != 0xD800; // not in D800..DFFF; surrogate range
}
/**
diff --git a/lib/jinterface/java_src/com/ericsson/otp/erlang/ignore_config_record.inf b/lib/jinterface/java_src/com/ericsson/otp/erlang/ignore_config_record.inf
deleted file mode 100644
index 0a5053eba3..0000000000
--- a/lib/jinterface/java_src/com/ericsson/otp/erlang/ignore_config_record.inf
+++ /dev/null
@@ -1 +0,0 @@
-This file makes clearmake use the -T switch for this subdirectory
diff --git a/lib/kernel/doc/src/gen_sctp.xml b/lib/kernel/doc/src/gen_sctp.xml
index 688cd0f78f..418bfae4b8 100644
--- a/lib/kernel/doc/src/gen_sctp.xml
+++ b/lib/kernel/doc/src/gen_sctp.xml
@@ -45,7 +45,15 @@
SUSE Linux Enterprise Server 10 (x86_64) kernel 2.6.16.27-0.6-smp,
with lksctp-tools-1.0.6, briefly on Solaris 10, and later on
SUSE Linux Enterprise Server 10 Service Pack 1 (x86_64)
- kernel 2.6.16.54-0.2.3-smp with lksctp-tools-1.0.7.</p>
+ kernel 2.6.16.54-0.2.3-smp with lksctp-tools-1.0.7,
+ and later also on FreeBSD 8.2.
+ </p>
+ <p>
+ This module was written for one-to-many style sockets
+ (type <c>seqpacket</c>). With the addition of
+ <seealso marker="#peeloff/2">peeloff/2</seealso>, one-to-one style
+ sockets (type <c>stream</c>) were introduced.
+ </p>
<p>Record definitions for the <c>gen_sctp</c> module can be found using:</p>
<pre> -include_lib("kernel/include/inet_sctp.hrl"). </pre>
<p>These record definitions use the "new" spelling 'adaptation',
@@ -254,15 +262,19 @@
</desc>
</func>
<func>
- <name name="listen" arity="2"/>
+ <name name="listen" arity="2" clause_i="1"/>
+ <name name="listen" arity="2" clause_i="2"/>
<fsummary>Set up a socket to listen.</fsummary>
<desc>
<p>Sets up a socket to listen on the IP address and port number
- it is bound to. <c><anno>IsServer</anno></c> must be <c>true</c>
- or <c>false</c>.
- In the contrast to TCP, in SCTP there is no listening queue length.
- If <c><anno>IsServer</anno></c> is <c>true</c> the socket accepts new associations, i.e.
- it will become an SCTP server socket.</p>
+ it is bound to.</p>
+ <p>For type <c>seqpacket</c> sockets (the default)
+ <c><anno>IsServer</anno></c> must be <c>true</c> or <c>false</c>.
+ In the contrast to TCP, in SCTP there is no listening queue length.
+ If <c><anno>IsServer</anno></c> is <c>true</c> the socket accepts new associations, i.e.
+ it will become an SCTP server socket.</p>
+ <p>For type <c>stream</c> sockets <anno>Backlog</anno> defines
+ the backlog queue length just like in TCP.</p>
</desc>
</func>
<func>
@@ -295,12 +307,40 @@
is used. In particular, the socket is opened in
<seealso marker="#option-binary">binary</seealso> and
<seealso marker="#option-active">passive</seealso> mode,
+ with <anno>SockType</anno> <c>seqpacket</c>,
and with reasonably large
<seealso marker="#option-sndbuf">kernel</seealso> and driver
<seealso marker="#option-buffer">buffers.</seealso></p>
</desc>
</func>
<func>
+ <name name="peeloff" arity="2"/>
+ <fsummary>
+ Peel off a type <c>stream</c> socket from a type <c>seqpacket</c> one
+ </fsummary>
+ <desc>
+ <p>
+ Branch off an existing association <anno>Assoc</anno>
+ in a socket <anno>Socket</anno> of type <c>seqpacket</c>
+ (one-to-may style) into
+ a new socket <anno>NewSocket</anno> of type <c>stream</c>
+ (one-to-one style).
+ </p>
+ <p>
+ The existing association argument <anno>Assoc</anno>
+ can be either a
+ <seealso marker="#record-sctp_assoc_change">
+ #sctp_assoc_change{}
+ </seealso>
+ record as returned from e.g
+ <seealso marker="#recv-2">recv/*</seealso>,
+ <seealso marker="#connect-5">connect/*</seealso> or
+ from a listening socket in active mode. Or it can be just
+ the field <c>assoc_id</c> integer from such a record.
+ </p>
+ </desc>
+ </func>
+ <func>
<name name="recv" arity="1"/>
<name name="recv" arity="2"/>
<fsummary>Receive a message from a socket</fsummary>
diff --git a/lib/kernel/doc/src/heart.xml b/lib/kernel/doc/src/heart.xml
index e2dbcbe63d..26d1e27822 100644
--- a/lib/kernel/doc/src/heart.xml
+++ b/lib/kernel/doc/src/heart.xml
@@ -42,7 +42,7 @@
system.</p>
<p>An Erlang runtime system to be monitored by a heart program,
should be started with the command line flag <c>-heart</c> (see
- also <seealso marker="erts:erl">erl(1)</seealso>. The <c>heart</c>
+ also <seealso marker="erts:erl">erl(1)</seealso>). The <c>heart</c>
process is then started automatically:</p>
<pre>
% <input>erl -heart ...</input></pre>
diff --git a/lib/kernel/doc/src/kernel_app.xml b/lib/kernel/doc/src/kernel_app.xml
index bf513b7815..0f71a4f0f2 100644
--- a/lib/kernel/doc/src/kernel_app.xml
+++ b/lib/kernel/doc/src/kernel_app.xml
@@ -4,7 +4,7 @@
<appref>
<header>
<copyright>
- <year>1996</year><year>2009</year>
+ <year>1996</year><year>2011</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -231,6 +231,15 @@ MaxT = TickTime + TickTime / 4</code>
<p><em>Note:</em> Normally, a terminating node is detected
immediately.</p>
</item>
+ <tag><c>shutdown_timeout = integer() | infinity</c></tag>
+ <item>
+ <p>Specifies the time <c>application_controller</c> will wait
+ for an application to terminate during node shutdown. If the
+ timer expires, <c>application_controller</c> will brutally
+ kill <c>application_master</c> of the hanging
+ application. If this parameter is undefined, it defaults
+ to <c>infinity</c>.</p>
+ </item>
<tag><c>sync_nodes_mandatory = [NodeName]</c></tag>
<item>
<p>Specifies which other nodes <em>must</em> be alive in order
diff --git a/lib/kernel/doc/src/make.dep b/lib/kernel/doc/src/make.dep
deleted file mode 100644
index f79d1c6367..0000000000
--- a/lib/kernel/doc/src/make.dep
+++ /dev/null
@@ -1,28 +0,0 @@
-# ----------------------------------------------------
-# >>>> Do not edit this file <<<<
-# This file was automaticly generated by
-# /home/otp/bin/docdepend
-# ----------------------------------------------------
-
-
-# ----------------------------------------------------
-# TeX files that the DVI file depend on
-# ----------------------------------------------------
-
-book.dvi: app.tex application.tex auth.tex book.tex \
- code.tex config.tex disk_log.tex erl_boot_server.tex \
- erl_ddll.tex erl_prim_loader_stub.tex erlang_stub.tex \
- error_handler.tex error_logger.tex file.tex \
- gen_sctp.tex gen_tcp.tex gen_udp.tex global.tex \
- global_group.tex heart.tex inet.tex inet_res.tex \
- init_stub.tex kernel_app.tex net_adm.tex net_kernel.tex \
- os.tex packages.tex pg2.tex ref_man.tex rpc.tex \
- seq_trace.tex user.tex wrap_log_reader.tex \
- zlib_stub.tex
-
-# ----------------------------------------------------
-# Source inlined when transforming from source to LaTeX
-# ----------------------------------------------------
-
-book.tex: ref_man.xml
-
diff --git a/lib/kernel/doc/src/net_kernel.xml b/lib/kernel/doc/src/net_kernel.xml
index 3b7a710664..e54a427ff0 100644
--- a/lib/kernel/doc/src/net_kernel.xml
+++ b/lib/kernel/doc/src/net_kernel.xml
@@ -210,6 +210,10 @@
<p><c>net_kernel</c> is currently changing
<c>net_ticktime</c> to <c><anno>NetTicktime</anno></c> seconds.</p>
</item>
+ <tag><c>ignored</c></tag>
+ <item>
+ <p>The local node is not alive.</p>
+ </item>
</taglist>
</desc>
</func>
diff --git a/lib/kernel/src/dist.hrl b/lib/kernel/include/dist.hrl
index aea1ab81ba..aea1ab81ba 100644
--- a/lib/kernel/src/dist.hrl
+++ b/lib/kernel/include/dist.hrl
diff --git a/lib/kernel/src/dist_util.hrl b/lib/kernel/include/dist_util.hrl
index f2b0598532..f2b0598532 100644
--- a/lib/kernel/src/dist_util.hrl
+++ b/lib/kernel/include/dist_util.hrl
diff --git a/lib/kernel/src/net_address.hrl b/lib/kernel/include/net_address.hrl
index 5342076507..5342076507 100644
--- a/lib/kernel/src/net_address.hrl
+++ b/lib/kernel/include/net_address.hrl
diff --git a/lib/kernel/src/Makefile b/lib/kernel/src/Makefile
index 9db6014a7d..02be6b5036 100644
--- a/lib/kernel/src/Makefile
+++ b/lib/kernel/src/Makefile
@@ -118,11 +118,14 @@ MODULES = \
user_sup \
wrap_log_reader
-HRL_FILES= ../include/file.hrl ../include/inet.hrl ../include/inet_sctp.hrl
+HRL_FILES= ../include/file.hrl ../include/inet.hrl ../include/inet_sctp.hrl \
+ ../include/dist.hrl ../include/dist_util.hrl \
+ ../include/net_address.hrl
+
INTERNAL_HRL_FILES= application_master.hrl disk_log.hrl \
- net_address.hrl inet_dns.hrl inet_res.hrl \
+ inet_dns.hrl inet_res.hrl \
inet_boot.hrl inet_config.hrl inet_int.hrl \
- dist.hrl dist_util.hrl inet_dns_record_adts.hrl
+ inet_dns_record_adts.hrl
ERL_FILES= $(MODULES:%=%.erl)
@@ -215,7 +218,7 @@ $(EBIN)/code_server.beam: ../include/file.hrl
$(EBIN)/disk_log.beam: disk_log.hrl
$(EBIN)/disk_log_1.beam: disk_log.hrl ../include/file.hrl
$(EBIN)/disk_log_server.beam: disk_log.hrl
-$(EBIN)/dist_util.beam: dist_util.hrl dist.hrl
+$(EBIN)/dist_util.beam: ../include/dist_util.hrl ../include/dist.hrl
$(EBIN)/erl_boot_server.beam: inet_boot.hrl
$(EBIN)/erl_epmd.beam: inet_int.hrl erl_epmd.hrl
$(EBIN)/file.beam: ../include/file.hrl
@@ -226,7 +229,7 @@ $(EBIN)/global.beam: ../../stdlib/include/ms_transform.hrl
$(EBIN)/hipe_unified_loader.beam: ../../hipe/main/hipe.hrl hipe_ext_format.hrl
$(EBIN)/inet.beam: ../include/inet.hrl inet_int.hrl ../include/inet_sctp.hrl
$(EBIN)/inet6_tcp.beam: inet_int.hrl
-$(EBIN)/inet6_tcp_dist.beam: net_address.hrl dist.hrl dist_util.hrl
+$(EBIN)/inet6_tcp_dist.beam: ../include/net_address.hrl ../include/dist.hrl ../include/dist_util.hrl
$(EBIN)/inet6_udp.beam: inet_int.hrl
$(EBIN)/inet6_sctp.beam: inet_int.hrl
$(EBIN)/inet_config.beam: inet_config.hrl ../include/inet.hrl
@@ -237,10 +240,10 @@ $(EBIN)/inet_hosts.beam: ../include/inet.hrl
$(EBIN)/inet_parse.beam: ../include/file.hrl
$(EBIN)/inet_res.beam: ../include/inet.hrl inet_res.hrl inet_dns.hrl inet_int.hrl
$(EBIN)/inet_tcp.beam: inet_int.hrl
-$(EBIN)/inet_udp_dist.beam: net_address.hrl dist.hrl dist_util.hrl
+$(EBIN)/inet_udp_dist.beam: ../include/net_address.hrl ../include/dist.hrl ../include/dist_util.hrl
$(EBIN)/inet_udp.beam: inet_int.hrl
$(EBIN)/inet_sctp.beam: inet_int.hrl ../include/inet_sctp.hrl
-$(EBIN)/net_kernel.beam: net_address.hrl
+$(EBIN)/net_kernel.beam: ../include/net_address.hrl
$(EBIN)/os.beam: ../include/file.hrl
$(EBIN)/ram_file.beam: ../include/file.hrl
$(EBIN)/wrap_log_reader.beam: disk_log.hrl ../include/file.hrl
diff --git a/lib/kernel/src/application.erl b/lib/kernel/src/application.erl
index fa3a4c3d36..caac4d926c 100644
--- a/lib/kernel/src/application.erl
+++ b/lib/kernel/src/application.erl
@@ -28,8 +28,6 @@
-export([get_application/0, get_application/1, info/0]).
-export([start_type/0]).
--export([behaviour_info/1]).
-
%%%-----------------------------------------------------------------
-type start_type() :: 'normal'
@@ -59,12 +57,12 @@
%%------------------------------------------------------------------
--spec behaviour_info(atom()) -> 'undefined' | [{atom(), byte()}].
+-callback start(StartType :: normal | {takeover, node()} | {failover, node()},
+ StartArgs :: term()) ->
+ {ok, pid()} | {ok, pid(), State :: term()} | {error, Reason :: term}.
-behaviour_info(callbacks) ->
- [{start,2},{stop,1}];
-behaviour_info(_Other) ->
- undefined.
+-callback stop(State :: term()) ->
+ term().
%%%-----------------------------------------------------------------
%%% This module is API towards application_controller and
diff --git a/lib/kernel/src/application_controller.erl b/lib/kernel/src/application_controller.erl
index 42f527f400..ebfe84463a 100644
--- a/lib/kernel/src/application_controller.erl
+++ b/lib/kernel/src/application_controller.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2010. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2011. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -1180,10 +1180,27 @@ terminate(Reason, S) ->
_ ->
ok
end,
+ ShutdownTimeout =
+ case application:get_env(kernel, shutdown_timeout) of
+ undefined -> infinity;
+ {ok,T} -> T
+ end,
foreach(fun({_AppName, Id}) when is_pid(Id) ->
+ Ref = erlang:monitor(process, Id),
+ unlink(Id),
exit(Id, shutdown),
receive
+ %% Proc died before link
{'EXIT', Id, _} -> ok
+ after 0 ->
+ receive
+ {'DOWN', Ref, process, Id, _} -> ok
+ after ShutdownTimeout ->
+ exit(Id, kill),
+ receive
+ {'DOWN', Ref, process, Id, _} -> ok
+ end
+ end
end;
(_) -> ok
end,
diff --git a/lib/kernel/src/code.erl b/lib/kernel/src/code.erl
index 882e9625fe..b7fda69ce0 100644
--- a/lib/kernel/src/code.erl
+++ b/lib/kernel/src/code.erl
@@ -324,15 +324,7 @@ start_link(Flags) ->
%%-----------------------------------------------------------------
do_start(Flags) ->
- %% The following module_info/1 calls are here to ensure
- %% that these modules are loaded prior to their use elsewhere in
- %% the code_server.
- %% Otherwise a deadlock may occur when the code_server is starting.
- code_server = code_server:module_info(module),
- packages = packages:module_info(module),
- catch hipe_unified_loader:load_hipe_modules(),
- Modules2 = [gb_sets, gb_trees, ets, os, binary, unicode, filename, lists],
- lists:foreach(fun (M) -> M = M:module_info(module) end, Modules2),
+ load_code_server_prerequisites(),
Mode = get_mode(Flags),
case init:get_argument(root) of
@@ -360,6 +352,25 @@ do_start(Flags) ->
{error, crash}
end.
+%% Make sure that all modules that the code_server process calls
+%% (directly or indirectly) are loaded. Otherwise the code_server
+%% process will deadlock.
+
+load_code_server_prerequisites() ->
+ %% Please keep the alphabetical order.
+ Needed = [binary,
+ ets,
+ filename,
+ gb_sets,
+ gb_trees,
+ hipe_unified_loader,
+ lists,
+ os,
+ packages,
+ unicode],
+ [M = M:module_info(module) || M <- Needed],
+ ok.
+
do_stick_dirs() ->
do_s(compiler),
do_s(stdlib),
diff --git a/lib/kernel/src/code_server.erl b/lib/kernel/src/code_server.erl
index e3d22e7999..32a12e2b52 100644
--- a/lib/kernel/src/code_server.erl
+++ b/lib/kernel/src/code_server.erl
@@ -32,6 +32,8 @@
-import(lists, [foreach/2]).
+-define(ANY_NATIVE_CODE_LOADED, any_native_code_loaded).
+
-record(state, {supervisor,
root,
path,
@@ -97,6 +99,8 @@ init(Ref, Parent, [Root,Mode0]) ->
State0
end,
+ put(?ANY_NATIVE_CODE_LOADED, false),
+
Parent ! {Ref,{ok,self()}},
loop(State#state{supervisor = Parent}).
@@ -1278,20 +1282,35 @@ load_native_code(Mod, Bin) ->
%% Therefore we must test for that the loader modules are available
%% before trying to to load native code.
case erlang:module_loaded(hipe_unified_loader) of
- false -> no_native;
- true -> hipe_unified_loader:load_native_code(Mod, Bin)
+ false ->
+ no_native;
+ true ->
+ Result = hipe_unified_loader:load_native_code(Mod, Bin),
+ case Result of
+ {module,_} ->
+ put(?ANY_NATIVE_CODE_LOADED, true);
+ _ ->
+ ok
+ end,
+ Result
end.
hipe_result_to_status(Result) ->
case Result of
- {module,_} -> Result;
- _ -> {error,Result}
+ {module,_} ->
+ put(?ANY_NATIVE_CODE_LOADED, true),
+ Result;
+ _ ->
+ {error,Result}
end.
post_beam_load(Mod) ->
- case erlang:module_loaded(hipe_unified_loader) of
- false -> ok;
- true -> hipe_unified_loader:post_beam_load(Mod)
+ %% post_beam_load/1 can potentially be very expensive because it
+ %% blocks multi-scheduling; thus we want to avoid the call if we
+ %% know that it is not needed.
+ case get(?ANY_NATIVE_CODE_LOADED) of
+ true -> hipe_unified_loader:post_beam_load(Mod);
+ false -> ok
end.
int_list([H|T]) when is_integer(H) -> int_list(T);
diff --git a/lib/kernel/src/disk_log.erl b/lib/kernel/src/disk_log.erl
index 9b8d2db437..d6bc23be6d 100644
--- a/lib/kernel/src/disk_log.erl
+++ b/lib/kernel/src/disk_log.erl
@@ -1240,20 +1240,29 @@ is_owner(Pid, L) ->
%% ok | throw(Error)
rename_file(File, NewFile, halt) ->
- file:rename(File, NewFile);
+ case file:rename(File, NewFile) of
+ ok ->
+ ok;
+ Else ->
+ file_error(NewFile, Else)
+ end;
rename_file(File, NewFile, wrap) ->
rename_file(wrap_file_extensions(File), File, NewFile, ok).
-rename_file([Ext|Exts], File, NewFile, Res) ->
- NRes = case file:rename(add_ext(File, Ext), add_ext(NewFile, Ext)) of
+rename_file([Ext|Exts], File, NewFile0, Res) ->
+ NewFile = add_ext(NewFile0, Ext),
+ NRes = case file:rename(add_ext(File, Ext), NewFile) of
ok ->
Res;
Else ->
- Else
+ file_error(NewFile, Else)
end,
- rename_file(Exts, File, NewFile, NRes);
+ rename_file(Exts, File, NewFile0, NRes);
rename_file([], _File, _NewFiles, Res) -> Res.
+file_error(FileName, {error, Error}) ->
+ {error, {file_error, FileName, Error}}.
+
%% "Old" error messages have been kept, arg_mismatch has been added.
%%-spec compare_arg(dlog_options(), #arg{},
compare_arg([], _A, none, _OrigHead) ->
@@ -1947,7 +1956,8 @@ monitor_request(Pid, Req) ->
receive
{'DOWN', Ref, process, Pid, _Info} ->
{error, no_such_log};
- {disk_log, Pid, Reply} ->
+ {disk_log, Pid, Reply} when not is_tuple(Reply) orelse
+ element(2, Reply) =/= disk_log_stopped ->
erlang:demonitor(Ref),
receive
{'DOWN', Ref, process, Pid, _Reason} ->
diff --git a/lib/kernel/src/error_handler.erl b/lib/kernel/src/error_handler.erl
index e1f99bf417..a67b11a888 100644
--- a/lib/kernel/src/error_handler.erl
+++ b/lib/kernel/src/error_handler.erl
@@ -88,12 +88,12 @@ int() -> int.
-spec crash(atom(), [term()]) -> no_return().
crash(Fun, Args) ->
- crash({Fun,Args}).
+ crash({Fun,Args,[]}).
-spec crash(atom(), atom(), arity()) -> no_return().
crash(M, F, A) ->
- crash({M,F,A}).
+ crash({M,F,A,[]}).
-spec crash(tuple()) -> no_return().
@@ -101,7 +101,8 @@ crash(Tuple) ->
try erlang:error(undef)
catch
error:undef ->
- erlang:raise(error, undef, [Tuple|tl(erlang:get_stacktrace())])
+ Stk = [Tuple|tl(erlang:get_stacktrace())],
+ erlang:raise(error, undef, Stk)
end.
%% If the code_server has not been started yet dynamic code loading
@@ -127,7 +128,7 @@ ensure_loaded(Module) ->
-spec stub_function(atom(), atom(), [_]) -> no_return().
stub_function(Mod, Func, Args) ->
- exit({undef,[{Mod,Func,Args}]}).
+ exit({undef,[{Mod,Func,Args,[]}]}).
check_inheritance(Module, Args) ->
Attrs = erlang:get_module_info(Module, attributes),
diff --git a/lib/kernel/src/file.erl b/lib/kernel/src/file.erl
index 5e4e1b0ba8..706c60caaf 100644
--- a/lib/kernel/src/file.erl
+++ b/lib/kernel/src/file.erl
@@ -1163,7 +1163,7 @@ path_open_first([Path|Rest], Name, Mode, LastError) ->
{error, _} = Error ->
Error;
FilePath ->
- FileName = filename:join(FilePath, Name),
+ FileName = fname_join(FilePath, Name),
case open(FileName, Mode) of
{ok, Fd} ->
{ok, Fd, FileName};
@@ -1176,6 +1176,11 @@ path_open_first([Path|Rest], Name, Mode, LastError) ->
path_open_first([], _Name, _Mode, LastError) ->
{error, LastError}.
+fname_join(".", Name) ->
+ Name;
+fname_join(Dir, Name) ->
+ filename:join(Dir, Name).
+
%%%-----------------------------------------------------------------
%%% Utility functions.
diff --git a/lib/kernel/src/gen_sctp.erl b/lib/kernel/src/gen_sctp.erl
index 6cebb7ab97..77ca26b845 100644
--- a/lib/kernel/src/gen_sctp.erl
+++ b/lib/kernel/src/gen_sctp.erl
@@ -27,7 +27,8 @@
-include("inet_sctp.hrl").
-export([open/0,open/1,open/2,close/1]).
--export([listen/2,connect/4,connect/5,connect_init/4,connect_init/5]).
+-export([listen/2,peeloff/2]).
+-export([connect/4,connect/5,connect_init/4,connect_init/5]).
-export([eof/2,abort/2]).
-export([send/3,send/4,recv/1,recv/2]).
-export([error_string/1]).
@@ -109,9 +110,11 @@ open() ->
| {ifaddr,IP}
| inet:address_family()
| {port,Port}
+ | {type,SockType}
| option(),
IP :: inet:ip_address() | any | loopback,
Port :: inet:port_number(),
+ SockType :: seqpacket | stream,
Socket :: sctp_socket().
open(Opts) when is_list(Opts) ->
@@ -134,9 +137,11 @@ open(X) ->
| {ifaddr,IP}
| inet:address_family()
| {port,Port}
+ | {type,SockType}
| option(),
IP :: inet:ip_address() | any | loopback,
Port :: inet:port_number(),
+ SockType :: seqpacket | stream,
Socket :: sctp_socket().
open(Port, Opts) when is_integer(Port), is_list(Opts) ->
@@ -161,17 +166,38 @@ close(S) ->
-spec listen(Socket, IsServer) -> ok | {error, Reason} when
Socket :: sctp_socket(),
IsServer :: boolean(),
+ Reason :: term();
+ (Socket, Backlog) -> ok | {error, Reason} when
+ Socket :: sctp_socket(),
+ Backlog :: integer(),
Reason :: term().
-listen(S, Flag) when is_port(S), is_boolean(Flag) ->
+listen(S, Backlog)
+ when is_port(S), is_boolean(Backlog);
+ is_port(S), is_integer(Backlog) ->
case inet_db:lookup_socket(S) of
{ok,Mod} ->
- Mod:listen(S, Flag);
+ Mod:listen(S, Backlog);
Error -> Error
end;
listen(S, Flag) ->
erlang:error(badarg, [S,Flag]).
+-spec peeloff(Socket, Assoc) -> {ok, NewSocket} | {error, Reason} when
+ Socket :: sctp_socket(),
+ Assoc :: #sctp_assoc_change{} | assoc_id(),
+ NewSocket :: sctp_socket(),
+ Reason :: term().
+
+peeloff(S, #sctp_assoc_change{assoc_id=AssocId}) when is_port(S) ->
+ peeloff(S, AssocId);
+peeloff(S, AssocId) when is_port(S), is_integer(AssocId) ->
+ case inet_db:lookup_socket(S) of
+ {ok,Mod} ->
+ Mod:peeloff(S, AssocId);
+ Error -> Error
+ end.
+
-spec connect(Socket, Addr, Port, Opts) -> {ok, Assoc} | {error, inet:posix()} when
Socket :: sctp_socket(),
Addr :: inet:ip_address() | inet:hostname(),
diff --git a/lib/kernel/src/global.erl b/lib/kernel/src/global.erl
index 7d15f8bf83..fa97614eca 100644
--- a/lib/kernel/src/global.erl
+++ b/lib/kernel/src/global.erl
@@ -28,7 +28,7 @@
%% External exports
-export([start/0, start_link/0, stop/0, sync/0, sync/1,
- safe_whereis_name/1, whereis_name/1, register_name/2,
+ whereis_name/1, register_name/2,
register_name/3, register_name_external/2, register_name_external/3,
unregister_name_external/1,re_register_name/2, re_register_name/3,
unregister_name/1, registered_names/0, send/2, node_disconnected/1,
@@ -203,10 +203,6 @@ send(Name, Msg) ->
whereis_name(Name) ->
where(Name).
--spec safe_whereis_name(term()) -> pid() | 'undefined'.
-safe_whereis_name(Name) ->
- gen_server:call(global_name_server, {whereis, Name}, infinity).
-
node_disconnected(Node) ->
global_name_server ! {nodedown, Node}.
@@ -510,8 +506,7 @@ init([]) ->
%% delay can sometimes be quite substantial. Global guarantees that
%% the name will eventually be removed, but there is no
%% synchronization between nodes; the name can be removed from some
-%% node(s) long before it is removed from other nodes. Using
-%% safe_whereis_name is no cure.
+%% node(s) long before it is removed from other nodes.
%%
%% - Global cannot handle problems with the distribution very well.
%% Depending on the value of the kernel variable 'net_ticktime' long
@@ -589,10 +584,6 @@ init([]) ->
{'reply', term(), state()} |
{'stop', 'normal', 'stopped', state()}.
-handle_call({whereis, Name}, From, S) ->
- do_whereis(Name, From),
- {noreply, S};
-
handle_call({registrar, Fun}, From, S) ->
S#state.the_registrar ! {trans_all_known, Fun, From},
{noreply, S};
@@ -1235,7 +1226,15 @@ ins_name_ext(Name, Pid, Method, RegNode, FromPidOrNode, ExtraInfo, S0) ->
where(Name) ->
case ets:lookup(global_names, Name) of
- [{_Name, Pid, _Method, _RPid, _Ref}] -> Pid;
+ [{_Name, Pid, _Method, _RPid, _Ref}] ->
+ if node(Pid) == node() ->
+ case is_process_alive(Pid) of
+ true -> Pid;
+ false -> undefined
+ end;
+ true ->
+ Pid
+ end;
[] -> undefined
end.
diff --git a/lib/kernel/src/hipe_unified_loader.erl b/lib/kernel/src/hipe_unified_loader.erl
index 1d3eb926ca..8b3aa0286d 100644
--- a/lib/kernel/src/hipe_unified_loader.erl
+++ b/lib/kernel/src/hipe_unified_loader.erl
@@ -36,7 +36,6 @@
-export([chunk_name/1,
%% Only the code and code_server modules may call the entries below!
- load_hipe_modules/0,
load_native_code/2,
post_beam_load/1,
load_module/3,
@@ -78,16 +77,6 @@ chunk_name(Architecture) ->
%%========================================================================
--spec load_hipe_modules() -> 'ok'.
-%% @doc
-%% Ensures HiPE's loader modules are loaded.
-%% Called from code.erl at start-up.
-
-load_hipe_modules() ->
- ok.
-
-%%========================================================================
-
-spec load_native_code(Mod, binary()) -> 'no_native' | {'module', Mod}
when is_subtype(Mod, atom()).
%% @doc
diff --git a/lib/kernel/src/inet.erl b/lib/kernel/src/inet.erl
index 48a6f3db65..b60c68e3a1 100644
--- a/lib/kernel/src/inet.erl
+++ b/lib/kernel/src/inet.erl
@@ -36,7 +36,7 @@
-export([i/0, i/1, i/2]).
--export([getll/1, getfd/1, open/7, fdopen/5]).
+-export([getll/1, getfd/1, open/8, fdopen/6]).
-export([tcp_controlling_process/2, udp_controlling_process/2,
tcp_close/1, udp_close/1]).
@@ -115,7 +115,8 @@
'mtu' | 'netmask' | 'flags' |'hwaddr'.
-type address_family() :: 'inet' | 'inet6'.
--type protocol_option() :: 'tcp' | 'udp' | 'sctp'.
+-type socket_protocol() :: 'tcp' | 'udp' | 'sctp'.
+-type socket_type() :: 'stream' | 'dgram' | 'seqpacket'.
-type stat_option() ::
'recv_cnt' | 'recv_max' | 'recv_avg' | 'recv_oct' | 'recv_dvi' |
'send_cnt' | 'send_max' | 'send_avg' | 'send_oct' | 'send_pend'.
@@ -748,6 +749,8 @@ sctp_opt([Opt|Opts], Mod, R, As) ->
sctp_opt(Opts, Mod, R#sctp_opts{port=P}, As);
Error -> Error
end;
+ {type,Type} when Type =:= seqpacket; Type =:= stream ->
+ sctp_opt(Opts, Mod, R#sctp_opts{type=Type}, As);
binary -> sctp_opt (Opts, Mod, R, As, mode, binary);
list -> sctp_opt (Opts, Mod, R, As, mode, list);
{sctp_module,_} -> sctp_opt (Opts, Mod, R, As); % Done with
@@ -996,13 +999,14 @@ gethostbyaddr_tm_native(Addr, Timer, Opts) ->
Addr :: ip_address(),
Port :: port_number(),
Opts :: [socket_setopt()],
- Protocol :: protocol_option(),
- Family :: 'inet' | 'inet6',
+ Protocol :: socket_protocol(),
+ Family :: address_family(),
+ Type :: socket_type(),
Module :: atom()) ->
{'ok', socket()} | {'error', posix()}.
-open(Fd, Addr, Port, Opts, Protocol, Family, Module) when Fd < 0 ->
- case prim_inet:open(Protocol, Family) of
+open(Fd, Addr, Port, Opts, Protocol, Family, Type, Module) when Fd < 0 ->
+ case prim_inet:open(Protocol, Family, Type) of
{ok,S} ->
case prim_inet:setopts(S, Opts) of
ok ->
@@ -1029,18 +1033,19 @@ open(Fd, Addr, Port, Opts, Protocol, Family, Module) when Fd < 0 ->
Error ->
Error
end;
-open(Fd, _Addr, _Port, Opts, Protocol, Family, Module) ->
- fdopen(Fd, Opts, Protocol, Family, Module).
+open(Fd, _Addr, _Port, Opts, Protocol, Family, Type, Module) ->
+ fdopen(Fd, Opts, Protocol, Family, Type, Module).
-spec fdopen(Fd :: non_neg_integer(),
Opts :: [socket_setopt()],
- Protocol :: protocol_option(),
+ Protocol :: socket_protocol(),
Family :: address_family(),
+ Type :: socket_type(),
Module :: atom()) ->
{'ok', socket()} | {'error', posix()}.
-fdopen(Fd, Opts, Protocol, Family, Module) ->
- case prim_inet:fdopen(Protocol, Fd, Family) of
+fdopen(Fd, Opts, Protocol, Family, Type, Module) ->
+ case prim_inet:fdopen(Protocol, Family, Type, Fd) of
{ok, S} ->
case prim_inet:setopts(S, Opts) of
ok ->
@@ -1056,18 +1061,24 @@ fdopen(Fd, Opts, Protocol, Family, Module) ->
%% socket stat
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-i() -> i(tcp), i(udp).
+i() -> i(tcp), i(udp), i(sctp).
i(Proto) -> i(Proto, [port, module, recv, sent, owner,
- local_address, foreign_address, state]).
+ local_address, foreign_address, state, type]).
i(tcp, Fs) ->
ii(tcp_sockets(), Fs, tcp);
i(udp, Fs) ->
- ii(udp_sockets(), Fs, udp).
+ ii(udp_sockets(), Fs, udp);
+i(sctp, Fs) ->
+ ii(sctp_sockets(), Fs, sctp).
ii(Ss, Fs, Proto) ->
- LLs = [h_line(Fs) | info_lines(Ss, Fs, Proto)],
+ LLs =
+ case info_lines(Ss, Fs, Proto) of
+ [] -> [];
+ InfoLines -> [h_line(Fs) | InfoLines]
+ end,
Maxs = foldl(
fun(Line,Max0) -> smax(Max0,Line) end,
duplicate(length(Fs),0),LLs),
@@ -1135,6 +1146,7 @@ info(S, F, Proto) ->
case prim_inet:gettype(S) of
{ok,{_,stream}} -> "STREAM";
{ok,{_,dgram}} -> "DGRAM";
+ {ok,{_,seqpacket}} -> "SEQPACKET";
_ -> " "
end;
fd ->
@@ -1186,6 +1198,7 @@ fmt_port(N, Proto) ->
%% Return a list of all tcp sockets
tcp_sockets() -> port_list("tcp_inet").
udp_sockets() -> port_list("udp_inet").
+sctp_sockets() -> port_list("sctp_inet").
%% Return all ports having the name 'Name'
port_list(Name) ->
diff --git a/lib/kernel/src/inet6_sctp.erl b/lib/kernel/src/inet6_sctp.erl
index 5bf3fca647..c47483bbdd 100644
--- a/lib/kernel/src/inet6_sctp.erl
+++ b/lib/kernel/src/inet6_sctp.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2007-2010. All Rights Reserved.
+%% Copyright Ericsson AB 2007-2011. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -32,7 +32,8 @@
-define(FAMILY, inet6).
-export([getserv/1,getaddr/1,getaddr/2,translate_ip/1]).
--export([open/1,close/1,listen/2,connect/5,sendmsg/3,send/4,recv/2]).
+-export([open/1,close/1,listen/2,peeloff/2,connect/5]).
+-export([sendmsg/3,send/4,recv/2]).
@@ -54,8 +55,8 @@ translate_ip(IP) ->
open(Opts) ->
case inet:sctp_options(Opts, ?MODULE) of
- {ok,#sctp_opts{fd=Fd,ifaddr=Addr,port=Port,opts=SOs}} ->
- inet:open(Fd, Addr, Port, SOs, sctp, ?FAMILY, ?MODULE);
+ {ok,#sctp_opts{fd=Fd,ifaddr=Addr,port=Port,type=Type,opts=SOs}} ->
+ inet:open(Fd, Addr, Port, SOs, sctp, ?FAMILY, Type, ?MODULE);
Error -> Error
end.
@@ -65,6 +66,14 @@ close(S) ->
listen(S, Flag) ->
prim_inet:listen(S, Flag).
+peeloff(S, AssocId) ->
+ case prim_inet:peeloff(S, AssocId) of
+ {ok, NewS}=Result ->
+ inet_db:register_socket(NewS, ?MODULE),
+ Result;
+ Error -> Error
+ end.
+
connect(S, Addr, Port, Opts, Timer) ->
inet_sctp:connect(S, Addr, Port, Opts, Timer).
diff --git a/lib/kernel/src/inet6_tcp.erl b/lib/kernel/src/inet6_tcp.erl
index cc45f6c7f6..c714b2bee0 100644
--- a/lib/kernel/src/inet6_tcp.erl
+++ b/lib/kernel/src/inet6_tcp.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2009. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2011. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -93,7 +93,7 @@ do_connect(Addr = {A,B,C,D,E,F,G,H}, Port, Opts, Time) when
port=BPort,
opts=SockOpts}}
when ?ip6(Ab,Bb,Cb,Db,Eb,Fb,Gb,Hb), ?port(BPort) ->
- case inet:open(Fd,BAddr,BPort,SockOpts,tcp,inet6,?MODULE) of
+ case inet:open(Fd,BAddr,BPort,SockOpts,tcp,inet6,stream,?MODULE) of
{ok, S} ->
case prim_inet:connect(S, Addr, Port, Time) of
ok -> {ok,S};
@@ -115,7 +115,7 @@ listen(Port, Opts) ->
port=BPort,
opts=SockOpts}=R}
when ?ip6(A,B,C,D,E,F,G,H), ?port(BPort) ->
- case inet:open(Fd,BAddr,BPort,SockOpts,tcp,inet6,?MODULE) of
+ case inet:open(Fd,BAddr,BPort,SockOpts,tcp,inet6,stream,?MODULE) of
{ok, S} ->
case prim_inet:listen(S, R#listen_opts.backlog) of
ok -> {ok, S};
@@ -149,5 +149,5 @@ accept(L,Timeout) ->
%% Create a port/socket from a file descriptor
%%
fdopen(Fd, Opts) ->
- inet:fdopen(Fd, Opts, tcp, inet6, ?MODULE).
+ inet:fdopen(Fd, Opts, tcp, inet6, stream, ?MODULE).
diff --git a/lib/kernel/src/inet6_udp.erl b/lib/kernel/src/inet6_udp.erl
index e81d417151..ca43c94211 100644
--- a/lib/kernel/src/inet6_udp.erl
+++ b/lib/kernel/src/inet6_udp.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2009. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2011. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -45,7 +45,7 @@ open(Port, Opts) ->
port=BPort,
opts=SockOpts}}
when ?ip6(A,B,C,D,E,F,G,H), ?port(BPort) ->
- inet:open(Fd,BAddr,BPort,SockOpts,udp,inet6,?MODULE);
+ inet:open(Fd,BAddr,BPort,SockOpts,udp,inet6,dgram,?MODULE);
{ok, _} -> exit(badarg)
end.
@@ -84,4 +84,4 @@ controlling_process(Socket, NewOwner) ->
%% Create a port/socket from a file descriptor
%%
fdopen(Fd, Opts) ->
- inet:fdopen(Fd, Opts, udp, inet6, ?MODULE).
+ inet:fdopen(Fd, Opts, udp, inet6, dgram, ?MODULE).
diff --git a/lib/kernel/src/inet_int.hrl b/lib/kernel/src/inet_int.hrl
index 6f1688c6a2..f8984b13fe 100644
--- a/lib/kernel/src/inet_int.hrl
+++ b/lib/kernel/src/inet_int.hrl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2010. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2011. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -29,7 +29,7 @@
-define(INET_AF_ANY, 3). % Fake for ANY in any address family
-define(INET_AF_LOOPBACK, 4). % Fake for LOOPBACK in any address family
-%% type codes (gettype, INET_REQ_GETTYPE)
+%% type codes to open and gettype - INET_REQ_GETTYPE
-define(INET_TYPE_STREAM, 1).
-define(INET_TYPE_DGRAM, 2).
-define(INET_TYPE_SEQPACKET, 3).
@@ -83,16 +83,19 @@
-define(INET_REQ_IFSET, 23).
-define(INET_REQ_SUBSCRIBE, 24).
-define(INET_REQ_GETIFADDRS, 25).
+-define(INET_REQ_ACCEPT, 26).
+-define(INET_REQ_LISTEN, 27).
%% TCP requests
--define(TCP_REQ_ACCEPT, 40).
--define(TCP_REQ_LISTEN, 41).
+%%-define(TCP_REQ_ACCEPT, 40). MOVED
+%%-define(TCP_REQ_LISTEN, 41). MERGED
-define(TCP_REQ_RECV, 42).
-define(TCP_REQ_UNRECV, 43).
-define(TCP_REQ_SHUTDOWN, 44).
%% UDP and SCTP requests
-define(PACKET_REQ_RECV, 60).
--define(SCTP_REQ_LISTEN, 61).
+%%-define(SCTP_REQ_LISTEN, 61). MERGED
-define(SCTP_REQ_BINDX, 62). %% Multi-home SCTP bind
+-define(SCTP_REQ_PEELOFF, 63).
%% subscribe codes, INET_REQ_SUBSCRIBE
-define(INET_SUBS_EMPTY_OUT_Q, 1).
@@ -100,7 +103,7 @@
%% reply codes for *_REQ_*
-define(INET_REP_ERROR, 0).
-define(INET_REP_OK, 1).
--define(INET_REP_SCTP, 2).
+-define(INET_REP, 2).
%% INET, TCP and UDP options:
-define(INET_OPT_REUSEADDR, 0).
@@ -399,6 +402,7 @@
ifaddr,
port = 0,
fd = -1,
+ type = seqpacket,
opts = [{mode, binary},
{buffer, ?SCTP_DEF_BUFSZ},
{sndbuf, ?SCTP_DEF_BUFSZ},
diff --git a/lib/kernel/src/inet_sctp.erl b/lib/kernel/src/inet_sctp.erl
index de74b573bd..2d799d79fa 100644
--- a/lib/kernel/src/inet_sctp.erl
+++ b/lib/kernel/src/inet_sctp.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2007-2010. All Rights Reserved.
+%% Copyright Ericsson AB 2007-2011. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -31,7 +31,8 @@
-define(FAMILY, inet).
-export([getserv/1,getaddr/1,getaddr/2,translate_ip/1]).
--export([open/1,close/1,listen/2,connect/5,sendmsg/3,send/4,recv/2]).
+-export([open/1,close/1,listen/2,peeloff/2,connect/5]).
+-export([sendmsg/3,send/4,recv/2]).
@@ -53,8 +54,8 @@ translate_ip(IP) ->
open(Opts) ->
case inet:sctp_options(Opts, ?MODULE) of
- {ok,#sctp_opts{fd=Fd,ifaddr=Addr,port=Port,opts=SOs}} ->
- inet:open(Fd, Addr, Port, SOs, sctp, ?FAMILY, ?MODULE);
+ {ok,#sctp_opts{fd=Fd,ifaddr=Addr,port=Port,type=Type,opts=SOs}} ->
+ inet:open(Fd, Addr, Port, SOs, sctp, ?FAMILY, Type, ?MODULE);
Error -> Error
end.
@@ -64,6 +65,14 @@ close(S) ->
listen(S, Flag) ->
prim_inet:listen(S, Flag).
+peeloff(S, AssocId) ->
+ case prim_inet:peeloff(S, AssocId) of
+ {ok, NewS}=Result ->
+ inet_db:register_socket(NewS, ?MODULE),
+ Result;
+ Error -> Error
+ end.
+
%% A non-blocking connect is implemented when the initial call is to
%% gen_sctp:connect_init which passes the value nowait as the Timer
connect(S, Addr, Port, Opts, Timer) ->
@@ -102,7 +111,7 @@ connect(S, Addr, Port, Opts, Timer) ->
connect_get_assoc(S, Addr, Port, false, Timer) ->
case recv(S, inet:timeout(Timer)) of
- {ok, {Addr, Port, [], #sctp_assoc_change{state=St}=Ev}} ->
+ {ok, {Addr, Port, _, #sctp_assoc_change{state=St}=Ev}} ->
if St =:= comm_up ->
%% Yes, successfully connected, return the whole
%% sctp_assoc_change event (containing, in particular,
@@ -123,7 +132,7 @@ connect_get_assoc(S, Addr, Port, false, Timer) ->
connect_get_assoc(S, Addr, Port, Active, Timer) ->
Timeout = inet:timeout(Timer),
receive
- {sctp,S,Addr,Port,{[],#sctp_assoc_change{state=St}=Ev}} ->
+ {sctp,S,Addr,Port,{_,#sctp_assoc_change{state=St}=Ev}} ->
case Active of
once ->
prim_inet:setopt(S, active, once);
diff --git a/lib/kernel/src/inet_tcp.erl b/lib/kernel/src/inet_tcp.erl
index 6dadccd6a9..4c2db16ce3 100644
--- a/lib/kernel/src/inet_tcp.erl
+++ b/lib/kernel/src/inet_tcp.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2009. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2011. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -95,7 +95,7 @@ do_connect({A,B,C,D}, Port, Opts, Time) when ?ip(A,B,C,D), ?port(Port) ->
port=BPort,
opts=SockOpts}}
when ?ip(Ab,Bb,Cb,Db), ?port(BPort) ->
- case inet:open(Fd,BAddr,BPort,SockOpts,tcp,inet,?MODULE) of
+ case inet:open(Fd,BAddr,BPort,SockOpts,tcp,inet,stream,?MODULE) of
{ok, S} ->
case prim_inet:connect(S, {A,B,C,D}, Port, Time) of
ok -> {ok,S};
@@ -117,7 +117,7 @@ listen(Port, Opts) ->
port=BPort,
opts=SockOpts}=R}
when ?ip(A,B,C,D), ?port(BPort) ->
- case inet:open(Fd,BAddr,BPort,SockOpts,tcp,inet,?MODULE) of
+ case inet:open(Fd,BAddr,BPort,SockOpts,tcp,inet,stream,?MODULE) of
{ok, S} ->
case prim_inet:listen(S, R#listen_opts.backlog) of
ok -> {ok, S};
@@ -150,4 +150,4 @@ accept(L,Timeout) ->
%% Create a port/socket from a file descriptor
%%
fdopen(Fd, Opts) ->
- inet:fdopen(Fd, Opts, tcp, inet, ?MODULE).
+ inet:fdopen(Fd, Opts, tcp, inet, stream, ?MODULE).
diff --git a/lib/kernel/src/inet_udp.erl b/lib/kernel/src/inet_udp.erl
index 60bd96f332..80d930fe10 100644
--- a/lib/kernel/src/inet_udp.erl
+++ b/lib/kernel/src/inet_udp.erl
@@ -52,7 +52,7 @@ open(Port, Opts) ->
ifaddr=BAddr={A,B,C,D},
port=BPort,
opts=SockOpts}} when ?ip(A,B,C,D), ?port(BPort) ->
- inet:open(Fd,BAddr,BPort,SockOpts,udp,inet,?MODULE);
+ inet:open(Fd,BAddr,BPort,SockOpts,udp,inet,dgram,?MODULE);
{ok, _} -> exit(badarg)
end.
@@ -93,7 +93,7 @@ controlling_process(Socket, NewOwner) ->
fdopen(Fd, Opts) ->
inet:fdopen(Fd,
optuniquify([{recbuf, ?RECBUF} | Opts]),
- udp, inet, ?MODULE).
+ udp, inet, dgram, ?MODULE).
%% Remove all duplicate options from an option list.
diff --git a/lib/kernel/src/kernel.appup.src b/lib/kernel/src/kernel.appup.src
index 54a63833e6..bded2408a7 100644
--- a/lib/kernel/src/kernel.appup.src
+++ b/lib/kernel/src/kernel.appup.src
@@ -1 +1,27 @@
-{"%VSN%",[],[]}.
+%% -*- erlang -*-
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 1999-2011. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+{"%VSN%",
+ %% Up from - max two major revisions back
+ [{<<"2\\.15(\\.[0-9]+)*">>,[restart_new_emulator]}, %% R15
+ {<<"2\\.14(\\.[0-9]+)*">>,[restart_new_emulator]}, %% R14
+ {<<"2\\.13(\\.[0-9]+)*">>,[restart_new_emulator]}],%% R13
+ %% Down to - max two major revisions back
+ [{<<"2\\.15(\\.[0-9]+)*">>,[restart_new_emulator]}, %% R15
+ {<<"2\\.14(\\.[0-9]+)*">>,[restart_new_emulator]}, %% R14
+ {<<"2\\.13(\\.[0-9]+)*">>,[restart_new_emulator]}] %% R13
+}.
diff --git a/lib/kernel/src/user_drv.erl b/lib/kernel/src/user_drv.erl
index c34f2ddeb0..e33b4830ab 100644
--- a/lib/kernel/src/user_drv.erl
+++ b/lib/kernel/src/user_drv.erl
@@ -117,8 +117,9 @@ server1(Iport, Oport, Shell) ->
{Curr,Shell1} =
case init:get_argument(remsh) of
{ok,[[Node]]} ->
- RShell = {list_to_atom(Node),shell,start,[]},
- RGr = group:start(self(), RShell),
+ ANode = list_to_atom(Node),
+ RShell = {ANode,shell,start,[]},
+ RGr = group:start(self(), RShell, rem_sh_opts(ANode)),
{RGr,RShell};
E when E =:= error ; E =:= {ok,[[]]} ->
{group:start(self(), Shell),Shell}
@@ -134,6 +135,9 @@ server1(Iport, Oport, Shell) ->
%% Enter the server loop.
server_loop(Iport, Oport, Curr, User, Gr).
+rem_sh_opts(Node) ->
+ [{expand_fun,fun(B)-> rpc:call(Node,edlin_expand,expand,[B]) end}].
+
%% start_user()
%% Start a group leader process and register it as 'user', unless,
%% of course, a 'user' already exists.
diff --git a/lib/kernel/src/user_sup.erl b/lib/kernel/src/user_sup.erl
index 35b7ff0cfe..7c97da189a 100644
--- a/lib/kernel/src/user_sup.erl
+++ b/lib/kernel/src/user_sup.erl
@@ -45,7 +45,7 @@ init([]) ->
Pid = start_slave(Master),
{ok, Pid, Pid};
{M, F, A} ->
- case start_user({M, F}, A) of
+ case start_user(M, F, A) of
{ok, Pid} ->
{ok, Pid, Pid};
Error ->
@@ -95,8 +95,8 @@ terminate(_Reason, UserPid) ->
%% is guaranteed that the user is started.
%%-----------------------------------------------------------------
-start_user(Func,A) ->
- apply(Func, A),
+start_user(Mod, Func, A) ->
+ apply(Mod, Func, A),
wait_for_user_p(100).
wait_for_user_p(0) ->
diff --git a/lib/kernel/test/application_SUITE.erl b/lib/kernel/test/application_SUITE.erl
index 2c5b8ccb66..f469a0af98 100644
--- a/lib/kernel/test/application_SUITE.erl
+++ b/lib/kernel/test/application_SUITE.erl
@@ -33,7 +33,7 @@
-export([config_change/1,
distr_changed_tc1/1, distr_changed_tc2/1,
- shutdown_func/1, do_shutdown/1]).
+ shutdown_func/1, do_shutdown/1, shutdown_timeout/1]).
-define(TESTCASE, testcase_name).
-define(testcase, ?config(?TESTCASE, Config)).
@@ -50,7 +50,7 @@ all() ->
load_use_cache, {group, reported_bugs}, start_phases,
script_start, nodedown_start, permit_false_start_local,
permit_false_start_dist, get_key,
- {group, distr_changed}, config_change, shutdown_func].
+ {group, distr_changed}, config_change, shutdown_func, shutdown_timeout].
groups() ->
[{reported_bugs, [],
@@ -1915,6 +1915,32 @@ do_shutdown(Reason) ->
+%%%-----------------------------------------------------------------
+%%% Tests the 'shutdown_timeout' kernel config parameter
+%%%-----------------------------------------------------------------
+shutdown_timeout(Config) when is_list(Config) ->
+ DataDir = ?config(data_dir,Config),
+ {ok,Cp1} = start_node(?MODULE_STRING++"_shutdown_timeout"),
+ wait_for_ready_net(),
+ ok = rpc:call(Cp1, application, set_env, [kernel, shutdown_timeout, 1000]),
+ rpc:call(Cp1, code, add_path, [filename:join([DataDir,deadlock])]),
+ ok = rpc:call(Cp1, application, start, [sasl]),
+ ok = rpc:call(Cp1, application, start, [deadlock]),
+ rpc:call(Cp1, deadlock, restart_and_fail, []),
+
+ ok = net_kernel:monitor_nodes(true),
+ _ = rpc:call(Cp1, init, stop, []),
+ receive
+ {nodedown,Cp1} ->
+ ok
+ after 10000 ->
+ ct:fail("timeout 10 sec: node termination hangs")
+ end,
+ ok.
+
+
+
+
%%-----------------------------------------------------------------
%% Utility functions
%%-----------------------------------------------------------------
diff --git a/lib/kernel/test/application_SUITE_data/Makefile.src b/lib/kernel/test/application_SUITE_data/Makefile.src
index a237f6badb..abc3c82907 100644
--- a/lib/kernel/test/application_SUITE_data/Makefile.src
+++ b/lib/kernel/test/application_SUITE_data/Makefile.src
@@ -2,7 +2,8 @@ EFLAGS=+debug_info
all: app_start_error.@EMULATOR@ trans_abnormal_sup.@EMULATOR@ \
trans_normal_sup.@EMULATOR@ transient.@EMULATOR@ \
- group_leader_sup.@EMULATOR@ group_leader.@EMULATOR@
+ group_leader_sup.@EMULATOR@ group_leader.@EMULATOR@ \
+ deadlock/deadlock.@EMULATOR@
app_start_error.@EMULATOR@: app_start_error.erl
erlc $(EFLAGS) app_start_error.erl
@@ -22,3 +23,5 @@ group_leader.@EMULATOR@: group_leader.erl
group_leader_sup.@EMULATOR@: group_leader_sup.erl
erlc $(EFLAGS) group_leader_sup.erl
+deadlock/deadlock.@EMULATOR@: deadlock/deadlock.erl
+ erlc $(EFLAGS) -o deadlock deadlock/deadlock.erl \ No newline at end of file
diff --git a/lib/kernel/test/application_SUITE_data/deadlock/deadlock.app b/lib/kernel/test/application_SUITE_data/deadlock/deadlock.app
new file mode 100644
index 0000000000..0c1001bed6
--- /dev/null
+++ b/lib/kernel/test/application_SUITE_data/deadlock/deadlock.app
@@ -0,0 +1,8 @@
+{application, deadlock, [
+ {vsn, "1"},
+ {registered, []},
+ {applications, [kernel, stdlib, sasl]},
+ {modules, [deadlock]},
+ {mod, {deadlock, []}},
+ {env, [{fail_start, false}]}
+]}.
diff --git a/lib/kernel/test/application_SUITE_data/deadlock/deadlock.erl b/lib/kernel/test/application_SUITE_data/deadlock/deadlock.erl
new file mode 100644
index 0000000000..5f68bf9078
--- /dev/null
+++ b/lib/kernel/test/application_SUITE_data/deadlock/deadlock.erl
@@ -0,0 +1,69 @@
+-module(deadlock).
+-behaviour(application).
+-compile(export_all).
+-define(SUP,deadlock_sup).
+-define(CHILD,deadlock_child).
+
+
+%%%-----------------------------------------------------------------
+%%% application callbacks
+start(_StartType, _StartArgs) ->
+ supervisor:start_link({local, ?SUP}, ?MODULE, [sup]).
+
+stop(_State) ->
+ ok.
+
+
+
+%%%-----------------------------------------------------------------
+%%% supervisor callbacks
+init([sup]) ->
+ {ok, {{one_for_one, 5, 10}, [
+ {
+ sasl_syslog_dm, {?MODULE, start_link, []},
+ permanent, brutal_kill, worker,
+ [deadlock]
+ }
+ ]}};
+
+
+%%%-----------------------------------------------------------------
+%%% gen_server callbacks
+init([child]) ->
+ case application:get_env(deadlock, fail_start) of
+ {ok, false} ->
+ %% we must not fail on the first init, otherwise supervisor
+ %% terminates immediately
+ {ok, []};
+ {ok, true} ->
+ timer:sleep(infinity), % init hangs!!!!
+ {ok, []}
+ end.
+
+handle_call(_Req, _From, State) ->
+ {reply, ok, State}.
+
+handle_cast(restart, State) ->
+ {stop, error, State}.
+
+handle_info(_Msg, State) ->
+ {noreply, State}.
+
+terminate(_Reason, _State) ->
+ ok.
+
+code_change(_OldVsn, State, _Extra) ->
+ {ok, State}.
+
+
+%%%-----------------------------------------------------------------
+%%% Start child
+start_link() ->
+ gen_server:start_link({local, ?CHILD}, ?MODULE, [child], []).
+
+
+%%%-----------------------------------------------------------------
+%%% Provoke hanging
+restart_and_fail() ->
+ application:set_env(deadlock, fail_start, true), % next init will hang
+ gen_server:cast(?CHILD, restart).
diff --git a/lib/kernel/test/code_SUITE.erl b/lib/kernel/test/code_SUITE.erl
index b677f34ed0..10ab3e4370 100644
--- a/lib/kernel/test/code_SUITE.erl
+++ b/lib/kernel/test/code_SUITE.erl
@@ -995,9 +995,9 @@ purge_stacktrace(Config) when is_list(Config) ->
error:function_clause ->
?line code:load_file(code_b_test),
?line case erlang:get_stacktrace() of
- [{?MODULE,_,[a]},
- {code_b_test,call,2},
- {?MODULE,purge_stacktrace,1}|_] ->
+ [{?MODULE,_,[a],_},
+ {code_b_test,call,2,_},
+ {?MODULE,purge_stacktrace,1,_}|_] ->
?line false = code:purge(code_b_test),
?line [] = erlang:get_stacktrace()
end
@@ -1007,8 +1007,8 @@ purge_stacktrace(Config) when is_list(Config) ->
error:function_clause ->
?line code:load_file(code_b_test),
?line case erlang:get_stacktrace() of
- [{code_b_test,call,[nofun,2]},
- {?MODULE,purge_stacktrace,1}|_] ->
+ [{code_b_test,call,[nofun,2],_},
+ {?MODULE,purge_stacktrace,1,_}|_] ->
?line false = code:purge(code_b_test),
?line [] = erlang:get_stacktrace()
end
@@ -1019,8 +1019,8 @@ purge_stacktrace(Config) when is_list(Config) ->
error:badarg ->
?line code:load_file(code_b_test),
?line case erlang:get_stacktrace() of
- [{code_b_test,call,Args},
- {?MODULE,purge_stacktrace,1}|_] ->
+ [{code_b_test,call,Args,_},
+ {?MODULE,purge_stacktrace,1,_}|_] ->
?line false = code:purge(code_b_test),
?line [] = erlang:get_stacktrace()
end
@@ -1481,7 +1481,7 @@ do_on_load_error(ReturnValue) ->
?line ErrorPid ! ReturnValue,
receive
{'DOWN',Ref,process,_,Exit} ->
- ?line {undef,[{on_load_error,main,[]}|_]} = Exit
+ ?line {undef,[{on_load_error,main,[],_}|_]} = Exit
end.
native_early_modules(suite) -> [];
diff --git a/lib/kernel/test/disk_log_SUITE.erl b/lib/kernel/test/disk_log_SUITE.erl
index ee1e2319b5..ad987fe7a7 100644
--- a/lib/kernel/test/disk_log_SUITE.erl
+++ b/lib/kernel/test/disk_log_SUITE.erl
@@ -1831,11 +1831,16 @@ block_queue2(Conf) when is_list(Conf) ->
%% Asynchronous stuff is ignored.
?line ok = disk_log:balog_terms(n, [<<"foo">>,<<"bar">>]),
?line ok = disk_log:balog_terms(n, [<<"more">>,<<"terms">>]),
+ Parent = self(),
?line Fun =
- fun() -> {error,disk_log_stopped} = disk_log:sync(n)
+ fun() ->
+ {error,no_such_log} = disk_log:sync(n),
+ receive {disk_log, _, {error, disk_log_stopped}} -> ok end,
+ Parent ! disk_log_stopped_ok
end,
?line spawn(Fun),
?line ok = sync_do(Pid, close),
+ ?line receive disk_log_stopped_ok -> ok end,
?line sync_do(Pid, terminate),
?line {ok,<<>>} = file:read_file(File ++ ".1"),
?line del(File, No),
@@ -2708,7 +2713,7 @@ error_log(Conf) when is_list(Conf) ->
% reopen (rename) fails, the log is terminated, ./File.2/ exists
?line {ok, n} = disk_log:open([{name, n}, {file, File}, {type, halt},
{format, external},{size, 100000}]),
- ?line {error, eisdir} = disk_log:reopen(n, LDir),
+ ?line {error, {file_error, _, eisdir}} = disk_log:reopen(n, LDir),
?line true = (P0 == pps()),
?line file:delete(File),
@@ -2719,7 +2724,7 @@ error_log(Conf) when is_list(Conf) ->
?line {ok, n} = disk_log:open([{name, n}, {file, File2}, {type, wrap},
{format, external},{size, {100, No}}]),
?line ok = disk_log:blog_terms(n, [B,B,B]),
- ?line {error, eisdir} = disk_log:reopen(n, File),
+ ?line {error, {file_error, _, eisdir}} = disk_log:reopen(n, File),
?line {error, no_such_log} = disk_log:close(n),
?line del(File2, No),
?line del(File, No),
diff --git a/lib/kernel/test/erl_boot_server_SUITE.erl b/lib/kernel/test/erl_boot_server_SUITE.erl
index cea3715ce4..bb64c01058 100644
--- a/lib/kernel/test/erl_boot_server_SUITE.erl
+++ b/lib/kernel/test/erl_boot_server_SUITE.erl
@@ -346,7 +346,7 @@ good_hosts(_Config) ->
[GoodHost1, GoodHost2, GoodHost3].
open_udp() ->
- ?line {ok, S} = prim_inet:open(udp, inet),
+ ?line {ok, S} = prim_inet:open(udp, inet, dgram),
?line ok = prim_inet:setopts(S, [{mode,list},{active,true},
{deliver,term},{broadcast,true}]),
?line {ok,_} = prim_inet:bind(S, {0,0,0,0}, 0),
diff --git a/lib/kernel/test/file_SUITE.erl b/lib/kernel/test/file_SUITE.erl
index 77fc7e73f9..85346762ac 100644
--- a/lib/kernel/test/file_SUITE.erl
+++ b/lib/kernel/test/file_SUITE.erl
@@ -3144,12 +3144,12 @@ ipread_int(Dir, ModeList) ->
{fun (Bin) when is_binary(Bin) -> Bin;
(List) when is_list(List) -> list_to_binary(List)
end,
- {erlang, size}};
+ fun erlang:byte_size/1};
false ->
{fun (Bin) when is_binary(Bin) -> binary_to_list(Bin);
(List) when is_list(List) -> List
end,
- {erlang, length}}
+ fun erlang:length/1}
end,
?line Pos = 4711,
?line Data = Conv("THE QUICK BROWN FOX JUMPS OVER A LAZY DOG"),
diff --git a/lib/kernel/test/gen_sctp_SUITE.erl b/lib/kernel/test/gen_sctp_SUITE.erl
index 1b534a5fc4..8f490b6643 100644
--- a/lib/kernel/test/gen_sctp_SUITE.erl
+++ b/lib/kernel/test/gen_sctp_SUITE.erl
@@ -30,33 +30,31 @@
-export(
[basic/1,
api_open_close/1,api_listen/1,api_connect_init/1,api_opts/1,
- xfer_min/1,xfer_active/1,def_sndrcvinfo/1,implicit_inet6/1]).
+ xfer_min/1,xfer_active/1,def_sndrcvinfo/1,implicit_inet6/1,
+ basic_stream/1, xfer_stream_min/1, peeloff/1, buffers/1]).
suite() -> [{ct_hooks,[ts_install_cth]}].
all() ->
[basic, api_open_close, api_listen, api_connect_init,
- api_opts, xfer_min, xfer_active, def_sndrcvinfo,
- implicit_inet6].
+ api_opts, xfer_min, xfer_active, def_sndrcvinfo, implicit_inet6,
+ basic_stream, xfer_stream_min, peeloff, buffers].
groups() ->
[].
-init_per_suite(Config) ->
- try gen_sctp:open() of
+init_per_suite(_Config) ->
+ case gen_sctp:open() of
{ok,Socket} ->
gen_sctp:close(Socket),
[];
- _ ->
- []
- catch
- error:badarg ->
- {skip,"SCTP not supported on this machine"};
- _:_ ->
- Config
+ {error,Error}
+ when Error =:= eprotonosupport;
+ Error =:= esocktnosupport ->
+ {skip,"SCTP not supported on this machine"}
end.
-end_per_suite(_Conifig) ->
+end_per_suite(_Config) ->
ok.
init_per_group(_GroupName, Config) ->
@@ -96,7 +94,7 @@ xfer_min(Config) when is_list(Config) ->
?line Stream = 0,
?line Data = <<"The quick brown fox jumps over a lazy dog 0123456789">>,
?line Loopback = {127,0,0,1},
- ?line {ok,Sb} = gen_sctp:open(),
+ ?line {ok,Sb} = gen_sctp:open([{type,seqpacket}]),
?line {ok,Pb} = inet:port(Sb),
?line ok = gen_sctp:listen(Sb, true),
@@ -108,29 +106,44 @@ xfer_min(Config) when is_list(Config) ->
inbound_streams=SaInboundStreams,
assoc_id=SaAssocId}=SaAssocChange} =
gen_sctp:connect(Sa, Loopback, Pb, []),
- ?line {ok,{Loopback,
- Pa,[],
+ ?line {SbAssocId,SaOutboundStreams,SaInboundStreams} =
+ case recv_event(log_ok(gen_sctp:recv(Sb, infinity))) of
+ {Loopback,Pa,
#sctp_assoc_change{state=comm_up,
error=0,
outbound_streams=SbOutboundStreams,
inbound_streams=SbInboundStreams,
- assoc_id=SbAssocId}}} =
- gen_sctp:recv(Sb, infinity),
- ?line SaOutboundStreams = SbInboundStreams,
- ?line SbOutboundStreams = SaInboundStreams,
+ assoc_id=AssocId}} ->
+ {AssocId,SbInboundStreams,SbOutboundStreams};
+ {Loopback,Pa,
+ #sctp_paddr_change{state=addr_confirmed,
+ addr={Loopback,Pa},
+ error=0,
+ assoc_id=AssocId}} ->
+ {Loopback,Pa,
+ #sctp_assoc_change{state=comm_up,
+ error=0,
+ outbound_streams=SbOutboundStreams,
+ inbound_streams=SbInboundStreams,
+ assoc_id=AssocId}} =
+ ?line recv_event(log_ok(gen_sctp:recv(Sb, infinity))),
+ {AssocId,SbInboundStreams,SbOutboundStreams}
+ end,
+
?line ok = gen_sctp:send(Sa, SaAssocId, 0, Data),
- ?line case gen_sctp:recv(Sb, infinity) of
- {ok,{Loopback,
- Pa,
- [#sctp_sndrcvinfo{stream=Stream,
- assoc_id=SbAssocId}],
- Data}} -> ok;
- {ok,{Loopback,
- Pa,[],
+ ?line case log_ok(gen_sctp:recv(Sb, infinity)) of
+ {Loopback,
+ Pa,
+ [#sctp_sndrcvinfo{stream=Stream,
+ assoc_id=SbAssocId}],
+ Data} -> ok;
+ Event1 ->
+ {Loopback,Pa,
#sctp_paddr_change{addr = {Loopback,_},
state = addr_available,
error = 0,
- assoc_id = SbAssocId}}} ->
+ assoc_id = SbAssocId}} =
+ recv_event(Event1),
{ok,{Loopback,
Pa,
[#sctp_sndrcvinfo{stream=Stream,
@@ -138,30 +151,40 @@ xfer_min(Config) when is_list(Config) ->
Data}} = gen_sctp:recv(Sb, infinity)
end,
?line ok = gen_sctp:send(Sb, SbAssocId, 0, Data),
- ?line {ok,{Loopback,
- Pb,
+ ?line case log_ok(gen_sctp:recv(Sa, infinity)) of
+ {Loopback,Pb,
[#sctp_sndrcvinfo{stream=Stream,
assoc_id=SaAssocId}],
- Data}} =
- gen_sctp:recv(Sa, infinity),
+ Data} ->
+ ok;
+ Event2 ->
+ {Loopback,Pb,
+ #sctp_paddr_change{addr={_,Pb},
+ state=addr_confirmed,
+ error=0,
+ assoc_id=SaAssocId}} =
+ ?line recv_event(Event2),
+ ?line {Loopback,
+ Pb,
+ [#sctp_sndrcvinfo{stream=Stream,
+ assoc_id=SaAssocId}],
+ Data} =
+ log_ok(gen_sctp:recv(Sa, infinity))
+ end,
%%
?line ok = gen_sctp:eof(Sa, SaAssocChange),
- ?line {ok,{Loopback,
- Pa,[],
- #sctp_shutdown_event{assoc_id=SbAssocId}}} =
- gen_sctp:recv(Sb, infinity),
- ?line {ok,{Loopback,
- Pb,[],
- #sctp_assoc_change{state=shutdown_comp,
- error=0,
- assoc_id=SaAssocId}}} =
- gen_sctp:recv(Sa, infinity),
- ?line {ok,{Loopback,
- Pa,[],
- #sctp_assoc_change{state=shutdown_comp,
- error=0,
- assoc_id=SbAssocId}}} =
- gen_sctp:recv(Sb, infinity),
+ ?line {Loopback,Pa,#sctp_shutdown_event{assoc_id=SbAssocId}} =
+ recv_event(log_ok(gen_sctp:recv(Sb, infinity))),
+ ?line {Loopback,Pb,
+ #sctp_assoc_change{state=shutdown_comp,
+ error=0,
+ assoc_id=SaAssocId}} =
+ recv_event(log_ok(gen_sctp:recv(Sa, infinity))),
+ ?line {Loopback,Pa,
+ #sctp_assoc_change{state=shutdown_comp,
+ error=0,
+ assoc_id=SbAssocId}} =
+ recv_event(log_ok(gen_sctp:recv(Sb, infinity))),
?line ok = gen_sctp:close(Sa),
?line ok = gen_sctp:close(Sb),
@@ -186,32 +209,52 @@ xfer_active(Config) when is_list(Config) ->
?line {ok,Sa} = gen_sctp:open([{active,true}]),
?line {ok,Pa} = inet:port(Sa),
- ?line {ok,#sctp_assoc_change{state=comm_up,
- error=0,
- outbound_streams=SaOutboundStreams,
- inbound_streams=SaInboundStreams,
- assoc_id=SaAssocId}=SaAssocChange} =
- gen_sctp:connect(Sa, Loopback, Pb, []),
+ ?line ok = gen_sctp:connect_init(Sa, Loopback, Pb, []),
+ ?line #sctp_assoc_change{state=comm_up,
+ error=0,
+ outbound_streams=SaOutboundStreams,
+ inbound_streams=SaInboundStreams,
+ assoc_id=SaAssocId} = SaAssocChange =
+ recv_assoc_change(Sa, Loopback, Pb, Timeout),
?line io:format("Sa=~p, Pa=~p, Sb=~p, Pb=~p, SaAssocId=~p, "
"SaOutboundStreams=~p, SaInboundStreams=~p~n",
[Sa,Pa,Sb,Pb,SaAssocId,
SaOutboundStreams,SaInboundStreams]),
- ?line SbAssocId =
- receive
- {sctp,Sb,Loopback,Pa,
- {[],
- #sctp_assoc_change{state=comm_up,
- error=0,
- outbound_streams=SbOutboundStreams,
- inbound_streams=SbInboundStreams,
- assoc_id=SBAI}}} ->
- ?line SaOutboundStreams = SbInboundStreams,
- ?line SaInboundStreams = SbOutboundStreams,
- SBAI
- after Timeout ->
- ?line test_server:fail({unexpected,flush()})
- end,
+ ?line #sctp_assoc_change{state=comm_up,
+ error=0,
+ outbound_streams=SbOutboundStreams,
+ inbound_streams=SbInboundStreams,
+ assoc_id=SbAssocId} =
+ recv_assoc_change(Sb, Loopback, Pa, Timeout),
+ ?line SbOutboundStreams = SaInboundStreams,
+ ?line SbInboundStreams = SaOutboundStreams,
?line io:format("SbAssocId=~p~n", [SbAssocId]),
+
+ ?line case recv_paddr_change(Sa, Loopback, Pb, 314) of
+ #sctp_paddr_change{state=addr_confirmed,
+ addr={_,Pb},
+ error=0,
+ assoc_id=SaAssocId} -> ok;
+ #sctp_paddr_change{state=addr_available,
+ addr={_,Pb},
+ error=0,
+ assoc_id=SaAssocId} -> ok;
+ timeout -> ok
+ end,
+ ?line case recv_paddr_change(Sb, Loopback, Pa, 314) of
+ #sctp_paddr_change{state=addr_confirmed,
+ addr={Loopback,Pa},
+ error=0,
+ assoc_id=SbAssocId} -> ok;
+ #sctp_paddr_change{state=addr_available,
+ addr={Loopback,P},
+ error=0,
+ assoc_id=SbAssocId} ->
+ ?line match_unless_solaris(Pa, P);
+ timeout -> ok
+ end,
+ ?line [] = flush(),
+
?line ok =
do_from_other_process(
fun () -> gen_sctp:send(Sa, SaAssocId, 0, Data) end),
@@ -219,21 +262,9 @@ xfer_active(Config) when is_list(Config) ->
{sctp,Sb,Loopback,Pa,
{[#sctp_sndrcvinfo{stream=Stream,
assoc_id=SbAssocId}],
- Data}} -> ok;
- {sctp,Sb,Loopback,Pa,
- {[],
- #sctp_paddr_change{addr = {Loopback,_},
- state = addr_available,
- error = 0,
- assoc_id = SbAssocId}}} ->
- ?line receive
- {sctp,Sb,Loopback,Pa,
- {[#sctp_sndrcvinfo{stream=Stream,
- assoc_id=SbAssocId}],
- Data}} -> ok
- end
+ Data}} -> ok
after Timeout ->
- ?line test_server:fail({unexpected,flush()})
+ ?line test_server:fail({timeout,flush()})
end,
?line ok = gen_sctp:send(Sb, SbAssocId, 0, Data),
?line receive
@@ -242,31 +273,28 @@ xfer_active(Config) when is_list(Config) ->
assoc_id=SaAssocId}],
Data}} -> ok
after Timeout ->
- ?line test_server:fail({unexpected,flush()})
+ ?line test_server:fail({timeout,flush()})
end,
%%
?line ok = gen_sctp:abort(Sa, SaAssocChange),
- ?line receive
- {sctp,Sb,Loopback,Pa,
- {[],
- #sctp_assoc_change{state=comm_lost,
- assoc_id=SbAssocId}}} -> ok
- after Timeout ->
- ?line test_server:fail({unexpected,flush()})
+ ?line case recv_assoc_change(Sb, Loopback, Pa, Timeout) of
+ #sctp_assoc_change{state=comm_lost,
+ assoc_id=SbAssocId} -> ok;
+ timeout ->
+ ?line test_server:fail({timeout,flush()})
end,
?line ok = gen_sctp:close(Sb),
+ ?line case recv_assoc_change(Sa, Loopback, Pb, Timeout) of
+ #sctp_assoc_change{state=comm_lost,
+ assoc_id=SaAssocId} -> ok;
+ timeout ->
+ ?line io:format("timeout waiting for comm_lost on Sa~n"),
+ ?line match_unless_solaris(ok, {timeout,flush()})
+ end,
?line receive
- {sctp,Sa,Loopback,Pb,
- {[],
- #sctp_assoc_change{state=comm_lost,
- assoc_id=SaAssocId}}} -> ok
- after Timeout ->
- ?line test_server:fail({unexpected,flush()})
- end,
- ?line receive
- {sctp_error,Sa,enotconn} -> ok % Solaris
- after 17 -> ok %% Only happens on Solaris
- end,
+ {sctp_error,Sa,enotconn} -> ok % Solaris
+ after 17 -> ok
+ end,
?line ok = gen_sctp:close(Sa),
%%
?line receive
@@ -275,6 +303,30 @@ xfer_active(Config) when is_list(Config) ->
end,
ok.
+recv_assoc_change(S, Addr, Port, Timeout) ->
+ receive
+ {sctp,S,Addr,Port,{[], #sctp_assoc_change{}=AssocChange}} ->
+ AssocChange;
+ {sctp,S,Addr,Port,
+ {[#sctp_sndrcvinfo{assoc_id=AssocId}],
+ #sctp_assoc_change{assoc_id=AssocId}=AssocChange}} ->
+ AssocChange
+ after Timeout ->
+ timeout
+ end.
+
+recv_paddr_change(S, Addr, Port, Timeout) ->
+ receive
+ {sctp,S,Addr,Port,{[], #sctp_paddr_change{}=PaddrChange}} ->
+ PaddrChange;
+ {sctp,S,Addr,Port,
+ {[#sctp_sndrcvinfo{assoc_id=AssocId}],
+ #sctp_paddr_change{assoc_id=AssocId}=PaddrChange}} ->
+ PaddrChange
+ after Timeout ->
+ timeout
+ end.
+
def_sndrcvinfo(doc) ->
"Test that #sctp_sndrcvinfo{} parameters set on a socket "
"are used by gen_sctp:send/4";
@@ -285,11 +337,11 @@ def_sndrcvinfo(Config) when is_list(Config) ->
?line Data = <<"What goes up, must come down.">>,
%%
?line S1 =
- ok(gen_sctp:open(
+ log_ok(gen_sctp:open(
0, [{sctp_default_send_param,#sctp_sndrcvinfo{ppid=17}}])),
?LOGVAR(S1),
?line P1 =
- ok(inet:port(S1)),
+ log_ok(inet:port(S1)),
?LOGVAR(P1),
?line #sctp_sndrcvinfo{ppid=17, context=0, timetolive=0, assoc_id=0} =
getopt(S1, sctp_default_send_param),
@@ -297,10 +349,10 @@ def_sndrcvinfo(Config) when is_list(Config) ->
gen_sctp:listen(S1, true),
%%
?line S2 =
- ok(gen_sctp:open()),
+ log_ok(gen_sctp:open()),
?LOGVAR(S2),
?line P2 =
- ok(inet:port(S2)),
+ log_ok(inet:port(S2)),
?LOGVAR(P2),
?line #sctp_sndrcvinfo{ppid=0, context=0, timetolive=0, assoc_id=0} =
getopt(S2, sctp_default_send_param),
@@ -309,32 +361,57 @@ def_sndrcvinfo(Config) when is_list(Config) ->
state=comm_up,
error=0,
assoc_id=S2AssocId} = S2AssocChange =
- ok(gen_sctp:connect(S2, Loopback, P1, [])),
+ log_ok(gen_sctp:connect(S2, Loopback, P1, [])),
?LOGVAR(S2AssocChange),
- ?line case ok(gen_sctp:recv(S1)) of
- {Loopback, P2,[],
+ ?line case recv_event(log_ok(gen_sctp:recv(S1))) of
+ {Loopback,P2,
#sctp_assoc_change{
+ state=comm_up,
+ error=0,
+ assoc_id=S1AssocId}} ->
+ ?LOGVAR(S1AssocId);
+ {Loopback,P2,
+ #sctp_paddr_change{
+ state=addr_confirmed,
+ error=0,
+ assoc_id=S1AssocId}} ->
+ ?LOGVAR(S1AssocId),
+ {Loopback,P2,
+ #sctp_assoc_change{
state=comm_up,
error=0,
- assoc_id=S1AssocId}} ->
- ?LOGVAR(S1AssocId)
+ assoc_id=S1AssocId}} =
+ recv_event(log_ok(gen_sctp:recv(S1)))
end,
+
?line #sctp_sndrcvinfo{
- ppid=17, context=0, timetolive=0, assoc_id=S1AssocId} =
+ ppid=17, context=0, timetolive=0} = %, assoc_id=S1AssocId} =
getopt(
S1, sctp_default_send_param, #sctp_sndrcvinfo{assoc_id=S1AssocId}),
?line #sctp_sndrcvinfo{
- ppid=0, context=0, timetolive=0, assoc_id=S2AssocId} =
+ ppid=0, context=0, timetolive=0} = %, assoc_id=S2AssocId} =
getopt(
S2, sctp_default_send_param, #sctp_sndrcvinfo{assoc_id=S2AssocId}),
%%
?line ok =
gen_sctp:send(S1, S1AssocId, 1, <<"1: ",Data/binary>>),
- ?line case ok(gen_sctp:recv(S2)) of
+ ?line case log_ok(gen_sctp:recv(S2)) of
{Loopback,P1,
[#sctp_sndrcvinfo{
stream=1, ppid=17, context=0, assoc_id=S2AssocId}],
- <<"1: ",Data/binary>>} -> ok
+ <<"1: ",Data/binary>>} -> ok;
+ Event1 ->
+ ?line {Loopback,P1,
+ #sctp_paddr_change{state=addr_confirmed,
+ addr={_,P1},
+ error=0,
+ assoc_id=S2AssocId}} =
+ recv_event(Event1),
+ ?line {Loopback,P1,
+ [#sctp_sndrcvinfo{
+ stream=1, ppid=17, context=0, assoc_id=S2AssocId}],
+ <<"1: ",Data/binary>>} =
+ log_ok(gen_sctp:recv(S2))
end,
%%
?line ok =
@@ -354,7 +431,7 @@ def_sndrcvinfo(Config) when is_list(Config) ->
%%
?line ok =
gen_sctp:send(S1, S1AssocId, 0, <<"2: ",Data/binary>>),
- ?line case ok(gen_sctp:recv(S2)) of
+ ?line case log_ok(gen_sctp:recv(S2)) of
{Loopback,P1,
[#sctp_sndrcvinfo{
stream=0, ppid=19, context=0, assoc_id=S2AssocId}],
@@ -362,16 +439,18 @@ def_sndrcvinfo(Config) when is_list(Config) ->
end,
?line ok =
gen_sctp:send(S2, S2AssocChange, 1, <<"3: ",Data/binary>>),
- ?line case ok(gen_sctp:recv(S1)) of
+ ?line case log_ok(gen_sctp:recv(S1)) of
{Loopback,P2,
[#sctp_sndrcvinfo{
stream=1, ppid=0, context=0, assoc_id=S1AssocId}],
<<"3: ",Data/binary>>} -> ok;
- {Loopback,P2,[],
- #sctp_paddr_change{
- addr={Loopback,_}, state=addr_available,
- error=0, assoc_id=S1AssocId}} ->
- ?line case ok(gen_sctp:recv(S1)) of
+ Event2 ->
+ {Loopback,P2,
+ #sctp_paddr_change{
+ addr={Loopback,_}, state=addr_available,
+ error=0, assoc_id=S1AssocId}} =
+ recv_event(Event2),
+ ?line case log_ok(gen_sctp:recv(S1)) of
{Loopback,P2,
[#sctp_sndrcvinfo{
stream=1, ppid=0, context=0,
@@ -387,7 +466,7 @@ def_sndrcvinfo(Config) when is_list(Config) ->
#sctp_sndrcvinfo{stream=0, ppid=20, assoc_id=S2AssocId},
<<"4: ",Data/binary>>)
end),
- ?line case ok(do_from_other_process(fun() -> gen_sctp:recv(S1) end)) of
+ ?line case log_ok(do_from_other_process(fun() -> gen_sctp:recv(S1) end)) of
{Loopback,P2,
[#sctp_sndrcvinfo{
stream=0, ppid=20, context=0, assoc_id=S1AssocId}],
@@ -416,8 +495,12 @@ getopt(S, Opt, Param) ->
setopt(S, Opt, Val) ->
inet:setopts(S, [{Opt,Val}]).
-ok({ok,X}) ->
- io:format("OK: ~p~n", [X]),
+log_ok(X) -> log(ok(X)).
+
+ok({ok,X}) -> X.
+
+log(X) ->
+ io:format("LOG[~w]: ~p~n", [self(),X]),
X.
flush() ->
@@ -520,7 +603,10 @@ api_listen(Config) when is_list(Config) ->
#sctp_assoc_change{
state=comm_lost}}} =
gen_sctp:recv(Sa, infinity);
- {error,#sctp_assoc_change{state=cant_assoc}} -> ok
+ {error,#sctp_assoc_change{state=cant_assoc}} ->
+ ok%;
+ %% {error,{Localhost,Pb,_,#sctp_assoc_change{state=cant_assoc}}} ->
+ %% ok
end,
?line ok = gen_sctp:listen(Sb, true),
?line {ok,#sctp_assoc_change{state=comm_up,
@@ -552,29 +638,41 @@ api_connect_init(Config) when is_list(Config) ->
?line {ok,Sa} = gen_sctp:open(),
?line case gen_sctp:connect_init(Sa, localhost, Pb, []) of
{error,econnrefused} ->
- ?line {ok,{Localhost,
- Pb,[],
- #sctp_assoc_change{state=comm_lost}}} =
- gen_sctp:recv(Sa, infinity);
+ ?line {Localhost,Pb,#sctp_assoc_change{state=comm_lost}} =
+ recv_event(log_ok(gen_sctp:recv(Sa, infinity)));
ok ->
- ?line {ok,{Localhost,
- Pb,[],
- #sctp_assoc_change{state=cant_assoc}}} =
- gen_sctp:recv(Sa, infinity)
+ ?line {Localhost,Pb,#sctp_assoc_change{state=cant_assoc}} =
+ recv_event(log_ok(gen_sctp:recv(Sa, infinity)))
end,
?line ok = gen_sctp:listen(Sb, true),
?line case gen_sctp:connect_init(Sa, localhost, Pb, []) of
ok ->
- ?line {ok,{Localhost,
- Pb,[],
- #sctp_assoc_change{
- state = comm_up}}} =
- gen_sctp:recv(Sa, infinity)
+ ?line {Localhost,Pb,#sctp_assoc_change{state=comm_up}} =
+ recv_event(log_ok(gen_sctp:recv(Sa, infinity)))
end,
?line ok = gen_sctp:close(Sa),
?line ok = gen_sctp:close(Sb),
ok.
+recv_event({Addr,Port,[],#sctp_assoc_change{}=AssocChange}) ->
+ {Addr,Port,AssocChange};
+recv_event({Addr,Port,
+ [#sctp_sndrcvinfo{assoc_id=Assoc}],
+ #sctp_assoc_change{assoc_id=Assoc}=AssocChange}) ->
+ {Addr,Port,AssocChange};
+recv_event({Addr,Port,[],#sctp_paddr_change{}=PaddrChange}) ->
+ {Addr,Port,PaddrChange};
+recv_event({Addr,Port,
+ [#sctp_sndrcvinfo{assoc_id=Assoc}],
+ #sctp_paddr_change{assoc_id=Assoc}=PaddrChange}) ->
+ {Addr,Port,PaddrChange};
+recv_event({Addr,Port,[],#sctp_shutdown_event{}=ShutdownEvent}) ->
+ {Addr,Port,ShutdownEvent};
+recv_event({Addr,Port,
+ [#sctp_sndrcvinfo{assoc_id=Assoc}],
+ #sctp_shutdown_event{assoc_id=Assoc}=ShutdownEvent}) ->
+ {Addr,Port,ShutdownEvent}.
+
api_opts(doc) ->
"Test socket options";
api_opts(suite) ->
@@ -600,7 +698,7 @@ api_opts(Config) when is_list(Config) ->
end.
implicit_inet6(Config) when is_list(Config) ->
- ?line Hostname = ok(inet:gethostname()),
+ ?line Hostname = log_ok(inet:gethostname()),
?line
case gen_sctp:open(0, [inet6]) of
{ok,S1} ->
@@ -613,16 +711,16 @@ implicit_inet6(Config) when is_list(Config) ->
?line ok = gen_sctp:close(S1),
%%
?line Localhost =
- ok(inet:getaddr("localhost", inet6)),
+ log_ok(inet:getaddr("localhost", inet6)),
?line io:format("~s ~p~n", ["localhost",Localhost]),
?line S2 =
- ok(gen_sctp:open(0, [{ip,Localhost}])),
+ log_ok(gen_sctp:open(0, [{ip,Localhost}])),
?line implicit_inet6(S2, Localhost),
?line ok = gen_sctp:close(S2),
%%
?line io:format("~s ~p~n", [Hostname,Host]),
?line S3 =
- ok(gen_sctp:open(0, [{ifaddr,Host}])),
+ log_ok(gen_sctp:open(0, [{ifaddr,Host}])),
?line implicit_inet6(S3, Host),
?line ok = gen_sctp:close(S1);
{error,eafnosupport} ->
@@ -635,25 +733,159 @@ implicit_inet6(Config) when is_list(Config) ->
implicit_inet6(S1, Addr) ->
?line ok = gen_sctp:listen(S1, true),
- ?line P1 = ok(inet:port(S1)),
- ?line S2 = ok(gen_sctp:open(0, [inet6])),
- ?line P2 = ok(inet:port(S2)),
+ ?line P1 = log_ok(inet:port(S1)),
+ ?line S2 = log_ok(gen_sctp:open(0, [inet6])),
+ ?line P2 = log_ok(inet:port(S2)),
?line #sctp_assoc_change{state=comm_up} =
- ok(gen_sctp:connect(S2, Addr, P1, [])),
- ?line case ok(gen_sctp:recv(S1)) of
- {Addr,P2,[],#sctp_assoc_change{state=comm_up}} ->
- ok
+ log_ok(gen_sctp:connect(S2, Addr, P1, [])),
+ ?line case recv_event(log_ok(gen_sctp:recv(S1))) of
+ {Addr,P2,#sctp_assoc_change{state=comm_up}} ->
+ ok;
+ {Addr,P2,#sctp_paddr_change{state=addr_confirmed,
+ addr={Addr,P2},
+ error=0}} ->
+ {Addr,P2,#sctp_assoc_change{state=comm_up}} =
+ recv_event(log_ok(gen_sctp:recv(S1)))
end,
- ?line case ok(inet:sockname(S1)) of
+ ?line case log_ok(inet:sockname(S1)) of
{Addr,P1} -> ok;
{{0,0,0,0,0,0,0,0},P1} -> ok
end,
- ?line case ok(inet:sockname(S2)) of
+ ?line case log_ok(inet:sockname(S2)) of
{Addr,P2} -> ok;
{{0,0,0,0,0,0,0,0},P2} -> ok
end,
?line ok = gen_sctp:close(S2).
+basic_stream(doc) ->
+ "Hello world stream socket";
+basic_stream(suite) ->
+ [];
+basic_stream(Config) when is_list(Config) ->
+ ?line {ok,S} = gen_sctp:open([{type,stream}]),
+ ?line ok = gen_sctp:listen(S, true),
+ ?line ok =
+ do_from_other_process(
+ fun () -> gen_sctp:listen(S, 10) end),
+ ?line ok = gen_sctp:close(S),
+ ok.
+
+xfer_stream_min(doc) ->
+ "Minimal data transfer";
+xfer_stream_min(suite) ->
+ [];
+xfer_stream_min(Config) when is_list(Config) ->
+ ?line Stream = 0,
+ ?line Data = <<"The quick brown fox jumps over a lazy dog 0123456789">>,
+ ?line Loopback = {127,0,0,1},
+ ?line {ok,Sb} = gen_sctp:open([{type,seqpacket}]),
+ ?line ?LOGVAR(Sb),
+ ?line {ok,Pb} = inet:port(Sb),
+ ?line ?LOGVAR(Pb),
+ ?line ok = gen_sctp:listen(Sb, true),
+
+ ?line {ok,Sa} = gen_sctp:open([{type,stream}]),
+ ?line ?LOGVAR(Sa),
+ ?line {ok,Pa} = inet:port(Sa),
+ ?line ?LOGVAR(Pa),
+ ?line #sctp_assoc_change{state=comm_up,
+ error=0,
+ outbound_streams=SaOutboundStreams,
+ inbound_streams=SaInboundStreams,
+ assoc_id=SaAssocId_X} =
+ log_ok(gen_sctp:connect(Sa, Loopback, Pb, [])),
+ ?line ?LOGVAR(SaAssocId_X),
+ ?line [{_,#sctp_paddrinfo{assoc_id=SaAssocId,state=active}}] =
+ log_ok(inet:getopts(Sa, [{sctp_get_peer_addr_info,
+ #sctp_paddrinfo{address={Loopback,Pb}}}])),
+ ?line ?LOGVAR(SaAssocId),
+ ?line match_unless_solaris(SaAssocId_X, SaAssocId),
+
+ ?line {SbOutboundStreams,SbInboundStreams,SbAssocId} =
+ case recv_event(log_ok(gen_sctp:recv(Sb, infinity))) of
+ {Loopback,Pa,
+ #sctp_assoc_change{state=comm_up,
+ error=0,
+ outbound_streams=OS,
+ inbound_streams=IS,
+ assoc_id=AI}} ->
+ {OS,IS,AI};
+ {Loopback,Pa,
+ #sctp_paddr_change{state=addr_confirmed,
+ addr={Loopback,Pa},
+ error=0,
+ assoc_id=AI}} ->
+ {Loopback,Pa,
+ ?line #sctp_assoc_change{state=comm_up,
+ error=0,
+ outbound_streams=OS,
+ inbound_streams=IS,
+ assoc_id=AI}} =
+ recv_event(log_ok(gen_sctp:recv(Sb, infinity))),
+ {OS,IS,AI}
+ end,
+ ?line ?LOGVAR(SbAssocId),
+ ?line SaOutboundStreams = SbInboundStreams,
+ ?line ?LOGVAR(SaOutboundStreams),
+ ?line SbOutboundStreams = SaInboundStreams,
+ ?line ?LOGVAR(SbOutboundStreams),
+ ?line ok = gen_sctp:send(Sa, SaAssocId, 0, Data),
+ ?line case gen_sctp:recv(Sb, infinity) of
+ {ok,{Loopback,
+ Pa,
+ [#sctp_sndrcvinfo{stream=Stream,
+ assoc_id=SbAssocId}],
+ Data}} -> ok;
+ {ok,{Loopback,
+ Pa,[],
+ #sctp_paddr_change{addr = {Loopback,_},
+ state = addr_available,
+ error = 0,
+ assoc_id = SbAssocId}}} ->
+ {ok,{Loopback,
+ Pa,
+ [#sctp_sndrcvinfo{stream=Stream,
+ assoc_id=SbAssocId}],
+ Data}} = gen_sctp:recv(Sb, infinity)
+ end,
+ ?line ok =
+ do_from_other_process(
+ fun () -> gen_sctp:send(Sb, SbAssocId, 0, Data) end),
+ ?line case log_ok(gen_sctp:recv(Sa, infinity)) of
+ {Loopback,Pb,
+ [#sctp_sndrcvinfo{stream=Stream,
+ assoc_id=SaAssocId}],
+ Data} -> ok;
+ Event1 ->
+ ?line {Loopback,Pb,
+ #sctp_paddr_change{state=addr_confirmed,
+ addr={_,Pb},
+ error=0,
+ assoc_id=SaAssocId}} =
+ recv_event(Event1),
+ ?line {Loopback,Pb,
+ [#sctp_sndrcvinfo{stream=Stream,
+ assoc_id=SaAssocId}],
+ Data} =
+ log_ok(gen_sctp:recv(Sa, infinity))
+ end,
+ ?line ok = gen_sctp:close(Sa),
+ ?line {Loopback,Pa,
+ #sctp_shutdown_event{assoc_id=SbAssocId}} =
+ recv_event(log_ok(gen_sctp:recv(Sb, infinity))),
+ ?line {Loopback,Pa,
+ #sctp_assoc_change{state=shutdown_comp,
+ error=0,
+ assoc_id=SbAssocId}} =
+ recv_event(log_ok(gen_sctp:recv(Sb, infinity))),
+ ?line ok = gen_sctp:close(Sb),
+
+ ?line receive
+ Msg -> test_server:fail({received,Msg})
+ after 17 -> ok
+ end,
+ ok.
+
do_from_other_process(Fun) ->
@@ -681,3 +913,419 @@ do_from_other_process(Fun) ->
{'DOWN',Mref,_,_,Reason} ->
erlang:exit(Reason)
end.
+
+
+
+peeloff(doc) ->
+ "Peel off an SCTP stream socket";
+peeloff(suite) ->
+ [];
+peeloff(Config) when is_list(Config) ->
+ ?line Addr = {127,0,0,1},
+ ?line Stream = 0,
+ ?line Timeout = 333,
+ ?line S1 = socket_open([{ifaddr,Addr}], Timeout),
+ ?line ?LOGVAR(S1),
+ ?line P1 = socket_call(S1, get_port),
+ ?line ?LOGVAR(P1),
+ ?line Socket1 = socket_call(S1, get_socket),
+ ?line ?LOGVAR(Socket1),
+ ?line socket_call(S1, {listen,true}),
+ ?line S2 = socket_open([{ifaddr,Addr}], Timeout),
+ ?line ?LOGVAR(S2),
+ ?line P2 = socket_call(S2, get_port),
+ ?line ?LOGVAR(P2),
+ ?line Socket2 = socket_call(S2, get_socket),
+ ?line ?LOGVAR(Socket2),
+ %%
+ ?line socket_call(S2, {connect_init,Addr,P1,[]}),
+ ?line S2Ai =
+ receive
+ {S2,{Addr,P1,
+ #sctp_assoc_change{
+ state=comm_up,
+ assoc_id=AssocId2}}} -> AssocId2
+ after Timeout ->
+ socket_bailout([S1,S2])
+ end,
+ ?line ?LOGVAR(S2Ai),
+ ?line S1Ai =
+ receive
+ {S1,{Addr,P2,
+ #sctp_assoc_change{
+ state=comm_up,
+ assoc_id=AssocId1}}} -> AssocId1
+ after Timeout ->
+ socket_bailout([S1,S2])
+ end,
+ ?line ?LOGVAR(S1Ai),
+ %%
+ ?line socket_call(S2, {send,S2Ai,Stream,<<"Number one">>}),
+ ?line
+ receive
+ {S1,{Addr,P2,S1Ai,Stream,<<"Number one">>}} -> ok
+ after Timeout ->
+ socket_bailout([S1,S2])
+ end,
+ ?line socket_call(S2, {send,Socket1,S1Ai,Stream,<<"Number two">>}),
+ ?line
+ receive
+ {S2,{Addr,P1,S2Ai,Stream,<<"Number two">>}} -> ok
+ after Timeout ->
+ socket_bailout([S1,S2])
+ end,
+ %%
+ ?line S3 = socket_peeloff(Socket1, S1Ai, Timeout),
+ ?line ?LOGVAR(S3),
+ ?line P3_X = socket_call(S3, get_port),
+ ?line ?LOGVAR(P3_X),
+ ?line P3 = case P3_X of 0 -> P1; _ -> P3_X end,
+ ?line [{_,#sctp_paddrinfo{assoc_id=S3Ai,state=active}}] =
+ socket_call(S3,
+ {getopts,[{sctp_get_peer_addr_info,
+ #sctp_paddrinfo{address={Addr,P2}}}]}),
+ %%?line S3Ai = S1Ai,
+ ?line ?LOGVAR(S3Ai),
+ %%
+ ?line socket_call(S3, {send,S3Ai,Stream,<<"Number three">>}),
+ ?line
+ receive
+ {S2,{Addr,P3,S2Ai,Stream,<<"Number three">>}} -> ok
+ after Timeout ->
+ socket_bailout([S1,S2,S3])
+ end,
+ ?line socket_call(S3, {send,Socket2,S2Ai,Stream,<<"Number four">>}),
+ ?line
+ receive
+ {S3,{Addr,P2,S3Ai,Stream,<<"Number four">>}} -> ok
+ after Timeout ->
+ socket_bailout([S1,S2,S3])
+ end,
+ %%
+ ?line inet:i(sctp),
+ ?line socket_close_verbose(S1),
+ ?line socket_close_verbose(S2),
+ ?line
+ receive
+ {S3,{Addr,P2,#sctp_shutdown_event{assoc_id=S3Ai_X}}} ->
+ ?line match_unless_solaris(S3Ai, S3Ai_X)
+ after Timeout ->
+ socket_bailout([S3])
+ end,
+ ?line
+ receive
+ {S3,{Addr,P2,#sctp_assoc_change{state=shutdown_comp,
+ assoc_id=S3Ai}}} -> ok
+ after Timeout ->
+ socket_bailout([S3])
+ end,
+ ?line socket_close_verbose(S3),
+ ?line [] = flush(),
+ ok.
+
+
+
+buffers(doc) ->
+ ["Check sndbuf and recbuf behaviour"];
+buffers(suite) ->
+ [];
+buffers(Config) when is_list(Config) ->
+ ?line Limit = 4096,
+ ?line Addr = {127,0,0,1},
+ ?line Stream = 1,
+ ?line Timeout = 3333,
+ ?line S1 = socket_open([{ip,Addr}], Timeout),
+ ?line ?LOGVAR(S1),
+ ?line P1 = socket_call(S1, get_port),
+ ?line ?LOGVAR(P1),
+ ?line ok = socket_call(S1, {listen,true}),
+ ?line S2 = socket_open([{ip,Addr}], Timeout),
+ ?line ?LOGVAR(S2),
+ ?line P2 = socket_call(S2, get_port),
+ ?line ?LOGVAR(P2),
+ %%
+ ?line socket_call(S2, {connect_init,Addr,P1,[]}),
+ ?line S2Ai =
+ receive
+ {S2,{Addr,P1,
+ #sctp_assoc_change{
+ state=comm_up,
+ assoc_id=AssocId2}}} -> AssocId2
+ after Timeout ->
+ socket_bailout([S1,S2])
+ end,
+ ?line S1Ai =
+ receive
+ {S1,{Addr,P2,
+ #sctp_assoc_change{
+ state=comm_up,
+ assoc_id=AssocId1}}} -> AssocId1
+ after Timeout ->
+ socket_bailout([S1,S2])
+ end,
+ %%
+ ?line socket_call(S1, {setopts,[{recbuf,Limit}]}),
+ ?line Recbuf =
+ case socket_call(S1, {getopts,[recbuf]}) of
+ [{recbuf,RB1}] when RB1 >= Limit -> RB1
+ end,
+ ?line Data = mk_data(Recbuf+Limit),
+ ?line socket_call(S2, {setopts,[{sndbuf,Recbuf+Limit}]}),
+ ?line socket_call(S2, {send,S2Ai,Stream,Data}),
+ ?line
+ receive
+ {S1,{Addr,P2,S1Ai,Stream,Data}} -> ok
+ after Timeout ->
+ socket_bailout([S1,S2])
+ end,
+ %%
+ ?line socket_close_verbose(S1),
+ ?line
+ receive
+ {S2,{Addr,P1,#sctp_shutdown_event{assoc_id=S2Ai}}} -> ok
+ after Timeout ->
+ socket_bailout([S2])
+ end,
+ ?line
+ receive
+ {S2,{Addr,P1,#sctp_assoc_change{state=shutdown_comp,
+ assoc_id=S2Ai}}} -> ok
+ after Timeout ->
+ socket_bailout([S2])
+ end,
+ ?line socket_close_verbose(S2),
+ ?line [] = flush(),
+ ok.
+
+mk_data(Bytes) ->
+ mk_data(0, Bytes, <<>>).
+%%
+mk_data(N, Bytes, Bin) when N < Bytes ->
+ mk_data(N+4, Bytes, <<Bin/binary,N:32>>);
+mk_data(_, _, Bin) ->
+ Bin.
+
+%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%% socket gen_server ultra light
+
+socket_open(SocketOpts, Timeout) ->
+ Opts = [{type,seqpacket},{active,once},binary|SocketOpts],
+ Starter =
+ fun () ->
+ {ok,Socket} =
+ gen_sctp:open(Opts),
+ Socket
+ end,
+ s_start(Starter, Timeout).
+
+socket_peeloff(Socket, AssocId, Timeout) ->
+ Opts = [{active,once},binary],
+ Starter =
+ fun () ->
+ {ok,NewSocket} =
+ gen_sctp:peeloff(Socket, AssocId),
+ ok = inet:setopts(NewSocket, Opts),
+ NewSocket
+ end,
+ s_start(Starter, Timeout).
+
+socket_close_verbose(S) ->
+ History = socket_history(socket_close(S)),
+ io:format("socket_close ~p:~n ~p.~n", [S,History]),
+ History.
+
+socket_close(S) ->
+ s_req(S, close).
+
+socket_call(S, Request) ->
+ s_req(S, {Request}).
+
+%% socket_get(S, Key) ->
+%% s_req(S, {get,Key}).
+
+socket_bailout([S|Ss]) ->
+ History = socket_history(socket_close(S)),
+ io:format("bailout ~p:~n ~p.~n", [S,History]),
+ socket_bailout(Ss);
+socket_bailout([]) ->
+ io:format("flush: ~p.~n", [flush()]),
+ test_server:fail(socket_bailout).
+
+socket_history({State,Flush}) ->
+ {lists:keysort(
+ 2,
+ lists:flatten(
+ [[{Key,Val} || Val <- Vals]
+ || {Key,Vals} <- gb_trees:to_list(State)])),
+ Flush}.
+
+s_handler(Socket) ->
+ fun ({listen,Listen}) ->
+ ok = gen_sctp:listen(Socket, Listen);
+ (get_port) ->
+ ok(inet:port(Socket));
+ (get_socket) ->
+ Socket;
+ ({connect_init,ConAddr,ConPort,ConOpts}) ->
+ ok = gen_sctp:connect_init(Socket, ConAddr, ConPort, ConOpts);
+ ({send,AssocId,Stream,Data}) ->
+ ok = gen_sctp:send(Socket, AssocId, Stream, Data);
+ ({send,OtherSocket,AssocId,Stream,Data}) ->
+ ok = gen_sctp:send(OtherSocket, AssocId, Stream, Data);
+ ({setopts,Opts}) ->
+ ok = inet:setopts(Socket, Opts);
+ ({getopts,Optnames}) ->
+ ok(inet:getopts(Socket, Optnames))
+ end.
+
+s_req(S, Req) ->
+ Mref = erlang:monitor(process, S),
+ S ! {self(),Mref,Req},
+ receive
+ {'DOWN',Mref,_,_,Error} ->
+ exit(Error);
+ {S,Mref,Reply} ->
+ erlang:demonitor(Mref),
+ receive {'DOWN',Mref,_,_,_} -> ok after 0 -> ok end,
+ Reply
+ end.
+
+s_start(Starter, Timeout) ->
+ Parent = self(),
+ Owner =
+ spawn_link(
+ fun () ->
+ s_start(Starter(), Timeout, Parent)
+ end),
+ Owner.
+
+s_start(Socket, Timeout, Parent) ->
+ Handler = s_handler(Socket),
+ try
+ s_loop(Socket, Timeout, Parent, Handler, gb_trees:empty())
+ catch
+ Class:Reason ->
+ Stacktrace = erlang:get_stacktrace(),
+ io:format(?MODULE_STRING":socket exception ~w:~w at~n"
+ "~p.~n", [Class,Reason,Stacktrace]),
+ erlang:raise(Class, Reason, Stacktrace)
+ end.
+
+s_loop(Socket, Timeout, Parent, Handler, State) ->
+ receive
+ {Parent,Ref,close} -> % socket_close()
+ erlang:send_after(Timeout, self(), {Parent,Ref,exit}),
+ s_loop(Socket, Timeout, Parent, Handler, State);
+ {Parent,Ref,exit} ->
+ ok = gen_sctp:close(Socket),
+ Key = exit,
+ Val = {now(),Socket},
+ NewState = gb_push(Key, Val, State),
+ Parent ! {self(),Ref,{NewState,flush()}};
+ {Parent,Ref,{Msg}} ->
+ Result = Handler(Msg),
+ Key = req,
+ Val = {now(),{Msg,Result}},
+ NewState = gb_push(Key, Val, State),
+ Parent ! {self(),Ref,Result},
+ s_loop(Socket, Timeout, Parent, Handler, NewState);
+ %% {Parent,Ref,{get,Key}} ->
+ %% Parent ! {self(),Ref,gb_get(Key, State)},
+ %% s_loop(Socket, Timeout, Parent, Handler, State);
+ {sctp,Socket,Addr,Port,
+ {[#sctp_sndrcvinfo{stream=Stream,assoc_id=AssocId}=SRI],Data}}
+ when not is_tuple(Data) ->
+ case gb_get({assoc_change,AssocId}, State) of
+ [{_,{Addr,Port,
+ #sctp_assoc_change{
+ state=comm_up,
+ inbound_streams=Is}}}|_]
+ when 0 =< Stream, Stream < Is-> ok;
+ [] -> ok
+ end,
+ Key = {msg,AssocId,Stream},
+ Val = {now(),{Addr,Port,SRI,Data}},
+ NewState = gb_push(Key, Val, State),
+ Parent ! {self(),{Addr,Port,AssocId,Stream,Data}},
+ again(Socket),
+ s_loop(Socket, Timeout, Parent, Handler, NewState);
+ {sctp,Socket,Addr,Port,
+ {SRI,#sctp_assoc_change{assoc_id=AssocId,state=St}=SAC}} ->
+ case SRI of
+ [#sctp_sndrcvinfo{assoc_id=AssocId,stream=0}] -> ok;
+ [] -> ok
+ end,
+ Key = {assoc_change,AssocId},
+ Val = {now(),{Addr,Port,SAC}},
+ case {gb_get(Key, State),St} of
+ {[],_} -> ok;
+ {[{_,{Addr,Port,#sctp_assoc_change{state=comm_up}}}|_],_}
+ when St =:= comm_lost; St =:= shutdown_comp -> ok
+ end,
+ NewState = gb_push(Key, Val, State),
+ Parent ! {self(),{Addr,Port,SAC}},
+ again(Socket),
+ s_loop(Socket, Timeout, Parent, Handler, NewState);
+ {sctp,Socket,Addr,Port,
+ {SRI,#sctp_paddr_change{assoc_id=AssocId,
+ addr={_,P},
+ state=St}=SPC}} ->
+ match_unless_solaris(Port, P),
+ case SRI of
+ [#sctp_sndrcvinfo{assoc_id=AssocId,stream=0}] -> ok;
+ [] -> ok
+ end,
+ case {gb_get({assoc_change,AssocId}, State),St} of
+ {[{_,{Addr,Port,#sctp_assoc_change{state=comm_up}}}|_],
+ addr_available} -> ok;
+ {[],addr_confirmed} -> ok
+ end,
+ Key = {paddr_change,AssocId},
+ Val = {now(),{Addr,Port,SPC}},
+ NewState = gb_push(Key, Val, State),
+ again(Socket),
+ s_loop(Socket, Timeout, Parent, Handler, NewState);
+ {sctp,Socket,Addr,Port,
+ {SRI,#sctp_shutdown_event{assoc_id=AssocId}=SSE}} ->
+ case SRI of
+ [#sctp_sndrcvinfo{assoc_id=AssocId,stream=0}] -> ok;
+ [] -> ok
+ end,
+ case gb_get({assoc_change,AssocId}, State) of
+ [{_,{Addr,Port,#sctp_assoc_change{state=comm_up}}}|_] -> ok;
+ [] -> ok
+ end,
+ Key = {shutdown_event,AssocId},
+ Val = {now(),{Addr,Port}},
+ NewState = gb_push(Key, Val, State),
+ Parent ! {self(), {Addr,Port,SSE}},
+ again(Socket),
+ s_loop(Socket, Timeout, Parent, Handler, NewState);
+ Unexpected ->
+ erlang:error({unexpected,Unexpected})
+ end.
+
+again(Socket) ->
+ inet:setopts(Socket, [{active,once}]).
+
+gb_push(Key, Val, GBT) ->
+ case gb_trees:lookup(Key, GBT) of
+ none ->
+ gb_trees:insert(Key, [Val], GBT);
+ {value,V} ->
+ gb_trees:update(Key, [Val|V], GBT)
+ end.
+
+gb_get(Key, GBT) ->
+ case gb_trees:lookup(Key, GBT) of
+ none ->
+ [];
+ {value,V} ->
+ V
+ end.
+
+match_unless_solaris(A, B) ->
+ case os:type() of
+ {unix,sunos} -> B;
+ _ -> A = B
+ end.
diff --git a/lib/kernel/test/gen_udp_SUITE.erl b/lib/kernel/test/gen_udp_SUITE.erl
index 514deaf065..2354f8accd 100644
--- a/lib/kernel/test/gen_udp_SUITE.erl
+++ b/lib/kernel/test/gen_udp_SUITE.erl
@@ -99,9 +99,9 @@ buffer_size(Config) when is_list(Config) ->
?line Bin = list_to_binary(lists:seq(0, Len-1)),
?line M = 8192 div Len,
?line Spec0 =
- [{opt,M},{safe,M-1},{long,M+1},
- {opt,2*M},{safe,2*M-1},{long,2*M+1},
- {opt,4*M},{safe,4*M-1},{long,4*M+1}],
+ [{opt,M},{safe,M-3},{long,M+1},
+ {opt,2*M},{safe,2*M-3},{long,2*M+1},
+ {opt,4*M},{safe,4*M-3},{long,4*M+1}],
?line Spec =
[case Tag of
opt ->
@@ -145,16 +145,27 @@ buffer_size_client(_, _, _, _, _, []) ->
?line ok;
buffer_size_client(Server, IP, Port,
Socket, Cnt, [Opts|T]) when is_list(Opts) ->
+ ?line io:format("buffer_size_client Cnt=~w setopts ~p.~n", [Cnt,Opts]),
?line ok = inet:setopts(Socket, Opts),
?line Server ! {self(),setopts,Cnt},
?line receive {Server,setopts,Cnt} -> ok end,
?line buffer_size_client(Server, IP, Port, Socket, Cnt+1, T);
buffer_size_client(Server, IP, Port,
- Socket, Cnt, [{B,Replies}|T]) when is_binary(B) ->
- ?line ok = gen_udp:send(Socket, IP, Port, B),
+ Socket, Cnt, [{B,Replies}|T]=Opts) when is_binary(B) ->
+ ?line io:format(
+ "buffer_size_client Cnt=~w send size ~w expecting ~p.~n",
+ [Cnt,size(B),Replies]),
+ ?line ok = gen_udp:send(Socket, IP, Port, <<Cnt,B/binary>>),
?line receive
{Server,Cnt,Reply} ->
- ?line case lists:member(Reply, Replies) of
+ ?line Tag =
+ if
+ is_tuple(Reply) ->
+ element(1, Reply);
+ is_atom(Reply) ->
+ Reply
+ end,
+ ?line case lists:member(Tag, Replies) of
true -> ok;
false ->
?line
@@ -162,34 +173,62 @@ buffer_size_client(Server, IP, Port,
byte_size(B),
inet:getopts(Socket,
[sndbuf,recbuf])})
- end
- end,
- ?line buffer_size_client(Server, IP, Port, Socket, Cnt+1, T).
+ end,
+ ?line buffer_size_client(Server, IP, Port, Socket, Cnt+1, T)
+ after 1313 ->
+ ?line buffer_size_client(Server, IP, Port, Socket, Cnt, Opts)
+ end.
buffer_size_server(_, _, _, _, _, []) ->
ok;
buffer_size_server(Client, IP, Port,
Socket, Cnt, [Opts|T]) when is_list(Opts) ->
receive {Client,setopts,Cnt} -> ok end,
+ ?line io:format("buffer_size_server Cnt=~w setopts ~p.~n", [Cnt,Opts]),
ok = inet:setopts(Socket, Opts),
Client ! {self(),setopts,Cnt},
buffer_size_server(Client, IP, Port, Socket, Cnt+1, T);
buffer_size_server(Client, IP, Port,
Socket, Cnt, [{B,_}|T]) when is_binary(B) ->
+ ?line io:format(
+ "buffer_size_server Cnt=~w expecting size ~w.~n",
+ [Cnt,size(B)]),
Client !
{self(),Cnt,
- receive
- {udp,Socket,IP,Port,D} when is_binary(D) ->
+ case buffer_size_server_recv(Socket, IP, Port, Cnt) of
+ D when is_binary(D) ->
SizeD = byte_size(D),
+ ?line io:format(
+ "buffer_size_server Cnt=~w received size ~w.~n",
+ [Cnt,SizeD]),
case B of
- D -> correct;
- <<D:SizeD/binary,_/binary>> -> truncated
+ D ->
+ correct;
+ <<D:SizeD/binary,_/binary>> ->
+ truncated;
+ _ ->
+ {unexpected,D}
end;
- {udp_error,Socket,Error} -> Error
- after 5000 -> timeout
+ Error ->
+ ?line io:format(
+ "buffer_size_server Cnt=~w received error ~w.~n",
+ [Cnt,Error]),
+ Error
end},
buffer_size_server(Client, IP, Port, Socket, Cnt+1, T).
+buffer_size_server_recv(Socket, IP, Port, Cnt) ->
+ receive
+ {udp,Socket,IP,Port,<<Cnt,B/binary>>} ->
+ B;
+ {udp,Socket,IP,Port,<<_/binary>>} ->
+ buffer_size_server_recv(Socket, IP, Port, Cnt);
+ {udp_error,Socket,Error} ->
+ Error
+ after 5000 ->
+ {timeout,flush()}
+ end.
+
%%-------------------------------------------------------------
diff --git a/lib/kernel/test/global_SUITE.erl b/lib/kernel/test/global_SUITE.erl
index 1e7bcf1766..60035b50a0 100644
--- a/lib/kernel/test/global_SUITE.erl
+++ b/lib/kernel/test/global_SUITE.erl
@@ -436,7 +436,7 @@ lock_global2(Id, Parent) ->
%cp1 - cp3 are started, and the name 'test' registered for a process on
%test_server. Then it is checked that the name is registered on all
-%nodes, using whereis_name and safe_whereis_name. Check that the same
+%nodes, using whereis_name. Check that the same
%name can't be registered with another value. Exit the registered
%process and check that the name disappears. Register a new process
%(Pid2) under the name 'test'. Let another new process (Pid3)
@@ -465,10 +465,6 @@ names(Config) when is_list(Config) ->
% test that it is registered at all nodes
?line
?UNTIL(begin
- (Pid =:= global:safe_whereis_name(test)) and
- (Pid =:= rpc:call(Cp1, global, safe_whereis_name, [test])) and
- (Pid =:= rpc:call(Cp2, global, safe_whereis_name, [test])) and
- (Pid =:= rpc:call(Cp3, global, safe_whereis_name, [test])) and
(Pid =:= global:whereis_name(test)) and
(Pid =:= rpc:call(Cp1, global, whereis_name, [test])) and
(Pid =:= rpc:call(Cp2, global, whereis_name, [test])) and
@@ -566,10 +562,7 @@ names_hidden(Config) when is_list(Config) ->
% Check that it didn't get registered on visible nodes
?line
- ?UNTIL((undefined =:= global:safe_whereis_name(test)) and
- (undefined =:= rpc:call(Cp1, global, safe_whereis_name, [test])) and
- (undefined =:= rpc:call(Cp2, global, safe_whereis_name, [test])) and
- (undefined =:= global:whereis_name(test)) and
+ ?UNTIL((undefined =:= global:whereis_name(test)) and
(undefined =:= rpc:call(Cp1, global, whereis_name, [test])) and
(undefined =:= rpc:call(Cp2, global, whereis_name, [test]))),
@@ -579,11 +572,7 @@ names_hidden(Config) when is_list(Config) ->
% test that it is registered at all nodes
?line
- ?UNTIL((Pid =:= global:safe_whereis_name(test)) and
- (Pid =:= rpc:call(Cp1, global, safe_whereis_name, [test])) and
- (Pid =:= rpc:call(Cp2, global, safe_whereis_name, [test])) and
- (HPid =:= rpc:call(Cp3, global, safe_whereis_name, [test])) and
- (Pid =:= global:whereis_name(test)) and
+ ?UNTIL((Pid =:= global:whereis_name(test)) and
(Pid =:= rpc:call(Cp1, global, whereis_name, [test])) and
(Pid =:= rpc:call(Cp2, global, whereis_name, [test])) and
(HPid =:= rpc:call(Cp3, global, whereis_name, [test])) and
diff --git a/lib/kernel/test/inet_SUITE.erl b/lib/kernel/test/inet_SUITE.erl
index aaa20b7398..7241b093d0 100644
--- a/lib/kernel/test/inet_SUITE.erl
+++ b/lib/kernel/test/inet_SUITE.erl
@@ -97,8 +97,12 @@ t_gethostbyaddr() ->
required(v4).
t_gethostbyaddr(doc) -> "Test the inet:gethostbyaddr/1 function.";
t_gethostbyaddr(Config) when is_list(Config) ->
- ?line {Name,FullName,IPStr,IP,Aliases,_,_} =
+ ?line {Name,FullName,IPStr,{A,B,C,D}=IP,Aliases,_,_} =
ct:get_config(test_host_ipv4_only),
+ ?line Rname = integer_to_list(D) ++ "." ++
+ integer_to_list(C) ++ "." ++
+ integer_to_list(B) ++ "." ++
+ integer_to_list(A) ++ ".in-addr.arpa",
?line {ok,HEnt} = inet:gethostbyaddr(IPStr),
?line {ok,HEnt} = inet:gethostbyaddr(IP),
?line {error,Error} = inet:gethostbyaddr(Name),
@@ -116,7 +120,7 @@ t_gethostbyaddr(Config) when is_list(Config) ->
ok;
_ ->
?line check_elems([{HEnt#hostent.h_name,[Name,FullName]},
- {HEnt#hostent.h_aliases,[[],Aliases]}])
+ {HEnt#hostent.h_aliases,[[],Aliases,[Rname]]}])
end,
?line {_DName, _DFullName, DIPStr, DIP, _, _, _} =
diff --git a/lib/kernel/test/inet_res_SUITE.erl b/lib/kernel/test/inet_res_SUITE.erl
index 8a3d220e46..15b0ed5718 100644
--- a/lib/kernel/test/inet_res_SUITE.erl
+++ b/lib/kernel/test/inet_res_SUITE.erl
@@ -136,21 +136,22 @@ ns_init(ZoneDir, PrivDir, DataDir) ->
atom_to_list(ZoneDir)]},
stderr_to_stdout,
eof]),
- ns_start(ZoneDir, NS, P);
+ ns_start(ZoneDir, PrivDir, NS, P);
_ ->
throw("Only run on Unix")
end.
-ns_start(ZoneDir, NS, P) ->
+ns_start(ZoneDir, PrivDir, NS, P) ->
case ns_collect(P) of
eof ->
erlang:error(eof);
"Running: "++_ ->
{ZoneDir,NS,P};
"Error: "++Error ->
+ ns_printlog(filename:join([PrivDir,ZoneDir,"named.log"])),
throw(Error);
_ ->
- ns_start(ZoneDir, NS, P)
+ ns_start(ZoneDir, PrivDir, NS, P)
end.
ns_end(undefined, _PrivDir) -> undefined;
diff --git a/lib/kernel/test/inet_res_SUITE_data/run-named b/lib/kernel/test/inet_res_SUITE_data/run-named
index 7caa3756ef..39e7b1d5aa 100755
--- a/lib/kernel/test/inet_res_SUITE_data/run-named
+++ b/lib/kernel/test/inet_res_SUITE_data/run-named
@@ -47,6 +47,7 @@ CONF_FILE=named.conf
INC_FILE=named_inc.conf
PID_FILE=named.pid
LOG_FILE=named.log
+EXIT_FILE=named.exit
error () {
r=$?
@@ -71,10 +72,14 @@ test -d "$SRCDIR" || \
test -f "$SRCDIR/$INC_FILE" || \
error "Missing file: $SRCDIR/$INC_FILE !"
-# Locate named and check version
+# Locate named and check version.
+# The bind-named name is used for tricking Apparmor and such
+# by copying/hardlinking the real named to that name.
NAMED=named
-for n in /usr/sbin/named /usr/sbin/in.named; do
- test -x "$n" && NAMED="$n"
+for n in /usr/local/bin/bind-named /usr/local/bin/named \
+ /usr/sbin/bind-named /usr/sbin/named /usr/sbin/in.named
+do
+ test -x "$n" && NAMED="$n" && break
done
NAMED_VER="`"$NAMED" -v 2>&1`" || \
error "Name server not found!"
@@ -145,19 +150,27 @@ cat >>"$CONF_FILE" <<-CONF_FILE
( cd "$SRCDIR" && ls -1 ) | while read f; do
cp -fp "$SRCDIR/$f" .
done
+rm -f "$EXIT_FILE"
# Start nameserver
echo "Cwd: `pwd`"
echo "Nameserver: $NAMED_VER"
echo "Port: $2"
echo "ZoneDir: $3"
-$NAMED $NAMED_FG -c "$CONF_FILE" >"$LOG_FILE" 2>&1 </dev/null &
-NAMED=$!
-trap "kill -TERM $NAMED >/dev/null 2>&1; wait $NAMED >/dev/null 2>&1" \
+echo "Command: $NAMED $NAMED_FG -c $CONF_FILE"
+($NAMED $NAMED_FG -c "$CONF_FILE" >"$LOG_FILE" 2>&1 </dev/null; \
+ echo "$?" >"$EXIT_FILE")&
+NAMED_PID=$!
+trap "kill -TERM $NAMED_PID >/dev/null 2>&1; wait $NAMED_PID >/dev/null 2>&1" \
0 1 2 3 15
sleep 2 # Give name server time to load its zone files
-echo "Running: Enter \`\`quit'' to terminate nameserver[$NAMED]..."
-while read LINE; do
- test :"$LINE" = :'quit' && break
-done
+if [ -f "$EXIT_FILE" ]; then
+ ERROR="`cat "$EXIT_FILE"`"
+ (exit "$ERROR")& error "$NAMED returned $ERROR on start"
+else
+ echo "Running: Enter \`\`quit'' to terminate nameserver[$NAMED_PID]..."
+ while read LINE; do
+ test :"$LINE" = :'quit' && break
+ done
+fi
echo "Closing: Terminating nameserver..."
diff --git a/lib/kernel/test/kernel_SUITE.erl b/lib/kernel/test/kernel_SUITE.erl
index 16b6c54939..0f29d895e5 100644
--- a/lib/kernel/test/kernel_SUITE.erl
+++ b/lib/kernel/test/kernel_SUITE.erl
@@ -32,7 +32,7 @@
-export([init_per_testcase/2, end_per_testcase/2]).
% Test cases must be exported.
--export([app_test/1]).
+-export([app_test/1, appup_test/1]).
%%
%% all/1
@@ -40,7 +40,7 @@
suite() -> [{ct_hooks,[ts_install_cth]}].
all() ->
- [app_test].
+ [app_test, appup_test].
groups() ->
[].
@@ -76,3 +76,63 @@ app_test(suite) ->
app_test(Config) when is_list(Config) ->
?line ok=?t:app_test(kernel),
ok.
+
+
+%% Test that appup allows upgrade from/downgrade to a maximum of two
+%% major releases back.
+appup_test(_Config) ->
+ application:load(kernel),
+ {_,_,Vsn} = lists:keyfind(kernel,1,application:loaded_applications()),
+ AppupFile = filename:join([code:lib_dir(kernel),ebin,"kernel.appup"]),
+ {ok,[{Vsn,UpFrom,DownTo}=AppupScript]} = file:consult(AppupFile),
+ ct:log("~p~n",[AppupScript]),
+ {OkVsns,NokVsns} = create_test_vsns(Vsn),
+ check_appup(OkVsns,UpFrom,{ok,[restart_new_emulator]}),
+ check_appup(OkVsns,DownTo,{ok,[restart_new_emulator]}),
+ check_appup(NokVsns,UpFrom,error),
+ check_appup(NokVsns,DownTo,error),
+ ok.
+
+create_test_vsns(Current) ->
+ [XStr,YStr|Rest] = string:tokens(Current,"."),
+ X = list_to_integer(XStr),
+ Y = list_to_integer(YStr),
+ SecondMajor = vsn(X,Y-2),
+ SecondMinor = SecondMajor ++ ".1.3",
+ FirstMajor = vsn(X,Y-1),
+ FirstMinor = FirstMajor ++ ".57",
+ ThisMajor = vsn(X,Y),
+ This =
+ case Rest of
+ [] ->
+ [];
+ ["1"] ->
+ [ThisMajor];
+ _ ->
+ ThisMinor = ThisMajor ++ ".1",
+ [ThisMajor,ThisMinor]
+ end,
+ OkVsns = This ++ [FirstMajor, FirstMinor, SecondMajor, SecondMinor],
+
+ ThirdMajor = vsn(X,Y-3),
+ ThirdMinor = ThirdMajor ++ ".10.12",
+ Illegal = ThisMajor ++ ",1",
+ Newer1Major = vsn(X,Y+1),
+ Newer1Minor = Newer1Major ++ ".1",
+ Newer2Major = ThisMajor ++ "1",
+ NokVsns = [ThirdMajor,ThirdMinor,
+ Illegal,
+ Newer1Major,Newer1Minor,
+ Newer2Major],
+ {OkVsns,NokVsns}.
+
+vsn(X,Y) ->
+ integer_to_list(X) ++ "." ++ integer_to_list(Y).
+
+check_appup([Vsn|Vsns],Instrs,Expected) ->
+ case systools_relup:appup_search_for_version(Vsn, Instrs) of
+ Expected -> check_appup(Vsns,Instrs,Expected);
+ Other -> ct:fail({unexpected_result_for_vsn,Vsn,Other})
+ end;
+check_appup([],_,_) ->
+ ok.
diff --git a/lib/kernel/test/pg2_SUITE.erl b/lib/kernel/test/pg2_SUITE.erl
index 0ac34e735c..520b53b4e4 100644
--- a/lib/kernel/test/pg2_SUITE.erl
+++ b/lib/kernel/test/pg2_SUITE.erl
@@ -47,6 +47,7 @@ init_per_testcase(Case, Config) ->
[{?TESTCASE, Case}, {watchdog, Dog} | Config].
end_per_testcase(_Case, _Config) ->
+ test_server_ctrl:kill_slavenodes(),
Dog = ?config(watchdog, _Config),
test_server:timetrap_cancel(Dog),
ok.
diff --git a/lib/kernel/test/wrap_log_reader_SUITE.erl b/lib/kernel/test/wrap_log_reader_SUITE.erl
index ffc8def626..96dc3e6d33 100644
--- a/lib/kernel/test/wrap_log_reader_SUITE.erl
+++ b/lib/kernel/test/wrap_log_reader_SUITE.erl
@@ -561,4 +561,4 @@ rec(M, Where) ->
end.
pps() ->
- {erlang:ports(), lists:filter({erlang, is_process_alive}, processes())}.
+ {erlang:ports(), lists:filter(fun erlang:is_process_alive/1, processes())}.
diff --git a/lib/kernel/test/zlib_SUITE.erl b/lib/kernel/test/zlib_SUITE.erl
index 4ad9c6923d..74bafe8935 100644
--- a/lib/kernel/test/zlib_SUITE.erl
+++ b/lib/kernel/test/zlib_SUITE.erl
@@ -42,8 +42,8 @@
end
end()).
--define(BARG, {'EXIT',{badarg,[{zlib,_,_}|_]}}).
--define(DATA_ERROR, {'EXIT',{data_error,[{zlib,_,_}|_]}}).
+-define(BARG, {'EXIT',{badarg,[{zlib,_,_,_}|_]}}).
+-define(DATA_ERROR, {'EXIT',{data_error,[{zlib,_,_,_}|_]}}).
init_per_testcase(_Func, Config) ->
Dog = test_server:timetrap(test_server:seconds(60)),
diff --git a/lib/kernel/vsn.mk b/lib/kernel/vsn.mk
index 8be265e79d..76c62ece67 100644
--- a/lib/kernel/vsn.mk
+++ b/lib/kernel/vsn.mk
@@ -1 +1 @@
-KERNEL_VSN = 2.14.5
+KERNEL_VSN = 2.15
diff --git a/lib/megaco/.gitignore b/lib/megaco/.gitignore
new file mode 100644
index 0000000000..1c5979cd62
--- /dev/null
+++ b/lib/megaco/.gitignore
@@ -0,0 +1,3 @@
+examples/meas/Makefile
+examples/meas/meas.sh.skel
+examples/meas/mstone1.sh.skel
diff --git a/lib/megaco/configure.in b/lib/megaco/configure.in
index 8f94a4efcf..42c50b8961 100644
--- a/lib/megaco/configure.in
+++ b/lib/megaco/configure.in
@@ -2,7 +2,7 @@ dnl Process this file with autoconf to produce a configure script. -*-m4-*-
dnl
dnl %CopyrightBegin%
dnl
-dnl Copyright Ericsson AB 2001-2010. All Rights Reserved.
+dnl Copyright Ericsson AB 2001-2011. All Rights Reserved.
dnl
dnl The contents of this file are subject to the Erlang Public License,
dnl Version 1.1, (the "License"); you may not use this file except in
@@ -208,7 +208,7 @@ if test "X$host" = "Xwin32"; then
else
case $host_os in
darwin*)
- CFLAGS="$CFLAGS -no-cpp-precomp -fno-common"
+ CFLAGS="$CFLAGS -fno-common"
;;
esac
@@ -273,5 +273,6 @@ if test "$PERL" = no_perl; then
AC_MSG_ERROR([Perl is required to build the flex scanner!])
fi
+AC_OUTPUT(examples/meas/Makefile:examples/meas/Makefile.in)
AC_OUTPUT(src/flex/$host/Makefile:src/flex/Makefile.in)
diff --git a/lib/megaco/doc/src/Makefile b/lib/megaco/doc/src/Makefile
index 4b3c117b20..f782afc3f6 100644
--- a/lib/megaco/doc/src/Makefile
+++ b/lib/megaco/doc/src/Makefile
@@ -27,14 +27,6 @@ VSN=$(MEGACO_VSN)
APPLICATION=megaco
# ----------------------------------------------------
-# Include dependency
-# ----------------------------------------------------
-
-ifndef DOCSUPPORT
-include make.dep
-endif
-
-# ----------------------------------------------------
# Release directory specification
# ----------------------------------------------------
RELSYSDIR = $(RELEASE_PATH)/lib/$(APPLICATION)-$(VSN)
@@ -73,35 +65,10 @@ EXTRA_FILES = \
MAN3_FILES = $(XML_REF3_FILES:%.xml=$(MAN3DIR)/%.3)
-ifdef DOCSUPPORT
-
HTML_REF_MAN_FILE = $(HTMLDIR)/index.html
TOP_PDF_FILE = $(PDFDIR)/$(APPLICATION)-$(VSN).pdf
-else
-
-TEX_FILES_BOOK = \
- $(BOOK_FILES:%.xml=%.tex)
-TEX_FILES_REF_MAN = $(XML_REF3_FILES:%.xml=%.tex) \
- $(XML_APPLICATION_FILES:%.xml=%.tex)
-TEX_FILES_USERS_GUIDE = \
- $(XML_CHAPTER_FILES:%.xml=%.tex)
-
-TOP_PDF_FILE = $(APPLICATION)-$(VSN).pdf
-TOP_PS_FILE = $(APPLICATION)-$(VSN).ps
-
-$(TOP_PDF_FILE): book.dvi ../../vsn.mk
- $(DVI2PS) $(DVIPS_FLAGS) -f $< | $(DISTILL) $(DISTILL_FLAGS) > $@
-
-$(TOP_PS_FILE): book.dvi $(APP_FILE)
- $(DVI2PS) $(DVIPS_FLAGS) -f $< > $@
-
-
-TOP_HTML_FILES = $(INDEX_TARGET)
-
-endif
-
INDEX_FILE = index.html
INDEX_SRC = $(INDEX_FILE).src
INDEX_TARGET = $(DOCDIR)/$(INDEX_FILE)
@@ -131,8 +98,6 @@ $(HTMLDIR)/%.jpg: %.jpg
$(HTMLDIR)/%.png: %.png
$(INSTALL_DATA) $< $@
-ifdef DOCSUPPORT
-
docs: pdf html man
ldocs: local_docs $(INDEX_TARGET)
@@ -147,41 +112,6 @@ clean clean_docs: clean_html clean_man
rm -f $(TOP_PDF_FILE) $(TOP_PDF_FILE:%.pdf=%.fo)
rm -f errs core *~
-else
-
-ifeq ($(DOCTYPE),pdf)
-docs: pdf
-else
-ifeq ($(DOCTYPE),ps)
-docs: ps
-else
-docs: html imgs man
-endif
-endif
-
-pdf: $(TOP_PDF_FILE)
-
-ps: $(TOP_PS_FILE)
-
-html: imgs $(HTML_FILES) $(TOP_HTML_FILES)
-
-mhtml: html $(HTML_REF3_FILES) $(HTML_CHAPTER_FILES)
-
-clean: clean_html clean_man clean_pdf
- rm -f core *~
- rm -f *.aux *.cites *.citeshd *.dvi *.idx *.ilg *.ind
- rm -f *.indhd *.lof *.lofhd *.lot *.lothd *.otpdef
- rm -f *.otpuse *.terms *.termshd *.toc *.makeindexlog *.dvipslog
- rm -f *.bib *.bbl *.blg *.bibhd
-
-clean_pdf:
- rm -f $(TOP_PDF_FILE) $(TOP_PS_FILE)
- rm -f $(TEX_FILES_USERS_GUIDE)
- rm -f $(TEX_FILES_REF_MAN)
- rm -f $(TEX_FILES_BOOK)
-
-endif
-
clean_man:
rm -f $(MAN3DIR)/*
@@ -203,8 +133,6 @@ debug opt:
info:
@echo "->Makefile<-"
@echo ""
- @echo "DOCSUPPORT = $(DOCSUPPORT)"
- @echo ""
@echo "INDEX_FILE = $(INDEX_FILE)"
@echo "INDEX_SRC = $(INDEX_SRC)"
@echo "INDEX_TARGET = $(INDEX_TARGET)"
@@ -216,10 +144,6 @@ info:
@echo ""
@echo "IMG_FILES = $(IMG_FILES)"
@echo ""
- @echo "TEX_FILES_USERS_GUIDE = $(TEX_FILES_USERS_GUIDE)"
- @echo "TEX_FILES_REF_MAN = $(TEX_FILES_REF_MAN)"
- @echo "TEX_FILES_BOOK = $(TEX_FILES_BOOK)"
- @echo ""
@echo "MAN3_FILES = $(MAN3_FILES)"
@echo ""
@echo "HTML_FILES = $(HTML_FILES)"
@@ -236,8 +160,6 @@ info:
# ----------------------------------------------------
include $(ERL_TOP)/make/otp_release_targets.mk
-ifdef DOCSUPPORT
-
release_docs_spec: docs
$(INSTALL_DIR) $(RELSYSDIR)/doc/pdf
$(INSTALL_DATA) $(TOP_PDF_FILE) $(RELSYSDIR)/doc/pdf
@@ -250,33 +172,6 @@ release_docs_spec: docs
$(INSTALL_DIR) $(RELSYSDIR)/doc/standard
$(INSTALL_DATA) $(STANDARDS) $(RELSYSDIR)/doc/standard
-else
-
-ifeq ($(DOCTYPE),pdf)
-release_docs_spec: pdf
- $(INSTALL_DIR) $(RELEASE_PATH)/pdf
- $(INSTALL_DATA) $(TOP_PDF_FILE) $(RELEASE_PATH)/pdf
-else
-ifeq ($(DOCTYPE),ps)
-release_docs_spec: ps
- $(INSTALL_DIR) $(RELEASE_PATH)/ps
- $(INSTALL_DATA) $(TOP_PS_FILE) $(RELEASE_PATH)/ps
-else
-release_docs_spec: docs
- $(INSTALL_DIR) $(RELSYSDIR)/doc/html
- $(INSTALL_DATA) $(IMG_FILES) $(EXTRA_FILES) $(HTML_FILES) \
- $(RELSYSDIR)/doc/html
- $(INSTALL_DATA) $(INFO_FILE) $(RELSYSDIR)
- $(INSTALL_DIR) $(RELEASE_PATH)/man/man3
- $(INSTALL_DATA) $(MAN3_FILES) $(RELEASE_PATH)/man/man3
- $(INSTALL_DATA) $(TOP_HTML_FILES) $(RELSYSDIR)/doc
- $(INSTALL_DIR) $(RELSYSDIR)/doc/standard
- $(INSTALL_DATA) $(STANDARDS) $(RELSYSDIR)/doc/standard
-endif
-endif
-
-endif
-
release_spec:
$(HTMLDIR)/megaco_architecture.html: megaco_architecture.xml
diff --git a/lib/megaco/doc/src/make.dep b/lib/megaco/doc/src/make.dep
deleted file mode 100644
index 0e2040ab50..0000000000
--- a/lib/megaco/doc/src/make.dep
+++ /dev/null
@@ -1,59 +0,0 @@
-#-*-makefile-*- ; force emacs to enter makefile-mode
-
-# %CopyrightBegin%
-#
-# Copyright Ericsson AB 2001-2009. All Rights Reserved.
-#
-# The contents of this file are subject to the Erlang Public License,
-# Version 1.1, (the "License"); you may not use this file except in
-# compliance with the License. You should have received a copy of the
-# Erlang Public License along with this software. If not, it can be
-# retrieved online at http://www.erlang.org/.
-#
-# Software distributed under the License is distributed on an "AS IS"
-# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
-# the License for the specific language governing rights and limitations
-# under the License.
-#
-# %CopyrightEnd%
-
-# ----------------------------------------------------
-# >>>> Do not edit this file <<<<
-# This file was automaticly generated by
-# /home/otp/bin/docdepend
-# ----------------------------------------------------
-
-
-# ----------------------------------------------------
-# TeX files that the DVI file depend on
-# ----------------------------------------------------
-
-book.dvi: book.tex megaco.tex megaco_architecture.tex \
- megaco_codec_meas.tex \
- megaco_codec_mstone1.tex megaco_codec_mstone2.tex \
- megaco_codec_transform.tex \
- megaco_debug.tex megaco_edist_compress.tex \
- megaco_encode.tex megaco_encoder.tex megaco_examples.tex \
- megaco_flex_scanner.tex megaco_intro.tex megaco_mib.tex \
- megaco_performance.tex megaco_run.tex megaco_tcp.tex \
- megaco_transport.tex megaco_transport_mechanisms.tex \
- megaco_udp.tex megaco_user.tex part.tex ref_man.tex
-
-# ----------------------------------------------------
-# Source inlined when transforming from source to LaTeX
-# ----------------------------------------------------
-
-book.tex: ref_man.xml
-
-# ----------------------------------------------------
-# Pictures that the DVI file depend on
-# ----------------------------------------------------
-
-book.dvi: call_flow.ps call_flow_cont.ps distr_node_config.ps \
- megaco_sys_arch.ps single_node_config.ps
-
-book.dvi: mstone1.ps
-
-book.dvi: MG-startup_flow_noMID.ps MGC_startup_call_flow.ps \
- MG_startup_call_flow.ps
-
diff --git a/lib/megaco/doc/src/notes.xml b/lib/megaco/doc/src/notes.xml
index 2aba8db71b..baf8c6a201 100644
--- a/lib/megaco/doc/src/notes.xml
+++ b/lib/megaco/doc/src/notes.xml
@@ -36,6 +36,61 @@
section is the version number of Megaco.</p>
+ <section><title>Megaco 3.15.1.2</title>
+
+ <p>Version 3.15.1.2 supports code replacement in runtime from/to
+ version 3.15.1.1, 3.15.1 and 3.15.</p>
+
+ <section>
+ <title>Improvements and new features</title>
+
+<!--
+ <p>-</p>
+-->
+
+ <list type="bulleted">
+ <item>
+ <p>Minor improvemnts to the emasurement tool mstone1. </p>
+ <p>Own Id: OTP-9604</p>
+ </item>
+
+ <item>
+ <p>ASN.1 no longer makes use of a driver to accelerate encode/decode,
+ instead it uses NIFs. The encoding config option is <em>still</em>
+ the same, i.e. <c>driver</c>. </p>
+ <p>Own Id: OTP-9672</p>
+ </item>
+
+ <item>
+ <p>The profiling test tool has been rewritten. </p>
+ <p>H&aring;kan Mattsson</p>
+ <p>Own Id: OTP-9679</p>
+ </item>
+
+ </list>
+
+ </section>
+
+ <section>
+ <title>Fixed bugs and malfunctions</title>
+
+ <p>-</p>
+
+ <!--
+ <list type="bulleted">
+ <item>
+ <p>Fixing miscellaneous things detected by dialyzer. </p>
+ <p>Own Id: OTP-9075</p>
+ </item>
+
+ </list>
+ -->
+
+ </section>
+
+ </section> <!-- 3.15.1.2 -->
+
+
<section><title>Megaco 3.15.1.1</title>
<p>Version 3.15.1.1 supports code replacement in runtime from/to
diff --git a/lib/megaco/examples/meas/Makefile b/lib/megaco/examples/meas/Makefile.in
index 0a6cbb44a6..6af7ef6c65 100644
--- a/lib/megaco/examples/meas/Makefile
+++ b/lib/megaco/examples/meas/Makefile.in
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2002-2009. All Rights Reserved.
+# Copyright Ericsson AB 2002-2011. All Rights Reserved.
#
# The contents of this file are subject to the Erlang Public License,
# Version 1.1, (the "License"); you may not use this file except in
@@ -35,12 +35,19 @@ VSN=$(MEGACO_VSN)
# ----------------------------------------------------
+# Configured variables
+# ----------------------------------------------------
+PERL = @PERL@
+
+
+# ----------------------------------------------------
# Release directory specification
# ----------------------------------------------------
RELSYSDIR = $(RELEASE_PATH)/lib/megaco-$(VSN)
EXAMPLE_RELSYSDIR = $(RELSYSDIR)/examples
MEAS_RELSYSDIR = $(EXAMPLE_RELSYSDIR)/meas
+
# ----------------------------------------------------
# Target Specs
# ----------------------------------------------------
@@ -49,9 +56,13 @@ include modules.mk
ERL_FILES = $(MODULES:%=%.erl)
-TARGET_FILES = \
+SCRIPT_SKELETONS = $(SCRIPT_SKELETON_SRC:%.src=%)
+
+ERL_TARGETS = \
$(ERL_FILES:%.erl=$(EBIN)/%.$(EMULATOR))
+TARGET_FILES = $(SCRIPT_SKELETONS) $(ERL_TARGETS)
+
# ----------------------------------------------------
# FLAGS
@@ -91,12 +102,27 @@ debug:
opt: $(TARGET_FILES)
+script_skeletons: $(SCRIPT_SKELETONS)
+
+info:
+ @echo "MODULES = $(MODULES)"
+ @echo "ERL_FILED = $(ERL_FILES)"
+ @echo ""
+ @echo "SCRIPT_SKELETON_SRC = $(SCRIPT_SKELETON_SRC)"
+ @echo "SCRIPT_SKELETONS = $(SCRIPT_SKELETONS)"
+ @echo ""
+ @echo "TARGET_FILES = $(TARGET_FILES)"
+ @echo ""
+
clean:
rm -f $(TARGET_FILES)
rm -f errs core *~
docs:
+conf:
+ cd ../..; $(MAKE) conf
+
# ----------------------------------------------------
# Release Target
@@ -120,6 +146,14 @@ release_docs_spec:
# Include dependencies
# ----------------------------------------------------
+meas.sh.skel: meas.sh.skel.src
+ @echo "transforming $< to $@"
+ $(PERL) -p -e 's?%VSN%?$(VSN)? ' < $< > $@
+
+mstone1.sh.skel: mstone1.sh.skel.src
+ @echo "transforming $< to $@"
+ $(PERL) -p -e 's?%VSN%?$(VSN)? ' < $< > $@
+
megaco_codec_transform.$(EMULATOR): megaco_codec_transform.erl
megaco_codec_meas.$(EMULATOR): megaco_codec_meas.erl
diff --git a/lib/megaco/examples/meas/meas.sh.skel b/lib/megaco/examples/meas/meas.sh.skel.src
index 76745ed8f4..c7bd6cdd2a 100644
--- a/lib/megaco/examples/meas/meas.sh.skel
+++ b/lib/megaco/examples/meas/meas.sh.skel.src
@@ -2,7 +2,7 @@
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2007-2010. All Rights Reserved.
+# Copyright Ericsson AB 2007-2011. All Rights Reserved.
#
# The contents of this file are subject to the Erlang Public License,
# Version 1.1, (the "License"); you may not use this file except in
@@ -22,7 +22,7 @@
#
ERL_HOME=<path to otp top dir>
-MEGACO_HOME=$ERL_HOME/lib/erlang/lib/<megaco dir>
+MEGACO_HOME=$ERL_HOME/lib/erlang/lib/megaco-%VSN%
MEAS_HOME=$MEGACO_HOME/examples/meas
PATH=$ERL_HOME/bin:$PATH
diff --git a/lib/megaco/examples/meas/modules.mk b/lib/megaco/examples/meas/modules.mk
index 8f1b45c8a6..26979933d7 100644
--- a/lib/megaco/examples/meas/modules.mk
+++ b/lib/megaco/examples/meas/modules.mk
@@ -2,7 +2,7 @@
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2002-2009. All Rights Reserved.
+# Copyright Ericsson AB 2002-2011. All Rights Reserved.
#
# The contents of this file are subject to the Erlang Public License,
# Version 1.1, (the "License"); you may not use this file except in
@@ -17,9 +17,9 @@
#
# %CopyrightEnd%
-SCRIPT_SKELETONS = \
- meas.sh.skel \
- mstone1.sh.skel
+SCRIPT_SKELETON_SRC = \
+ meas.sh.skel.src \
+ mstone1.sh.skel.src
MESSAGE_PACKAGES = \
time_test.msgs
diff --git a/lib/megaco/examples/meas/mstone1.sh.skel b/lib/megaco/examples/meas/mstone1.sh.skel.src
index b7c7e41007..54a6c61a58 100644
--- a/lib/megaco/examples/meas/mstone1.sh.skel
+++ b/lib/megaco/examples/meas/mstone1.sh.skel.src
@@ -3,7 +3,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2007-2009. All Rights Reserved.
+# Copyright Ericsson AB 2007-2011. All Rights Reserved.
#
# The contents of this file are subject to the Erlang Public License,
# Version 1.1, (the "License"); you may not use this file except in
@@ -59,7 +59,7 @@ Options:
"
ERL_HOME=<path to otp top dir>
-MEGACO_HOME=$ERL_HOME/lib/erlang/lib/<megaco dir>
+MEGACO_HOME=$ERL_HOME/lib/erlang/lib/megaco-%VSN%
MEAS_HOME=$MEGACO_HOME/examples/meas
PATH=$ERL_HOME/bin:$PATH
diff --git a/lib/megaco/src/app/megaco.appup.src b/lib/megaco/src/app/megaco.appup.src
index 7107178d1a..7f6fe0c733 100644
--- a/lib/megaco/src/app/megaco.appup.src
+++ b/lib/megaco/src/app/megaco.appup.src
@@ -139,10 +139,17 @@
%% |
%% v
%% 3.15.1.1
+%% |
+%% v
+%% 3.15.1.2
%%
%%
{"%VSN%",
[
+ {"3.15.1.1",
+ [
+ ]
+ },
{"3.15.1",
[
]
@@ -160,6 +167,10 @@
}
],
[
+ {"3.15.1.1",
+ [
+ ]
+ },
{"3.15.1",
[
]
diff --git a/lib/megaco/src/binary/depend.mk b/lib/megaco/src/binary/depend.mk
index 5ec4977175..c9ca34bcf6 100644
--- a/lib/megaco/src/binary/depend.mk
+++ b/lib/megaco/src/binary/depend.mk
@@ -2,7 +2,7 @@
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2001-2009. All Rights Reserved.
+# Copyright Ericsson AB 2001-2011. All Rights Reserved.
#
# The contents of this file are subject to the Erlang Public License,
# Version 1.1, (the "License"); you may not use this file except in
@@ -24,9 +24,9 @@
# but for per_bin it means that a stage in the encode
# is done in the asn1 driver.
#
-# +driver
+# +nif
# For ber_bin this means that part of the decode is done
-# in the asn1 driver.
+# in the asn1 nif.
#
# +asn1config
# This is only used by the ber_bin, and means that
@@ -45,22 +45,22 @@ endif
BER_V1_FLAGS = $(ASN1_CT_OPTS)
BER_BIN_V1_FLAGS = $(ASN1_CT_OPTS) +asn1config +optimize
-BER_BIN_DRV_V1_FLAGS = $(ASN1_CT_OPTS) +asn1config +optimize +driver
+BER_BIN_DRV_V1_FLAGS = $(ASN1_CT_OPTS) +asn1config +optimize +nif
BER_V2_FLAGS = $(ASN1_CT_OPTS)
BER_BIN_V2_FLAGS = $(ASN1_CT_OPTS) +asn1config +optimize
-BER_BIN_DRV_V2_FLAGS = $(ASN1_CT_OPTS) +asn1config +optimize +driver
+BER_BIN_DRV_V2_FLAGS = $(ASN1_CT_OPTS) +asn1config +optimize +nif
BER_PREV3A_FLAGS = $(ASN1_CT_OPTS)
BER_BIN_PREV3A_FLAGS = $(ASN1_CT_OPTS) +asn1config +optimize
-BER_BIN_DRV_PREV3A_FLAGS = $(ASN1_CT_OPTS) +asn1config +optimize +driver
+BER_BIN_DRV_PREV3A_FLAGS = $(ASN1_CT_OPTS) +asn1config +optimize +nif
BER_PREV3B_FLAGS = $(ASN1_CT_OPTS)
BER_BIN_PREV3B_FLAGS = $(ASN1_CT_OPTS) +asn1config +optimize
-BER_BIN_DRV_PREV3B_FLAGS = $(ASN1_CT_OPTS) +asn1config +optimize +driver
+BER_BIN_DRV_PREV3B_FLAGS = $(ASN1_CT_OPTS) +asn1config +optimize +nif
BER_PREV3C_FLAGS = $(ASN1_CT_OPTS)
BER_BIN_PREV3C_FLAGS = $(ASN1_CT_OPTS) +asn1config +optimize
-BER_BIN_DRV_PREV3C_FLAGS = $(ASN1_CT_OPTS) +asn1config +optimize +driver
+BER_BIN_DRV_PREV3C_FLAGS = $(ASN1_CT_OPTS) +asn1config +optimize +nif
BER_V3_FLAGS = $(ASN1_CT_OPTS)
BER_BIN_V3_FLAGS = $(ASN1_CT_OPTS) +asn1config +optimize
-BER_BIN_DRV_V3_FLAGS = $(ASN1_CT_OPTS) +asn1config +optimize +driver
+BER_BIN_DRV_V3_FLAGS = $(ASN1_CT_OPTS) +asn1config +optimize +nif
PER_V1_FLAGS = $(ASN1_CT_OPTS)
PER_BIN_V1_FLAGS = $(ASN1_CT_OPTS)
PER_BIN_DRV_V1_FLAGS = $(ASN1_CT_OPTS) +optimize
@@ -83,17 +83,16 @@ PER_BIN_DRV_V3_FLAGS = $(ASN1_CT_OPTS) +optimize
# --- Version 1 ---
-$(BER_ASN1_V1_SPEC).erl $(BER_ASN1_V1_SPEC).hrl: \
+$(BER_ASN1_V1_SPEC).erl: \
$(BER_ASN1_V1_SPEC).set.asn \
$(ASN1_V1_SPEC).asn
@echo "$(BER_ASN1_V1_SPEC):"
$(ERLC) -bber $(BER_V1_FLAGS) $(BER_ASN1_V1_SPEC).set.asn
$(EBIN)/$(BER_ASN1_V1_SPEC).$(EMULATOR): \
- $(BER_ASN1_V1_SPEC).erl \
- $(BER_ASN1_V1_SPEC).hrl
+ $(BER_ASN1_V1_SPEC).erl
-$(BER_BIN_ASN1_V1_SPEC).erl $(BER_BIN_ASN1_V1_SPEC).hrl: \
+$(BER_BIN_ASN1_V1_SPEC).erl: \
$(BER_BIN_ASN1_V1_SPEC).set.asn \
$(BER_BIN_ASN1_V1_SPEC).asn1config \
$(ASN1_V1_SPEC).asn
@@ -101,10 +100,9 @@ $(BER_BIN_ASN1_V1_SPEC).erl $(BER_BIN_ASN1_V1_SPEC).hrl: \
$(ERLC) -bber_bin $(BER_BIN_V1_FLAGS) $(BER_BIN_ASN1_V1_SPEC).set.asn
$(EBIN)/$(BER_BIN_ASN1_V1_SPEC).$(EMULATOR): \
- $(BER_BIN_ASN1_V1_SPEC).erl \
- $(BER_BIN_ASN1_V1_SPEC).hrl
+ $(BER_BIN_ASN1_V1_SPEC).erl
-$(BER_BIN_DRV_ASN1_V1_SPEC).erl $(BER_BIN_DRV_ASN1_V1_SPEC).hrl: \
+$(BER_BIN_DRV_ASN1_V1_SPEC).erl: \
$(BER_BIN_DRV_ASN1_V1_SPEC).set.asn \
$(BER_BIN_DRV_ASN1_V1_SPEC).asn1config \
$(ASN1_V1_SPEC).asn
@@ -112,53 +110,48 @@ $(BER_BIN_DRV_ASN1_V1_SPEC).erl $(BER_BIN_DRV_ASN1_V1_SPEC).hrl: \
$(ERLC) -bber_bin $(BER_BIN_DRV_V1_FLAGS) $(BER_BIN_DRV_ASN1_V1_SPEC).set.asn
$(EBIN)/$(BER_BIN_DRV_ASN1_V1_SPEC).$(EMULATOR): \
- $(BER_BIN_DRV_ASN1_V1_SPEC).erl \
- $(BER_BIN_DRV_ASN1_V1_SPEC).hrl
+ $(BER_BIN_DRV_ASN1_V1_SPEC).erl
-$(PER_ASN1_V1_SPEC).erl $(PER_ASN1_V1_SPEC).hrl: \
+$(PER_ASN1_V1_SPEC).erl: \
$(PER_ASN1_V1_SPEC).set.asn \
$(ASN1_V1_SPEC).asn
@echo "$(PER_ASN1_V1_SPEC):"
$(ERLC) -bper $(PER_V1_FLAGS) $(PER_ASN1_V1_SPEC).set.asn
$(EBIN)/$(PER_ASN1_V1_SPEC).$(EMULATOR): \
- $(PER_ASN1_V1_SPEC).erl \
- $(PER_ASN1_V1_SPEC).hrl
+ $(PER_ASN1_V1_SPEC).erl
-$(PER_BIN_ASN1_V1_SPEC).erl $(PER_BIN_ASN1_V1_SPEC).hrl: \
+$(PER_BIN_ASN1_V1_SPEC).erl: \
$(PER_BIN_ASN1_V1_SPEC).set.asn \
$(ASN1_V1_SPEC).asn
@echo "$(PER_BIN_ASN1_V1_SPEC):"
$(ERLC) -bper_bin $(PER_BIN_V1_FLAGS) $(PER_BIN_ASN1_V1_SPEC).set.asn
$(EBIN)/$(PER_BIN_ASN1_V1_SPEC).$(EMULATOR): \
- $(PER_BIN_ASN1_V1_SPEC).erl \
- $(PER_BIN_ASN1_V1_SPEC).hrl
+ $(PER_BIN_ASN1_V1_SPEC).erl
-$(PER_BIN_DRV_ASN1_V1_SPEC).erl $(PER_BIN_DRV_ASN1_V1_SPEC).hrl: \
+$(PER_BIN_DRV_ASN1_V1_SPEC).erl: \
$(PER_BIN_DRV_ASN1_V1_SPEC).set.asn \
$(ASN1_V1_SPEC).asn
@echo "$(PER_BIN_DRV_ASN1_V1_SPEC):"
$(ERLC) -bper_bin $(PER_BIN_DRV_V1_FLAGS) $(PER_BIN_DRV_ASN1_V1_SPEC).set.asn
$(EBIN)/$(PER_BIN_DRV_ASN1_V1_SPEC).$(EMULATOR): \
- $(PER_BIN_DRV_ASN1_V1_SPEC).erl \
- $(PER_BIN_DRV_ASN1_V1_SPEC).hrl
+ $(PER_BIN_DRV_ASN1_V1_SPEC).erl
# --- Version 2 ---
-$(BER_ASN1_V2_SPEC).erl $(BER_ASN1_V2_SPEC).hrl: \
+$(BER_ASN1_V2_SPEC).erl: \
$(BER_ASN1_V2_SPEC).set.asn \
$(ASN1_V2_SPEC).asn
@echo "$(BER_ASN1_V2_SPEC):"
$(ERLC) -bber $(BER_V2_FLAGS) $(BER_ASN1_V2_SPEC).set.asn
$(EBIN)/$(BER_ASN1_V2_SPEC).$(EMULATOR): \
- $(BER_ASN1_V2_SPEC).erl \
- $(BER_ASN1_V2_SPEC).hrl
+ $(BER_ASN1_V2_SPEC).erl
-$(BER_BIN_ASN1_V2_SPEC).erl $(BER_BIN_ASN1_V2_SPEC).hrl: \
+$(BER_BIN_ASN1_V2_SPEC).erl: \
$(BER_BIN_ASN1_V2_SPEC).set.asn \
$(BER_BIN_ASN1_V2_SPEC).asn1config \
$(ASN1_V2_SPEC).asn
@@ -166,10 +159,9 @@ $(BER_BIN_ASN1_V2_SPEC).erl $(BER_BIN_ASN1_V2_SPEC).hrl: \
$(ERLC) -bber_bin $(BER_BIN_V2_FLAGS) $(BER_BIN_ASN1_V2_SPEC).set.asn
$(EBIN)/$(BER_BIN_ASN1_V2_SPEC).$(EMULATOR): \
- $(BER_BIN_ASN1_V2_SPEC).erl \
- $(BER_BIN_ASN1_V2_SPEC).hrl
+ $(BER_BIN_ASN1_V2_SPEC).erl
-$(BER_BIN_DRV_ASN1_V2_SPEC).erl $(BER_BIN_DRV_ASN1_V2_SPEC).hrl: \
+$(BER_BIN_DRV_ASN1_V2_SPEC).erl: \
$(BER_BIN_DRV_ASN1_V2_SPEC).set.asn \
$(BER_BIN_DRV_ASN1_V2_SPEC).asn1config \
$(ASN1_V2_SPEC).asn
@@ -177,55 +169,50 @@ $(BER_BIN_DRV_ASN1_V2_SPEC).erl $(BER_BIN_DRV_ASN1_V2_SPEC).hrl: \
$(ERLC) -bber_bin $(BER_BIN_DRV_V2_FLAGS) $(BER_BIN_DRV_ASN1_V2_SPEC).set.asn
$(EBIN)/$(BER_BIN_DRV_ASN1_V2_SPEC).$(EMULATOR): \
- $(BER_BIN_DRV_ASN1_V2_SPEC).erl \
- $(BER_BIN_DRV_ASN1_V2_SPEC).hrl
+ $(BER_BIN_DRV_ASN1_V2_SPEC).erl
-$(PER_ASN1_V2_SPEC).erl $(PER_ASN1_V2_SPEC).hrl: \
+$(PER_ASN1_V2_SPEC).erl: \
$(PER_ASN1_V2_SPEC).set.asn \
$(ASN1_V2_SPEC).asn
@echo "$(PER_ASN1_V2_SPEC):"
$(ERLC) -bper $(PER_V2_FLAGS) $(PER_ASN1_V2_SPEC).set.asn
$(EBIN)/$(PER_ASN1_V2_SPEC).$(EMULATOR): \
- $(PER_ASN1_V2_SPEC).erl \
- $(PER_ASN1_V2_SPEC).hrl
+ $(PER_ASN1_V2_SPEC).erl
-$(PER_BIN_ASN1_V2_SPEC).erl $(PER_BIN_ASN1_V2_SPEC).hrl: \
+$(PER_BIN_ASN1_V2_SPEC).erl: \
$(PER_BIN_ASN1_V2_SPEC).set.asn \
$(ASN1_V2_SPEC).asn
@echo "$(PER_BIN_ASN1_V2_SPEC):"
$(ERLC) -bper_bin $(PER_BIN_V2_FLAGS) $(PER_BIN_ASN1_V2_SPEC).set.asn
$(EBIN)/$(PER_BIN_ASN1_V2_SPEC).$(EMULATOR): \
- $(PER_BIN_ASN1_V2_SPEC).erl \
- $(PER_BIN_ASN1_V2_SPEC).hrl
+ $(PER_BIN_ASN1_V2_SPEC).erl
-$(PER_BIN_DRV_ASN1_V2_SPEC).erl $(PER_BIN_DRV_ASN1_V2_SPEC).hrl: \
+$(PER_BIN_DRV_ASN1_V2_SPEC).erl: \
$(PER_BIN_DRV_ASN1_V2_SPEC).set.asn \
$(ASN1_V2_SPEC).asn
@echo "$(PER_BIN_DRV_ASN1_V2_SPEC):"
$(ERLC) -bper_bin $(PER_BIN_DRV_V2_FLAGS) $(PER_BIN_DRV_ASN1_V2_SPEC).set.asn
$(EBIN)/$(PER_BIN_DRV_ASN1_V2_SPEC).$(EMULATOR): \
- $(PER_BIN_DRV_ASN1_V2_SPEC).erl \
- $(PER_BIN_DRV_ASN1_V2_SPEC).hrl
+ $(PER_BIN_DRV_ASN1_V2_SPEC).erl
# --- Version 3 ---
# -- (prev3a) --
-$(BER_ASN1_PREV3A_SPEC).erl $(BER_ASN1_PREV3A_SPEC).hrl: \
+$(BER_ASN1_PREV3A_SPEC).erl: \
$(BER_ASN1_PREV3A_SPEC).set.asn \
$(ASN1_PREV3A_SPEC).asn
@echo "$(BER_ASN1_PREV3A_SPEC):"
$(ERLC) -bber $(BER_PREV3A_FLAGS) $(BER_ASN1_PREV3A_SPEC).set.asn
$(EBIN)/$(BER_ASN1_PREV3A_SPEC).$(EMULATOR): \
- $(BER_ASN1_PREV3A_SPEC).erl \
- $(BER_ASN1_PREV3A_SPEC).hrl
+ $(BER_ASN1_PREV3A_SPEC).erl
-$(BER_BIN_ASN1_PREV3A_SPEC).erl $(BER_BIN_ASN1_PREV3A_SPEC).hrl: \
+$(BER_BIN_ASN1_PREV3A_SPEC).erl: \
$(BER_BIN_ASN1_PREV3A_SPEC).set.asn \
$(BER_BIN_ASN1_PREV3A_SPEC).asn1config \
$(ASN1_PREV3A_SPEC).asn
@@ -233,10 +220,9 @@ $(BER_BIN_ASN1_PREV3A_SPEC).erl $(BER_BIN_ASN1_PREV3A_SPEC).hrl: \
$(ERLC) -bber_bin $(BER_BIN_PREV3A_FLAGS) $(BER_BIN_ASN1_PREV3A_SPEC).set.asn
$(EBIN)/$(BER_BIN_ASN1_PREV3A_SPEC).$(EMULATOR): \
- $(BER_BIN_ASN1_PREV3A_SPEC).erl \
- $(BER_BIN_ASN1_PREV3A_SPEC).hrl
+ $(BER_BIN_ASN1_PREV3A_SPEC).erl
-$(BER_BIN_DRV_ASN1_PREV3A_SPEC).erl $(BER_BIN_DRV_ASN1_PREV3A_SPEC).hrl: \
+$(BER_BIN_DRV_ASN1_PREV3A_SPEC).erl: \
$(BER_BIN_DRV_ASN1_PREV3A_SPEC).set.asn \
$(BER_BIN_DRV_ASN1_PREV3A_SPEC).asn1config \
$(ASN1_PREV3A_SPEC).asn
@@ -244,52 +230,47 @@ $(BER_BIN_DRV_ASN1_PREV3A_SPEC).erl $(BER_BIN_DRV_ASN1_PREV3A_SPEC).hrl: \
$(ERLC) -bber_bin $(BER_BIN_DRV_PREV3A_FLAGS) $(BER_BIN_DRV_ASN1_PREV3A_SPEC).set.asn
$(EBIN)/$(BER_BIN_DRV_ASN1_PREV3A_SPEC).$(EMULATOR): \
- $(BER_BIN_DRV_ASN1_PREV3A_SPEC).erl \
- $(BER_BIN_DRV_ASN1_PREV3A_SPEC).hrl
+ $(BER_BIN_DRV_ASN1_PREV3A_SPEC).erl
-$(PER_ASN1_PREV3A_SPEC).erl $(PER_ASN1_PREV3A_SPEC).hrl: \
+$(PER_ASN1_PREV3A_SPEC).erl: \
$(PER_ASN1_PREV3A_SPEC).set.asn \
$(ASN1_PREV3A_SPEC).asn
@echo "$(PER_ASN1_PREV3A_SPEC):"
$(ERLC) -bper $(PER_PREV3A_FLAGS) $(PER_ASN1_PREV3A_SPEC).set.asn
$(EBIN)/$(PER_ASN1_PREV3A_SPEC).$(EMULATOR): \
- $(PER_ASN1_PREV3A_SPEC).erl \
- $(PER_ASN1_PREV3A_SPEC).hrl
+ $(PER_ASN1_PREV3A_SPEC).erl
-$(PER_BIN_ASN1_PREV3A_SPEC).erl $(PER_BIN_ASN1_PREV3A_SPEC).hrl: \
+$(PER_BIN_ASN1_PREV3A_SPEC).erl: \
$(PER_BIN_ASN1_PREV3A_SPEC).set.asn \
$(ASN1_PREV3A_SPEC).asn
@echo "$(PER_BIN_ASN1_PREV3A_SPEC):"
$(ERLC) -bper_bin $(PER_BIN_PREV3A_FLAGS) $(PER_BIN_ASN1_PREV3A_SPEC).set.asn
$(EBIN)/$(PER_BIN_ASN1_PREV3A_SPEC).$(EMULATOR): \
- $(PER_BIN_ASN1_PREV3A_SPEC).erl \
- $(PER_BIN_ASN1_PREV3A_SPEC).hrl
+ $(PER_BIN_ASN1_PREV3A_SPEC).erl
-$(PER_BIN_DRV_ASN1_PREV3A_SPEC).erl $(PER_BIN_DRV_ASN1_PREV3A_SPEC).hrl: \
+$(PER_BIN_DRV_ASN1_PREV3A_SPEC).erl: \
$(PER_BIN_DRV_ASN1_PREV3A_SPEC).set.asn \
$(ASN1_PREV3A_SPEC).asn
@echo "$(PER_BIN_DRV_ASN1_PREV3A_SPEC):"
$(ERLC) -bper_bin $(PER_BIN_DRV_PREV3A_FLAGS) $(PER_BIN_DRV_ASN1_PREV3A_SPEC).set.asn
$(EBIN)/$(PER_BIN_DRV_ASN1_PREV3A_SPEC).$(EMULATOR): \
- $(PER_BIN_DRV_ASN1_PREV3A_SPEC).erl \
- $(PER_BIN_DRV_ASN1_PREV3A_SPEC).hrl
+ $(PER_BIN_DRV_ASN1_PREV3A_SPEC).erl
# -- (prev3b) --
-$(BER_ASN1_PREV3B_SPEC).erl $(BER_ASN1_PREV3B_SPEC).hrl: \
+$(BER_ASN1_PREV3B_SPEC).erl: \
$(BER_ASN1_PREV3B_SPEC).set.asn \
$(ASN1_PREV3B_SPEC).asn
@echo "$(BER_ASN1_PREV3B_SPEC):"
$(ERLC) -bber $(BER_PREV3B_FLAGS) $(BER_ASN1_PREV3B_SPEC).set.asn
$(EBIN)/$(BER_ASN1_PREV3B_SPEC).$(EMULATOR): \
- $(BER_ASN1_PREV3B_SPEC).erl \
- $(BER_ASN1_PREV3B_SPEC).hrl
+ $(BER_ASN1_PREV3B_SPEC).erl
-$(BER_BIN_ASN1_PREV3B_SPEC).erl $(BER_BIN_ASN1_PREV3B_SPEC).hrl: \
+$(BER_BIN_ASN1_PREV3B_SPEC).erl: \
$(BER_BIN_ASN1_PREV3B_SPEC).set.asn \
$(BER_BIN_ASN1_PREV3B_SPEC).asn1config \
$(ASN1_PREV3B_SPEC).asn
@@ -297,10 +278,9 @@ $(BER_BIN_ASN1_PREV3B_SPEC).erl $(BER_BIN_ASN1_PREV3B_SPEC).hrl: \
$(ERLC) -bber_bin $(BER_BIN_PREV3B_FLAGS) $(BER_BIN_ASN1_PREV3B_SPEC).set.asn
$(EBIN)/$(BER_BIN_ASN1_PREV3B_SPEC).$(EMULATOR): \
- $(BER_BIN_ASN1_PREV3B_SPEC).erl \
- $(BER_BIN_ASN1_PREV3B_SPEC).hrl
+ $(BER_BIN_ASN1_PREV3B_SPEC).erl
-$(BER_BIN_DRV_ASN1_PREV3B_SPEC).erl $(BER_BIN_DRV_ASN1_PREV3B_SPEC).hrl: \
+$(BER_BIN_DRV_ASN1_PREV3B_SPEC).erl: \
$(BER_BIN_DRV_ASN1_PREV3B_SPEC).set.asn \
$(BER_BIN_DRV_ASN1_PREV3B_SPEC).asn1config \
$(ASN1_PREV3B_SPEC).asn
@@ -308,53 +288,48 @@ $(BER_BIN_DRV_ASN1_PREV3B_SPEC).erl $(BER_BIN_DRV_ASN1_PREV3B_SPEC).hrl: \
$(ERLC) -bber_bin $(BER_BIN_DRV_PREV3B_FLAGS) $(BER_BIN_DRV_ASN1_PREV3B_SPEC).set.asn
$(EBIN)/$(BER_BIN_DRV_ASN1_PREV3B_SPEC).$(EMULATOR): \
- $(BER_BIN_DRV_ASN1_PREV3B_SPEC).erl \
- $(BER_BIN_DRV_ASN1_PREV3B_SPEC).hrl
+ $(BER_BIN_DRV_ASN1_PREV3B_SPEC).erl
-$(PER_ASN1_PREV3B_SPEC).erl $(PER_ASN1_PREV3B_SPEC).hrl: \
+$(PER_ASN1_PREV3B_SPEC).erl: \
$(PER_ASN1_PREV3B_SPEC).set.asn \
$(ASN1_PREV3B_SPEC).asn
@echo "$(PER_ASN1_PREV3B_SPEC):"
$(ERLC) -bper $(PER_PREV3B_FLAGS) $(PER_ASN1_PREV3B_SPEC).set.asn
$(EBIN)/$(PER_ASN1_PREV3B_SPEC).$(EMULATOR): \
- $(PER_ASN1_PREV3B_SPEC).erl \
- $(PER_ASN1_PREV3B_SPEC).hrl
+ $(PER_ASN1_PREV3B_SPEC).erl
-$(PER_BIN_ASN1_PREV3B_SPEC).erl $(PER_BIN_ASN1_PREV3B_SPEC).hrl: \
+$(PER_BIN_ASN1_PREV3B_SPEC).erl: \
$(PER_BIN_ASN1_PREV3B_SPEC).set.asn \
$(ASN1_PREV3B_SPEC).asn
@echo "$(PER_BIN_ASN1_PREV3B_SPEC):"
$(ERLC) -bper_bin $(PER_BIN_PREV3B_FLAGS) $(PER_BIN_ASN1_PREV3B_SPEC).set.asn
$(EBIN)/$(PER_BIN_ASN1_PREV3B_SPEC).$(EMULATOR): \
- $(PER_BIN_ASN1_PREV3B_SPEC).erl \
- $(PER_BIN_ASN1_PREV3B_SPEC).hrl
+ $(PER_BIN_ASN1_PREV3B_SPEC).erl
-$(PER_BIN_DRV_ASN1_PREV3B_SPEC).erl $(PER_BIN_DRV_ASN1_PREV3B_SPEC).hrl: \
+$(PER_BIN_DRV_ASN1_PREV3B_SPEC).erl: \
$(PER_BIN_DRV_ASN1_PREV3B_SPEC).set.asn \
$(ASN1_PREV3B_SPEC).asn
@echo "$(PER_BIN_DRV_ASN1_PREV3B_SPEC):"
$(ERLC) -bper_bin $(PER_BIN_DRV_PREV3B_FLAGS) $(PER_BIN_DRV_ASN1_PREV3B_SPEC).set.asn
$(EBIN)/$(PER_BIN_DRV_ASN1_PREV3B_SPEC).$(EMULATOR): \
- $(PER_BIN_DRV_ASN1_PREV3B_SPEC).erl \
- $(PER_BIN_DRV_ASN1_PREV3B_SPEC).hrl
+ $(PER_BIN_DRV_ASN1_PREV3B_SPEC).erl
# -- (prev3c) --
-$(BER_ASN1_PREV3C_SPEC).erl $(BER_ASN1_PREV3C_SPEC).hrl: \
+$(BER_ASN1_PREV3C_SPEC).erl: \
$(BER_ASN1_PREV3C_SPEC).set.asn \
$(ASN1_PREV3C_SPEC).asn
@echo "$(BER_ASN1_PREV3C_SPEC):"
$(ERLC) -bber $(BER_PREV3C_FLAGS) $(BER_ASN1_PREV3C_SPEC).set.asn
$(EBIN)/$(BER_ASN1_PREV3C_SPEC).$(EMULATOR): \
- $(BER_ASN1_PREV3C_SPEC).erl \
- $(BER_ASN1_PREV3C_SPEC).hrl
+ $(BER_ASN1_PREV3C_SPEC).erl
-$(BER_BIN_ASN1_PREV3C_SPEC).erl $(BER_BIN_ASN1_PREV3C_SPEC).hrl: \
+$(BER_BIN_ASN1_PREV3C_SPEC).erl: \
$(BER_BIN_ASN1_PREV3C_SPEC).set.asn \
$(BER_BIN_ASN1_PREV3C_SPEC).asn1config \
$(ASN1_PREV3C_SPEC).asn
@@ -362,10 +337,9 @@ $(BER_BIN_ASN1_PREV3C_SPEC).erl $(BER_BIN_ASN1_PREV3C_SPEC).hrl: \
$(ERLC) -bber_bin $(BER_BIN_PREV3C_FLAGS) $(BER_BIN_ASN1_PREV3C_SPEC).set.asn
$(EBIN)/$(BER_BIN_ASN1_PREV3C_SPEC).$(EMULATOR): \
- $(BER_BIN_ASN1_PREV3C_SPEC).erl \
- $(BER_BIN_ASN1_PREV3C_SPEC).hrl
+ $(BER_BIN_ASN1_PREV3C_SPEC).erl
-$(BER_BIN_DRV_ASN1_PREV3C_SPEC).erl $(BER_BIN_DRV_ASN1_PREV3C_SPEC).hrl: \
+$(BER_BIN_DRV_ASN1_PREV3C_SPEC).erl: \
$(BER_BIN_DRV_ASN1_PREV3C_SPEC).set.asn \
$(BER_BIN_DRV_ASN1_PREV3C_SPEC).asn1config \
$(ASN1_PREV3C_SPEC).asn
@@ -373,53 +347,48 @@ $(BER_BIN_DRV_ASN1_PREV3C_SPEC).erl $(BER_BIN_DRV_ASN1_PREV3C_SPEC).hrl: \
$(ERLC) -bber_bin $(BER_BIN_DRV_PREV3C_FLAGS) $(BER_BIN_DRV_ASN1_PREV3C_SPEC).set.asn
$(EBIN)/$(BER_BIN_DRV_ASN1_PREV3C_SPEC).$(EMULATOR): \
- $(BER_BIN_DRV_ASN1_PREV3C_SPEC).erl \
- $(BER_BIN_DRV_ASN1_PREV3C_SPEC).hrl
+ $(BER_BIN_DRV_ASN1_PREV3C_SPEC).erl
-$(PER_ASN1_PREV3C_SPEC).erl $(PER_ASN1_PREV3C_SPEC).hrl: \
+$(PER_ASN1_PREV3C_SPEC).erl: \
$(PER_ASN1_PREV3C_SPEC).set.asn \
$(ASN1_PREV3C_SPEC).asn
@echo "$(PER_ASN1_PREV3C_SPEC):"
$(ERLC) -bper $(PER_PREV3C_FLAGS) $(PER_ASN1_PREV3C_SPEC).set.asn
$(EBIN)/$(PER_ASN1_PREV3C_SPEC).$(EMULATOR): \
- $(PER_ASN1_PREV3C_SPEC).erl \
- $(PER_ASN1_PREV3C_SPEC).hrl
+ $(PER_ASN1_PREV3C_SPEC).erl
-$(PER_BIN_ASN1_PREV3C_SPEC).erl $(PER_BIN_ASN1_PREV3C_SPEC).hrl: \
+$(PER_BIN_ASN1_PREV3C_SPEC).erl: \
$(PER_BIN_ASN1_PREV3C_SPEC).set.asn \
$(ASN1_PREV3C_SPEC).asn
@echo "$(PER_BIN_ASN1_PREV3C_SPEC):"
$(ERLC) -bper_bin $(PER_BIN_PREV3C_FLAGS) $(PER_BIN_ASN1_PREV3C_SPEC).set.asn
$(EBIN)/$(PER_BIN_ASN1_PREV3C_SPEC).$(EMULATOR): \
- $(PER_BIN_ASN1_PREV3C_SPEC).erl \
- $(PER_BIN_ASN1_PREV3C_SPEC).hrl
+ $(PER_BIN_ASN1_PREV3C_SPEC).erl
-$(PER_BIN_DRV_ASN1_PREV3C_SPEC).erl $(PER_BIN_DRV_ASN1_PREV3C_SPEC).hrl: \
+$(PER_BIN_DRV_ASN1_PREV3C_SPEC).erl: \
$(PER_BIN_DRV_ASN1_PREV3C_SPEC).set.asn \
$(ASN1_PREV3C_SPEC).asn
@echo "$(PER_BIN_DRV_ASN1_PREV3C_SPEC):"
$(ERLC) -bper_bin $(PER_BIN_DRV_PREV3C_FLAGS) $(PER_BIN_DRV_ASN1_PREV3C_SPEC).set.asn
$(EBIN)/$(PER_BIN_DRV_ASN1_PREV3C_SPEC).$(EMULATOR): \
- $(PER_BIN_DRV_ASN1_PREV3C_SPEC).erl \
- $(PER_BIN_DRV_ASN1_PREV3C_SPEC).hrl
+ $(PER_BIN_DRV_ASN1_PREV3C_SPEC).erl
# -- (v3) --
-$(BER_ASN1_V3_SPEC).erl $(BER_ASN1_V3_SPEC).hrl: \
+$(BER_ASN1_V3_SPEC).erl: \
$(BER_ASN1_V3_SPEC).set.asn \
$(ASN1_V3_SPEC).asn
@echo "$(BER_ASN1_V3_SPEC):"
$(ERLC) -bber $(BER_V3_FLAGS) $(BER_ASN1_V3_SPEC).set.asn
$(EBIN)/$(BER_ASN1_V3_SPEC).$(EMULATOR): \
- $(BER_ASN1_V3_SPEC).erl \
- $(BER_ASN1_V3_SPEC).hrl
+ $(BER_ASN1_V3_SPEC).erl
-$(BER_BIN_ASN1_V3_SPEC).erl $(BER_BIN_ASN1_V3_SPEC).hrl: \
+$(BER_BIN_ASN1_V3_SPEC).erl: \
$(BER_BIN_ASN1_V3_SPEC).set.asn \
$(BER_BIN_ASN1_V3_SPEC).asn1config \
$(ASN1_V3_SPEC).asn
@@ -427,10 +396,9 @@ $(BER_BIN_ASN1_V3_SPEC).erl $(BER_BIN_ASN1_V3_SPEC).hrl: \
$(ERLC) -bber_bin $(BER_BIN_V3_FLAGS) $(BER_BIN_ASN1_V3_SPEC).set.asn
$(EBIN)/$(BER_BIN_ASN1_V3_SPEC).$(EMULATOR): \
- $(BER_BIN_ASN1_V3_SPEC).erl \
- $(BER_BIN_ASN1_V3_SPEC).hrl
+ $(BER_BIN_ASN1_V3_SPEC).erl
-$(BER_BIN_DRV_ASN1_V3_SPEC).erl $(BER_BIN_DRV_ASN1_V3_SPEC).hrl: \
+$(BER_BIN_DRV_ASN1_V3_SPEC).erl: \
$(BER_BIN_DRV_ASN1_V3_SPEC).set.asn \
$(BER_BIN_DRV_ASN1_V3_SPEC).asn1config \
$(ASN1_V3_SPEC).asn
@@ -438,38 +406,34 @@ $(BER_BIN_DRV_ASN1_V3_SPEC).erl $(BER_BIN_DRV_ASN1_V3_SPEC).hrl: \
$(ERLC) -bber_bin $(BER_BIN_DRV_V3_FLAGS) $(BER_BIN_DRV_ASN1_V3_SPEC).set.asn
$(EBIN)/$(BER_BIN_DRV_ASN1_V3_SPEC).$(EMULATOR): \
- $(BER_BIN_DRV_ASN1_V3_SPEC).erl \
- $(BER_BIN_DRV_ASN1_V3_SPEC).hrl
+ $(BER_BIN_DRV_ASN1_V3_SPEC).erl
-$(PER_ASN1_V3_SPEC).erl $(PER_ASN1_V3_SPEC).hrl: \
+$(PER_ASN1_V3_SPEC).erl: \
$(PER_ASN1_V3_SPEC).set.asn \
$(ASN1_V3_SPEC).asn
@echo "$(PER_ASN1_V3_SPEC):"
$(ERLC) -bper $(PER_V3_FLAGS) $(PER_ASN1_V3_SPEC).set.asn
$(EBIN)/$(PER_ASN1_V3_SPEC).$(EMULATOR): \
- $(PER_ASN1_V3_SPEC).erl \
- $(PER_ASN1_V3_SPEC).hrl
+ $(PER_ASN1_V3_SPEC).erl
-$(PER_BIN_ASN1_V3_SPEC).erl $(PER_BIN_ASN1_V3_SPEC).hrl: \
+$(PER_BIN_ASN1_V3_SPEC).erl: \
$(PER_BIN_ASN1_V3_SPEC).set.asn \
$(ASN1_V3_SPEC).asn
@echo "$(PER_BIN_ASN1_V3_SPEC):"
$(ERLC) -bper_bin $(PER_BIN_V3_FLAGS) $(PER_BIN_ASN1_V3_SPEC).set.asn
$(EBIN)/$(PER_BIN_ASN1_V3_SPEC).$(EMULATOR): \
- $(PER_BIN_ASN1_V3_SPEC).erl \
- $(PER_BIN_ASN1_V3_SPEC).hrl
+ $(PER_BIN_ASN1_V3_SPEC).erl
-$(PER_BIN_DRV_ASN1_V3_SPEC).erl $(PER_BIN_DRV_ASN1_V3_SPEC).hrl: \
+$(PER_BIN_DRV_ASN1_V3_SPEC).erl: \
$(PER_BIN_DRV_ASN1_V3_SPEC).set.asn \
$(ASN1_V3_SPEC).asn
@echo "$(PER_BIN_DRV_ASN1_V3_SPEC):"
$(ERLC) -bper_bin $(PER_BIN_DRV_V3_FLAGS) $(PER_BIN_DRV_ASN1_V3_SPEC).set.asn
$(EBIN)/$(PER_BIN_DRV_ASN1_V3_SPEC).$(EMULATOR): \
- $(PER_BIN_DRV_ASN1_V3_SPEC).erl \
- $(PER_BIN_DRV_ASN1_V3_SPEC).hrl
+ $(PER_BIN_DRV_ASN1_V3_SPEC).erl
# -------------
diff --git a/lib/megaco/src/flex/Makefile.in b/lib/megaco/src/flex/Makefile.in
index 5af651d89b..2c46a673e4 100644
--- a/lib/megaco/src/flex/Makefile.in
+++ b/lib/megaco/src/flex/Makefile.in
@@ -391,7 +391,9 @@ $(STD_DRV).c: $(STD_DRV).flex
$(MT_DRV).c: $(MT_DRV).flex
$(LEX) $(MT_LEX_FLAGS) -P$* -o$@ $<
-solibs: $(LIBDIR) $(OBJDIR) $(SOLIBS)
+_create_dirs := $(shell mkdir -p $(OBJDIR) $(LIBDIR))
+
+solibs: $(SOLIBS)
$(OBJDIR)/$(STD_DRV).o: $(STD_DRV).c
@echo "compiling std driver:"
@@ -411,10 +413,3 @@ $(LIBDIR)/$(STD_DRV).$(DED_EXT): $(OBJDIR)/$(STD_DRV).o
$(LIBDIR)/$(MT_DRV).$(DED_EXT): $(OBJDIR)/$(MT_DRV).o
@echo "linking multi-threaded driver:"
$(LD) $(LDFLAGS) -o $@ $<
-
-$(LIBDIR):
- -mkdir -p $(LIBDIR)
-
-$(OBJDIR):
- -mkdir -p $(OBJDIR)
-
diff --git a/lib/megaco/test/megaco_codec_v1_test.erl b/lib/megaco/test/megaco_codec_v1_test.erl
index 3a548c4d9e..e9c19605dd 100644
--- a/lib/megaco/test/megaco_codec_v1_test.erl
+++ b/lib/megaco/test/megaco_codec_v1_test.erl
@@ -371,9 +371,9 @@ profile_decode_text_messages(Slogan, Codec, Config, Msgs0) ->
decode_text_messages(Codec, Config, Bins, [])
end,
%% Make a dry run, just to make sure all modules are loaded:
- io:format("make a dry run..~n", []),
+ io:format("make a dry run...~n", []),
(catch Fun()),
- io:format("make the run..~n", []),
+ io:format("make the run...~n", []),
megaco_profile:profile(Slogan, Fun).
%% (catch megaco_codec_v1_test:profile_encode_compact_text_messages()).
diff --git a/lib/megaco/test/megaco_codec_v2_test.erl b/lib/megaco/test/megaco_codec_v2_test.erl
index c3a80febba..1d3fcb36e9 100644
--- a/lib/megaco/test/megaco_codec_v2_test.erl
+++ b/lib/megaco/test/megaco_codec_v2_test.erl
@@ -346,9 +346,9 @@ profile_decode_text_messages(Slogan, Codec, Config, Msgs0) ->
decode_text_messages(Codec, Config, Bins, [])
end,
%% Make a dry run, just to make sure all modules are loaded:
- io:format("make a dry run..~n", []),
+ io:format("make a dry run...~n", []),
(catch Fun()),
- io:format("make the run..~n", []),
+ io:format("make the run...~n", []),
megaco_profile:profile(Slogan, Fun).
%% (catch megaco_codec_v2_test:profile_encode_compact_text_messages()).
diff --git a/lib/megaco/test/megaco_mess_test.erl b/lib/megaco/test/megaco_mess_test.erl
index ded1506271..383e3df774 100644
--- a/lib/megaco/test/megaco_mess_test.erl
+++ b/lib/megaco/test/megaco_mess_test.erl
@@ -34,12 +34,12 @@
%% -compile(export_all).
-export([
- all/0,groups/0,init_per_group/2,end_per_group/2,
- init_per_testcase/2,
- end_per_testcase/2,
+ all/0, groups/0,
+ init_per_suite/1, end_per_suite/1,
+ init_per_group/2, end_per_group/2,
+ init_per_testcase/2, end_per_testcase/2,
connect/1,
-
request_and_reply_plain/1,
request_and_no_reply/1,
@@ -347,39 +347,83 @@ end_per_testcase(Case, Config) ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
all() ->
- [connect, {group, request_and_reply},
- {group, pending_ack}, dist, {group, tickets}].
+ [
+ connect,
+ {group, request_and_reply},
+ {group, pending_ack},
+ dist,
+ {group, tickets}
+ ].
groups() ->
- [{request_and_reply, [],
- [request_and_reply_plain, request_and_no_reply,
+ [
+ {request_and_reply, [],
+ [request_and_reply_plain,
+ request_and_no_reply,
request_and_reply_pending_ack_no_pending,
request_and_reply_pending_ack_one_pending,
single_trans_req_and_reply,
single_trans_req_and_reply_sendopts,
- request_and_reply_and_ack, request_and_reply_and_no_ack,
+ request_and_reply_and_ack,
+ request_and_reply_and_no_ack,
request_and_reply_and_late_ack,
trans_req_and_reply_and_req]},
{pending_ack, [],
[pending_ack_plain,
request_and_pending_and_late_reply]},
{tickets, [],
- [otp_4359, otp_4836, otp_5805, otp_5881, otp_5887,
- otp_6253, otp_6275, otp_6276, {group, otp_6442},
- {group, otp_6865}, otp_7189, otp_7259, otp_7713,
- {group, otp_8183}, otp_8212]},
+ [otp_4359,
+ otp_4836,
+ otp_5805,
+ otp_5881,
+ otp_5887,
+ otp_6253,
+ otp_6275,
+ otp_6276,
+ {group, otp_6442},
+ {group, otp_6865},
+ otp_7189,
+ otp_7259,
+ otp_7713,
+ {group, otp_8183},
+ otp_8212]},
{otp_6442, [],
- [otp_6442_resend_request1, otp_6442_resend_request2,
- otp_6442_resend_reply1, otp_6442_resend_reply2]},
+ [otp_6442_resend_request1,
+ otp_6442_resend_request2,
+ otp_6442_resend_reply1,
+ otp_6442_resend_reply2]},
{otp_6865, [],
[otp_6865_request_and_reply_plain_extra1,
otp_6865_request_and_reply_plain_extra2]},
- {otp_8183, [], [otp_8183_request1]}].
+ {otp_8183, [], [otp_8183_request1]}
+ ].
+
+
+init_per_suite(Config) ->
+ io:format("~w:init_per_suite -> entry with"
+ "~n Config: ~p"
+ "~n", [?MODULE, Config]),
+ Config.
+
+end_per_suite(_Config) ->
+ io:format("~w:end_per_suite -> entry with"
+ "~n _Config: ~p"
+ "~n", [?MODULE, _Config]),
+ ok.
+
init_per_group(_GroupName, Config) ->
+ io:format("~w:init_per_group -> entry with"
+ "~n _GroupName: ~p"
+ "~n Config: ~p"
+ "~n", [?MODULE, _GroupName, Config]),
Config.
end_per_group(_GroupName, Config) ->
+ io:format("~w:end_per_group -> entry with"
+ "~n _GroupName: ~p"
+ "~n Config: ~p"
+ "~n", [?MODULE, _GroupName, Config]),
Config.
@@ -394,12 +438,16 @@ connect(Config) when is_list(Config) ->
PrelMid = preliminary_mid,
MgMid = ipv4_mid(4711),
+ d("connect -> start megaco app",[]),
?VERIFY(ok, application:start(megaco)),
+ d("connect -> start (MG) user ~p",[MgMid]),
?VERIFY(ok, megaco:start_user(MgMid, [{send_mod, bad_send_mod},
{request_timer, infinity},
{reply_timer, infinity}])),
+ d("connect -> get receive info for ~p",[MgMid]),
MgRH = user_info(MgMid, receive_handle),
+ d("connect -> (MG) try connect to MGC",[]),
{ok, PrelCH} = ?VERIFY({ok, _}, megaco:connect(MgRH, PrelMid, sh, self())),
connections([PrelCH]),
@@ -6776,16 +6824,12 @@ rapalr_mg_notify_request_ar(Rid, Tid, Cid) ->
-
-
-
-
-
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
dist(suite) ->
[];
dist(Config) when is_list(Config) ->
+ ?SKIP("Needs a re-write..."),
[_Local, Dist] = ?ACQUIRE_NODES(2, Config),
d("dist -> start proxy",[]),
megaco_mess_user_test:start_proxy(),
@@ -6897,7 +6941,11 @@ dist(Config) when is_list(Config) ->
?VERIFY(ok, application:stop(megaco)),
?RECEIVE([]),
- d("dist -> done",[]),
+
+ d("dist -> stop proxy",[]),
+ megaco_mess_user_test:stop_proxy(),
+
+ d("dist -> done", []),
ok.
diff --git a/lib/megaco/test/megaco_profile.erl b/lib/megaco/test/megaco_profile.erl
index d0b62610e1..344c551970 100644
--- a/lib/megaco/test/megaco_profile.erl
+++ b/lib/megaco/test/megaco_profile.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2010. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2009. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -24,50 +24,102 @@
-module(megaco_profile).
--export([profile/2]).
-
+-export([profile/2, prepare/2, analyse/1,
+ fprof_to_calltree/1, fprof_to_calltree/2, fprof_to_calltree/3]).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Execute Fun and profile it with fprof.
-profile(Slogan, Fun) when is_function(Fun) ->
+profile(Slogan, Fun) when is_function(Fun, 0) ->
Pids = [self()],
- profile(Slogan, Fun, Pids).
+ {ok, TraceFile} = prepare(Slogan, Pids),
+ Res = (catch Fun()),
+ {ok, _DestFile} = analyse(Slogan),
+ ok = file:delete(TraceFile),
+ {ok, _TreeFile} = fprof_to_calltree(Slogan),
+ Res.
-profile(Slogan, Fun, Pids) ->
+%% Prepare for tracing
+prepare(Slogan, Pids) ->
TraceFile = lists:concat(["profile_", Slogan, "-fprof.trace"]),
- DestFile = lists:concat(["profile_", Slogan, ".fprof"]),
- TreeFile = lists:concat(["profile_", Slogan, ".calltree"]),
- erlang:garbage_collect(),
{ok, _Pid} = fprof:start(),
+ erlang:garbage_collect(),
TraceOpts = [start,
- {cpu_time, false},
- {procs, Pids},
- {file, TraceFile}
+ {cpu_time, false},
+ {procs, Pids},
+ {file, TraceFile}
],
- ok = fprof:trace(TraceOpts),
- Res = (catch Fun()),
- ok = fprof:trace(stop),
- ok = fprof:profile([{file, TraceFile}]),
- ok = fprof:analyse([{dest, DestFile}]),
- ok = fprof:stop(),
- ok = file:delete(TraceFile),
- reformat_total(DestFile, TreeFile),
- Res.
+ ok = fprof:trace(TraceOpts),
+ {ok, TraceFile}.
-reformat_total(FromFile, ToFile) ->
- {ok, ConsultedFromFile} = file:consult(FromFile),
- [_AnalysisOpts, [Totals] | Terms] = ConsultedFromFile,
- {totals, _, TotalAcc, _} = Totals,
+%% Stop tracing and analyse it
+analyse(Slogan) ->
+ fprof:trace(stop),
+ TraceFile = lists:concat(["profile_", Slogan, "-fprof.trace"]),
+ DestFile = lists:concat(["profile_", Slogan, ".fprof"]),
+ try
+ case fprof:profile([{file, TraceFile}]) of
+ ok ->
+ ok = fprof:analyse([{dest, DestFile}, {totals, false}]),
+ {ok, DestFile};
+ {error, Reason} ->
+ {error, Reason}
+ end
+ after
+ fprof:stop()
+ end.
+
+fprof_to_calltree(Slogan) ->
+ fprof_to_calltree(Slogan, 0).
+
+fprof_to_calltree(Slogan, MinPercent) ->
+ DestFile = lists:concat(["profile_", Slogan, ".fprof"]),
+ TreeFile = lists:concat(["profile_", Slogan, ".calltree"]),
+ fprof_to_calltree(DestFile, TreeFile, MinPercent).
+
+%% Create a calltree from an fprof file
+fprof_to_calltree(FromFile, ToFile, MinPercent) ->
+ ReplyTo = self(),
+ Ref = make_ref(),
+ spawn_link(fun() ->
+ ReplyTo ! {Ref, do_fprof_to_calltree(FromFile, ToFile, MinPercent)}
+ end),
+ wait_for_reply(Ref).
+
+wait_for_reply(Ref) ->
+ receive
+ {Ref, Res} ->
+ Res;
+ {'EXIT', normal} ->
+ wait_for_reply(Ref);
+ {'EXIT', Reason} ->
+ exit(Reason)
+ end.
+
+do_fprof_to_calltree(FromFile, ToFile, MinPercent) ->
{ok, Fd} = file:open(ToFile, [write, raw]),
- Indent = "",
- log(Fd, Indent, TotalAcc, Totals),
- Processes = split_processes(Terms, [], []),
- Reformat = fun(P) -> reformat_process(Fd, " " ++ Indent, TotalAcc, P) end,
- lists:foreach(Reformat, Processes),
- file:close(Fd).
+ {ok, ConsultedFromFile} = file:consult(FromFile),
+ [_AnalysisOpts, [_Totals] | Terms] = ConsultedFromFile,
+ Processes = split_processes(Terms, [], []),
+ Indent = "",
+ Summary = collapse_processes(Processes),
+ {_Label, _Cnt, Acc, _Own, _Roots, Details} = Summary,
+ %% log(Fd, Label, Indent, Acc, {Label, Cnt, Acc, Own}, [], 0),
+ gen_calltree(Fd, Indent, Acc, Summary, MinPercent),
+ Delim = io_lib:format("\n~80..=c\n\n", [$=]),
+ Write =
+ fun(P) ->
+ file:write(Fd, Delim),
+ gen_calltree(Fd, Indent, Acc, P, MinPercent)
+ end,
+ lists:foreach(Write, Processes),
+ file:write(Fd, Delim),
+ gen_details(Fd, Acc, Details),
+ file:close(Fd),
+ {ok, ToFile}.
+%% Split all fprof terms into a list of processes
split_processes([H | T], ProcAcc, TotalAcc) ->
if
is_tuple(H) ->
@@ -75,64 +127,185 @@ split_processes([H | T], ProcAcc, TotalAcc) ->
is_list(H), ProcAcc =:= [] ->
split_processes(T, [H], TotalAcc);
is_list(H) ->
- split_processes(T, [H], [lists:reverse(ProcAcc) | TotalAcc])
+ ProcAcc2 = rearrange_process(lists:reverse(ProcAcc)),
+ split_processes(T, [H], [ProcAcc2 | TotalAcc])
end;
split_processes([], [], TotalAcc) ->
- lists:reverse(TotalAcc);
+ lists:reverse(lists:keysort(3, TotalAcc));
split_processes([], ProcAcc, TotalAcc) ->
- lists:reverse([lists:reverse(ProcAcc) | TotalAcc]).
-
-reformat_process(Fd, Indent, TotalAcc, Terms) ->
- case Terms of
- [[{ProcLabel, _, _, _}] | All] -> ok;
- [[{ProcLabel,_,_,_} | _] | All] -> ok
- end,
- [{_, {TopKey, TopCnt, TopAcc, TopOwn}, _} | _] = All,
- Process = {ProcLabel, TopCnt, TopAcc, TopOwn},
- log(Fd, Indent, TotalAcc, Process),
- reformat_calls(Fd, " " ++ Indent, TotalAcc, TopKey, All, []).
-
-reformat_calls(Fd, Indent, TotalAcc, Key, Terms, Stack) ->
- {_CalledBy, Current, Calls} = find(Key, Terms),
- log(Fd, Indent, TotalAcc, Current),
- case lists:member(Key, Stack) of
- true ->
- ok;
- false ->
- case Key of
- {io_lib, _, _} ->
- ok;
- {disk_log, _, _} ->
- ok;
- {lists, flatten, _} ->
- ok;
- {lists, keysort, _} ->
- ok;
- _ ->
- Fun = fun({NextKey, _, _, _}) ->
- reformat_calls(Fd,
- " " ++ Indent,
- TotalAcc,
- NextKey,
- Terms,
- [Key | Stack])
- end,
- lists:foreach(Fun, Calls)
- end
+ ProcAcc2 = rearrange_process(lists:reverse(ProcAcc)),
+ lists:reverse(lists:keysort(3, [ProcAcc2 | TotalAcc])).
+
+%% Rearrange the raw process list into a more useful format
+rearrange_process([[{Label, _Cnt, _Acc, _Own} | _ ] | Details]) ->
+ do_rearrange_process(Details, Details, Label, [], []).
+
+do_rearrange_process([{CalledBy, Current, _Calls} | T], Orig, Label, Roots, Undefs) ->
+ case [{undefined, Cnt, safe_max(Acc, Own), Own} ||
+ {undefined, Cnt, Acc, Own} <- CalledBy] of
+ [] ->
+ do_rearrange_process(T, Orig, Label, Roots, Undefs);
+ NewUndefs ->
+ do_rearrange_process(T, Orig, Label, [Current | Roots], NewUndefs ++ Undefs)
+ end;
+do_rearrange_process([], Details, Label, Roots, Undefs) ->
+ [{undefined, Cnt, Acc, Own}] = collapse_calls(Undefs, []),
+ Details2 = sort_details(3, Details),
+ {Label, Cnt, Acc, Own, lists:reverse(lists:keysort(3, Roots)), Details2}.
+
+%% Compute a summary of the rearranged process info
+collapse_processes(Processes) ->
+ Headers = lists:map(fun({_L, C, A, O, _R, _D}) -> {"SUMMARY", C, A, O} end,
+ Processes),
+ [{Label, Cnt, Acc, Own}] = collapse_calls(Headers, []),
+ Details = lists:flatmap(fun({_L, _C, _A, _O, _R, D}) -> D end, Processes),
+ Details2 = do_collapse_processes(sort_details(1, Details), []),
+ Roots = lists:flatmap(fun({_L, _C, _A, _O, R, _D}) -> R end, Processes),
+ RootMFAs = lists:usort([MFA || {MFA, _, _, _} <- Roots]),
+ Roots2 = [R || RootMFA <- RootMFAs,
+ {_, {MFA, _, _, _} = R, _} <- Details2,
+ MFA =:= RootMFA],
+ Roots3 = collapse_calls(Roots2, []),
+ {Label, Cnt, Acc, Own, Roots3, Details2}.
+
+do_collapse_processes([{CalledBy1, {MFA, Cnt1, Acc1, Own1}, Calls1} | T1],
+ [{CalledBy2, {MFA, Cnt2, Acc2, Own2}, Calls2} | T2]) ->
+ Cnt = Cnt1 + Cnt2,
+ Acc = Acc1 + Acc2,
+ Own = Own1 + Own2,
+ Current = {MFA, Cnt, Acc, Own},
+ CalledBy0 = CalledBy1 ++ CalledBy2,
+ Calls0 = Calls1 ++ Calls2,
+ CalledBy = collapse_calls(lists:keysort(3, CalledBy0), []),
+ Calls = collapse_calls(lists:keysort(3, Calls0), []),
+ do_collapse_processes(T1, [{CalledBy, Current, Calls} | T2]);
+do_collapse_processes([{CalledBy, Current, Calls} | T1],
+ T2) ->
+ do_collapse_processes(T1, [{CalledBy, Current, Calls} | T2]);
+do_collapse_processes([],
+ T2) ->
+ sort_details(3, T2).
+
+%% Reverse sort on acc field
+sort_details(Pos, Details) ->
+ Pivot = fun({_CalledBy1, Current1, _Calls1},
+ {_CalledBy2, Current2, _Calls2}) ->
+ element(Pos, Current1) =< element(Pos, Current2)
+ end,
+ lists:reverse(lists:sort(Pivot, Details)).
+
+%% Compute a summary from a list of call tuples
+collapse_calls([{MFA, Cnt1, Acc1, Own1} | T1],
+ [{MFA, Cnt2, Acc2, Own2} | T2]) ->
+ Cnt = Cnt1 + Cnt2,
+ Acc = safe_sum(Acc1, Acc2),
+ Own = Own1 + Own2,
+ collapse_calls(T1, [{MFA, Cnt, Acc, Own} | T2]);
+collapse_calls([{MFA, Cnt, Acc, Own} | T1],
+ T2) ->
+ collapse_calls(T1, [{MFA, Cnt, Acc, Own} | T2]);
+collapse_calls([],
+ T2) ->
+ lists:reverse(lists:keysort(3, T2)).
+
+safe_sum(Int1, Int2) ->
+ if
+ Int1 =:= undefined -> Int2;
+ Int2 =:= undefined -> Int1;
+ true -> Int1 + Int2
+ end.
+
+safe_max(Int1, Int2) ->
+ if
+ Int1 =:= undefined ->
+ io:format("111\n", []),
+ Int2;
+ Int2 =:= undefined ->
+ io:format("222\n", []),
+ Int1;
+ Int2 > Int1 -> Int2;
+ true -> Int1
+ end.
+
+%% Compute a calltree and write it to file
+gen_calltree(Fd, Indent, TotalAcc, {Label, Cnt, Acc, Own, Roots, Details}, MinPercent) ->
+ Header = {Label, Cnt, Acc, Own},
+ MetaLabel = "Process",
+ Diff = length(Label) - length(MetaLabel),
+ IoList = io_lib:format("~s~s Lvl Pct Cnt Acc Own Calls => MFA\n",
+ [MetaLabel, lists:duplicate(Diff, $\ )]),
+ file:write(Fd, IoList),
+ log(Fd, Label, Indent, TotalAcc, Header, Roots, MinPercent),
+ NewIndent = " " ++ Indent,
+ Fun = fun({MFA, _C, _A, _O}) ->
+ [put_detail(Label, D) || D <- Details],
+ gen_calls(Fd, Label, NewIndent, TotalAcc, MFA, MinPercent)
+ end,
+ lists:foreach(Fun, Roots).
+
+gen_calls(Fd, Label, Indent, TotalAcc, MFA, MinPercent) ->
+ case get_detail(Label, MFA) of
+ {read, {_CalledBy, Current, _Calls}} ->
+ log(Fd, Label, Indent, TotalAcc, Current, -1, MinPercent);
+ {unread, {_CalledBy, Current, Calls}} ->
+ log(Fd, Label, Indent, TotalAcc, Current, Calls, MinPercent),
+ NewIndent = " " ++ Indent,
+ Fun = fun({NextMFA, _, _, _}) ->
+ gen_calls(Fd, Label, NewIndent, TotalAcc,
+ NextMFA, MinPercent)
+ end,
+ lists:foreach(Fun, Calls)
+ end.
+
+put_detail(Label, {_, {MFA, _, _, _}, _} = Detail) ->
+ put({Label, MFA}, {unread, Detail}).
+
+get_detail(Label, MFA) ->
+ Val = get({Label, MFA}),
+ case Val of
+ {unread, Detail} ->
+ put({Label, MFA}, {read, Detail}),
+ Val;
+ {read, _Detail} ->
+ Val
+ end.
+
+gen_details(Fd, Total, Details) ->
+ IoList = io_lib:format("Pct Cnt Acc Own MFA\n", []),
+ file:write(Fd, IoList),
+ do_gen_details(Fd, Total, Details).
+
+do_gen_details(Fd, Total, [{_CalledBy, {MFA, Cnt, Acc, Own}, _Calls} | Details]) ->
+ MFAStr = io_lib:format("~p", [MFA]),
+ {_, Percent} = calc_percent(Acc, Own, Total),
+ IoList = io_lib:format("~3.. B% ~10.3B ~10.3f ~10.3f => ~s\n",
+ [Percent, Cnt, Acc, Own, MFAStr]),
+ file:write(Fd, IoList),
+ do_gen_details(Fd, Total, Details);
+do_gen_details(_Fd, _Total, []) ->
+ ok.
+
+log(Fd, Label, Indent, Acc, Current, Calls, MinPercent) when is_list(Calls) ->
+ log(Fd, Label, Indent, Acc, Current, length(Calls), MinPercent);
+log(Fd, Label, Indent, Total, {MFA, Cnt, Acc, Own}, N, MinPercent) ->
+ {Max, Percent} = calc_percent(Acc, Own, Total),
+ if
+ Percent >= MinPercent ->
+ do_log(Fd, Label, Indent, Percent, MFA, Cnt, Max, Own, N);
+ true ->
+ ok
end.
-find(Key, [{_, {Key, _, _, _}, _} = H | _]) ->
- H;
-find(Key, [{_, {_, _, _, _}, _} | T]) ->
- find(Key, T).
-
-log(Fd, Indent, Total, {Label, Cnt, Acc, Own}) ->
- Percent = case Acc of
- undefined -> 100;
- _ -> trunc((lists:max([Acc, Own]) * 100) / Total)
- end,
- Label2 = io_lib:format("~p", [Label]),
- IoList = io_lib:format("~s~p% ~s \t~p \t~p \t~p\n",
- [Indent, Percent, Label2, Cnt, trunc(Acc), trunc(Own)]),
+do_log(Fd, Label, Indent, Percent, MFA, Cnt, Acc, Own, N) ->
+ MFAStr = io_lib:format("~p", [MFA]),
+ CallsStr = io_lib:format(" ~5.. s ", [lists:concat([N])]),
+ IoList = io_lib:format("~s ~3.. B "
+ "~s~3.. B% ~10.. B ~10.. B ~10.. B ~s => ~s\n",
+ [Label, length(Indent) div 2,
+ Indent, Percent, Cnt,
+ round(Acc), round(Own), CallsStr, MFAStr]),
file:write(Fd, IoList).
+calc_percent(Acc, Own, Total) ->
+ Max = safe_max(Acc, Own),
+ {Max, round((Max * 100) / Total)}.
diff --git a/lib/megaco/test/megaco_test_lib.erl b/lib/megaco/test/megaco_test_lib.erl
index 41f6c2c4cb..282fd91b44 100644
--- a/lib/megaco/test/megaco_test_lib.erl
+++ b/lib/megaco/test/megaco_test_lib.erl
@@ -21,6 +21,7 @@
%%----------------------------------------------------------------------
%% Purpose: Lightweight test server
%%----------------------------------------------------------------------
+%%
-module(megaco_test_lib).
@@ -684,7 +685,7 @@ skip(Actual, File, Line) ->
fatal_skip(Actual, File, Line) ->
error(Actual, File, Line),
- exit(shutdown).
+ exit({skipped, {fatal, Actual, File, Line}}).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -749,6 +750,7 @@ proxy_loop(OwnId, Controller) ->
proxy_loop(OwnId, Controller)
end.
+
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Test server callbacks
init_per_testcase(_Case, Config) ->
@@ -852,10 +854,10 @@ watchdog(Pid, Time) ->
prepare_test_case(Actions, N, Config, File, Line) ->
OrigNodes = lookup_config(nodes, Config),
TestNodes = lookup_config(nodenames, Config), %% For testserver
- This = node(),
+ This = node(),
SomeNodes = OrigNodes ++ (TestNodes -- OrigNodes),
- AllNodes = [This | (SomeNodes -- [This])],
- Nodes = pick_n_nodes(N, AllNodes, File, Line),
+ AllNodes = [This | (SomeNodes -- [This])],
+ Nodes = pick_n_nodes(N, AllNodes, File, Line),
start_nodes(Nodes, File, Line),
do_prepare_test_case(Actions, Nodes, Config, File, Line).
diff --git a/lib/megaco/vsn.mk b/lib/megaco/vsn.mk
index c1476488ca..35acffcb64 100644
--- a/lib/megaco/vsn.mk
+++ b/lib/megaco/vsn.mk
@@ -18,6 +18,6 @@
# %CopyrightEnd%
APPLICATION = megaco
-MEGACO_VSN = 3.15.1.1
+MEGACO_VSN = 3.15.1.2
PRE_VSN =
APP_VSN = "$(APPLICATION)-$(MEGACO_VSN)$(PRE_VSN)"
diff --git a/lib/mnesia/doc/src/Makefile b/lib/mnesia/doc/src/Makefile
index f45b5137a3..f2e581f9d3 100644
--- a/lib/mnesia/doc/src/Makefile
+++ b/lib/mnesia/doc/src/Makefile
@@ -29,14 +29,6 @@ VSN=$(MNESIA_VSN)
APPLICATION=mnesia
# ----------------------------------------------------
-# Include dependency
-# ----------------------------------------------------
-
-ifndef DOCSUPPORT
-include make.dep
-endif
-
-# ----------------------------------------------------
# Release directory specification
# ----------------------------------------------------
RELSYSDIR = $(RELEASE_PATH)/lib/$(APPLICATION)-$(VSN)
@@ -105,31 +97,10 @@ EXTRA_FILES = summary.html.src \
MAN3_FILES = $(XML_REF3_FILES:%.xml=$(MAN3DIR)/%.3)
-ifdef DOCSUPPORT
-
HTML_REF_MAN_FILE = $(HTMLDIR)/index.html
TOP_PDF_FILE = $(PDFDIR)/$(APPLICATION)-$(VSN).pdf
-else
-TEX_FILES_BOOK = \
- $(BOOK_FILES:%.xml=%.tex)
-TEX_FILES_REF_MAN = $(XML_REF3_FILES:%.xml=%.tex) \
- $(XML_APPLICATION_FILES:%.xml=%.tex)
-TEX_FILES_USERS_GUIDE = \
- $(XML_CHAPTER_FILES:%.xml=%.tex)
-
-TOP_PDF_FILE = $(APPLICATION)-$(VSN).pdf
-TOP_PS_FILE = $(APPLICATION)-$(VSN).ps
-
-$(TOP_PDF_FILE): book.dvi ../../vsn.mk
- $(DVI2PS) $(DVIPS_FLAGS) -f $< | $(DISTILL) $(DISTILL_FLAGS) > $@
-
-$(TOP_PS_FILE): book.dvi ../../vsn.mk
- $(DVI2PS) $(DVIPS_FLAGS) -f $< > $@
-
-endif
-
# ----------------------------------------------------
# FLAGS
# ----------------------------------------------------
@@ -142,8 +113,6 @@ DVIPS_FLAGS +=
$(HTMLDIR)/%.gif: %.gif
$(INSTALL_DATA) $< $@
-ifdef DOCSUPPORT
-
docs: pdf html man
$(TOP_PDF_FILE): $(XML_FILES)
@@ -158,33 +127,6 @@ clean clean_docs:
rm -f $(TOP_PDF_FILE) $(TOP_PDF_FILE:%.pdf=%.fo)
rm -f errs core *~
-else
-
-ifeq ($(DOCTYPE),pdf)
-docs: pdf
-else
-ifeq ($(DOCTYPE),ps)
-docs: ps
-else
-docs: html gifs man
-endif
-endif
-
-pdf: $(TOP_PDF_FILE)
-
-ps: $(TOP_PS_FILE)
-
-html: $(HTML_FILES)
-
-
-clean clean_docs clean_tex:
- rm -f $(TEX_FILES_USERS_GUIDE) $(TEX_FILES_REF_MAN) $(TEX_FILES_BOOK)
- rm -f $(HTML_FILES) $(MAN3_FILES)
- rm -f $(TOP_PDF_FILE) $(TOP_PS_FILE)
- rm -f errs core *~ *xmls_output *xmls_errs $(LATEX_CLEAN)
-
-endif
-
man: $(MAN3_FILES)
gifs: $(GIF_FILES:%=$(HTMLDIR)/%)
@@ -199,8 +141,6 @@ debug opt:
# ----------------------------------------------------
include $(ERL_TOP)/make/otp_release_targets.mk
-ifdef DOCSUPPORT
-
release_docs_spec: docs
$(INSTALL_DIR) $(RELSYSDIR)/doc/pdf
$(INSTALL_DATA) $(TOP_PDF_FILE) $(RELSYSDIR)/doc/pdf
@@ -211,30 +151,4 @@ release_docs_spec: docs
$(INSTALL_DIR) $(RELEASE_PATH)/man/man3
$(INSTALL_DATA) $(MAN3_FILES) $(RELEASE_PATH)/man/man3
-else
-
-ifeq ($(DOCTYPE),pdf)
-release_docs_spec: pdf
- $(INSTALL_DIR) $(RELEASE_PATH)/pdf
- $(INSTALL_DATA) $(TOP_PDF_FILE) $(RELEASE_PATH)/pdf
-else
-ifeq ($(DOCTYPE),ps)
-release_docs_spec: ps
- $(INSTALL_DIR) $(RELEASE_PATH)/ps
- $(INSTALL_DATA) $(TOP_PS_FILE) $(RELEASE_PATH)/ps
-else
-release_docs_spec: docs
- $(INSTALL_DIR) $(RELSYSDIR)/doc/html
- $(INSTALL_DATA) $(GIF_FILES) $(EXTRA_FILES) $(HTML_FILES) \
- $(RELSYSDIR)/doc/html
- $(INSTALL_DATA) $(INFO_FILE) $(RELSYSDIR)
- $(INSTALL_DIR) $(RELEASE_PATH)/man/man3
- $(INSTALL_DATA) $(MAN3_FILES) $(RELEASE_PATH)/man/man3
-endif
-endif
-
-endif
-
-
release_spec:
-
diff --git a/lib/mnesia/doc/src/make.dep b/lib/mnesia/doc/src/make.dep
deleted file mode 100644
index 6e79484cb3..0000000000
--- a/lib/mnesia/doc/src/make.dep
+++ /dev/null
@@ -1,46 +0,0 @@
-# ----------------------------------------------------
-# >>>> Do not edit this file <<<<
-# This file was automaticly generated by
-# /home/otp/bin/docdepend
-# ----------------------------------------------------
-
-
-# ----------------------------------------------------
-# TeX files that the DVI file depend on
-# ----------------------------------------------------
-
-book.dvi: Mnesia_App_A.tex Mnesia_App_B.tex Mnesia_App_C.tex \
- Mnesia_App_D.tex Mnesia_chap1.tex Mnesia_chap2.tex \
- Mnesia_chap3.tex Mnesia_chap4.tex Mnesia_chap5.tex \
- Mnesia_chap7.tex Mnesia_chap8.tex book.tex \
- mnesia.tex mnesia_frag_hash.tex mnesia_registry.tex \
- part.tex ref_man.tex
-
-# ----------------------------------------------------
-# Source inlined when transforming from source to LaTeX
-# ----------------------------------------------------
-
-Mnesia_App_B.tex: ../../src/mnesia_backup.erl
-
-Mnesia_App_C.tex: ../../src/mnesia_frag.erl
-
-Mnesia_App_D.tex: ../../src/mnesia_frag_hash.erl
-
-Mnesia_chap2.tex: company.erl company.hrl
-
-Mnesia_chap3.tex: company.erl
-
-Mnesia_chap4.tex: company.erl
-
-Mnesia_chap5.tex: FRUITS company.erl company_o.erl company_o.hrl
-
-Mnesia_chap7.tex: bup.erl
-
-book.tex: ref_man.xml
-
-# ----------------------------------------------------
-# Pictures that the DVI file depend on
-# ----------------------------------------------------
-
-book.dvi: company.ps
-
diff --git a/lib/mnesia/doc/src/notes.xml b/lib/mnesia/doc/src/notes.xml
index 8ef573a948..1bb80f8fe3 100644
--- a/lib/mnesia/doc/src/notes.xml
+++ b/lib/mnesia/doc/src/notes.xml
@@ -38,7 +38,35 @@
thus constitutes one section in this document. The title of each
section is the version number of Mnesia.</p>
- <section><title>Mnesia 4.5</title>
+ <section><title>Mnesia 4.5.1</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Fix deadlock in mnesia:del_table_copy/2.</p>
+ <p>
+ Own Id: OTP-9689 Aux Id: seq11927 </p>
+ </item>
+ </list>
+ </section>
+
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ Allow schema operations when using different mnesia
+ versions.</p>
+ <p>
+ Own Id: OTP-9657 Aux Id: seq11926 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Mnesia 4.5</title>
<section><title>Fixed Bugs and Malfunctions</title>
<list>
diff --git a/lib/mnesia/src/mnesia.appup.src b/lib/mnesia/src/mnesia.appup.src
index fe4e5e2e7a..e0954ad206 100644
--- a/lib/mnesia/src/mnesia.appup.src
+++ b/lib/mnesia/src/mnesia.appup.src
@@ -1,12 +1,14 @@
%% -*- erlang -*-
-{"%VSN%",
+{"%VSN%",
[
+ {"4.5", [{restart_application, mnesia}]},
{"4.4.19", [{restart_application, mnesia}]},
{"4.4.18", [{restart_application, mnesia}]},
{"4.4.17", [{restart_application, mnesia}]},
{"4.4.16", [{restart_application, mnesia}]}
],
[
+ {"4.5", [{restart_application, mnesia}]},
{"4.4.19", [{restart_application, mnesia}]},
{"4.4.18", [{restart_application, mnesia}]},
{"4.4.17", [{restart_application, mnesia}]},
diff --git a/lib/mnesia/src/mnesia_bup.erl b/lib/mnesia/src/mnesia_bup.erl
index 47dcdad7ac..14414537b9 100644
--- a/lib/mnesia/src/mnesia_bup.erl
+++ b/lib/mnesia/src/mnesia_bup.erl
@@ -372,7 +372,9 @@ mk_str() ->
lists:concat([node()] ++ Now ++ ".TMP").
make_initial_backup(Ns, Opaque, Mod) ->
- Schema = [{schema, schema, mnesia_schema:get_initial_schema(disc_copies, Ns)}],
+ Orig = mnesia_schema:get_initial_schema(disc_copies, Ns),
+ Modded = proplists:delete(storage_properties, proplists:delete(majority, Orig)),
+ Schema = [{schema, schema, Modded}],
O2 = do_apply(Mod, open_write, [Opaque], Opaque),
O3 = do_apply(Mod, write, [O2, [mnesia_log:backup_log_header()]], O2),
O4 = do_apply(Mod, write, [O3, Schema], O3),
diff --git a/lib/mnesia/src/mnesia_controller.erl b/lib/mnesia/src/mnesia_controller.erl
index 1d3bd55b48..6a561394d5 100644
--- a/lib/mnesia/src/mnesia_controller.erl
+++ b/lib/mnesia/src/mnesia_controller.erl
@@ -289,40 +289,7 @@ get_remote_cstructs() ->
get_cstructs() ->
{cstructs, Cstructs, Running} = call(get_cstructs),
Node = node(group_leader()),
- {cstructs, normalize_cstructs(Cstructs, Node), Running}.
-
-normalize_cstructs(Cstructs, Node) ->
- %% backward-compatibility hack; normalize before returning
- case rpc:call(Node, mnesia_lib, val, [{schema,cstruct}]) of
- {badrpc, _} ->
- %% assume it's not a schema merge
- Cstructs;
- #cstruct{} ->
- %% same format
- Cstructs;
- Cstruct ->
- %% some other format
- RemoteFields = [F || {F,_} <- rpc:call(Node, mnesia_schema, cs2list, [Cstruct])],
- [convert_cs(Cs, RemoteFields) || Cs <- Cstructs]
- end.
-
-convert_cs(Cs, Fields) ->
- MyFields = record_info(fields, cstruct),
- convert(tl(tuple_to_list(Cs)), MyFields, Fields, []).
-
-convert([H|T], [F|FsL], [F|FsR], Acc) ->
- convert(T, FsL, FsR, [H|Acc]);
-convert([H|T], [Fl|FsL] = L, [Fr|FsR] = R, Acc) ->
- case {lists:member(Fl, FsR), lists:member(Fr, FsL)} of
- {true, false} ->
- convert(T, L, FsR, [H|Acc]);
- {false, true} ->
- %% Field Fl doesn't exist on receiver side; skip.
- convert(T, FsL, R, Acc)
- end;
-convert([], _, _, Acc) ->
- list_to_tuple([cstruct|lists:reverse(Acc)]).
-
+ {cstructs, mnesia_schema:normalize_cs(Cstructs, Node), Running}.
update(Fun) ->
call({update,Fun}).
diff --git a/lib/mnesia/src/mnesia_event.erl b/lib/mnesia/src/mnesia_event.erl
index ec6b99ecaa..5a060a28ff 100644
--- a/lib/mnesia/src/mnesia_event.erl
+++ b/lib/mnesia/src/mnesia_event.erl
@@ -121,7 +121,7 @@ handle_system_event({mnesia_up, Node}, State) ->
{ok, State#state{nodes = Nodes}};
handle_system_event({mnesia_down, Node}, State) ->
- case mnesia:system_info(fallback_activated) of
+ case mnesia:system_info(fallback_activated) andalso Node =/= node() of
true ->
case mnesia_monitor:get_env(fallback_error_function) of
{mnesia, lkill} ->
@@ -129,8 +129,8 @@ handle_system_event({mnesia_down, Node}, State) ->
"must be restarted. Forcing shutdown "
"after mnesia_down from ~p...~n",
report_fatal(Msg, [Node], nocore, State#state.dumped_core),
- mnesia:lkill(),
- exit(fatal);
+ catch exit(whereis(mnesia_monitor), fatal),
+ {ok, State};
{UserMod, UserFunc} ->
Msg = "Warning: A fallback is installed and Mnesia got mnesia_down "
"from ~p. ~n",
diff --git a/lib/mnesia/src/mnesia_frag.erl b/lib/mnesia/src/mnesia_frag.erl
index 9e77fe0b9f..4a1616e054 100644
--- a/lib/mnesia/src/mnesia_frag.erl
+++ b/lib/mnesia/src/mnesia_frag.erl
@@ -758,7 +758,7 @@ make_activate(Tab, Props) ->
[] ->
Cs2 = Cs#cstruct{frag_properties = Props},
[Cs3] = expand_cstruct(Cs2, activate),
- TabDef = mnesia_schema:cs2list(Cs3),
+ TabDef = mnesia_schema:vsn_cs2list(Cs3),
Op = {op, change_table_frag, activate, TabDef},
[[Op]];
BadProps ->
@@ -783,7 +783,7 @@ make_deactivate(Tab) ->
mnesia:abort({combine_error, Tab, "Too many fragments"});
true ->
Cs2 = Cs#cstruct{frag_properties = []},
- TabDef = mnesia_schema:cs2list(Cs2),
+ TabDef = mnesia_schema:vsn_cs2list(Cs2),
Op = {op, change_table_frag, deactivate, TabDef},
[[Op]]
end.
@@ -850,7 +850,7 @@ make_add_frag(Tab, SortedNs) ->
SplitOps = split(Tab, FH2, FromIndecies, FragNames, []),
Cs2 = replace_frag_hash(Cs, FH2),
- TabDef = mnesia_schema:cs2list(Cs2),
+ TabDef = mnesia_schema:vsn_cs2list(Cs2),
BaseOp = {op, change_table_frag, {add_frag, SortedNs}, TabDef},
[BaseOp, NewOp | SplitOps].
@@ -962,7 +962,7 @@ make_del_frag(Tab) ->
LastFrag = element(N, FragNames),
[LastOp] = mnesia_schema:make_delete_table(LastFrag, single_frag),
Cs2 = replace_frag_hash(Cs, FH2),
- TabDef = mnesia_schema:cs2list(Cs2),
+ TabDef = mnesia_schema:vsn_cs2list(Cs2),
BaseOp = {op, change_table_frag, del_frag, TabDef},
[BaseOp, LastOp | MergeOps];
_ ->
@@ -1075,7 +1075,7 @@ make_add_node(Tab, Node) when is_atom(Node) ->
Props = Cs#cstruct.frag_properties,
Props2 = lists:keyreplace(node_pool, 1, Props, {node_pool, Pool2}),
Cs2 = Cs#cstruct{frag_properties = Props2},
- TabDef = mnesia_schema:cs2list(Cs2),
+ TabDef = mnesia_schema:vsn_cs2list(Cs2),
Op = {op, change_table_frag, {add_node, Node}, TabDef},
[Op];
true ->
@@ -1104,7 +1104,7 @@ make_del_node(Tab, Node) when is_atom(Node) ->
Pool2 = Pool -- [Node],
Props = lists:keyreplace(node_pool, 1, Cs#cstruct.frag_properties, {node_pool, Pool2}),
Cs2 = Cs#cstruct{frag_properties = Props},
- TabDef = mnesia_schema:cs2list(Cs2),
+ TabDef = mnesia_schema:vsn_cs2list(Cs2),
Op = {op, change_table_frag, {del_node, Node}, TabDef},
[Op];
false ->
diff --git a/lib/mnesia/src/mnesia_frag_hash.erl b/lib/mnesia/src/mnesia_frag_hash.erl
index 610ba2535c..d70579c3b3 100644
--- a/lib/mnesia/src/mnesia_frag_hash.erl
+++ b/lib/mnesia/src/mnesia_frag_hash.erl
@@ -101,21 +101,19 @@ del_frag(OldState) ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-key_to_frag_number(#hash_state{function = phash, next_n_to_split = SplitN, n_doubles = L}, Key) ->
- P = SplitN,
- A = erlang:phash(Key, power2(L)),
+key_to_frag_number(#hash_state{function = phash, n_fragments = N, n_doubles = L}, Key) ->
+ A = erlang:phash(Key, power2(L + 1)),
if
- A < P ->
- erlang:phash(Key, power2(L + 1));
+ A > N ->
+ A - power2(L);
true ->
A
end;
-key_to_frag_number(#hash_state{function = phash2, next_n_to_split = SplitN, n_doubles = L}, Key) ->
- P = SplitN,
- A = erlang:phash2(Key, power2(L)) + 1,
+key_to_frag_number(#hash_state{function = phash2, n_fragments = N, n_doubles = L}, Key) ->
+ A = erlang:phash2(Key, power2(L + 1)) + 1,
if
- A < P ->
- erlang:phash2(Key, power2(L + 1)) + 1;
+ A > N ->
+ A - power2(L);
true ->
A
end;
diff --git a/lib/mnesia/src/mnesia_lib.erl b/lib/mnesia/src/mnesia_lib.erl
index e8b8c58c70..ae6631646c 100644
--- a/lib/mnesia/src/mnesia_lib.erl
+++ b/lib/mnesia/src/mnesia_lib.erl
@@ -413,7 +413,7 @@ pr_other(Var, Other) ->
[self(), process_info(self(), registered_name),
Var, Other, Why]),
case Other of
- {badarg, [{ets, lookup_element, _}|_]} ->
+ {badarg, [{ets, lookup_element, _, _}|_]} ->
exit(Why);
_ ->
erlang:error(Why)
diff --git a/lib/mnesia/src/mnesia_loader.erl b/lib/mnesia/src/mnesia_loader.erl
index eb83168498..c4b22814a8 100644
--- a/lib/mnesia/src/mnesia_loader.erl
+++ b/lib/mnesia/src/mnesia_loader.erl
@@ -429,7 +429,7 @@ init_table(Tab, disc_only_copies, Fun, DetsInfo,Sender) ->
{ErtsVer, DetsData} ->
Res = (catch dets:is_compatible_bchunk_format(Tab, DetsData)),
case Res of
- {'EXIT',{undef,[{dets,_,_}|_]}} ->
+ {'EXIT',{undef,[{dets,_,_,_}|_]}} ->
Sender ! {self(), {old_protocol, Tab}},
dets:init_table(Tab, Fun); %% Old dets version
{'EXIT', What} ->
diff --git a/lib/mnesia/src/mnesia_monitor.erl b/lib/mnesia/src/mnesia_monitor.erl
index e110ad3241..8cb2e92c08 100644
--- a/lib/mnesia/src/mnesia_monitor.erl
+++ b/lib/mnesia/src/mnesia_monitor.erl
@@ -536,7 +536,11 @@ handle_info({'EXIT', Pid, R}, State) when Pid == State#state.supervisor ->
handle_info({'EXIT', Pid, fatal}, State) when node(Pid) == node() ->
dbg_out("~p got FATAL ERROR from: ~p~n",[?MODULE, Pid]),
- exit(State#state.supervisor, shutdown),
+ %% This may hang supervisor if a shutdown happens at the same time as an fatal
+ %% is in progress
+ %% exit(State#state.supervisor, shutdown),
+ %% It is better to kill an innocent process
+ catch exit(whereis(mnesia_locker), kill),
{noreply, State};
handle_info(Msg = {'EXIT',Pid,_}, State) ->
diff --git a/lib/mnesia/src/mnesia_schema.erl b/lib/mnesia/src/mnesia_schema.erl
index 05be474aea..179e15197e 100644
--- a/lib/mnesia/src/mnesia_schema.erl
+++ b/lib/mnesia/src/mnesia_schema.erl
@@ -39,9 +39,10 @@
change_table_load_order/2,
change_table_majority/2,
change_table_frag/2,
- clear_table/1,
+%% clear_table/1, %% removed since it is not a schema op anymore
create_table/1,
cs2list/1,
+ vsn_cs2list/1,
del_snmp/1,
del_table_copy/2,
del_table_index/2,
@@ -65,6 +66,7 @@
merge_schema/0,
merge_schema/1,
move_table/3,
+ normalize_cs/2,
opt_create_dir/2,
prepare_commit/3,
purge_dir/2,
@@ -626,6 +628,17 @@ do_insert_schema_ops(Store, [Head | Tail]) ->
do_insert_schema_ops(_Store, []) ->
ok.
+api_list2cs(List) when is_list(List) ->
+ Name = pick(unknown, name, List, must),
+ Keys = check_keys(Name, List, record_info(fields, cstruct)),
+ check_duplicates(Name, Keys),
+ list2cs(List);
+api_list2cs(Other) ->
+ mnesia:abort({badarg, Other}).
+
+vsn_cs2list(Cs) ->
+ cs2list(need_old_cstructs(), Cs).
+
cs2list(Cs) when is_record(Cs, cstruct) ->
Tags = record_info(fields, cstruct),
rec2list(Tags, Tags, 2, Cs);
@@ -648,7 +661,7 @@ cs2list(Cs) when element(1, Cs) == cstruct, tuple_size(Cs) == 17 ->
cs2list(false, Cs) ->
cs2list(Cs);
-cs2list(ver4_4_18, Cs) ->
+cs2list(ver4_4_18, Cs) -> %% Or earlier
Orig = record_info(fields, cstruct),
Tags = [name,type,ram_copies,disc_copies,disc_only_copies,
load_order,access_mode,index,snmp,local_content,
@@ -671,13 +684,19 @@ rec2list([], _, _Pos, _Rec) ->
rec2list(Tags, [_|Orig], Pos, Rec) ->
rec2list(Tags, Orig, Pos+1, Rec).
-api_list2cs(List) when is_list(List) ->
- Name = pick(unknown, name, List, must),
- Keys = check_keys(Name, List, record_info(fields, cstruct)),
- check_duplicates(Name, Keys),
- list2cs(List);
-api_list2cs(Other) ->
- mnesia:abort({badarg, Other}).
+normalize_cs(Cstructs, Node) ->
+ %% backward-compatibility hack; normalize before returning
+ case need_old_cstructs([Node]) of
+ false ->
+ Cstructs;
+ Version ->
+ %% some other format
+ [convert_cs(Version, Cs) || Cs <- Cstructs]
+ end.
+
+convert_cs(Version, Cs) ->
+ Fields = [Value || {_, Value} <- cs2list(Version, Cs)],
+ list_to_tuple([cstruct|Fields]).
list2cs(List) when is_list(List) ->
Name = pick(unknown, name, List, must),
@@ -1048,7 +1067,7 @@ unsafe_make_create_table(Cs) ->
Nodes = mnesia_lib:intersect(mnesia_lib:cs_to_nodes(Cs), RunningNodes),
Store = Ts#tidstore.store,
mnesia_locker:wlock_no_exist(Tid, Store, Tab, Nodes),
- [{op, create_table, cs2list(Cs)}].
+ [{op, create_table, vsn_cs2list(Cs)}].
check_if_exists(Tab) ->
TidTs = get_tid_ts_and_lock(schema, write),
@@ -1133,7 +1152,7 @@ make_delete_table2(Tab) ->
Cs = val({Tab, cstruct}),
ensure_active(Cs),
ensure_writable(Tab),
- {op, delete_table, cs2list(Cs)}.
+ {op, delete_table, vsn_cs2list(Cs)}.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Change fragmentation of a table
@@ -1152,10 +1171,6 @@ do_change_table_frag(Tab, _Change) ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Clear a table
-%% No need for a schema transaction
-clear_table(Tab) ->
- schema_transaction(fun() -> do_clear_table(Tab) end).
-
do_clear_table(schema) ->
mnesia:abort({bad_type, schema});
do_clear_table(Tab) ->
@@ -1166,7 +1181,7 @@ do_clear_table(Tab) ->
make_clear_table(Tab) ->
Cs = val({Tab, cstruct}),
ensure_writable(Tab),
- [{op, clear_table, cs2list(Cs)}].
+ [{op, clear_table, vsn_cs2list(Cs)}].
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -1206,7 +1221,7 @@ make_add_table_copy(Tab, Node, Storage) ->
IsRunning == false ->
mnesia:abort({not_active, schema, Node})
end,
- [{op, add_table_copy, Storage, Node, cs2list(Cs2)}].
+ [{op, add_table_copy, Storage, Node, vsn_cs2list(Cs2)}].
del_table_copy(Tab, Node) ->
schema_transaction(fun() -> do_del_table_copy(Tab, Node) end).
@@ -1235,11 +1250,11 @@ make_del_table_copy(Tab, Node) ->
ensure_not_active(Tab, Node),
verify_cstruct(Cs2),
Ops = remove_node_from_tabs(val({schema, tables}), Node),
- [{op, del_table_copy, ram_copies, Node, cs2list(Cs2)} | Ops];
+ [{op, del_table_copy, ram_copies, Node, vsn_cs2list(Cs2)} | Ops];
_ ->
ensure_active(Cs),
verify_cstruct(Cs2),
- [{op, del_table_copy, Storage, Node, cs2list(Cs2)}]
+ [{op, del_table_copy, Storage, Node, vsn_cs2list(Cs2)}]
end.
remove_node_from_tabs([], _Node) ->
@@ -1253,7 +1268,7 @@ remove_node_from_tabs([Tab|Rest], Node) ->
unknown ->
case IsFragModified of
true ->
- [{op, change_table_frag, {del_node, Node}, cs2list(Cs)} |
+ [{op, change_table_frag, {del_node, Node}, vsn_cs2list(Cs)} |
remove_node_from_tabs(Rest, Node)];
false ->
remove_node_from_tabs(Rest, Node)
@@ -1262,11 +1277,11 @@ remove_node_from_tabs([Tab|Rest], Node) ->
Cs2 = new_cs(Cs, Node, Storage, del),
case mnesia_lib:cs_to_nodes(Cs2) of
[] ->
- [{op, delete_table, cs2list(Cs)} |
+ [{op, delete_table, vsn_cs2list(Cs)} |
remove_node_from_tabs(Rest, Node)];
_Ns ->
verify_cstruct(Cs2),
- [{op, del_table_copy, ram_copies, Node, cs2list(Cs2)}|
+ [{op, del_table_copy, ram_copies, Node, vsn_cs2list(Cs2)}|
remove_node_from_tabs(Rest, Node)]
end
end.
@@ -1318,9 +1333,9 @@ make_move_table(Tab, FromNode, ToNode) ->
Cs2 = new_cs(Cs, ToNode, Storage, add),
Cs3 = new_cs(Cs2, FromNode, Storage, del),
verify_cstruct(Cs3),
- [{op, add_table_copy, Storage, ToNode, cs2list(Cs2)},
+ [{op, add_table_copy, Storage, ToNode, vsn_cs2list(Cs2)},
{op, sync_trans},
- {op, del_table_copy, Storage, FromNode, cs2list(Cs3)}].
+ {op, del_table_copy, Storage, FromNode, vsn_cs2list(Cs3)}].
%% end of functions to add and delete nodes to tables
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -1357,7 +1372,7 @@ make_change_table_copy_type(Tab, Node, ToS) ->
Cs3 = new_cs(Cs2, Node, ToS, add),
verify_cstruct(Cs3),
- [{op, change_table_copy_type, Node, FromS, ToS, cs2list(Cs3)}].
+ [{op, change_table_copy_type, Node, FromS, ToS, vsn_cs2list(Cs3)}].
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% change index functions ....
@@ -1383,7 +1398,7 @@ make_add_table_index(Tab, Pos) ->
Ix2 = lists:sort([Pos | Ix]),
Cs2 = Cs#cstruct{index = Ix2},
verify_cstruct(Cs2),
- [{op, add_index, Pos, cs2list(Cs2)}].
+ [{op, add_index, Pos, vsn_cs2list(Cs2)}].
del_table_index(Tab, Pos) ->
schema_transaction(fun() -> do_del_table_index(Tab, Pos) end).
@@ -1404,7 +1419,7 @@ make_del_table_index(Tab, Pos) ->
verify(true, lists:member(Pos, Ix), {no_exists, Tab, Pos}),
Cs2 = Cs#cstruct{index = lists:delete(Pos, Ix)},
verify_cstruct(Cs2),
- [{op, del_index, Pos, cs2list(Cs2)}].
+ [{op, del_index, Pos, vsn_cs2list(Cs2)}].
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -1427,7 +1442,7 @@ make_add_snmp(Tab, Ustruct) ->
verify(true, mnesia_snmp_hook:check_ustruct(Ustruct), Error),
Cs2 = Cs#cstruct{snmp = Ustruct},
verify_cstruct(Cs2),
- [{op, add_snmp, Ustruct, cs2list(Cs2)}].
+ [{op, add_snmp, Ustruct, vsn_cs2list(Cs2)}].
del_snmp(Tab) ->
schema_transaction(fun() -> do_del_snmp(Tab) end).
@@ -1445,7 +1460,7 @@ make_del_snmp(Tab) ->
ensure_active(Cs),
Cs2 = Cs#cstruct{snmp = []},
verify_cstruct(Cs2),
- [{op, del_snmp, cs2list(Cs2)}].
+ [{op, del_snmp, vsn_cs2list(Cs2)}].
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%
@@ -1477,26 +1492,26 @@ make_transform(Tab, Fun, NewAttrs, NewRecName) ->
[] ->
Cs2 = Cs#cstruct{attributes = NewAttrs, record_name = NewRecName},
verify_cstruct(Cs2),
- [{op, transform, Fun, cs2list(Cs2)}];
+ [{op, transform, Fun, vsn_cs2list(Cs2)}];
PosList ->
DelIdx = fun(Pos, Ncs) ->
Ix = Ncs#cstruct.index,
Ncs1 = Ncs#cstruct{index = lists:delete(Pos, Ix)},
- Op = {op, del_index, Pos, cs2list(Ncs1)},
+ Op = {op, del_index, Pos, vsn_cs2list(Ncs1)},
{Op, Ncs1}
end,
AddIdx = fun(Pos, Ncs) ->
Ix = Ncs#cstruct.index,
Ix2 = lists:sort([Pos | Ix]),
Ncs1 = Ncs#cstruct{index = Ix2},
- Op = {op, add_index, Pos, cs2list(Ncs1)},
+ Op = {op, add_index, Pos, vsn_cs2list(Ncs1)},
{Op, Ncs1}
end,
{DelOps, Cs1} = lists:mapfoldl(DelIdx, Cs, PosList),
Cs2 = Cs1#cstruct{attributes = NewAttrs, record_name = NewRecName},
{AddOps, Cs3} = lists:mapfoldl(AddIdx, Cs2, PosList),
verify_cstruct(Cs3),
- lists:flatten([DelOps, {op, transform, Fun, cs2list(Cs2)}, AddOps])
+ lists:flatten([DelOps, {op, transform, Fun, vsn_cs2list(Cs2)}, AddOps])
end.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -1520,7 +1535,7 @@ make_change_table_access_mode(Tab, Mode) ->
verify(false, OldMode == Mode, {already_exists, Tab, Mode}),
Cs2 = Cs#cstruct{access_mode = Mode},
verify_cstruct(Cs2),
- [{op, change_table_access_mode, cs2list(Cs2), OldMode, Mode}].
+ [{op, change_table_access_mode, vsn_cs2list(Cs2), OldMode, Mode}].
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -1541,7 +1556,7 @@ make_change_table_load_order(Tab, LoadOrder) ->
OldLoadOrder = Cs#cstruct.load_order,
Cs2 = Cs#cstruct{load_order = LoadOrder},
verify_cstruct(Cs2),
- [{op, change_table_load_order, cs2list(Cs2), OldLoadOrder, LoadOrder}].
+ [{op, change_table_load_order, vsn_cs2list(Cs2), OldLoadOrder, LoadOrder}].
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -1571,14 +1586,14 @@ make_change_table_majority(Tab, Majority) ->
ensure_active(CsT),
CsT2 = CsT#cstruct{majority = Majority},
verify_cstruct(CsT2),
- {op, change_table_majority, cs2list(CsT2),
+ {op, change_table_majority, vsn_cs2list(CsT2),
OldMajority, Majority}
end, FragNames);
false -> [];
{_, _} -> mnesia:abort({bad_type, Tab})
end,
verify_cstruct(Cs2),
- [{op, change_table_majority, cs2list(Cs2), OldMajority, Majority} | FragOps].
+ [{op, change_table_majority, vsn_cs2list(Cs2), OldMajority, Majority} | FragOps].
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -1619,7 +1634,7 @@ make_write_table_properties(Tab, [Prop | Props], Cs) ->
MergedProps = lists:merge(DelProps, [Prop]),
Cs2 = Cs#cstruct{user_properties = MergedProps},
verify_cstruct(Cs2),
- [{op, write_property, cs2list(Cs2), Prop} |
+ [{op, write_property, vsn_cs2list(Cs2), Prop} |
make_write_table_properties(Tab, Props, Cs2)];
make_write_table_properties(_Tab, [], _Cs) ->
[].
@@ -1740,7 +1755,7 @@ make_delete_table_properties(Tab, [PropKey | PropKeys], Cs) ->
Props = lists:keydelete(PropKey, 1, OldProps),
Cs2 = Cs#cstruct{user_properties = Props},
verify_cstruct(Cs2),
- [{op, delete_property, cs2list(Cs2), PropKey} |
+ [{op, delete_property, vsn_cs2list(Cs2), PropKey} |
make_delete_table_properties(Tab, PropKeys, Cs2)];
make_delete_table_properties(_Tab, [], _Cs) ->
[].
@@ -2166,12 +2181,17 @@ receive_sync(Nodes, Pids) ->
{abort, Else}
end.
-lock_del_table(Tab, Node, Cs, Father) ->
+lock_del_table(Tab, NewNode, Cs0, Father) ->
Ns = val({schema, active_replicas}),
process_flag(trap_exit,true),
Lock = fun() ->
mnesia:write_lock_table(Tab),
- {Res, []} = rpc:multicall(Ns, ?MODULE, set_where_to_read, [Tab, Node, Cs]),
+ %% Sigh using cs record
+ Set = fun(Node) ->
+ [Cs] = normalize_cs([Cs0], Node),
+ rpc:call(Node, ?MODULE, set_where_to_read, [Tab, NewNode, Cs])
+ end,
+ Res = [Set(Node) || Node <- Ns],
Filter = fun(ok) ->
false;
({badrpc, {'EXIT', {undef, _}}}) ->
@@ -2353,11 +2373,12 @@ undo_prepare_op(Tid, {op, add_table_copy, Storage, Node, TabDef}) ->
undo_prepare_op(_Tid, {op, del_table_copy, _, Node, TabDef})
when Node == node() ->
+ WriteLocker = get(mnesia_lock),
+ WriteLocker =/= undefined andalso (WriteLocker ! die),
Cs = list2cs(TabDef),
Tab = Cs#cstruct.name,
mnesia_lib:set({Tab, where_to_read}, Node);
-
undo_prepare_op(_Tid, {op, change_table_copy_type, N, FromS, ToS, TabDef})
when N == node() ->
Cs = list2cs(TabDef),
@@ -2829,6 +2850,9 @@ fetch_cstructs(Node) ->
rpc:call(Node, mnesia_controller, get_remote_cstructs, [])
end.
+need_old_cstructs() ->
+ need_old_cstructs(val({schema, where_to_write})).
+
need_old_cstructs(Nodes) ->
Filter = fun(Node) -> not mnesia_monitor:needs_protocol_conversion(Node) end,
case lists:dropwhile(Filter, Nodes) of
diff --git a/lib/mnesia/test/mnesia_evil_backup.erl b/lib/mnesia/test/mnesia_evil_backup.erl
index 63f4146d98..9e0a8db1ae 100644
--- a/lib/mnesia/test/mnesia_evil_backup.erl
+++ b/lib/mnesia/test/mnesia_evil_backup.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1998-2010. All Rights Reserved.
+%% Copyright Ericsson AB 1998-2011. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -244,9 +244,9 @@ restore(Config, Op) ->
[rpc:call(Node, ?MODULE, check_tab, [Res31, ?LINE]) || Node <- Nodes],
%% Restore all tables on it's nodes
- mnesia_schema:clear_table(Tab1),
- mnesia_schema:clear_table(Tab2),
- mnesia_schema:clear_table(Tab3),
+ mnesia:clear_table(Tab1),
+ mnesia:clear_table(Tab2),
+ mnesia:clear_table(Tab3),
[mnesia:dirty_write({Tab1, N, N+1}) || N <- lists:seq(1, 11)],
[mnesia:dirty_write({Tab2, N, N+1}) || N <- lists:seq(1, 11)],
[mnesia:dirty_write({Tab3, N, N+1}) || N <- lists:seq(1, 11)],
diff --git a/lib/mnesia/test/mnesia_evil_coverage_test.erl b/lib/mnesia/test/mnesia_evil_coverage_test.erl
index 668eba176f..c1918071a1 100644
--- a/lib/mnesia/test/mnesia_evil_coverage_test.erl
+++ b/lib/mnesia/test/mnesia_evil_coverage_test.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2010. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2011. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -244,7 +244,7 @@ db_node_lifecycle(Config) when is_list(Config) ->
?match([], mnesia_test_lib:start_mnesia(AllNodes)),
?match([SNs, SNs, SNs],
- lists:map({lists, sort},
+ lists:map(fun lists:sort/1,
element(1, rpc:multicall(AllNodes, mnesia, table_info,
[schema, disc_copies])))),
@@ -259,7 +259,7 @@ db_node_lifecycle(Config) when is_list(Config) ->
mnesia:change_table_copy_type(schema, Node2, disc_copies)),
?match([SNs, SNs, SNs],
- lists:map({lists, sort},
+ lists:map(fun lists:sort/1,
element(1, rpc:multicall(AllNodes, mnesia, table_info,
[schema, disc_copies])))),
@@ -1795,7 +1795,7 @@ subscribe_extended(Config) when is_list(Config) ->
?match({mnesia_table_event, {delete, schema, {schema, Tab1}, [{schema, Tab1, _}],_}}, recv_event()),
?match({mnesia_table_event, {write, schema, {schema, Tab1, _}, [], _}}, recv_event()),
- ?match({atomic, ok}, mnesia_schema:clear_table(Tab2)),
+ ?match({atomic, ok}, mnesia:clear_table(Tab2)),
?match({mnesia_table_event, {delete, schema, {schema, Tab2}, [{schema, Tab2, _}],_}},
recv_event()),
?match({mnesia_table_event, {write, schema, {schema, Tab2, _}, [], _}}, recv_event()),
diff --git a/lib/mnesia/test/mnesia_frag_hash_test.erl b/lib/mnesia/test/mnesia_frag_hash_test.erl
new file mode 100644
index 0000000000..095d25e74f
--- /dev/null
+++ b/lib/mnesia/test/mnesia_frag_hash_test.erl
@@ -0,0 +1,94 @@
+-module(mnesia_frag_hash_test).
+
+-export([test/0]).
+
+-define(NUM_FRAGS, 20).
+-define(NUM_KEYS, 10000).
+
+-record(hash_state,
+ {n_fragments,
+ next_n_to_split,
+ n_doubles,
+ function}).
+
+% OLD mnesia_frag_hash:key_to_frag_number/2.
+old_key_to_frag_number(#hash_state{function = phash, next_n_to_split = SplitN, n_doubles = L}, Key) ->
+ P = SplitN,
+ A = erlang:phash(Key, power2(L)),
+ if
+ A < P ->
+ erlang:phash(Key, power2(L + 1));
+ true ->
+ A
+ end;
+old_key_to_frag_number(#hash_state{function = phash2, next_n_to_split = SplitN, n_doubles = L}, Key) ->
+ P = SplitN,
+ A = erlang:phash2(Key, power2(L)) + 1,
+ if
+ A < P ->
+ erlang:phash2(Key, power2(L + 1)) + 1;
+ true ->
+ A
+ end;
+old_key_to_frag_number(OldState, Key) ->
+ State = convert_old_state(OldState),
+ old_key_to_frag_number(State, Key).
+
+
+% NEW mnesia_frag_hash:key_to_frag_number/2.
+new_key_to_frag_number(#hash_state{function = phash, n_fragments = N, n_doubles = L}, Key) ->
+ A = erlang:phash(Key, power2(L + 1)),
+ if
+ A > N ->
+ A - power2(L);
+ true ->
+ A
+ end;
+new_key_to_frag_number(#hash_state{function = phash2, n_fragments = N, n_doubles = L}, Key) ->
+ A = erlang:phash2(Key, power2(L + 1)) + 1,
+ if
+ A > N ->
+ A - power2(L);
+ true ->
+ A
+ end;
+new_key_to_frag_number(OldState, Key) ->
+ State = convert_old_state(OldState),
+ new_key_to_frag_number(State, Key).
+
+
+% Helpers for key_to_frag_number functions.
+
+power2(Y) ->
+ 1 bsl Y. % trunc(math:pow(2, Y)).
+
+convert_old_state({hash_state, N, P, L}) ->
+ #hash_state{n_fragments = N,
+ next_n_to_split = P,
+ n_doubles = L,
+ function = phash}.
+
+
+test() ->
+ test2(mnesia_frag_hash:init_state(undefined, undefined)), % phash2
+ test2({hash_state, 1, 1, 0}). % phash
+
+test2(I) ->
+ test_keys(I),
+ lists:foldl(
+ fun(_, S) -> test_frag(S) end,
+ I, lists:seq(1, ?NUM_FRAGS)),
+ ok.
+
+test_frag(State) ->
+ {State2,_,_} = mnesia_frag_hash:add_frag(State),
+ test_keys(State2),
+ State2.
+
+test_keys(State) ->
+ [test_key(State, Key) || Key <- lists:seq(1, ?NUM_KEYS)].
+
+test_key(State, Key) ->
+ Old = old_key_to_frag_number(State, Key),
+ New = new_key_to_frag_number(State, Key),
+ Old = New.
diff --git a/lib/mnesia/test/mnesia_install_test.erl b/lib/mnesia/test/mnesia_install_test.erl
index 5d55fcac0e..3a2d44aa95 100644
--- a/lib/mnesia/test/mnesia_install_test.erl
+++ b/lib/mnesia/test/mnesia_install_test.erl
@@ -205,7 +205,7 @@ silly_upgrade(Config) when is_list(Config) ->
?match(ok, mnesia:install_fallback(Bup2)),
file:delete(Bup2),
%% Will generate intentional crash, fatal error
- ?match([], mnesia_test_lib:stop_mnesia([Node2])),
+ ?match([], mnesia_test_lib:stop_mnesia([Node2])),
wait_till_dead([Node1, Node2]),
?match([], mnesia_test_lib:start_mnesia([Node1, Node2], [Tab1, Tab2])),
?match(match, verify_state(Tab1, Tab2, CpState)),
@@ -213,22 +213,29 @@ silly_upgrade(Config) when is_list(Config) ->
?match(ok, mnesia:install_fallback(Bup)),
file:delete(Bup),
%% Will generate intentional crash, fatal error
- ?match([], mnesia_test_lib:stop_mnesia([Node1, Node2])),
+ ?match([], mnesia_test_lib:stop_mnesia([Node1, Node2])),
wait_till_dead([Node1, Node2]),
?match([], mnesia_test_lib:start_mnesia([Node1, Node2], [Tab1, Tab2])),
CpState2 = [X || X <- CpState, element(1, X) /= Tab1],
?match(match, verify_state(Tab1, Tab2, CpState2)),
?verify_mnesia(Nodes, []).
-wait_till_dead([]) -> ok;
-wait_till_dead([N|Ns]) ->
+wait_till_dead([]) ->
+ ok; %% timer:sleep(5);
+wait_till_dead(Repeat = [N|Ns]) ->
Apps = rpc:call(N, application, which_applications, []),
case lists:keymember(mnesia, 1, Apps) of
- true ->
+ true ->
timer:sleep(10),
- wait_till_dead([N|Ns]);
- false ->
- wait_till_dead(Ns)
+ wait_till_dead(Repeat);
+ false ->
+ case rpc:call(N, erlang, whereis, [mnesia_monitor]) of
+ undefined ->
+ wait_till_dead(Ns);
+ _ ->
+ timer:sleep(10),
+ wait_till_dead(Repeat)
+ end
end.
add_some_records(Tab1, Tab2, Old) ->
diff --git a/lib/mnesia/vsn.mk b/lib/mnesia/vsn.mk
index a21ab007ef..ebf79dd2ae 100644
--- a/lib/mnesia/vsn.mk
+++ b/lib/mnesia/vsn.mk
@@ -1 +1 @@
-MNESIA_VSN = 4.5
+MNESIA_VSN = 4.5.1
diff --git a/lib/observer/doc/src/make.dep b/lib/observer/doc/src/make.dep
deleted file mode 100644
index 3c1b3df771..0000000000
--- a/lib/observer/doc/src/make.dep
+++ /dev/null
@@ -1,29 +0,0 @@
-# ----------------------------------------------------
-# >>>> Do not edit this file <<<<
-# This file was automaticly generated by
-# /home/otp/bin/docdepend
-# ----------------------------------------------------
-
-
-# ----------------------------------------------------
-# TeX files that the DVI file depend on
-# ----------------------------------------------------
-
-book.dvi: book.tex crashdump.tex crashdump_ug.tex etop.tex \
- etop_ug.tex observer_app.tex part.tex ref_man.tex \
- ttb.tex ttb_ug.tex
-
-# ----------------------------------------------------
-# Source inlined when transforming from source to LaTeX
-# ----------------------------------------------------
-
-book.tex: ref_man.xml
-
-# ----------------------------------------------------
-# Pictures that the DVI file depend on
-# ----------------------------------------------------
-
-book.dvi: etop_5.ps etop_lines.ps etop_main.ps etop_opt.ps
-
-book.dvi: et_modsprocs.ps et_processes.ps
-
diff --git a/lib/observer/doc/src/ttb.xml b/lib/observer/doc/src/ttb.xml
index 2c80891925..4e63aecbf2 100644
--- a/lib/observer/doc/src/ttb.xml
+++ b/lib/observer/doc/src/ttb.xml
@@ -25,11 +25,12 @@
<title>ttb</title>
<prepared>Siri hansen</prepared>
+ <prepared>Bartlomiej Puzon</prepared>
<responsible></responsible>
<docno>1</docno>
<approved></approved>
<checked></checked>
- <date>2002-02-25</date>
+ <date>2010-08-13</date>
<rev>PA1</rev>
<file>ttb.sgml</file>
</header>
@@ -43,6 +44,35 @@
</description>
<funcs>
<func>
+ <name>start_trace(Nodes, Patterns, FlagSpec, Opts) -> Result</name>
+ <fsummary>Start a trace port on each given node.</fsummary>
+ <type>
+ <v>Result = see p/2</v>
+ <v>Nodes = see tracer/2</v>
+ <v>Patterns = [tuple()]</v>
+ <v>FlagSpec = {Procs, Flags}</v>
+ <v>Proc = see p/2</v>
+ <v>Flags = see p/2</v>
+ <v>Opts = see tracer/2</v>
+ </type>
+ <desc>
+ <p>This function is a shortcut allowing to start a trace with one command. Each
+ tuple in <c>Patterns</c> is converted to list which is in turn passed to
+ <c>ttb:tpl</c>.
+ The call:<code type="none">
+ttb:start_trace([Node, OtherNode],
+[{mod, foo, []}, {mod, bar, 2}],
+{all, call},
+[{file, File}, {handler,{fun myhandler/4, S}}])</code>
+ is equivalent to <code type="none">
+ttb:start_trace([Node, OtherNode], [{file, File}, {handler,{fun myhandler/4, S}}]),
+ttb:tpl(mod, foo, []),
+ttb:tpl(mod, bar, 2, []),
+ttb:p(all, call)</code>
+ </p>
+ </desc>
+ </func>
+ <func>
<name>tracer() -> Result</name>
<fsummary>This is equivalent to tracer(node()).</fsummary>
<desc>
@@ -50,6 +80,17 @@
</desc>
</func>
<func>
+ <name>tracer(Shortcut) -> Result</name>
+ <fsummary>Handy shortcuts for common tracing settings</fsummary>
+ <type>
+ <v>Shortcut = shell | dbg</v>
+ </type>
+ <desc>
+ <p><c>shell</c> is equivalent to <c>tracer(node(),[{file, {local, "ttb"}}, shell])</c>.</p>
+ <p><c>dbg</c> is equivalent to <c>tracer(node(),[{shell, only}])</c>.</p>
+ </desc>
+ </func>
+ <func>
<name>tracer(Nodes) -> Result</name>
<fsummary>This is equivalent to tracer(Nodes,[]).</fsummary>
<desc>
@@ -62,14 +103,21 @@
<type>
<v>Result = {ok, ActivatedNodes} | {error,Reason}</v>
<v>Nodes = atom() | [atom()] | all | existing | new</v>
- <v>Opts = [Opt]</v>
- <v>Opt = {file,Client} | {handler, FormatHandler} | {process_info,PI}</v>
+ <v>Opts = Opt | [Opt]</v>
+ <v>Opt = {file,Client} | {handler, FormatHandler} | {process_info,PI} |
+ shell | {shell, ShellSpec} | {timer, TimerSpec} | {overload, {MSec, Module, Function}}
+ | {flush, MSec} | resume | {resume, FetchTimeout}</v>
+ <v>TimerSpec = MSec | {MSec, StopOpts}</v>
+ <v>MSec = FetchTimeout = integer()</v>
+ <v>Module = Function = atom() </v>
+ <v>StopOpts = see stop/2</v>
<v>Client = File | {local, File}</v>
<v>File = Filename | Wrap</v>
<v>Filename = string()</v>
<v>Wrap = {wrap,Filename} | {wrap,Filename,Size,Count}</v>
<v>FormatHandler = See format/2</v>
<v>PI = true | false </v>
+ <v>ShellSpec = true | false | only</v>
</type>
<desc>
<p>This function starts a file trace port on all given nodes
@@ -96,7 +144,70 @@
is the process' registered name its globally registered name,
or its initial function. It is possible to turn off this
functionality by setting <c>PI = false</c>.
- </p>
+ </p>
+ <p>The <c>{shell, ShellSpec}</c> option indicates that the trace messages should
+ be printed on the console as they are received by the tracing
+ process. This implies <c>{local, File}</c> trace client. If the ShellSpec
+ is <c>only</c> (instead of <c>true</c>), no trace logs are stored.
+ </p>
+ <p>The <c>shell</c> option is a shortcut for <c>{shell, true}</c>.</p>
+ <p>The <c>timer</c> option indicates that the trace should be
+ automatically stopped after <c>MSec</c> milliseconds. <c>StopOpts</c>
+ are passed to <c>ttb:stop/2</c> command if specified (default is <c>[]</c>).
+ Note that the timing is approximate, as delays related to
+ network communication are always present. The timer starts after
+ <c>ttb:p/2</c> is issued, so you can set up your trace patterns before.
+ </p>
+ <p>The <c>overload</c> option allows to enable overload
+ checking on the nodes under trace. <c>Module:Function(check)</c>
+ is performed each <c>MSec</c> milliseconds. If the check returns
+ <c>true</c>, the tracing is disabled on a given node.<br/>
+ <c>Module:Function</c> should be able to handle at least three
+ atoms: <c>init</c>, <c>check</c> and <c>stop</c>. <c>init</c> and
+ <c>stop</c> give the user a possibility to initialize and clean
+ up the check environment.<br/>
+ When a node gets overloaded, it is not possible to issue <c>ttb:p</c>
+ nor any command from the <c>ttb:tp</c> family, as it would lead to
+ inconsistent tracing state (different trace specifications on
+ different node).
+ </p>
+ <p>The <c>flush</c> option periodically flushes all file trace
+ port clients (see <c>dbg:flush_trace_port/1</c>). When enabled,
+ the buffers are freed each <c>MSec</c> milliseconds. This option is
+ not allowed with <c>{file, {local, File}}</c> tracing.
+ </p>
+ <p><c>{resume, FetchTimeout}</c> enables the autoresume feature.
+ Whenever enabled, remote nodes try to reconnect to the controlling node
+ in case they were restarted. The feature requires <c>runtime_tools</c>
+ application to be started (so it has to be present in the <c>.boot</c>
+ scripts if the traced nodes run with embedded erlang). If this is
+ not possible, resume may be performed manually by starting
+ <c>runtime_tools</c> remotely using <c>rpc:call/4</c>.<br/>
+ <c>ttb</c> tries to fetch all logs from a reconnecting node before
+ reinitializing the trace. This has to finish within FetchTimeout milliseconds
+ or is aborted<br/>
+ By default, autostart information is stored in a file called
+ <c>ttb_autostart.bin</c> on each node. If this is not desired
+ (i.e. on diskless nodes), a custom module to handle autostart
+ information storage and retrieval can be provided by specifying
+ <c>ttb_autostart_module</c> environment variable for the <c>runtime_tools</c>
+ application. The module has to respond to the following API:
+ <taglist>
+ <tag><c>write_config(Data) -> ok</c></tag>
+ <item>Store the provided data for further retrieval. It is
+ important to realize that the data storage used must not
+ be affected by the node crash.</item>
+ <tag><c>read_config() -> {ok, Data} | {error, Error}</c></tag>
+ <item>Retrieve configuration stored with <c>write_config(Data)</c>.</item>
+ <tag><c>delete_config() -> ok</c></tag>
+ <item>Delete configuration stored with <c>write_config(Data)</c>.
+ Note that after this call any subsequent calls to <c>read_config</c>
+ must return <c>{error, Error}</c>.
+ </item>
+ </taglist>
+ </p>
+ <p>The <c>resume</c> option implies the default <c>FetchTimeout</c>, which is
+ 10 seconds</p>
</desc>
</func>
<func>
@@ -110,7 +221,7 @@
</type>
<desc>
<p>This function sets the given trace flags on the given
- processes.
+ processes. The <c>timestamp</c> flag is always turned on.
</p>
<p>Please turn to the Reference manual for module <c>dbg</c>
for details about the possible trace flags. The parameter
@@ -119,6 +230,9 @@
registered names or process identifiers. If a registered name
is given, the flags are set on processes with this name on all
active nodes.</p>
+ <p>Issuing this command starts the timer for this trace if
+ <c>timer</c> option was specified with <c>tracer/2</c>.
+ </p>
</desc>
</func>
<func>
@@ -155,6 +269,18 @@
<tag><c>ctpg</c></tag>
<item>Clear trace pattern on global function calls</item>
</taglist>
+ <p>With <c>tp</c> and <c>tpl</c> one of match specification shortcuts
+ may be used (example: <c>ttb:tp(foo_module, caller)</c>). The shortcuts are:
+ <taglist>
+ <item><c>return</c> - for <c>[{'_',[],[{return_trace}]}]</c>
+ (report the return value)</item>
+ <item><c>caller</c> - for <c>[{'_',[],[{message,{caller}}]}]</c>
+ (report the calling function)</item>
+ <item><c>{codestr, Str}</c> - for <c>dbg:fun2ms/1</c> arguments
+ passed as strings (example: <c>"fun(_) -> return_trace() end"</c>)
+ </item>
+ </taglist>
+ </p>
</desc>
</func>
<func>
@@ -189,7 +315,7 @@
</desc>
</func>
<func>
- <name>write_config(ConfigFile,Config,Opt) -> ok | {error,Reason}</name>
+ <name>write_config(ConfigFile,Config,Opts) -> ok | {error,Reason}</name>
<fsummary>Creates a config file.</fsummary>
<type>
<v>ConfigFile = string()</v>
@@ -197,7 +323,8 @@
<v>Mod = atom()</v>
<v>Func = atom()</v>
<v>Args = [term()]</v>
- <v>Opt = [] | [append]</v>
+ <v>Opts = Opt | [Opt]</v>
+ <v>Opt = append</v>
</type>
<desc>
<p>This function creates or extends a config file which can be
@@ -213,9 +340,9 @@
should be a list of integers pointing out the entries to be
stored.
</p>
- <p>If <c>Opt</c> is not given or if it is <c>[]</c>,
+ <p>If <c>Opts</c> is not given or if it is <c>[]</c>,
<c>ConfigFile</c> is deleted and a new file is created. If
- <c>Opt = [append]</c>, <c>ConfigFile</c> will not be deleted.
+ <c>Opts = [append]</c>, <c>ConfigFile</c> will not be deleted.
The new information will be appended at the end of the file.</p>
</desc>
</func>
@@ -226,7 +353,9 @@
<v>ConfigFile = string()</v>
</type>
<desc>
- <p>Executes all entries in the given config file.</p>
+ <p>Executes all entries in the given config file. Note that the history
+ of the last trace is always available in the file named
+ <c>ttb_last_config</c>.</p>
</desc>
</func>
<func>
@@ -243,6 +372,9 @@
</p>
<p>The content of a config file can be listed with
<c>list_config/1</c>.</p>
+ <p> Note that the history
+ of the last trace is always available in the file named
+ <c>ttb_last_config</c>.</p>
</desc>
</func>
<func>
@@ -334,29 +466,51 @@
</desc>
</func>
<func>
- <name>stop(Opts) -> stopped</name>
+ <name>stop(Opts) -> stopped | {stopped, Dir}</name>
<fsummary>Stop tracing and fetch/format logs from all nodes</fsummary>
<type>
- <v>Opts = [Opt]</v>
- <v>Opt = fetch | format</v>
+ <v>Opts = Opt | [Opt]</v>
+ <v>Opt = nofetch | {fetch_dir, Dir} | format | {format, FormatOpts} | return_fetch_dir</v>
+ <v>Dir = string()</v>
+ <v>FormatOpts = see format/2</v>
</type>
<desc>
- <p>Stops tracing on all nodes.
- </p>
- <p>The <c>fetch</c> option indicates that trace logs shall be
- collected from all nodes after tracing is stopped. This option
- is useful if nodes on remote machines are traced. Logs and
- trace information files are then sent to the trace control
+ <p>Stops tracing on all nodes. Logs and
+ trace information files are sent to the trace control
node and stored in a directory named
- <c>ttb_upload-Timestamp</c>, where <c>Timestamp</c> is on the
+ <c>ttb_upload_FileName-Timestamp</c>, where <c>Filename</c> is
+ the one provided with <c>{file, File}</c> during trace setup
+ and <c>Timestamp</c> is of the
form <c>yyyymmdd-hhmmss</c>. Even logs from nodes on the same
machine as the trace control node are moved to this directory.
- </p>
+ The history list is saved to a file named <c>ttb_last_config</c>
+ for further reference (as it will be not longer accessible
+ through history and configuration management functions (like
+ <c>ttb:list_history/0</c>).
+ </p>
+ <p>The <c>nofetch</c> option indicates that trace logs shall not be
+ collected after tracing is stopped.
+ </p>
+ <p>The <c>{fetch, Dir}</c> option allows to specify the directory
+ to fetch the data to. If the directory already exists, an
+ error is thrown.
+ </p>
<p>The <c>format</c> option indicates that the trace logs
- shall be formatted after tracing is stopped. Note that this
- option also implies the <c>fetch</c> option, i.e. logs are
- collected in a new directory on the trace control node before
- formatting. All logs in the directory will be merged.</p>
+ shall be formatted after tracing is stopped. All logs in the fetch directory will be merged.
+ You may use <c>{format, FormatOpts}</c> to pass additional
+ arguments to <c>format/2</c>.</p>
+ <p>The <c>return_fetch_dir</c> option indicates that the return value
+ should be <c>{stopped, Dir}</c> and not just <c>stopped</c>.
+ This implies <c>fetch</c>.
+ </p>
+ </desc>
+ </func>
+ <func>
+ <name>get_et_handler()</name>
+ <fsummary>Returns <c>et</c> handler.</fsummary>
+ <desc>
+ <p>The <c>et</c> handler returned by the function may be used with <c>format/2</c>
+ or <c>tracer/2</c>. Example: <c>ttb:format(Dir, [{handler, ttb:get_et_handler()}])</c>.</p>
</desc>
</func>
<func>
@@ -372,37 +526,40 @@
<type>
<v>File = string() | [string()]</v>
<d>This can be the name of a binary log, a list of such logs or the name of a directory containing one or more binary logs.</d>
- <v>Options = [Opt]</v>
- <v>Opt = {out,Out} | {handler,FormatHandler}</v>
+ <v>Options = Opt | [Opt]</v>
+ <v>Opt = {out,Out} | {handler,FormatHandler} | disable_sort</v>
<v>Out = standard_io | string()</v>
- <v>FormatHandler = {Function, InitialState} | et</v>
+ <v>FormatHandler = {Function, InitialState}</v>
<v>Function = fun(Fd,Trace,TraceInfo,State) -> State</v>
<v>Fd = standard_io | FileDescriptor</v>
<d>This is the file descriptor of the destination file <c>Out</c></d>
<v>Trace = tuple()</v>
<d>This is the trace message. Please turn to the Reference manual for the <c>erlang</c>module for details.</d>
<v>TraceInfo = [{Key,ValueList}]</v>
- <d>This includes the keys <c>flags</c>, <c>client</c>and <c>node</c>, and if <c>handler</c>is given as option to the tracer function, this is also included. In addition all information written with the <c>write_trace_info/2</c>function is included. </d>
+ <d>This includes the keys <c>flags</c>, <c>client</c> and <c>node</c>, and if <c>handler</c> is given as option to the tracer function, this is also included. In addition all information written with the <c>write_trace_info/2</c>function is included. </d>
</type>
<desc>
- <p>Reads the given binary trace log(s). If a directory or a
- list of logs is given and the <c>timestamp</c> flag was set
- during tracing, the trace messages from the different logs are
- merged according to the timestamps.
- </p>
+ <p>Reads the given binary trace log(s). The logs are processed
+ in the order of their timestamp as long as <c>disable_sort</c>
+ option is not given.
+ </p>
<p>If <c>FormatHandler = {Function,InitialState}</c>,
<c>Function</c> will be called for each trace message. If
- <c>FormatHandler = et</c>, <c>et_viewer</c> in the <em>Event Tracer</em> application (<c>et</c>) is used for presenting the
- trace log graphically. <c>ttb</c> provides a few different
+ <c>FormatHandler = get_et_handler()</c>, <c>et_viewer</c> in
+ the <em>Event Tracer</em> application (<c>et</c>) is used for presenting
+ the trace log graphically. <c>ttb</c> provides a few different
filters which can be selected from the Filter menu in the
<c>et_viewer</c>. If <c>FormatHandler</c> is not given, a
default handler is used which presents each trace message as a
line of text.
</p>
+ <p>The state returned from each call of <c>Function</c> is passed to the next call,
+ even if next call is to format a message from another log file.
+ </p>
<p>If <c>Out</c> is given, <c>FormatHandler</c> gets the
- filedescriptor to <c>Out</c> as the first parameter.
+ file descriptor to <c>Out</c> as the first parameter.
</p>
- <p><c>Out</c> is ignored if <c>FormatHandler = et</c>.
+ <p><c>Out</c> is ignored if <c>et</c> format handler is used.
</p>
<p>Wrap logs can be formatted one by one or all in one go. To
format one of the wrap logs in a set, give the exact name of
diff --git a/lib/observer/doc/src/ttb_ug.xml b/lib/observer/doc/src/ttb_ug.xml
index 44b7b08fd3..4f2b55a22a 100644
--- a/lib/observer/doc/src/ttb_ug.xml
+++ b/lib/observer/doc/src/ttb_ug.xml
@@ -4,7 +4,7 @@
<chapter>
<header>
<copyright>
- <year>2002</year><year>2009</year>
+ <year>2002</year><year>2010</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -48,11 +48,13 @@
<item>Formatting of binary trace logs and merging of logs from
multiple nodes.</item>
</list>
- <p>Even though the intention of the Trace Tool Builder is to serve
- as a base for tailor made trace tools, it is of course possible
- to use it directly from the erlang shell. The application only
- allows the use of file port tracer, so if you would like would
- like to use other types of trace clients you will be better off
+ <p>The intention of the Trace Tool Builder is to serve
+ as a base for tailor made trace tools, but you may use it directly
+ from the erlang shell (it may mimic <c>dbg</c> behaviour while
+ still providing useful additions like match specification shortcuts).
+ The application only
+ allows the use of file port tracer, so if you would like
+ to use other types of trace clients you will be better off
using <c>dbg</c> directly instead.</p>
</section>
@@ -64,14 +66,15 @@
trace flags on the processes you want to trace with
<c>ttb:p/2</c>. Then, when the tracing is completed, you must stop
the tracer with <c>ttb:stop/0/1</c> and format the trace log with
- <c>ttb:format/1/2</c>.
+ <c>ttb:format/1/2</c> (as long as there is anything to format, of
+ course).
</p>
- <p><c>ttb:tracer/0/1/2</c> opens a file trace port on each node
- that shall be traced. All trace messages will be written to this
- port and end up in a binary file (the binary trace log).
+ <p><c>ttb:tracer/0/1/2</c> opens a trace port on each node
+ that shall be traced. By default, trace messages are written
+ to binary files on remote nodes(the binary trace log).
</p>
- <p><c>ttb:p/2</c> specifies which processes that shall be
- traced. Trace flags given in this call specifies what to trace on
+ <p><c>ttb:p/2</c> specifies which processes shall be
+ traced. Trace flags given in this call specify what to trace on
each process. You can call this function several times if you like
different trace flags to be set on different processes.
</p>
@@ -105,14 +108,15 @@
-export([f/0]).
f() ->
receive
- From when pid(From) ->
+ From when is_pid(From) ->
Now = erlang:now(),
From ! {self(),Now}
end. </code>
<p>The following example shows the basic use of <c>ttb</c> from
the erlang shell. Default options are used both for starting the
- tracer and for formatting. This gives a trace log named
- <c>Node-ttb</c>, where <c>Node</c> is the name of the node. The
+ tracer and for formatting (the custom fetch dir is however provided).
+ This gives a trace log named <c>Node-ttb</c> in the newly-created
+ directory, where <c>Node</c> is the name of the node. The
default handler prints the formatted trace messages in the
shell.</p>
<code type="none"><![CDATA[
@@ -131,11 +135,11 @@ f() ->
(tiger@durin)50>
(tiger@durin)50> %% Here I set a trace pattern on erlang:now/0
(tiger@durin)50> %% The trace pattern is a simple match spec
-(tiger@durin)50> %% generated by dbg:fun2ms/1. It indicates that
-(tiger@durin)50> %% the return value shall be traced.
-(tiger@durin)50> MS = dbg:fun2ms(fun(_) -> return_trace() end).
-[{'_',[],[{return_trace}]}]
-(tiger@durin)51> ttb:tp(erlang,now,MS).
+(tiger@durin)50> %% indicating that the return value should be
+(tiger@durin)50> %% traced. Refer to the reference_manual for
+(tiger@durin)50> %% the full list of match spec shortcuts
+(tiger@durin)50> %% available.
+(tiger@durin)51> ttb:tp(erlang,now,return).
{ok,[{matched,tiger@durin,1},{saved,1}]}
(tiger@durin)52>
(tiger@durin)52> %% I run my test (i.e. send a message to
@@ -145,11 +149,11 @@ f() ->
(tiger@durin)53>
(tiger@durin)53> %% And then I have to stop ttb in order to flush
(tiger@durin)53> %% the trace port buffer
-(tiger@durin)53> ttb:stop().
-stopped
+(tiger@durin)53> ttb:stop([return, {fetch_dir, "fetch"}]).
+{stopped, "fetch"}
(tiger@durin)54>
(tiger@durin)54> %% Finally I format my trace log
-(tiger@durin)54> ttb:format("tiger@durin-ttb").
+(tiger@durin)54> ttb:format("fetch").
({<0.125.0>,{m,f,0},tiger@durin}) call erlang:now()
({<0.125.0>,{m,f,0},tiger@durin}) returned from erlang:now/0 ->
{1031,133451,667611}
@@ -166,11 +170,9 @@ ok ]]></code>
-module(mydebug).
-export([start/0,trc/1,stop/0,format/1]).
-export([print/4]).
-
%% Include ms_transform.hrl so that I can use dbg:fun2ms/2 to
%% generate match specifications.
-include_lib("stdlib/include/ms_transform.hrl").
-
%%% -------------Tool API-------------
%%% ----------------------------------
%%% Star the "mydebug" tool
@@ -180,28 +182,28 @@ start() ->
%% module shall be used as format handler
ttb:tracer(all,[{file,"debug_log"},{handler,{{?MODULE,print},0}}]),
%% All processes (existing and new) shall trace function calls
- %% and include a timestamp in each trace message
- ttb:p(all,[call,timestamp]).
+ %% We want trace messages to be sorted upon format, which requires
+ %% timestamp flag. The flag is however enabled by default in ttb.
+ ttb:p(all,call).
%%% Set trace pattern on function(s)
-trc(M) when atom(M) ->
+trc(M) when is_atom(M) ->
trc({M,'_','_'});
-trc({M,F}) when atom(M), atom(F) ->
+trc({M,F}) when is_atom(M), is_atom(F) ->
trc({M,F,'_'});
-trc({M,F,_A}=MFA) when atom(M), atom(F) ->
- %% This match spec specifies that return values shall
- %% be traced. NOTE that ms_transform.hrl must be included
- %% if dbg:fun2ms/1 shall be used!
+trc({M,F,_A}=MFA) when is_atom(M), is_atom(F) ->
+ %% This match spec shortcut specifies that return values shall
+ %% be traced.
MatchSpec = dbg:fun2ms(fun(_) -> return_trace() end),
ttb:tpl(MFA,MatchSpec).
%%% Format a binary trace log
-format(File) ->
- ttb:format(File).
+format(Dir) ->
+ ttb:format(Dir).
%%% Stop the "mydebug" tool
stop() ->
- ttb:stop().
+ ttb:stop(return).
%%% --------Internal functions--------
%%% ----------------------------------
@@ -226,9 +228,9 @@ do_print(Out,{trace_ts,P,return_from,{M,F,A},R,Ts},N) ->
[N,Ts,P,M,F,A,R]). ]]></code>
<p>To distinguish trace logs produced with this tool from other
logs, the <c>file</c> option is used in <c>tracer/2</c>. The
- logs will therefore be named <c>Node-debug_log</c>, where
- <c>Node</c> is the name of the node where the log is produced.
- </p>
+ logs will therefore be fetched to a directory named
+ <c>ttb_upload_debug_log-YYYYMMDD-HHMMSS</c>
+ </p>
<p>By using the <c>handler</c> option when starting the tracer,
the information about how to format the file is stored in the
trace information file (<c>.ti</c>). This is not necessary, as
@@ -278,13 +280,157 @@ do_print(Out,{trace_ts,P,return_from,{M,F,A},R,Ts},N) ->
must be given to the <c>tracer/2</c> function with the value
<c>{local, File}</c>, e.g.</p>
<code type="none">
-(trace_control@durin)1> ttb:tracer(mynode@diskless,[{file,{local,
-{wrap,"mytrace"}}}]).
+(trace_control@durin)1> ttb:tracer(mynode@diskless,{file,{local,
+{wrap,"mytrace"}}}).
{ok,[mynode@diskless]} </code>
</section>
</section>
<section>
+ <title>Additional tracing options</title>
+ <p>When setting up a trace, several features may be turned on:</p>
+ <list type="bulleted">
+ <item>time-constrained tracing,</item>
+ <item>overload protection,</item>
+ <item>autoresuming.</item>
+ </list>
+ <section>
+ <title>Time-constrained tracing</title>
+ <p>Sometimes, it may be helpful to enable trace for a
+ given period of time (i.e. to monitor a system for 24 hours
+ or half of a second). This may be done by issuing additional
+ <c>{timer, TimerSpec}</c> option. If <c>TimerSpec</c> has the
+ form of <c>MSec</c>, the trace is stopped after <c>MSec</c>
+ milliseconds using <c>ttb:stop/0</c>. If any additional options
+ are provided (<c>TimerSpec = {MSec, Opts}</c>), <c>ttb:stop/1</c>
+ is called instead with <c>Opts</c> as the arguments. The timer
+ is started with <c>ttb:p/2</c>, so any trace patterns should
+ be set up before. <c>ttb:start_trace/4</c>
+ always sets up all pattern before invoking <c>ttb:p/2</c>.
+ Note that due to network and processing delays the the period
+ of tracing is approximate.
+ The example below shows how to set up a trace which will be
+ automatically stopped and formatted after 5 seconds
+ </p><code>
+(tiger@durin)1>ttb:start_trace([node()],
+ [{erlang, now,[]}],
+ {all, call},
+ [{timer, {5000, format}}]).
+</code>
+ </section>
+ <section>
+ <label>Overload protection</label>
+ <p>When tracing live systems, special care needs to be always taken
+ not to overload a node with too heavy tracing. <c>ttb</c> provides
+ the <c>overload</c> option to help to address the problem.</p>
+ <p><c>{overload, MSec, Module, Function}</c> instructs the ttb backend
+ (called <c>observer_backend</c>, part of the <c>runtime_tools</c>
+ application) to perform overload check every <c>MSec</c> milliseconds.
+ If the check (namely <c>Module:Function(check)</c>) returns
+ <c>true</c>, tracing is disabled on the selected node.</p>
+ <p>Overload protection activated on one node does not
+ affect other nodes, where the tracing continues as normal.
+ <c>ttb:stop/0/1</c> fetches data from all clients, including everything
+ that has been collected before overload protection was activated.
+ Note that
+ changing trace details (with <c>ttb:p</c> and <c>ttb:tp/tpl...</c>)
+ once overload protection gets activated in one of the traced
+ nodes is not permitted in order not to allow trace setup
+ to be inconsistent between nodes.
+ </p>
+ <p><c>Module:Function</c> provided with the <c>overload</c> option must
+ handle three calls: <c>init</c>, <c>check</c> and <c>stop</c>. <c>init</c>
+ and <c>stop</c> allows to perform some setup and teardown required by
+ the check. An overload check module could look like this (note that
+ <c>check</c> is always called by the same process, so <c>put</c> and
+ <c>get</c> are possible).
+ </p><code>
+-module(overload).
+-export([check/1]).
+
+check(init) ->
+ Pid = sophisticated_module:start(),
+ put(pid, Pid);
+check(check) ->
+ get(pid) ! is_overloaded,
+ receive
+ Reply ->
+ Reply
+ after 5000 ->
+ true
+ end;
+check(stop) ->
+ get(pid) ! stop.</code>
+ </section>
+ <section>
+ <title>Autoresume</title>
+ <p>It is possible that a node (probably a buggy one, hence traced)
+ crashes. In order to automatically resume tracing on the node
+ as soon as it gets back, <c>resume</c> has to be used. When
+ it is, the failing node tries to reconnect
+ to trace control node as soon as <c>runtime tools</c> is started.
+ This implies that <c>runtime_tools</c> must be included in
+ other node's startup chain (if it is not, one could still
+ resume tracing by starting <c>runtime_tools</c> manually,
+ i.e. by an RPC call).</p>
+ <p>In order not to loose the data that the failing node stored
+ up to the point of crash, the control node will try to fetch
+ it before restarting trace. This must happen within the allowed
+ time frame or is aborted (default is 10 seconds, can be customized with
+ <c>{resume, MSec}</c>). The data fetched this way is then
+ merged with all other traces.</p>
+ <p>Autostart feature requires additional data to be stored on
+ traced nodes. By default, the data is stored automatically
+ to the file called "ttb_autostart.bin" in the traced node's cwd.
+ Users may decide to change this behaviour (i.e. on diskless
+ nodes) by specifying their own module to handle autostart data
+ storage and retrieval (<c>ttb_autostart_module</c>
+ environment variable of <c>runtime_tools</c>). Please see the
+ ttb's reference manual to see the module's API. This example
+ shows the default handler</p>
+ <code>
+-module(ttb_autostart).
+-export([read_config/0,
+ write_config/1,
+ delete_config/0]).
+
+-define(AUTOSTART_FILENAME, "ttb_autostart.bin").
+
+delete_config() ->
+ file:delete(?AUTOSTART_FILENAME).
+
+read_config() ->
+ case file:read_file(?AUTOSTART_FILENAME) of
+ {ok, Data} -> {ok, binary_to_term(Data)};
+ Error -> Error
+ end.
+
+write_config(Data) ->
+ file:write_file(?AUTOSTART_FILENAME, term_to_binary(Data)).
+ </code>
+ <p>Remember that file trace ports buffer the data
+ by default. If the node crashes, trace messages are not
+ flushed to the binary log. If the chance of failure is
+ high, it might be a good idea to automatically flush
+ the buffers every now and then. Passing <c>{flush, MSec}</c>
+ as one of <c>ttb:tracer/2</c> option flushes all buffers
+ every <c>MSec</c> milliseconds.</p>
+ </section>
+ <section>
+ <title>dbg mode</title>
+ <p>The <c>{shell, ShellType}</c> option allows to make <c>ttb</c>
+ operation similar to <c>dbg</c>. Using <c>{shell, true}</c>
+ displays all trace messages in the shell before storing them.
+ <c>{shell, only}</c> additionally disables message storage
+ (so that the tool behaves exactly like dbg). This is allowed
+ only with ip trace ports (<c>{trace, {local, File}}</c>).
+ </p>
+ <p>The command <c>ttb:tracer(dbg)</c> is a shortcut for the pure-dbg
+ mode (<c>{shell, only}</c>).</p>
+ </section>
+ </section>
+
+ <section>
<marker id="trace_info"></marker>
<title>Trace Information and the .ti File</title>
<p>In addition to the trace log file(s), a file with the extension
@@ -292,13 +438,9 @@ do_print(Out,{trace_ts,P,return_from,{M,F,A},R,Ts},N) ->
is the trace information file. It is a binary file, and it
contains the process information, trace flags used, the name of
the node to which it belongs and all information written with the
- <c>write_trace_info/2</c> function.
- </p>
- <p>To be able to use all this information during formatting, it is
- important that the trace information file exists in the same
- directory as the trace log, and that it has the same name as the
- trace log with the additional extension <c>.ti</c>.
- </p>
+ <c>write_trace_info/2</c> function. .ti files are always fetched
+ with other logs when the trace is stopped.
+ </p>
<p>Except for the process information, everything in the trace
information file is passed on to the handler function when
formatting. The <c>TI</c> parameter is a list of
@@ -327,7 +469,12 @@ do_print(Out,{trace_ts,P,return_from,{M,F,A},R,Ts},N) ->
each log. <c>ttb</c> will create a new binary log each time a log
reaches the maximum size. When the the maximum number of logs are
reached, the oldest log is deleted before a new one is created.
- </p>
+ </p>
+ <p>Note that the overall size of data generated by ttb may be greater
+ than the wrap specification would suggest - if a traced node restarts
+ and autoresume is enabled, old wrap log is always stored and
+ a new one is created.
+ </p>
<p>Wrap logs can be formatted one by one or all at once. See
<seealso marker="#format">Formatting</seealso>.
</p>
@@ -348,12 +495,10 @@ do_print(Out,{trace_ts,P,return_from,{M,F,A},R,Ts},N) ->
present the trace log graphically (see <seealso marker="#et_viewer">Presenting trace logs with Event Tracer</seealso>).
</p>
<p>The first argument to <c>ttb:format/1/2</c> specifies which
- binary log(s) to format. This can be the name of one binary log, a
- list of such logs or the name of a directory containing one or
- more binary logs. If this argument indicates more than one log,
- and the <c>timestamp</c> flag was set when tracing, the trace
- messages from the different logs will be merged according to the
- timestamps in each message.
+ binary log(s) to format. This is usually the name of a directory
+ that ttb created during log fetch. Unless there is the <c>disable_sort</c>
+ option provided, the logs from different files are always sorted
+ according to timestamp in traces.
</p>
<p>The second argument to <c>ttb:format/2</c> is a list of
options. The <c>out</c> option specifies the destination where the
@@ -363,7 +508,10 @@ do_print(Out,{trace_ts,P,return_from,{M,F,A},R,Ts},N) ->
option is not given, the <c>handler</c> option given when starting
the tracer is used. If the <c>handler</c> option was not given
when starting the tracer either, a default handler is used, which
- prints each trace message as a line of text.
+ prints each trace message as a line of text. The <c>disable_sort</c>
+ option indicates that there logs should not be merged according to
+ timestamp, but processed one file after another (this might be
+ a bit faster).
</p>
<p>A format handler is a fun taking four arguments. This fun will
be called for each trace message in the binary log(s). A simple
@@ -396,10 +544,24 @@ end </code>
<c>handle_gc/4</c> in the module <c>multitrace.erl</c> which can
be found in the <c>src</c> directory of the Observer application.
</p>
- <p>By giving the format handler <c>et</c>, you can have the trace
+ <p>The actual trace message is passed as the second argument (<c>Trace</c>).
+ The possible values of <c>Trace</c> are:</p>
+ <list type="bulleted">
+ <item>all trace messages described in <c>erlang:trace/3</c> documentation,
+ </item>
+ <item><c>{drop, N}</c> if ip tracer is used (see <c>dbg:trace_port/2</c>),
+ </item>
+ <item><c>end_of_trace</c> received once when all trace messages have
+ been processed.</item>
+ </list>
+ <p>By giving the format handler <c>ttb:get_et_handler()</c>, you can have the trace
log presented graphically with <c>et_viewer</c> in the Event
Tracer application (see <seealso marker="#et_viewer">Presenting trace logs with Event Tracer</seealso>).
- </p>
+ </p>
+ <p>You may always decide not to format the whole trace data contained
+ in the fetch directory, but analyze single files instead. In order
+ to do so, a single file (or list of files) have to be passed as
+ the first argument to <c>format/1/2</c>.</p>
<p>Wrap logs can be formatted one by one or all in one go. To
format one of the wrap logs in a set, give the exact name of the
file. To format the whole set of wrap logs, give the name with '*'
@@ -407,7 +569,7 @@ end </code>
</p>
<p>Start tracing:</p>
<code type="none">
-(tiger@durin)1> ttb:tracer(node(),[{file,{wrap,"trace"}}]).
+(tiger@durin)1> ttb:tracer(node(),{file,{wrap,"trace"}}).
{ok,[tiger@durin]}
(tiger@durin)2> ttb:p(...)
... </code>
@@ -443,7 +605,7 @@ ok
to the User's Guide and Reference Manuals for the <c>et</c>
application.
</p>
- <p>By giving the format handler <c>et</c>, you can have the
+ <p>By giving the format handler <c>ttb:get_et_handler()</c>, you can have the
trace log presented graphically with <c>et_viewer</c> in the
Event Tracer application. <c>ttb</c> provides a few different
filters which can be selected from the Filter menu in the
@@ -495,9 +657,23 @@ ok
filters respectively, except that each module or function can
have several vertical lines, one for each process it resides on.
</p>
- <p>As an example this module is used, and the function
- <c>bar:f1()</c> is called from another module <c>foo</c>.</p>
+ <p>In the next example, modules <c>foo</c> and <c>bar</c> are used:</p>
<code type="none">
+-module(foo).
+-export([start/0,go/0]).
+
+start() ->
+ spawn(?MODULE, go, []).
+
+go() ->
+ receive
+ stop ->
+ ok;
+ go ->
+ bar:f1(),
+ go()
+ end.
+</code><code type="none">
-module(bar).
-export([f1/0,f3/0]).
f1() ->
@@ -506,12 +682,23 @@ f1() ->
f2() ->
spawn(?MODULE,f3,[]).
f3() ->
- ok. </code>
- <p>The <c>call</c> and <c>return_to</c> flags are used, and
- trace pattern is set on local calls in module <c>bar</c>.
- </p>
- <p><c>ttb:format("tiger@durin-ttb", [{handler, et}])</c> gives the
- following result:
+ ok.</code>
+
+ <p>Now let's set up the trace.</p>
+<code>
+(tiger@durin)1>%%First we retrieve the Pid to limit traced processes set
+(tiger@durin)1>Pid = foo:start().
+(tiger@durin)2>%%Now we set up tracing
+(tiger@durin)2>ttb:tracer().
+(tiger@durin)3>ttb:p(Pid, [call, return_to, procs, set_on_spawn]).
+(tiger@durin)4>ttb:tpl(bar, []).
+(tiger@durin)5>%%Invoke our test function and see output with et viewer
+(tiger@durin)5>Pid ! go.
+(tiger@durin)6>ttb:stop({format, {handler, ttb:get_et_handler()}}).
+</code>
+
+ <p>This shoud render a result similar to the
+ following:
</p>
<p></p>
<image file="et_processes.gif">
@@ -520,25 +707,37 @@ f3() ->
<image file="et_modsprocs.gif">
<icaption>Filter: "mods_and_procs"</icaption>
</image>
+
+ <p>Note, that we can use <c>ttb:start_trace/4</c> function to help
+ us here:</p>
+<code>
+(tiger@durin)1>Pid = foo:start().
+(tiger@durin)2>ttb:start_trace([node()],
+ [{bar,[]}],
+ {Pid, [call, return_to, procs, set_on_spawn]}
+ {handler, ttb:get_et_handler()}).
+(tiger@durin)3>Pid ! go.
+(tiger@durin)4>ttb:stop(format).
+</code>
+
</section>
</section>
<section>
<marker id="fetch_format"></marker>
<title>Automatically collect and format logs from all nodes</title>
- <p>If the option <c>fetch</c> is given to the <c>ttb:stop/1</c>
- function, trace logs and trace information files are fetched
- from all nodes after tracing is stopped. The logs are stored in a
- new directory named <c>ttb_upload-Timestamp</c> under the working
- directory of the trace control node.
+ <p>By default <c>ttb:stop/1</c> fetches trace logs and
+ trace information files from all nodes. The logs are stored in a
+ new directory named <c>ttb_upload-Filename-Timestamp</c> under the working
+ directory of the trace control node. Fetching may be disabled by
+ providing the <c>nofetch</c> option to <c>ttb:stop/1</c>. User can
+ specify a fetch directory of his choice passing the
+ <c>{fetch_dir, Dir}</c> option.
</p>
<p>If the option <c>format</c> is given to <c>ttb:stop/1</c>, the
trace logs are automatically formatted after tracing is
- stopped. Note that <c>format</c> also implies <c>fetch</c>,
- i.e. the trace logs will be collected from all nodes as for the
- <c>fetch</c> option before they are formatted. All logs in the
- upload directory are merged during formatting.
- </p>
+ stopped.
+ </p>
</section>
<section>
@@ -546,13 +745,18 @@ f3() ->
<p>For the tracing functionality, <c>dbg</c> could be used instead
of the <c>ttb</c> for setting trace flags on processes and trace
patterns for call trace, i.e. the functions <c>p</c>, <c>tp</c>,
- <c>tpl</c>, <c>ctp</c>, <c>ctpl</c> and <c>ctpg</c>. The only
- thing added by <c>ttb</c> for these functions is that all calls
- are stored in the history buffer and can be recalled and stored in
- a configuration file. This makes it easy to setup the same trace
- environment e.g. if you want to compare two test runs. It also
- reduces the amount of typing when using <c>ttb</c> from the erlang
- shell.
+ <c>tpl</c>, <c>ctp</c>, <c>ctpl</c> and <c>ctpg</c>. There are only
+ two things added by <c>ttb</c> for these functions:
+ <list type="bulleted">
+ <item>all calls are stored in the history buffer and can be
+ recalled and stored in a configuration file. This makes it
+ easy to setup the same trace environment e.g. if you want to
+ compare two test runs. It also reduces the amount of
+ typing when using <c>ttb</c> from the erlang shell;</item>
+ <item>shortcuts are provided for the most common match
+ specifications (in order not to force the user to use
+ <c>dbg:fun2ms</c> continually</item>).
+ </list>
</p>
<p>Use <c>list_history/0</c> to see the content of the history
buffer, and <c>run_history/1</c> to re-execute one of the entries.
@@ -574,7 +778,8 @@ f3() ->
selected entries from the history by calling
<c>ttb:write_config(ConfigFile,NumList)</c>, where
<c>NumList</c> is a list of integers pointing out the history
- entries to write.
+ entries to write. Moreover, the history buffer is always dumped
+ to <c>ttb_last_config</c> when <c>ttb:stop/0/1</c> is called.
</p>
<p>User defined entries can also be written to a config file by
calling the function
@@ -720,9 +925,7 @@ ok
{ok,[{matched,1},{saved,1}]}
(tiger@durin)113> dbg:get_tracer(), seq_trace:reset_trace().
true
-(tiger@durin)114> ttb:stop().
-ok
-(tiger@durin)115> ttb:format("tiger@durin-ttb").
+(tiger@durin)114> ttb:stop(format).
({<0.158.0>,{shell,evaluator,3},tiger@durin}) call dbg:get_tracer()
SeqTrace [0]: ({<0.158.0>,{shell,evaluator,3},tiger@durin})
{<0.237.0>,dbg,tiger@durin} ! {<0.158.0>,{get_tracer,tiger@durin}}
@@ -743,9 +946,7 @@ ok
(tiger@durin)117> seq_trace:set_token(send,true), dbg:get_tracer(),
seq_trace:reset_trace().
true
-(tiger@durin)118> ttb:stop().
-ok
-(tiger@durin)119> ttb:format("tiger@durin-ttb").
+(tiger@durin)118> ttb:stop(format).
SeqTrace [0]: ({<0.158.0>,{shell,evaluator,3},tiger@durin})
{<0.246.0>,dbg,tiger@durin} ! {<0.158.0>,{get_tracer,tiger@durin}}
[Serial: {0,1}]
diff --git a/lib/observer/priv/erlang_observer.png b/lib/observer/priv/erlang_observer.png
new file mode 100644
index 0000000000..78e70461b1
--- /dev/null
+++ b/lib/observer/priv/erlang_observer.png
Binary files differ
diff --git a/lib/observer/src/Makefile b/lib/observer/src/Makefile
index 3875b62101..95954d8587 100644
--- a/lib/observer/src/Makefile
+++ b/lib/observer/src/Makefile
@@ -1,19 +1,19 @@
#
# %CopyrightBegin%
-#
+#
# Copyright Ericsson AB 2002-2011. All Rights Reserved.
-#
+#
# The contents of this file are subject to the Erlang Public License,
# Version 1.1, (the "License"); you may not use this file except in
# compliance with the License. You should have received a copy of the
# Erlang Public License along with this software. If not, it can be
# retrieved online at http://www.erlang.org/.
-#
+#
# Software distributed under the License is distributed on an "AS IS"
# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
# the License for the specific language governing rights and limitations
# under the License.
-#
+#
# %CopyrightEnd%
#
include $(ERL_TOP)/make/target.mk
@@ -41,8 +41,19 @@ MODULES= \
etop_gui \
etop_tr \
etop_txt \
+ observer \
+ observer_lib \
+ observer_wx \
+ observer_pro_wx \
+ observer_procinfo \
+ observer_sys_wx \
+ observer_trace_wx \
+ observer_traceoptions_wx \
+ observer_tv_table \
+ observer_tv_wx \
ttb \
ttb_et
+
HRL_FILES= \
../include/etop.hrl
INTERNAL_HRL_FILES= \
@@ -54,7 +65,7 @@ EXAMPLE_FILES= multitrace.erl
TARGET_FILES= $(MODULES:%=$(EBIN)/%.$(EMULATOR)) $(APP_TARGET) $(APPUP_TARGET)
PRIVDIR= ../priv
-WEBTOOLFILES= $(PRIVDIR)/crashdump_viewer.tool
+WEBTOOLFILES= $(PRIVDIR)/crashdump_viewer.tool $(PRIVDIR)/erlang_observer.png
BINDIR= $(PRIVDIR)/bin
ifeq ($(findstring win32,$(TARGET)),win32)
WIN32_EXECUTABLES= $(BINDIR)/etop.bat $(BINDIR)/getop.bat $(BINDIR)/cdv.bat
@@ -109,7 +120,7 @@ docs:
# ----------------------------------------------------
# Release Target
-# ----------------------------------------------------
+# ----------------------------------------------------
include $(ERL_TOP)/make/otp_release_targets.mk
release_spec: opt
diff --git a/lib/observer/src/observer.erl b/lib/observer/src/observer.erl
new file mode 100644
index 0000000000..098100e8ee
--- /dev/null
+++ b/lib/observer/src/observer.erl
@@ -0,0 +1,25 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2011. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+
+-module(observer).
+
+-export([start/0]).
+
+
+start() ->
+ observer_wx:start().
diff --git a/lib/observer/src/observer_defs.hrl b/lib/observer/src/observer_defs.hrl
new file mode 100644
index 0000000000..d83a1e2fa5
--- /dev/null
+++ b/lib/observer/src/observer_defs.hrl
@@ -0,0 +1,62 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2011. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+
+-record(trace_options, {send = false,
+ treceive = false,
+ functions = false,
+ events = false,
+ on_1st_spawn = false,
+ on_all_spawn = false,
+ on_1st_link = false,
+ on_all_link = false,
+ main_window = true}).
+
+-record(match_spec, {name = "",
+ term = [],
+ str = [],
+ func = ""}).
+
+-record(tpattern, {m, fa, ms}).
+
+-record(traced_func, {func_name, %atom
+ arity, %integer
+ match_spec = #match_spec{}}).
+
+-record(on_spawn, {checkbox, all_spawn, first_spawn}).
+
+-record(on_link, {checkbox, all_link, first_link}).
+
+-record(pid, {window, traced}).
+
+-record(create_menu,
+ {id,
+ text,
+ type = append,
+ check = false
+ }).
+
+-record(attrs, {even, odd, deleted, changed, searched}).
+-define(EVEN(Row), ((Row rem 2) =:= 0)).
+-define(BG_EVEN, {230,230,250}).
+-define(BG_ODD, {255,255,255}).
+-define(BG_DELETED, {100,100,100}).
+-define(FG_DELETED, {240,30,30}).
+-define(BG_SEARCHED,{235,215,90}).
+-define(BG_CHANGED, {230,230,250}).
+
+-define(LCTRL_WDECR, 4). %% Remove some pixels in column width to avoid creating unnecessary scrollbar
diff --git a/lib/observer/src/observer_lib.erl b/lib/observer/src/observer_lib.erl
new file mode 100644
index 0000000000..90c270e977
--- /dev/null
+++ b/lib/observer/src/observer_lib.erl
@@ -0,0 +1,297 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2011. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+
+-module(observer_lib).
+
+-export([get_wx_parent/1,
+ display_info_dialog/1,
+ interval_dialog/4, start_timer/1, stop_timer/1,
+ display_info/2, fill_info/2, update_info/2, to_str/1,
+ create_menus/3, create_menu_item/3,
+ create_attrs/0
+ ]).
+
+-include_lib("wx/include/wx.hrl").
+-include("observer_defs.hrl").
+
+get_wx_parent(Window) ->
+ Parent = wxWindow:getParent(Window),
+ case wx:is_null(Parent) of
+ true -> Window;
+ false -> get_wx_parent(Parent)
+ end.
+
+interval_dialog(Parent0, {Timer, Value}, Min, Max) ->
+ Parent = get_wx_parent(Parent0),
+ Dialog = wxDialog:new(Parent, ?wxID_ANY, "Update Interval",
+ [{style, ?wxDEFAULT_DIALOG_STYLE bor
+ ?wxRESIZE_BORDER}]),
+ Panel = wxPanel:new(Dialog),
+ Check = wxCheckBox:new(Panel, ?wxID_ANY, "Periodical refresh"),
+ wxCheckBox:setValue(Check, Timer /= false),
+ Style = ?wxSL_HORIZONTAL bor ?wxSL_AUTOTICKS bor ?wxSL_LABELS,
+ Slider = wxSlider:new(Panel, ?wxID_ANY, Value, Min, Max,
+ [{style, Style}, {size, {200, -1}}]),
+ wxWindow:enable(Slider, [{enable, Timer /= false}]),
+ InnerSizer = wxBoxSizer:new(?wxVERTICAL),
+ Buttons = wxDialog:createButtonSizer(Dialog, ?wxOK bor ?wxCANCEL),
+ Flags = [{flag, ?wxEXPAND bor ?wxALL}, {border, 2}],
+ wxSizer:add(InnerSizer, Check, Flags),
+ wxSizer:add(InnerSizer, Slider, Flags),
+ wxPanel:setSizer(Panel, InnerSizer),
+ TopSizer = wxBoxSizer:new(?wxVERTICAL),
+ wxSizer:add(TopSizer, Panel, [{flag, ?wxEXPAND bor ?wxALL}, {border, 5}]),
+ wxSizer:add(TopSizer, Buttons, [{flag, ?wxEXPAND}]),
+ wxWindow:setSizerAndFit(Dialog, TopSizer),
+ wxSizer:setSizeHints(TopSizer, Dialog),
+ wxCheckBox:connect(Check, command_checkbox_clicked,
+ [{callback, fun(#wx{event=#wxCommand{commandInt=Enable0}},_) ->
+ Enable = Enable0 > 0,
+ wxWindow:enable(Slider, [{enable, Enable}])
+ end}]),
+ Res = case wxDialog:showModal(Dialog) of
+ ?wxID_OK ->
+ Enabled = wxCheckBox:isChecked(Check),
+ setup_timer(Enabled, {Timer, wxSlider:getValue(Slider)});
+ ?wxID_CANCEL ->
+ {Timer, Value}
+ end,
+ wxDialog:destroy(Dialog),
+ Res.
+
+stop_timer(Timer = {false, _}) -> Timer;
+stop_timer(Timer = {true, _}) -> Timer;
+stop_timer(Timer = {_, Intv}) ->
+ setup_timer(false, Timer),
+ {true, Intv}.
+start_timer(Intv) when is_integer(Intv) ->
+ setup_timer(true, {true, Intv});
+start_timer(Timer) ->
+ setup_timer(true, Timer).
+
+setup_timer(false, {Timer, Value})
+ when is_boolean(Timer) ->
+ {false, Value};
+setup_timer(true, {false, Value}) ->
+ {ok, Timer} = timer:send_interval(Value * 1000, refresh_interval),
+ {Timer, Value};
+setup_timer(Bool, {Timer, Old}) ->
+ timer:cancel(Timer),
+ setup_timer(Bool, {false, Old}).
+
+display_info_dialog(Str) ->
+ Dlg = wxMessageDialog:new(wx:null(), Str),
+ wxMessageDialog:showModal(Dlg),
+ wxMessageDialog:destroy(Dlg),
+ ok.
+
+%% display_info(Parent, [{Title, [{Label, Info}]}]) -> {Panel, Sizer, InfoFieldsToUpdate}
+display_info(Frame, Info) ->
+ Panel = wxPanel:new(Frame),
+ wxWindow:setBackgroundColour(Panel, {255,255,255}),
+ Sizer = wxBoxSizer:new(?wxVERTICAL),
+ wxSizer:addSpacer(Sizer, 5),
+ Add = fun(BoxInfo) ->
+ {Box, InfoFs} = create_box(Panel, BoxInfo),
+ wxSizer:add(Sizer, Box, [{flag, ?wxEXPAND bor ?wxALL},
+ {border, 5}]),
+ wxSizer:addSpacer(Sizer, 5),
+ InfoFs
+ end,
+ InfoFs = [Add(I) || I <- Info],
+ wxWindow:setSizerAndFit(Panel, Sizer),
+ {Panel, Sizer, InfoFs}.
+
+fill_info([{Str, Key}|Rest], Data) when is_atom(Key); is_function(Key) ->
+ [{Str, get_value(Key, Data)} | fill_info(Rest, Data)];
+fill_info([{Str, {Format, Key}}|Rest], Data)
+ when is_atom(Key); is_function(Key), is_atom(Format) ->
+ [{Str, {Format, get_value(Key,Data)}} | fill_info(Rest, Data)];
+fill_info([{Str,SubStructure}|Rest], Data) when is_list(SubStructure) ->
+ [{Str, fill_info(SubStructure, Data)}|fill_info(Rest,Data)];
+fill_info([{Str,Attrib,SubStructure}|Rest], Data) ->
+ [{Str, Attrib, fill_info(SubStructure, Data)}|fill_info(Rest,Data)];
+fill_info([], _) -> [].
+
+get_value(Key, Data) when is_atom(Key) ->
+ proplists:get_value(Key,Data);
+get_value(Fun, Data) when is_function(Fun) ->
+ Fun(Data).
+
+update_info([Fields|Fs], [{_Header, SubStructure}| Rest]) ->
+ update_info2(Fields, SubStructure),
+ update_info(Fs, Rest);
+update_info([Fields|Fs], [{_Header, _Attrib, SubStructure}| Rest]) ->
+ update_info2(Fields, SubStructure),
+ update_info(Fs, Rest);
+update_info([], []) ->
+ ok.
+
+update_info2([Field|Fs], [{_Str, Value}|Rest]) ->
+ wxStaticText:setLabel(Field, to_str(Value)),
+ update_info2(Fs, Rest);
+update_info2([], []) -> ok.
+
+
+to_str(Value) when is_atom(Value) ->
+ atom_to_list(Value);
+to_str({bytes, B}) ->
+ KB = B div 1024,
+ MB = KB div 1024,
+ if
+ MB > 10 -> integer_to_list(MB) ++ " mB";
+ KB > 0 -> integer_to_list(KB) ++ " kB";
+ true -> integer_to_list(B) ++ " B "
+ end;
+to_str({time_ms, MS}) ->
+ S = MS div 1000,
+ Min = S div 60,
+ Hours = Min div 60,
+ Days = Hours div 24,
+ if
+ Days > 0 -> integer_to_list(Days) ++ " Days";
+ Hours > 0 -> integer_to_list(Hours) ++ " Hours";
+ Min > 0 -> integer_to_list(Min) ++ " Mins";
+ true -> integer_to_list(S) ++ " Secs"
+ end;
+
+to_str({func, {F,A}}) when is_atom(F), is_integer(A) ->
+ lists:concat([F, "/", A]);
+to_str({func, {F,'_'}}) when is_atom(F) ->
+ atom_to_list(F);
+to_str({A, B}) when is_atom(A), is_atom(B) ->
+ lists:concat([A, ":", B]);
+to_str({M,F,A}) when is_atom(M), is_atom(F), is_integer(A) ->
+ lists:concat([M, ":", F, "/", A]);
+to_str(Value) when is_list(Value) ->
+ case lists:all(fun(X) -> is_integer(X) end, Value) of
+ true -> Value;
+ false ->
+ lists:foldl(fun(X, Acc) ->
+ to_str(X) ++ " " ++ Acc end,
+ "", Value)
+ end;
+to_str(Port) when is_port(Port) ->
+ erlang:port_to_list(Port);
+to_str(Pid) when is_pid(Pid) ->
+ pid_to_list(Pid);
+to_str(No) when is_integer(No) ->
+ integer_to_list(No);
+to_str(Term) ->
+ io_lib:format("~w", [Term]).
+
+create_menus(Menus, MenuBar, Type) ->
+ Add = fun({Tag, Ms}, Index) ->
+ create_menu(Tag, Ms, Index, MenuBar, Type)
+ end,
+ [{First, _}|_] = Menus,
+ OnMac = os:type() =:= {unix, darwin},
+ Index = if Type =:= default -> 0;
+ First =:= "File" -> 0;
+ OnMac -> 0;
+ true -> 1
+ end,
+ wx:foldl(Add, Index, Menus),
+ ok.
+
+create_menu("File", MenuItems, Index, MenuBar, Type) ->
+ OnMac = os:type() =:= {unix, darwin},
+ if OnMac, Type =:= default ->
+ Index;
+ not OnMac, Type =:= plugin ->
+ MenuId = wxMenuBar:findMenu(MenuBar, "File"),
+ Menu = wxMenuBar:getMenu(MenuBar, MenuId),
+ lists:foldl(fun(Record, N) ->
+ create_menu_item(Record, Menu, N)
+ end, 0, MenuItems),
+ Index + 1;
+ true ->
+ Menu = wxMenu:new(),
+ lists:foldl(fun(Record, N) ->
+ create_menu_item(Record, Menu, N)
+ end, 0, MenuItems),
+ wxMenuBar:insert(MenuBar, Index, Menu, "File"),
+ Index+1
+ end;
+create_menu(Name, MenuItems, Index, MenuBar, _Type) ->
+ Menu = wxMenu:new(),
+ lists:foldl(fun(Record, N) ->
+ create_menu_item(Record, Menu, N)
+ end, 0, MenuItems),
+ wxMenuBar:insert(MenuBar, Index, Menu, Name),
+ Index+1.
+
+create_menu_item(#create_menu{id = ?wxID_HELP=Id}, Menu, Index) ->
+ wxMenu:insert(Menu, Index, Id),
+ Index+1;
+create_menu_item(#create_menu{id = Id, text = Text, type = Type, check = Check}, Menu, Index) ->
+ case Type of
+ append ->
+ wxMenu:insert(Menu, Index, Id, [{text, Text}]);
+ check ->
+ wxMenu:insertCheckItem(Menu, Index, Id, Text),
+ wxMenu:check(Menu, Id, Check);
+ radio ->
+ wxMenu:insertRadioItem(Menu, Index, Id, Text),
+ wxMenu:check(Menu, Id, Check);
+ separator ->
+ wxMenu:insertSeparator(Menu, Index)
+ end,
+ Index+1;
+create_menu_item(separator, Menu, Index) ->
+ wxMenu:insertSeparator(Menu, Index),
+ Index+1.
+
+create_attrs() ->
+ Font = wxSystemSettings:getFont(?wxSYS_DEFAULT_GUI_FONT),
+ Text = case wxSystemSettings:getColour(?wxSYS_COLOUR_LISTBOXTEXT) of
+ {255,255,255,_} -> {10,10,10}; %% Is white on Mac for some reason
+ Color -> Color
+ end,
+ #attrs{even = wxListItemAttr:new(Text, ?BG_EVEN, Font),
+ odd = wxListItemAttr:new(Text, ?BG_ODD, Font),
+ deleted = wxListItemAttr:new(?FG_DELETED, ?BG_DELETED, Font),
+ changed = wxListItemAttr:new(Text, ?BG_CHANGED, Font),
+ searched = wxListItemAttr:new(Text, ?BG_SEARCHED, Font)
+ }.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+get_box_info({Title, List}) when is_list(List) -> {Title, ?wxALIGN_LEFT, List};
+get_box_info({Title, left, List}) -> {Title, ?wxALIGN_LEFT, List};
+get_box_info({Title, right, List}) -> {Title, ?wxALIGN_RIGHT, List}.
+
+create_box(Panel, Data) ->
+ {Title, Align, Info} = get_box_info(Data),
+ Box = wxStaticBoxSizer:new(?wxHORIZONTAL, Panel, [{label, Title}]),
+ Left = wxBoxSizer:new(?wxVERTICAL),
+ Right = wxBoxSizer:new(?wxVERTICAL),
+ Expand = [{flag, ?wxEXPAND}],
+ ExpAlign = [{flag, Align}],
+ AddRow = fun({Desc, Value}) ->
+ wxSizer:add(Left, wxStaticText:new(Panel, ?wxID_ANY, Desc ++ ":"), Expand),
+ Field = wxStaticText:new(Panel, ?wxID_ANY, to_str(Value)),
+ wxSizer:add(Right, Field, ExpAlign),
+ Field
+ end,
+ InfoFields = [AddRow(Entry) || Entry <- Info],
+ wxSizer:add(Box, Left),
+ wxSizer:addSpacer(Box, 10),
+ wxSizer:add(Box, Right),
+ wxSizer:addSpacer(Box, 30),
+ {Box, InfoFields}.
diff --git a/lib/observer/src/observer_pro_wx.erl b/lib/observer/src/observer_pro_wx.erl
new file mode 100644
index 0000000000..cfc1c0665f
--- /dev/null
+++ b/lib/observer/src/observer_pro_wx.erl
@@ -0,0 +1,608 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2011. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+-module(observer_pro_wx).
+
+-behaviour(wx_object).
+
+-export([start_link/2]).
+
+%% wx_object callbacks
+-export([init/1, handle_info/2, terminate/2, code_change/3, handle_call/3,
+ handle_event/2, handle_cast/2]).
+
+-include_lib("wx/include/wx.hrl").
+-include("../include/etop.hrl").
+-include("observer_defs.hrl").
+-include("etop_defs.hrl").
+
+%% Defines
+-define(COL_PID, 0).
+-define(COL_NAME, 1).
+-define(COL_TIME, 2).
+-define(COL_REDS, 3).
+-define(COL_MEM, 4).
+-define(COL_MSG, 5).
+-define(COL_FUN, 6).
+
+-define(ID_KILL, 201).
+-define(ID_PROC, 202).
+-define(ID_REFRESH, 203).
+-define(ID_REFRESH_INTERVAL, 204).
+-define(ID_DUMP_TO_FILE, 205).
+-define(ID_TRACEMENU, 206).
+-define(ID_TRACE_ALL_MENU, 207).
+-define(ID_TRACE_NEW_MENU, 208).
+-define(ID_ACCUMULATE, 209).
+
+%% Records
+
+-record(sort,
+ {
+ sort_key=?COL_REDS,
+ sort_incr=false
+ }).
+
+-record(holder, {parent,
+ info,
+ sort=#sort{},
+ accum=[],
+ attrs,
+ node,
+ backend_pid
+ }).
+
+-record(state, {parent,
+ grid,
+ panel,
+ popup_menu,
+ parent_notebook,
+ timer,
+ procinfo_menu_pids=[],
+ sel={[], []},
+ holder}).
+
+start_link(Notebook, Parent) ->
+ wx_object:start_link(?MODULE, [Notebook, Parent], []).
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+init([Notebook, Parent]) ->
+ Attrs = observer_lib:create_attrs(),
+ Self = self(),
+ Holder = spawn_link(fun() -> init_table_holder(Self, Attrs) end),
+ {ProPanel, State} = setup(Notebook, Parent, Holder),
+ {ProPanel, State#state{holder=Holder}}.
+
+setup(Notebook, Parent, Holder) ->
+ ProPanel = wxPanel:new(Notebook, []),
+
+ Grid = create_list_box(ProPanel, Holder),
+ Sizer = wxBoxSizer:new(?wxVERTICAL),
+ wxSizer:add(Sizer, Grid, [{flag, ?wxEXPAND bor ?wxALL},
+ {proportion, 1},
+ {border,4}]),
+
+ wxWindow:setSizer(ProPanel, Sizer),
+
+ Popup = create_popup_menu(ProPanel),
+
+ State = #state{parent=Parent,
+ grid=Grid,
+ panel=ProPanel,
+ popup_menu=Popup,
+ parent_notebook=Notebook,
+ holder=Holder,
+ timer={false, 10}
+ },
+ {ProPanel, State}.
+
+
+%% UI-creation
+
+create_pro_menu(Parent, Holder) ->
+ MenuEntries = [{"File",
+ [#create_menu{id=?ID_DUMP_TO_FILE, text="Dump to file"}]},
+ {"View",
+ [#create_menu{id=?ID_ACCUMULATE, text="Accumulate",
+ type=check,
+ check=call(Holder, {get_accum, self()})},
+ separator,
+ #create_menu{id=?ID_REFRESH, text="Refresh\tCtrl-R"},
+ #create_menu{id=?ID_REFRESH_INTERVAL, text="Refresh Interval"}]},
+ {"Trace",
+ [#create_menu{id=?ID_TRACEMENU, text="Trace selected processes"},
+ #create_menu{id=?ID_TRACE_NEW_MENU, text="Trace new processes"}
+ %% , #create_menu{id=?ID_TRACE_ALL_MENU, text="Trace all processes"}
+ ]}
+ ],
+ observer_wx:create_menus(Parent, MenuEntries).
+
+create_popup_menu(ParentFrame) ->
+ MiniFrame = wxMiniFrame:new(ParentFrame, ?wxID_ANY, "Options", [{style, ?wxFRAME_FLOAT_ON_PARENT}]),
+ Panel = wxPanel:new(MiniFrame),
+ Sizer = wxBoxSizer:new(?wxVERTICAL),
+ TraceBtn = wxButton:new(Panel, ?ID_TRACEMENU, [{label, "Trace selected"},
+ {style, ?wxNO_BORDER}]),
+ ProcBtn = wxButton:new(Panel, ?ID_PROC, [{label, "Process info"},
+ {style, ?wxNO_BORDER}]),
+ KillBtn = wxButton:new(Panel, ?ID_KILL, [{label, "Kill process"},
+ {style, ?wxNO_BORDER}]),
+
+ wxButton:connect(TraceBtn, command_button_clicked),
+ wxButton:connect(ProcBtn, command_button_clicked),
+ wxButton:connect(KillBtn, command_button_clicked),
+ wxSizer:add(Sizer, TraceBtn, [{flag, ?wxEXPAND}, {proportion, 1}]),
+ wxSizer:add(Sizer, ProcBtn, [{flag, ?wxEXPAND}, {proportion, 1}]),
+ wxSizer:add(Sizer, KillBtn, [{flag, ?wxEXPAND}, {proportion, 1}]),
+ wxPanel:setSizer(Panel, Sizer),
+ wxSizer:setSizeHints(Sizer, MiniFrame),
+ MiniFrame.
+
+create_list_box(Panel, Holder) ->
+ Style = ?wxLC_REPORT bor ?wxLC_VIRTUAL bor ?wxLC_HRULES,
+ ListCtrl = wxListCtrl:new(Panel, [{style, Style},
+ {onGetItemText,
+ fun(_, Row, Col) ->
+ call(Holder, {get_row, self(), Row, Col})
+ end},
+ {onGetItemAttr,
+ fun(_, Item) ->
+ call(Holder, {get_attr, self(), Item})
+ end}
+ ]),
+ Li = wxListItem:new(),
+ AddListEntry = fun({Name, Align, DefSize}, Col) ->
+ wxListItem:setText(Li, Name),
+ wxListItem:setAlign(Li, Align),
+ wxListCtrl:insertColumn(ListCtrl, Col, Li),
+ wxListCtrl:setColumnWidth(ListCtrl, Col, DefSize),
+ Col + 1
+ end,
+ ListItems = [{"Pid", ?wxLIST_FORMAT_CENTRE, 120},
+ {"Name or Initial Func", ?wxLIST_FORMAT_LEFT, 200},
+ {"Time", ?wxLIST_FORMAT_CENTRE, 50},
+ {"Reds", ?wxLIST_FORMAT_RIGHT, 100},
+ {"Memory", ?wxLIST_FORMAT_RIGHT, 100},
+ {"MsgQ", ?wxLIST_FORMAT_RIGHT, 50},
+ {"Current Function", ?wxLIST_FORMAT_LEFT, 200}],
+ lists:foldl(AddListEntry, 0, ListItems),
+ wxListItem:destroy(Li),
+
+ wxListCtrl:setItemCount(ListCtrl, 1),
+ wxListCtrl:connect(ListCtrl, size, [{skip, true}]),
+ wxListCtrl:connect(ListCtrl, command_list_item_activated),
+ wxListCtrl:connect(ListCtrl, command_list_item_right_click),
+ wxListCtrl:connect(ListCtrl, command_list_col_click),
+ %% Use focused instead of selected, selected doesn't generate events
+ %% for all multiple selections on Linux
+ wxListCtrl:connect(ListCtrl, command_list_item_focused),
+ ListCtrl.
+
+dump_to_file(Parent, FileName, Holder) ->
+ case file:open(FileName, [write]) of
+ {ok, Fd} ->
+ %% Holder closes the file when it's done
+ Holder ! {dump, Fd};
+ {error, Reason} ->
+ FailMsg = file:format_error(Reason),
+ MD = wxMessageDialog:new(Parent, FailMsg),
+ wxDialog:showModal(MD),
+ wxDialog:destroy(MD)
+ end.
+
+start_procinfo(undefined, _Frame, Opened) ->
+ Opened;
+start_procinfo(Pid, Frame, Opened) ->
+ case lists:member(Pid, Opened) of
+ true ->
+ Opened;
+ false ->
+ observer_procinfo:start(Pid, Frame, self()),
+ [Pid | Opened]
+ end.
+
+call(Holder, What) ->
+ Ref = erlang:monitor(process, Holder),
+ Holder ! What,
+ receive
+ {'DOWN', Ref, _, _, _} -> "";
+ {Holder, Res} ->
+ erlang:demonitor(Ref),
+ Res
+ after 2000 ->
+ io:format("Hanging call ~p~n",[What]),
+ ""
+ end.
+
+%%%%%%%%%%%%%%%%%%%%%%% Callbacks %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+handle_info({holder_updated, Count}, State0=#state{grid=Grid}) ->
+ State = update_selection(State0),
+
+ wxListCtrl:setItemCount(Grid, Count),
+ wxListCtrl:refreshItems(Grid, 0, Count-1),
+
+ {noreply, State};
+
+handle_info(refresh_interval, #state{holder=Holder}=State) ->
+ Holder ! refresh,
+ {noreply, State};
+
+handle_info({procinfo_menu_closed, Pid},
+ #state{procinfo_menu_pids=Opened}=State) ->
+ NewPids = lists:delete(Pid, Opened),
+ {noreply, State#state{procinfo_menu_pids=NewPids}};
+
+handle_info({active, Node},
+ #state{holder=Holder, timer=Timer, parent=Parent}=State) ->
+ create_pro_menu(Parent, Holder),
+ Holder ! {change_node, Node},
+ {noreply, State#state{timer=observer_lib:start_timer(Timer)}};
+
+handle_info(not_active, #state{timer=Timer0}=State) ->
+ Timer = observer_lib:stop_timer(Timer0),
+ {noreply, State#state{timer=Timer}};
+
+handle_info({node, Node}, #state{holder=Holder}=State) ->
+ Holder ! {change_node, Node},
+ {noreply, State};
+
+handle_info(Info, State) ->
+ io:format("~p:~p, Unexpected info: ~p~n", [?MODULE, ?LINE, Info]),
+ {noreply, State}.
+
+terminate(_Reason, #state{holder=Holder}) ->
+ Holder ! stop,
+ etop:stop(),
+ ok.
+
+code_change(_, _, State) ->
+ {stop, not_yet_implemented, State}.
+
+
+handle_call(Msg, _From, State) ->
+ io:format("~p:~p: Unhandled call ~p~n",[?MODULE, ?LINE, Msg]),
+ {reply, ok, State}.
+
+
+handle_cast(Msg, State) ->
+ io:format("~p:~p: Unhandled cast ~p~n", [?MODULE, ?LINE, Msg]),
+ {noreply, State}.
+
+%%%%%%%%%%%%%%%%%%%%LOOP%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+handle_event(#wx{id=?ID_DUMP_TO_FILE}, #state{panel=Panel, holder=Holder}=State) ->
+ FD = wxFileDialog:new(Panel,
+ [{style,?wxFD_SAVE bor ?wxFD_OVERWRITE_PROMPT}]),
+ case wxFileDialog:showModal(FD) of
+ ?wxID_OK ->
+ Path = wxFileDialog:getPath(FD),
+ wxDialog:destroy(FD),
+ dump_to_file(Panel, Path, Holder);
+ _ ->
+ wxDialog:destroy(FD)
+ end,
+ {noreply, State};
+
+handle_event(#wx{id=?ID_ACCUMULATE,
+ event=#wxCommand{type=command_menu_selected, commandInt=CmdInt}},
+ #state{holder=Holder}=State) ->
+ Holder ! {accum, CmdInt =:= 1},
+ {noreply, State};
+
+handle_event(#wx{id=?ID_REFRESH, event=#wxCommand{type=command_menu_selected}},
+ #state{holder=Holder}=State) ->
+ Holder ! refresh,
+ {noreply, State};
+
+handle_event(#wx{id=?ID_REFRESH_INTERVAL},
+ #state{panel=Panel, timer=Timer0}=State) ->
+ Timer = observer_lib:interval_dialog(Panel, Timer0, 1, 5*60),
+ {noreply, State#state{timer=Timer}};
+
+handle_event(#wx{id=?ID_KILL},
+ #state{popup_menu=Pop,sel={[_|Ids], [ToKill|Pids]}}=State) ->
+ wxWindow:show(Pop, [{show, false}]),
+ exit(ToKill, kill),
+ {noreply, State#state{sel={Ids,Pids}}};
+
+
+handle_event(#wx{id = ?ID_PROC},
+ #state{panel=Panel,
+ popup_menu=Pop,
+ sel={_, [Pid|_]},
+ procinfo_menu_pids=Opened}=State) ->
+ wxWindow:show(Pop, [{show, false}]),
+ Opened2 = start_procinfo(Pid, Panel, Opened),
+ {noreply, State#state{procinfo_menu_pids=Opened2}};
+
+handle_event(#wx{id = ?ID_TRACEMENU},
+ #state{popup_menu=Pop, sel={_, Pids}, panel=Panel}=State) ->
+ wxWindow:show(Pop, [{show, false}]),
+ case Pids of
+ [] ->
+ observer_wx:create_txt_dialog(Panel, "No selected processes", "Tracer", ?wxICON_EXCLAMATION),
+ {noreply, State};
+ Pids ->
+ observer_trace_wx:add_processes(observer_wx:get_tracer(), Pids),
+ {noreply, State}
+ end;
+
+handle_event(#wx{id=?ID_TRACE_NEW_MENU, event=#wxCommand{type=command_menu_selected}}, State) ->
+ observer_trace_wx:add_processes(observer_wx:get_tracer(), [new]),
+ {noreply, State};
+
+handle_event(#wx{event=#wxSize{size={W,_}}},
+ #state{grid=Grid}=State) ->
+ wx:batch(fun() ->
+ Cols = wxListCtrl:getColumnCount(Grid),
+ Last = lists:foldl(fun(I, Last) ->
+ Last - wxListCtrl:getColumnWidth(Grid, I)
+ end, W-Cols*3-?LCTRL_WDECR, lists:seq(0, Cols - 2)),
+ Size = max(200, Last),
+ %% io:format("Width ~p ~p => ~p~n",[W, Last, Size]),
+ wxListCtrl:setColumnWidth(Grid, Cols-1, Size)
+ end),
+ {noreply, State};
+
+handle_event(#wx{event=#wxList{type=command_list_item_right_click,
+ itemIndex=Row}},
+ #state{popup_menu=Popup,
+ holder=Holder}=State) ->
+
+ case call(Holder, {get_row, self(), Row, pid}) of
+ {error, undefined} ->
+ wxWindow:show(Popup, [{show, false}]),
+ undefined;
+ {ok, _} ->
+ wxWindow:move(Popup, wx_misc:getMousePosition()),
+ wxWindow:show(Popup)
+ end,
+ {noreply, State};
+
+handle_event(#wx{event=#wxList{type=command_list_item_focused,
+ itemIndex=Row}},
+ #state{grid=Grid,popup_menu=Pop,holder=Holder} = State) ->
+ case Row >= 0 of
+ true ->
+ wxWindow:show(Pop, [{show, false}]),
+ SelIds = [Row|lists:delete(Row, get_selected_items(Grid))],
+ Pids = call(Holder, {get_pids, self(), SelIds}),
+ %% io:format("Focused ~p -> ~p~n",[State#state.sel, {SelIds, Pids}]),
+ {noreply, State#state{sel={SelIds, Pids}}};
+ false ->
+ %% io:format("Focused -1~n",[]),
+ {noreply, State}
+ end;
+
+handle_event(#wx{event=#wxList{type=command_list_col_click, col=Col}},
+ #state{holder=Holder}=State) ->
+ Holder ! {change_sort, Col},
+ {noreply, State};
+
+handle_event(#wx{event=#wxList{type=command_list_item_activated}},
+ #state{panel=Panel, procinfo_menu_pids=Opened,
+ sel={_, [Pid|_]}}=State)
+ when Pid =/= undefined ->
+ Opened2 = start_procinfo(Pid, Panel, Opened),
+ {noreply, State#state{procinfo_menu_pids=Opened2}};
+
+handle_event(Event, State) ->
+ io:format("~p:~p: handle event ~p\n", [?MODULE, ?LINE, Event]),
+ {noreply, State}.
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+update_selection(State=#state{holder=Holder, grid=Grid,
+ sel={SelIds0, SelPids0}}) ->
+ Sel = {SelIds,_SelPids} = call(Holder, {get_rows_from_pids, self(), SelPids0}),
+ set_focus(SelIds0, SelIds, Grid),
+ case SelIds =:= SelIds0 of
+ true -> ok;
+ false ->
+ wx:batch(fun() ->
+ [wxListCtrl:setItemState(Grid, I, 0, ?wxLIST_STATE_SELECTED) ||
+ I <- SelIds0],
+ [wxListCtrl:setItemState(Grid, I, 16#FFFF, ?wxLIST_STATE_SELECTED) ||
+ I <- SelIds]
+ end)
+ end,
+ %%io:format("Update ~p -> ~p~n",[{SelIds0, SelPids0}, Sel]),
+ State#state{sel=Sel}.
+
+get_selected_items(Grid) ->
+ get_selected_items(Grid, -1, []).
+
+get_selected_items(Grid, Index, ItemAcc) ->
+ Item = wxListCtrl:getNextItem(Grid, Index, [{geometry, ?wxLIST_NEXT_ALL},
+ {state, ?wxLIST_STATE_SELECTED}]),
+ case Item of
+ -1 ->
+ lists:reverse(ItemAcc);
+ _ ->
+ get_selected_items(Grid, Item, [Item | ItemAcc])
+ end.
+
+set_focus([], [], _Grid) -> ok;
+set_focus([Same|_], [Same|_], _Grid) -> ok;
+set_focus([], [New|_], Grid) ->
+ wxListCtrl:setItemState(Grid, New, 16#FFFF, ?wxLIST_STATE_FOCUSED);
+set_focus([Old|_], [], Grid) ->
+ wxListCtrl:setItemState(Grid, Old, 0, ?wxLIST_STATE_FOCUSED);
+set_focus([Old|_], [New|_], Grid) ->
+ wxListCtrl:setItemState(Grid, Old, 0, ?wxLIST_STATE_FOCUSED),
+ wxListCtrl:setItemState(Grid, New, 16#FFFF, ?wxLIST_STATE_FOCUSED).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%TABLE HOLDER%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+init_table_holder(Parent, Attrs) ->
+ Backend = spawn_link(node(), observer_backend,etop_collect,[self()]),
+ table_holder(#holder{parent=Parent,
+ info=#etop_info{procinfo=[]},
+ node=node(),
+ backend_pid=Backend,
+ attrs=Attrs
+ }).
+
+table_holder(#holder{info=#etop_info{procinfo=Info}, attrs=Attrs,
+ node=Node, backend_pid=Backend}=S0) ->
+ receive
+ {get_row, From, Row, Col} ->
+ get_row(From, Row, Col, Info),
+ table_holder(S0);
+ {get_attr, From, Row} ->
+ get_attr(From, Row, Attrs),
+ table_holder(S0);
+ {Backend, EtopInfo=#etop_info{}} ->
+ State = handle_update(EtopInfo, S0),
+ table_holder(State#holder{backend_pid=undefined});
+ refresh when is_pid(Backend)->
+ table_holder(S0); %% Already updating
+ refresh ->
+ Pid = spawn_link(Node,observer_backend,etop_collect,[self()]),
+ table_holder(S0#holder{backend_pid=Pid});
+ {change_sort, Col} ->
+ State = change_sort(Col, S0),
+ table_holder(State);
+ {get_pids, From, Indices} ->
+ get_pids(From, Indices, Info),
+ table_holder(S0);
+ {get_rows_from_pids, From, Pids} ->
+ get_rows_from_pids(From, Pids, Info),
+ table_holder(S0);
+
+ {get_node, From} ->
+ From ! {self(), Node},
+ table_holder(S0);
+ {change_node, NewNode} ->
+ case Node == NewNode of
+ true ->
+ table_holder(S0);
+ false ->
+ self() ! refresh,
+ table_holder(S0#holder{node=NewNode})
+ end;
+ {accum, Bool} ->
+ table_holder(change_accum(Bool,S0));
+ {get_accum, From} ->
+ From ! {self(), S0#holder.accum == true},
+ table_holder(S0);
+ {dump, Fd} ->
+ etop_txt:do_update(Fd, S0#holder.info, #opts{node=Node}),
+ file:close(Fd),
+ table_holder(S0);
+ stop ->
+ ok;
+ What ->
+ io:format("Table holder got ~p~n",[What]),
+ table_holder(S0)
+ end.
+
+change_sort(Col, S0=#holder{parent=Parent, info=EI=#etop_info{procinfo=Data}, sort=Sort0}) ->
+ {Sort, ProcInfo}=sort(Col, Sort0, Data),
+ Parent ! {holder_updated, length(Data)},
+ S0#holder{info=EI#etop_info{procinfo=ProcInfo}, sort=Sort}.
+
+change_accum(true, S0) ->
+ S0#holder{accum=true};
+change_accum(false, S0=#holder{info=#etop_info{procinfo=Info}}) ->
+ self() ! refresh,
+ S0#holder{accum=lists:sort(Info)}.
+
+handle_update(EI=#etop_info{procinfo=ProcInfo0},
+ S0=#holder{parent=Parent, sort=Sort=#sort{sort_key=KeyField}}) ->
+ {ProcInfo1, S1} = accum(ProcInfo0, S0),
+ {_SO, ProcInfo} = sort(KeyField, Sort#sort{sort_key=undefined}, ProcInfo1),
+ Parent ! {holder_updated, length(ProcInfo)},
+ S1#holder{info=EI#etop_info{procinfo=ProcInfo}}.
+
+accum(ProcInfo, State=#holder{accum=true}) ->
+ {ProcInfo, State};
+accum(ProcInfo0, State=#holder{accum=Previous}) ->
+ ProcInfo = lists:sort(ProcInfo0),
+ {accum2(ProcInfo,Previous,[]), State#holder{accum=ProcInfo}}.
+
+accum2([PI=#etop_proc_info{pid=Pid, reds=Reds, runtime=RT}|PIs],
+ [#etop_proc_info{pid=Pid, reds=OldReds, runtime=OldRT}|Old], Acc) ->
+ accum2(PIs, Old, [PI#etop_proc_info{reds=Reds-OldReds, runtime=RT-OldRT}|Acc]);
+accum2(PIs=[#etop_proc_info{pid=Pid}|_], [#etop_proc_info{pid=OldPid}|Old], Acc)
+ when Pid > OldPid ->
+ accum2(PIs, Old, Acc);
+accum2([PI|PIs], Old, Acc) ->
+ accum2(PIs, Old, [PI|Acc]);
+accum2([], _, Acc) -> Acc.
+
+sort(Col, Opt=#sort{sort_key=Col, sort_incr=Bool}, Table) ->
+ {Opt#sort{sort_incr=not Bool}, lists:reverse(Table)};
+sort(Col, S=#sort{sort_incr=true}, Table) ->
+ {S#sort{sort_key=Col}, lists:keysort(col_to_element(Col), Table)};
+sort(Col, S=#sort{sort_incr=false}, Table) ->
+ {S#sort{sort_key=Col}, lists:reverse(lists:keysort(col_to_element(Col), Table))}.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+get_procinfo_data(Col, Info) ->
+ element(col_to_element(Col), Info).
+col_to_element(?COL_PID) -> #etop_proc_info.pid;
+col_to_element(?COL_NAME) -> #etop_proc_info.name;
+col_to_element(?COL_MEM) -> #etop_proc_info.mem;
+col_to_element(?COL_TIME) -> #etop_proc_info.runtime;
+col_to_element(?COL_REDS) -> #etop_proc_info.reds;
+col_to_element(?COL_FUN) -> #etop_proc_info.cf;
+col_to_element(?COL_MSG) -> #etop_proc_info.mq.
+
+get_pids(From, Indices, ProcInfo) ->
+ Processes = [(lists:nth(I+1, ProcInfo))#etop_proc_info.pid || I <- Indices],
+ From ! {self(), Processes}.
+
+get_row(From, Row, pid, Info) ->
+ Pid = case Row =:= -1 of
+ true -> {error, undefined};
+ false -> {ok, get_procinfo_data(?COL_PID, lists:nth(Row+1, Info))}
+ end,
+ From ! {self(), Pid};
+get_row(From, Row, Col, Info) ->
+ Data = case Row+1 > length(Info) of
+ true ->
+ "";
+ false ->
+ ProcInfo = lists:nth(Row+1, Info),
+ get_procinfo_data(Col, ProcInfo)
+ end,
+ From ! {self(), observer_lib:to_str(Data)}.
+
+get_rows_from_pids(From, Pids0, Info) ->
+ Res = lists:foldl(fun(Pid, Data = {Ids, Pids}) ->
+ case index(Pid, Info, 0) of
+ false -> Data;
+ Index -> {[Index|Ids], [Pid|Pids]}
+ end
+ end, {[],[]}, Pids0),
+ From ! {self(), Res}.
+
+get_attr(From, Row, Attrs) ->
+ Attribute = case Row rem 2 =:= 0 of
+ true -> Attrs#attrs.even;
+ false -> Attrs#attrs.odd
+ end,
+ From ! {self(), Attribute}.
+
+index(Pid, [#etop_proc_info{pid=Pid}|_], Index) -> Index;
+index(Pid, [_|PI], Index) -> index(Pid, PI, Index+1);
+index(_, _, _) -> false.
diff --git a/lib/observer/src/observer_procinfo.erl b/lib/observer/src/observer_procinfo.erl
new file mode 100644
index 0000000000..127599a39e
--- /dev/null
+++ b/lib/observer/src/observer_procinfo.erl
@@ -0,0 +1,274 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2011. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+
+-module(observer_procinfo).
+
+-behaviour(wx_object).
+
+-export([start/3]).
+
+-export([init/1, handle_event/2, handle_cast/2, terminate/2, code_change/3,
+ handle_call/3, handle_info/2]).
+
+-include_lib("wx/include/wx.hrl").
+-include("observer_defs.hrl").
+
+-define(REFRESH, 601).
+-define(SELECT_ALL, 603).
+-define(ID_NOTEBOOK, 604).
+
+-record(state, {parent,
+ frame,
+ pid,
+ pages=[]
+ }).
+
+-record(worker, {panel, callback}).
+
+start(Process, ParentFrame, Parent) ->
+ wx_object:start(?MODULE, [Process, ParentFrame, Parent], []).
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+init([Pid, ParentFrame, Parent]) ->
+ try
+ Title=case observer_wx:try_rpc(node(Pid), erlang, process_info, [Pid, registered_name]) of
+ [] -> io_lib:format("~p",[Pid]);
+ {registered_name, Registered} -> atom_to_list(Registered)
+ end,
+ Frame=wxFrame:new(ParentFrame, ?wxID_ANY, [atom_to_list(node(Pid)), $:, Title],
+ [{style, ?wxDEFAULT_FRAME_STYLE}, {size, {800,700}}]),
+ MenuBar = wxMenuBar:new(),
+ create_menus(MenuBar),
+ wxFrame:setMenuBar(Frame, MenuBar),
+
+ Notebook = wxNotebook:new(Frame, ?ID_NOTEBOOK, [{style, ?wxBK_DEFAULT}]),
+
+ ProcessPage = init_panel(Notebook, "Process Information", Pid, fun init_process_page/2),
+ MessagePage = init_panel(Notebook, "Messages", Pid, fun init_message_page/2),
+ DictPage = init_panel(Notebook, "Dictionary", Pid, fun init_dict_page/2),
+ StackPage = init_panel(Notebook, "Stack Trace", Pid, fun init_stack_page/2),
+
+ wxFrame:connect(Frame, close_window),
+ wxMenu:connect(Frame, command_menu_selected),
+ %% wxNotebook:connect(Notebook, command_notebook_page_changed, [{skip,true}]),
+ wxFrame:show(Frame),
+ {Frame, #state{parent=Parent,
+ pid=Pid,
+ frame=Frame,
+ pages=[ProcessPage,MessagePage,DictPage,StackPage]
+ }}
+ catch error:{badrpc, _} ->
+ observer_wx:return_to_localnode(ParentFrame, node(Pid)),
+ {stop, badrpc, #state{parent=Parent, pid=Pid}};
+ Error:Reason ->
+ io:format("~p:~p: ~p ~p~n ~p~n",
+ [?MODULE, ?LINE, Error, Reason, erlang:get_stacktrace()])
+ end.
+
+init_panel(Notebook, Str, Pid, Fun) ->
+ Panel = wxPanel:new(Notebook),
+ Sizer = wxBoxSizer:new(?wxHORIZONTAL),
+ {Window,Callback} = Fun(Panel, Pid),
+ wxSizer:add(Sizer, Window, [{flag, ?wxEXPAND bor ?wxALL}, {proportion, 1}, {border, 5}]),
+ wxPanel:setSizer(Panel, Sizer),
+ true = wxNotebook:addPage(Notebook, Panel, Str),
+ #worker{panel=Panel, callback=Callback}.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%Callbacks%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+handle_event(#wx{event=#wxClose{type=close_window}}, State) ->
+ {stop, shutdown, State};
+
+handle_event(#wx{id=?wxID_CLOSE, event=#wxCommand{type=command_menu_selected}}, State) ->
+ {stop, shutdown, State};
+
+handle_event(#wx{id=?REFRESH}, #state{pages=Pages}=State) ->
+ [(W#worker.callback)() || W <- Pages],
+ {noreply, State};
+
+handle_event(Event, State) ->
+ io:format("~p: ~p, Handle event: ~p~n", [?MODULE, ?LINE, Event]),
+ {noreply, State}.
+
+handle_info(Info, State) ->
+ io:format("~p: ~p, Handle info: ~p~n", [?MODULE, ?LINE, Info]),
+ {noreply, State}.
+
+handle_call(Call, _From, State) ->
+ io:format("~p ~p: Got call ~p~n",[?MODULE, ?LINE, Call]),
+ {reply, ok, State}.
+
+handle_cast(Cast, State) ->
+ io:format("~p ~p: Got cast ~p~n", [?MODULE, ?LINE, Cast]),
+ {noreply, State}.
+
+terminate(_Reason, #state{parent=Parent,pid=Pid,frame=Frame}) ->
+ Parent ! {procinfo_menu_closed, Pid},
+ case Frame of
+ undefined -> ok;
+ _ -> wxFrame:destroy(Frame)
+ end,
+ ok.
+
+code_change(_, _, State) ->
+ {stop, not_yet_implemented, State}.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+init_process_page(Panel, Pid) ->
+ Fields = process_info_fields(Pid),
+ {FPanel, _, UpFields} = observer_lib:display_info(Panel, Fields),
+ {FPanel, fun() -> observer_lib:update_info(UpFields, process_info_fields(Pid)) end}.
+
+init_text_page(Parent) ->
+ Style = ?wxTE_MULTILINE bor ?wxTE_RICH2 bor ?wxTE_READONLY,
+ Text = wxTextCtrl:new(Parent, ?wxID_ANY, [{style, Style}]),
+ Font = observer_wx:get_attrib({font, fixed}),
+ Attr = wxTextAttr:new(?wxBLACK, [{font, Font}]),
+ true = wxTextCtrl:setDefaultStyle(Text, Attr),
+ wxTextAttr:destroy(Attr),
+ Text.
+
+init_message_page(Parent, Pid) ->
+ Text = init_text_page(Parent),
+ Format = fun(Message, Number) ->
+ {io_lib:format("~-4.w ~p~n", [Number, Message]),
+ Number+1}
+ end,
+ Update = fun() ->
+ {messages,RawMessages} =
+ observer_wx:try_rpc(node(Pid), erlang, process_info, [Pid, messages]),
+ {Messages,_} = lists:mapfoldl(Format, 1, RawMessages),
+ Last = wxTextCtrl:getLastPosition(Text),
+ wxTextCtrl:remove(Text, 0, Last),
+ case Messages =:= [] of
+ true ->
+ wxTextCtrl:writeText(Text, "No messages");
+ false ->
+ wxTextCtrl:writeText(Text, Messages)
+ end
+ end,
+ Update(),
+ {Text, Update}.
+
+init_dict_page(Parent, Pid) ->
+ Text = init_text_page(Parent),
+ Update = fun() ->
+ {dictionary,RawDict} =
+ observer_wx:try_rpc(node(Pid), erlang, process_info, [Pid, dictionary]),
+ Dict = [io_lib:format("~-20.w ~p~n", [K, V]) || {K, V} <- RawDict],
+ Last = wxTextCtrl:getLastPosition(Text),
+ wxTextCtrl:remove(Text, 0, Last),
+ wxTextCtrl:writeText(Text, Dict)
+ end,
+ Update(),
+ {Text, Update}.
+
+init_stack_page(Parent, Pid) ->
+ Text = init_text_page(Parent),
+ Format = fun({Mod, Fun, Arg, Info}) ->
+ Str = io_lib:format("~w:~w/~w", [Mod,Fun,Arg]),
+ case Info of
+ [{file,File},{line,Line}] ->
+ io_lib:format("~-45.s ~s:~w~n", [Str,File,Line]);
+ _ ->
+ [Str,$\n]
+ end
+ end,
+ Update = fun() ->
+ {current_stacktrace,RawBt} =
+ observer_wx:try_rpc(node(Pid), erlang, process_info,
+ [Pid, current_stacktrace]),
+ Last = wxTextCtrl:getLastPosition(Text),
+ wxTextCtrl:remove(Text, 0, Last),
+ [wxTextCtrl:writeText(Text, Format(Entry)) || Entry <- RawBt]
+ end,
+ Update(),
+ {Text, Update}.
+
+create_menus(MenuBar) ->
+ Menus = [{"File", [#create_menu{id=?wxID_CLOSE, text="Close"}]},
+ {"View", [#create_menu{id=?REFRESH, text="Refresh\tCtrl-R"}]}],
+ observer_lib:create_menus(Menus, MenuBar, new_window).
+
+process_info_fields(Pid) ->
+ RawInfo = observer_wx:try_rpc(node(Pid), erlang, process_info, [Pid, item_list()]),
+ Struct = [{"Overview",
+ [{"Initial Call", initial_call},
+ {"Current Function", current_function},
+ {"Registered Name", registered_name},
+ {"Status", status},
+ {"Message Queue Len",message_queue_len},
+ {"Priority", priority},
+ {"Trap Exit", trap_exit},
+ {"Reductions", reductions},
+ {"Binary", binary},
+ {"Last Calls", last_calls},
+ {"Catch Level", catchlevel},
+ {"Trace", trace},
+ {"Suspending", suspending},
+ {"Sequential Trace Token", sequential_trace_token},
+ {"Error Handler", error_handler}]},
+ {"Connections",
+ [{"Group Leader", group_leader},
+ {"Links", links},
+ {"Monitors", monitors},
+ {"Monitored by", monitored_by}]},
+ {"Memory and Garbage Collection", right,
+ [{"Memory", {bytes, memory}},
+ {"Stack and Heaps", {bytes, total_heap_size}},
+ {"Heap Size", {bytes, heap_size}},
+ {"Stack Size", {bytes, stack_size}},
+ {"GC Min Heap Size", {bytes, get_gc_info(min_heap_size)}},
+ {"GC FullSweep After", get_gc_info(fullsweep_after)}
+ ]}],
+ observer_lib:fill_info(Struct, RawInfo).
+
+item_list() ->
+ [ %% backtrace,
+ binary,
+ catchlevel,
+ current_function,
+ %% dictionary,
+ error_handler,
+ garbage_collection,
+ group_leader,
+ heap_size,
+ initial_call,
+ last_calls,
+ links,
+ memory,
+ message_queue_len,
+ %% messages,
+ monitored_by,
+ monitors,
+ priority,
+ reductions,
+ registered_name,
+ sequential_trace_token,
+ stack_size,
+ status,
+ suspending,
+ total_heap_size,
+ trace,
+ trap_exit].
+
+get_gc_info(Arg) ->
+ fun(Data) ->
+ GC = proplists:get_value(garbage_collection, Data),
+ proplists:get_value(Arg, GC)
+ end.
diff --git a/lib/observer/src/observer_sys_wx.erl b/lib/observer/src/observer_sys_wx.erl
new file mode 100644
index 0000000000..ddedcf3829
--- /dev/null
+++ b/lib/observer/src/observer_sys_wx.erl
@@ -0,0 +1,223 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2011. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+-module(observer_sys_wx).
+
+-behaviour(wx_object).
+
+-export([start_link/2]).
+%% wx_object callbacks
+-export([init/1, handle_info/2, terminate/2, code_change/3, handle_call/3,
+ handle_event/2, handle_cast/2]).
+
+-export([sys_info/0]).
+
+-include_lib("wx/include/wx.hrl").
+-include("observer_defs.hrl").
+
+-define(ID_REFRESH, 101).
+-define(ID_REFRESH_INTERVAL, 102).
+
+%% Records
+-record(sys_wx_state,
+ {parent,
+ node,
+ parent_notebook,
+ panel, sizer,
+ menubar,
+ fields,
+ timer}).
+
+start_link(Notebook, Parent) ->
+ wx_object:start_link(?MODULE, [Notebook, Parent], []).
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+init([Notebook, Parent]) ->
+ SysInfo = sys_info(),
+ {Info, Stat} = info_fields(),
+ Panel = wxPanel:new(Notebook),
+ Sizer = wxBoxSizer:new(?wxHORIZONTAL),
+ {FPanel0, _FSizer0, Fields0} =
+ observer_lib:display_info(Panel, observer_lib:fill_info(Info, SysInfo)),
+ {FPanel1, _FSizer1, Fields1} =
+ observer_lib:display_info(Panel, observer_lib:fill_info(Stat, SysInfo)),
+ wxSizer:add(Sizer, FPanel0, [{flag, ?wxEXPAND bor ?wxTOP bor ?wxBOTTOM bor ?wxLEFT},
+ {proportion, 1}, {border, 5}]),
+ wxSizer:add(Sizer, FPanel1, [{flag, ?wxEXPAND bor ?wxTOP bor ?wxBOTTOM bor ?wxRIGHT},
+ {proportion, 1}, {border, 5}]),
+ wxPanel:setSizer(Panel, Sizer),
+ Timer = observer_lib:start_timer(10),
+ {Panel, #sys_wx_state{parent=Parent,
+ parent_notebook=Notebook,
+ panel=Panel, sizer=Sizer,
+ timer=Timer, fields=Fields0 ++ Fields1}}.
+
+create_sys_menu(Parent) ->
+ View = {"View", [#create_menu{id = ?ID_REFRESH, text = "Refresh\tCtrl-R"},
+ #create_menu{id = ?ID_REFRESH_INTERVAL, text = "Refresh interval"}]},
+ observer_wx:create_menus(Parent, [View]).
+
+update_syspage(#sys_wx_state{node = Node, fields=Fields, sizer=Sizer}) ->
+ SysInfo = observer_wx:try_rpc(Node, ?MODULE, sys_info, []),
+ {Info, Stat} = info_fields(),
+ observer_lib:update_info(Fields, observer_lib:fill_info(Info, SysInfo) ++
+ observer_lib:fill_info(Stat, SysInfo)),
+ wxSizer:layout(Sizer).
+
+info_fields() ->
+ Info = [{"System and Architecture",
+ [{"System Version", otp_release},
+ {"Erts Version", version},
+ {"Compiled for", system_architecture},
+ {"Emulator Wordsize", wordsize_external},
+ {"Process Wordsize", wordsize_internal},
+ {"Smp Support", smp_support},
+ {"Thread Support", threads},
+ {"Async thread pool size", thread_pool_size}
+ ]},
+ {"CPU's and Threads",
+ [{"System Logical CPU's", logical_processors},
+ {"Erlang Logical CPU's", logical_processors_online},
+ {"Used Logical CPU's", logical_processors_available}
+ ]}
+ ],
+ Stat = [{"Memory Usage", right,
+ [{"Total", total},
+ {"Processes", processes},
+ {"Atoms", atom},
+ {"Binaries", binary},
+ {"Code", code},
+ {"Ets", ets}
+ ]},
+ {"Statistics", right,
+ [{"Up time", uptime},
+ {"Max Processes", process_limit},
+ {"Processes", process_count},
+ {"Run Queue", run_queue},
+ {"IO Input", io_input},
+ {"IO Output", io_output}
+ ]}
+ ],
+ {Info, Stat}.
+
+%%%%%%%%%%%%%%%%%%%%%%% Callbacks %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+handle_info(refresh_interval, #sys_wx_state{panel = Panel,
+ node = Node} = State) ->
+ try
+ update_syspage(State)
+ catch error:{badrpc, _} ->
+ observer_wx:return_to_localnode(Panel, Node)
+ end,
+ {noreply, State};
+
+handle_info({node, Node}, #sys_wx_state{panel = Panel} = State) ->
+ UpdState = State#sys_wx_state{node = Node},
+ try
+ update_syspage(UpdState),
+ {noreply, UpdState}
+ catch error:{badrpc, _} ->
+ observer_wx:return_to_localnode(Panel, Node),
+ {noreply, State}
+ end;
+
+handle_info({active, Node}, #sys_wx_state{parent = Parent, panel = Panel,
+ timer = Timer} = State) ->
+ UpdState = State#sys_wx_state{node = Node},
+ create_sys_menu(Parent),
+ try
+ update_syspage(UpdState),
+ {noreply, UpdState#sys_wx_state{timer=observer_lib:start_timer(Timer)}}
+ catch error:{badrpc, _} ->
+ observer_wx:return_to_localnode(Panel, Node),
+ {noreply, State}
+ end;
+
+
+handle_info(not_active, #sys_wx_state{timer = Timer} = State) ->
+ {noreply, State#sys_wx_state{timer = observer_lib:stop_timer(Timer)}};
+
+handle_info(Info, State) ->
+ io:format("~p:~p: Unhandled info: ~p~n", [?MODULE, ?LINE, Info]),
+ {noreply, State}.
+
+terminate(_Reason, _State) ->
+ ok.
+
+code_change(_, _, State) ->
+ {stop, not_yet_implemented, State}.
+
+handle_call(Msg, _From, State) ->
+ io:format("~p~p: Unhandled Call ~p~n",[?MODULE, ?LINE, Msg]),
+ {reply, ok, State}.
+
+handle_cast(Msg, State) ->
+ io:format("~p~p: Unhandled cast ~p~n",[?MODULE, ?LINE, Msg]),
+ {noreply, State}.
+
+handle_event(#wx{id = ?ID_REFRESH, event = #wxCommand{type = command_menu_selected}},
+ #sys_wx_state{node = Node, panel = Panel} = State) ->
+ try
+ update_syspage(State)
+ catch error:{badrpc, _} ->
+ observer_wx:return_to_localnode(Panel, Node)
+ end,
+ {noreply, State};
+
+handle_event(#wx{id = ?ID_REFRESH_INTERVAL,
+ event = #wxCommand{type = command_menu_selected}},
+ #sys_wx_state{timer = Timer0, parent_notebook = Notebook} = State) ->
+ Timer = observer_lib:interval_dialog(Notebook, Timer0, 1, 5*60),
+ {noreply, State#sys_wx_state{timer=Timer}};
+
+handle_event(Event, State) ->
+ io:format("~p:~p: Unhandled event ~p\n", [?MODULE,?LINE,Event]),
+ {noreply, State}.
+
+
+sys_info() ->
+ {{_,Input},{_,Output}} = erlang:statistics(io),
+ [{process_count, erlang:system_info(process_count)},
+ {process_limit, erlang:system_info(process_limit)},
+ {uptime, {time_ms, element(1, erlang:statistics(wall_clock))}},
+ {run_queue, erlang:statistics(run_queue)},
+ {io_input, {bytes, Input}},
+ {io_output, {bytes, Output}},
+ {logical_processors, erlang:system_info(logical_processors)},
+ {logical_processors_available, erlang:system_info(logical_processors_available)},
+ {logical_processors_online, erlang:system_info(logical_processors_online)},
+
+ {total, {bytes, erlang:memory(total)}},
+ %%{processes_used, erlang:memory(processes_used)},
+ {processes, {bytes, erlang:memory(processes)}},
+ %%{atom_used, erlang:memory(atom_used)},
+ {atom, {bytes, erlang:memory(atom)}},
+ {binary, {bytes, erlang:memory(binary)}},
+ {code, {bytes, erlang:memory(code)}},
+ {ets, {bytes, erlang:memory(ets)}},
+
+ {otp_release, erlang:system_info(otp_release)},
+ {version, erlang:system_info(version)},
+ {system_architecture, erlang:system_info(system_architecture)},
+ {kernel_poll, erlang:system_info(kernel_poll)},
+ {smp_support, erlang:system_info(smp_support)},
+ {threads, erlang:system_info(threads)},
+ {thread_pool_size, erlang:system_info(thread_pool_size)},
+ {wordsize_internal, erlang:system_info({wordsize, internal})},
+ {wordsize_external, erlang:system_info({wordsize, external})}
+ ].
diff --git a/lib/observer/src/observer_trace_wx.erl b/lib/observer/src/observer_trace_wx.erl
new file mode 100644
index 0000000000..0ab7db121b
--- /dev/null
+++ b/lib/observer/src/observer_trace_wx.erl
@@ -0,0 +1,628 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2011. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+
+-module(observer_trace_wx).
+
+-export([start_link/2, add_processes/2]).
+-export([init/1, handle_info/2, terminate/2, code_change/3, handle_call/3,
+ handle_event/2, handle_cast/2]).
+
+-behaviour(wx_object).
+
+-include_lib("wx/include/wx.hrl").
+-include("observer_defs.hrl").
+
+-define(OPTIONS, 301).
+-define(SAVE_BUFFER, 302).
+-define(CLOSE, 303).
+-define(CLEAR, 304).
+-define(SAVE_TRACEOPTS, 305).
+-define(LOAD_TRACEOPTS, 306).
+-define(TOGGLE_TRACE, 307).
+-define(ADD_NEW, 308).
+-define(ADD_TP, 309).
+-define(PROCESSES, 350).
+-define(MODULES, 351).
+-define(FUNCTIONS, 352).
+-define(TRACERWIN, 353).
+
+-record(state,
+ {parent,
+ panel,
+ p_view,
+ m_view,
+ f_view,
+ nodes = [],
+ toggle_button,
+ tpids = [], %% #tpid
+ def_trace_opts = [],
+ tpatterns = dict:new(), % Key =:= Module::atom, Value =:= {M, F, A, MatchSpec}
+ match_specs = []}). % [ #match_spec{} ]
+
+-record(tpid, {pid, opts}).
+
+start_link(Notebook, ParentPid) ->
+ wx_object:start_link(?MODULE, [Notebook, ParentPid], []).
+
+add_processes(Tracer, Pids) when is_list(Pids) ->
+ wx_object:cast(Tracer, {add_processes, Pids}).
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+init([Notebook, ParentPid]) ->
+ wx:batch(fun() -> create_window(Notebook, ParentPid) end).
+
+create_window(Notebook, ParentPid) ->
+ %% Create the window
+ Panel = wxPanel:new(Notebook, [{size, wxWindow:getClientSize(Notebook)}]),
+ Sizer = wxBoxSizer:new(?wxVERTICAL),
+ Splitter = wxSplitterWindow:new(Panel, [{size, wxWindow:getClientSize(Panel)}]),
+ ProcessView = create_process_view(Splitter),
+ {MatchSpecView,ModView,FuncView} = create_matchspec_view(Splitter),
+ wxSplitterWindow:setSashGravity(Splitter, 0.5),
+ wxSplitterWindow:setMinimumPaneSize(Splitter,50),
+ wxSplitterWindow:splitHorizontally(Splitter, ProcessView, MatchSpecView),
+ wxSizer:add(Sizer, Splitter, [{flag, ?wxEXPAND bor ?wxALL}, {border, 5}, {proportion, 1}]),
+ %% Buttons
+ Buttons = wxBoxSizer:new(?wxHORIZONTAL),
+ ToggleButton = wxToggleButton:new(Panel, ?TOGGLE_TRACE, "Start Trace", []),
+ wxSizer:add(Buttons, ToggleButton),
+ New = wxButton:new(Panel, ?ADD_NEW, [{label, "Trace New Processes"}]),
+ wxSizer:add(Buttons, New),
+ ATP = wxButton:new(Panel, ?ADD_TP, [{label, "Add Trace Pattern"}]),
+ wxSizer:add(Buttons, ATP),
+ wxMenu:connect(Panel, command_togglebutton_clicked, []),
+ wxMenu:connect(Panel, command_button_clicked, []),
+ wxSizer:add(Sizer, Buttons, [{flag, ?wxALL},{border, 2}, {proportion,0}]),
+ wxWindow:setSizer(Panel, Sizer),
+ {Panel, #state{parent=ParentPid, panel=Panel,
+ p_view=ProcessView, m_view=ModView, f_view=FuncView,
+ toggle_button = ToggleButton,
+ match_specs=default_matchspecs()}}.
+
+default_matchspecs() ->
+ Ms = [{"Return Trace", [{'_', [], [{return_trace}]}], "fun(_) -> return_trace() end"},
+ {"Exception Trace", [{'_', [], [{exception_trace}]}], "fun(_) -> exception_trace() end"},
+ {"Message Caller", [{'_', [], [{message,{caller}}]}], "fun(_) -> message(caller()) end"},
+ {"Message Dump", [{'_', [], [{message,{process_dump}}]}], "fun(_) -> message(process_dump()) end"}],
+ [make_ms(Name,Term,FunStr) || {Name,Term,FunStr} <- Ms].
+
+create_process_view(Parent) ->
+ Style = ?wxLC_REPORT bor ?wxLC_SINGLE_SEL bor ?wxLC_HRULES,
+ Grid = wxListCtrl:new(Parent, [{winid, ?PROCESSES}, {style, Style}]),
+ Li = wxListItem:new(),
+ AddListEntry = fun({Name, Align, DefSize}, Col) ->
+ wxListItem:setText(Li, Name),
+ wxListItem:setAlign(Li, Align),
+ wxListCtrl:insertColumn(Grid, Col, Li),
+ wxListCtrl:setColumnWidth(Grid, Col, DefSize),
+ Col + 1
+ end,
+ ListItems = [{"Process Id", ?wxLIST_FORMAT_CENTER, 120},
+ {"Trace Options", ?wxLIST_FORMAT_LEFT, 300}],
+ lists:foldl(AddListEntry, 0, ListItems),
+ wxListItem:destroy(Li),
+
+ %% wxListCtrl:connect(Grid, command_list_item_activated),
+ %% wxListCtrl:connect(Grid, command_list_item_selected),
+ wxListCtrl:connect(Grid, size, [{skip, true}]),
+
+ wxWindow:setFocus(Grid),
+ Grid.
+
+create_matchspec_view(Parent) ->
+ Panel = wxPanel:new(Parent),
+ MainSz = wxBoxSizer:new(?wxHORIZONTAL),
+ Style = ?wxLC_REPORT bor ?wxLC_SINGLE_SEL bor ?wxLC_HRULES,
+ Splitter = wxSplitterWindow:new(Panel, []),
+ Modules = wxListCtrl:new(Splitter, [{winid, ?MODULES}, {style, Style}]),
+ Funcs = wxListCtrl:new(Splitter, [{winid, ?FUNCTIONS}, {style, Style}]),
+ Li = wxListItem:new(),
+ wxListItem:setText(Li, "Modules"),
+ wxListCtrl:insertColumn(Modules, 0, Li),
+ wxListItem:setText(Li, "Functions"),
+ wxListCtrl:insertColumn(Funcs, 0, Li),
+ wxListCtrl:setColumnWidth(Funcs, 0, 150),
+ wxListItem:setText(Li, "Match Spec"),
+ wxListCtrl:insertColumn(Funcs, 1, Li),
+ wxListCtrl:setColumnWidth(Funcs, 1, 300),
+ wxListItem:destroy(Li),
+ wxSplitterWindow:setSashGravity(Splitter, 0.0),
+ wxSplitterWindow:setMinimumPaneSize(Splitter,50),
+ wxSplitterWindow:splitVertically(Splitter, Modules, Funcs, [{sashPosition, 150}]),
+ wxSizer:add(MainSz, Splitter, [{flag, ?wxEXPAND}, {proportion, 1}]),
+
+ wxListCtrl:connect(Modules, size, [{skip, true}]),
+ wxListCtrl:connect(Funcs, size, [{skip, true}]),
+ wxListCtrl:connect(Modules, command_list_item_selected),
+ %% wxListCtrl:connect(Funcs, command_list_item_selected),
+ wxPanel:setSizer(Panel, MainSz),
+ {Panel, Modules, Funcs}.
+
+create_menues(Parent) ->
+ Menus = [{"File", [#create_menu{id = ?LOAD_TRACEOPTS, text = "Load settings"},
+ #create_menu{id = ?SAVE_TRACEOPTS, text = "Save settings"}]
+ }],
+ observer_wx:create_menus(Parent, Menus).
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%Main window
+handle_event(#wx{obj=Obj, event=#wxSize{size={W,_}}}, State) ->
+ case wx:getObjectType(Obj) =:= wxListCtrl of
+ true ->
+ wx:batch(fun() ->
+ Cols = wxListCtrl:getColumnCount(Obj),
+ Last = lists:foldl(fun(I, Last) ->
+ Last - wxListCtrl:getColumnWidth(Obj, I)
+ end, W-?LCTRL_WDECR, lists:seq(0, Cols - 2)),
+ Size = max(150, Last),
+ wxListCtrl:setColumnWidth(Obj, Cols-1, Size)
+ end);
+ false ->
+ ok
+ end,
+ {noreply, State};
+
+handle_event(#wx{id=?ADD_NEW}, State = #state{panel=Parent, def_trace_opts=TraceOpts}) ->
+ case observer_traceoptions_wx:process_trace(Parent, TraceOpts) of
+ {ok, Opts} ->
+ Process = #tpid{pid=new, opts=Opts},
+ {noreply, do_add_processes([Process], State#state{def_trace_opts=Opts})};
+ cancel ->
+ {noreply, State}
+ end;
+
+handle_event(#wx{id=?ADD_TP},
+ State = #state{panel=Parent, nodes=Nodes, match_specs=Ms}) ->
+ Node = case Nodes of
+ [N|_] -> N;
+ [] -> node()
+ end,
+ case observer_traceoptions_wx:trace_pattern(self(), Parent, Node, Ms) of
+ cancel ->
+ {noreply, State};
+ Patterns ->
+ {noreply, do_add_patterns(Patterns, State)}
+ end;
+
+handle_event(#wx{id=?MODULES, event=#wxList{type=command_list_item_selected, itemIndex=Row}},
+ State = #state{tpatterns=TPs, m_view=Mview, f_view=Fview}) ->
+ Module = list_to_atom(wxListCtrl:getItemText(Mview, Row)),
+ update_functions_view(dict:fetch(Module, TPs), Fview),
+ {noreply, State};
+
+
+handle_event(#wx{event = #wxCommand{type = command_togglebutton_clicked, commandInt = 1}},
+ #state{panel = Panel,
+ nodes = Nodes,
+ tpids = TProcs,
+ tpatterns = TPs,
+ toggle_button = ToggleBtn} = State) ->
+ LogWin = wxFrame:new(Panel, ?TRACERWIN, "Trace Log", [{size, {750, 800}}]),
+ Text = wxTextCtrl:new(LogWin, ?wxID_ANY,
+ [{style, ?wxTE_MULTILINE bor ?wxTE_RICH2 bor
+ ?wxTE_DONTWRAP bor ?wxTE_READONLY}]),
+ Font = observer_wx:get_attrib({font, fixed}),
+ Attr = wxTextAttr:new(?wxBLACK, [{font, Font}]),
+ true = wxTextCtrl:setDefaultStyle(Text, Attr),
+ Env = wx:get_env(),
+ Write = fun(Trace) ->
+ wx:set_env(Env),
+ wxTextCtrl:appendText(Text, textformat(Trace))
+ end,
+ {ok, _} = ttb:tracer(Nodes, [{file, {local,"/tmp/foo"}}, {shell, {only, Write}}]),
+ setup_ttb(dict:to_list(TPs), TProcs),
+ wxFrame:connect(LogWin, close_window, [{skip, true}]),
+ wxFrame:show(LogWin),
+ wxToggleButton:setLabel(ToggleBtn, "Stop Trace"),
+ {noreply, State};
+
+handle_event(#wx{event = #wxCommand{type = command_togglebutton_clicked, commandInt = 0}},
+ #state{toggle_button = ToggleBtn} = State) ->
+ %%Stop tracing
+ ttb:stop(nofetch),
+ wxToggleButton:setLabel(ToggleBtn, "Start Trace"),
+ {noreply, State};
+
+handle_event(#wx{id=?TRACERWIN, event=#wxClose{}},
+ #state{toggle_button = ToggleBtn} = State) ->
+ %%Stop tracing
+ ttb:stop(nofetch),
+ wxToggleButton:setLabel(ToggleBtn, "Start Trace"),
+ {noreply, State};
+
+%% handle_event(#wx{id = ?CLEAR, event = #wxCommand{type = command_menu_selected}},
+%% #state{text_ctrl = TxtCtrl} = State) ->
+%% wxTextCtrl:clear(TxtCtrl),
+%% {noreply, State};
+
+%% handle_event(#wx{id = ?SAVE_BUFFER, event = #wxCommand{type = command_menu_selected}},
+%% #state{frame = Frame, text_ctrl = TxtCtrl} = State) ->
+%% Dialog = wxFileDialog:new(Frame, [{style, ?wxFD_SAVE bor ?wxFD_OVERWRITE_PROMPT}]),
+%% case wxFileDialog:showModal(Dialog) of
+%% ?wxID_OK ->
+%% Path = wxFileDialog:getPath(Dialog),
+%% wxDialog:destroy(Dialog),
+%% case filelib:is_file(Path) of
+%% true ->
+%% observer_wx:create_txt_dialog(Frame, "File already exists: " ++ Path ++ "\n",
+%% "Error", ?wxICON_ERROR);
+%% false ->
+%% wxTextCtrl:saveFile(TxtCtrl, [{file, Path}])
+%% end;
+%% _ ->
+%% wxDialog:destroy(Dialog),
+%% ok
+%% end,
+%% {noreply, State};
+
+handle_event(#wx{id = ?SAVE_TRACEOPTS,
+ event = #wxCommand{type = command_menu_selected}},
+ #state{panel = Panel,
+ def_trace_opts = TraceOpts,
+ match_specs = MatchSpecs,
+ tpatterns = TracePatterns
+ } = State) ->
+ Dialog = wxFileDialog:new(Panel, [{style, ?wxFD_SAVE bor ?wxFD_OVERWRITE_PROMPT}]),
+ case wxFileDialog:showModal(Dialog) of
+ ?wxID_OK ->
+ Path = wxFileDialog:getPath(Dialog),
+ write_file(Panel, Path, TraceOpts, MatchSpecs, dict:to_list(TracePatterns));
+ _ ->
+ ok
+ end,
+ wxDialog:destroy(Dialog),
+ {noreply, State};
+
+handle_event(#wx{id = ?LOAD_TRACEOPTS,
+ event = #wxCommand{type = command_menu_selected}},
+ #state{panel = Panel} = State) ->
+ Dialog = wxFileDialog:new(Panel, [{style, ?wxFD_FILE_MUST_EXIST}]),
+ State2 = case wxFileDialog:showModal(Dialog) of
+ ?wxID_OK ->
+ Path = wxFileDialog:getPath(Dialog),
+ read_settings(Path, State);
+ _ ->
+ State
+ end,
+ wxDialog:destroy(Dialog),
+ {noreply, State2};
+
+handle_event(#wx{id=ID, event = What}, State) ->
+ io:format("~p:~p: Unhandled event: ~p, ~p ~n", [?MODULE, self(), ID, What]),
+ {noreply, State}.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+handle_call(Msg, _From, State) ->
+ io:format("~p~p: Got Call ~p~n",[?MODULE, ?LINE, Msg]),
+ {reply, ok, State}.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+handle_cast({add_processes, Pids}, State = #state{panel=Parent, def_trace_opts=TraceOpts}) ->
+ case observer_traceoptions_wx:process_trace(Parent, TraceOpts) of
+ {ok, Opts} ->
+ POpts = [#tpid{pid=Pid, opts=Opts} || Pid <- Pids],
+ {noreply, do_add_processes(POpts, State#state{def_trace_opts=Opts})};
+ cancel ->
+ {noreply, State}
+ end;
+handle_cast(Msg, State) ->
+ io:format("~p ~p: Unhandled cast ~p~n", [?MODULE, ?LINE, Msg]),
+ {noreply, State}.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+handle_info({active, _Node}, State=#state{parent=Parent}) ->
+ create_menues(Parent),
+ {noreply, State};
+
+handle_info(not_active, State) ->
+ {noreply, State};
+
+handle_info({update_ms, NewMs}, State) ->
+ {noreply, State#state{match_specs=NewMs}};
+
+handle_info(Any, State) ->
+ io:format("~p~p: received unexpected message: ~p\n", [?MODULE, self(), Any]),
+ {noreply, State}.
+
+terminate(_Reason, #state{nodes=_Nodes}) ->
+ %% case observer_wx:try_rpc(Node, erlang, whereis, [dbg]) of
+ %% undefined -> fine;
+ %% Pid -> exit(Pid, kill)
+ %% end,
+ ok.
+
+code_change(_, _, State) ->
+ {stop, not_yet_implemented, State}.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+do_add_processes(POpts, S0=#state{p_view=LCtrl, tpids=OldPids, nodes=Ns0}) ->
+ case merge_pids(POpts, OldPids) of
+ {OldPids, [], []} ->
+ S0;
+ {Pids, New, _Changed} ->
+ update_process_view(Pids, LCtrl),
+ Ns1 = lists:usort([node(Pid) || #tpid{pid=Pid} <- New, is_pid(Pid)]),
+ Nodes = case ordsets:subtract(Ns1, Ns0) of
+ [] -> Ns0; %% No new Nodes
+ NewNs ->
+ %% Handle new nodes
+ %% BUGBUG add trace patterns for new nodes
+ ordsets:union(NewNs, Ns0)
+ end,
+ S0#state{tpids=Pids, nodes=Nodes}
+ end.
+
+update_process_view(Pids, LCtrl) ->
+ wxListCtrl:deleteAllItems(LCtrl),
+ wx:foldl(fun(#tpid{pid=Pid, opts=Opts}, Row) ->
+ _Item = wxListCtrl:insertItem(LCtrl, Row, ""),
+ ?EVEN(Row) andalso
+ wxListCtrl:setItemBackgroundColour(LCtrl, Row, ?BG_EVEN),
+ wxListCtrl:setItem(LCtrl, Row, 0, observer_lib:to_str(Pid)),
+ wxListCtrl:setItem(LCtrl, Row, 1, observer_lib:to_str(Opts)),
+ Row+1
+ end, 0, Pids).
+
+do_add_patterns({Module, NewPs}, State=#state{tpatterns=TPs0, m_view=Mview, f_view=Fview}) ->
+ Old = case dict:find(Module, TPs0) of
+ {ok, Prev} -> Prev;
+ error -> []
+ end,
+ case merge_patterns(NewPs, Old) of
+ {Old, [], []} ->
+ State;
+ {MPatterns, _New, _Changed} ->
+ TPs = dict:store(Module, MPatterns, TPs0),
+ update_modules_view(lists:sort(dict:fetch_keys(TPs)), Module, Mview),
+ update_functions_view(dict:fetch(Module, TPs), Fview),
+ State#state{tpatterns=TPs}
+ end.
+
+update_modules_view(Mods, Module, LCtrl) ->
+ wxListCtrl:deleteAllItems(LCtrl),
+ wx:foldl(fun(Mod, Row) ->
+ _Item = wxListCtrl:insertItem(LCtrl, Row, ""),
+ ?EVEN(Row) andalso
+ wxListCtrl:setItemBackgroundColour(LCtrl, Row, ?BG_EVEN),
+ wxListCtrl:setItem(LCtrl, Row, 0, observer_lib:to_str(Mod)),
+ (Mod =:= Module) andalso
+ wxListCtrl:setItemState(LCtrl, Row, 16#FFFF, ?wxLIST_STATE_SELECTED),
+ Row+1
+ end, 0, Mods).
+
+update_functions_view(Funcs, LCtrl) ->
+ wxListCtrl:deleteAllItems(LCtrl),
+ wx:foldl(fun(#tpattern{fa=FA, ms=#match_spec{str=Ms}}, Row) ->
+ _Item = wxListCtrl:insertItem(LCtrl, Row, ""),
+ ?EVEN(Row) andalso wxListCtrl:setItemBackgroundColour(LCtrl, Row, ?BG_EVEN),
+ wxListCtrl:setItem(LCtrl, Row, 0, observer_lib:to_str({func,FA})),
+ wxListCtrl:setItem(LCtrl, Row, 1, Ms),
+ Row+1
+ end, 0, Funcs).
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+merge_pids([N1=#tpid{pid=new}|Ns], [N2=#tpid{pid=new}|Old]) ->
+ {Pids, New, Changed} = merge_pids_1(Ns,Old),
+ {[N1|Pids], New, [{N2,N2}|Changed]};
+merge_pids([N1=#tpid{pid=new}|Ns], Old) ->
+ {Pids, New, Changed} = merge_pids_1(Ns,Old),
+ {[N1|Pids], [N1|New], Changed};
+merge_pids(Ns, [N2=#tpid{pid=new}|Old]) ->
+ {Pids, New, Changed} = merge_pids_1(Ns,Old),
+ {[N2|Pids], New, Changed};
+merge_pids(New, Old) ->
+ merge_pids_1(New, Old).
+
+merge_pids_1(New, Old) ->
+ merge(lists:sort(New), Old, #tpid.pid, [], [], []).
+
+merge_patterns(New, Old) ->
+ merge(lists:sort(New), Old, #tpattern.fa, [], [], []).
+
+
+merge([N|Ns], [N|Os], El, New, Ch, All) ->
+ merge(Ns, Os, El, New, Ch, [N|All]);
+merge([N|Ns], [O|Os], El, New, Ch, All)
+ when element(El, N) == element(El, O) ->
+ merge(Ns, Os, El, New, [{O,N}|Ch], [N|All]);
+merge([N|Ns], Os=[O|_], El, New, Ch, All)
+ when element(El, N) < element(El, O) ->
+ merge(Ns, Os, El, [N|New], Ch, [N|All]);
+merge(Ns=[N|_], [O|Os], El, New, Ch, All)
+ when element(El, N) > element(El, O) ->
+ merge(Ns, Os, El, New, Ch, [O|All]);
+merge([], Os, _El, New, Ch, All) ->
+ {lists:reverse(All, Os), New, Ch};
+merge(Ns, [], _El, New, Ch, All) ->
+ {lists:reverse(All, Ns), Ns++New, Ch}.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+setup_ttb(TPs, TPids) ->
+ _R1 = [setup_tps(FTP, []) || {_, FTP} <- TPs],
+ _R2 = [ttb:p(Pid, dbg_flags(Flags)) || #tpid{pid=Pid, opts=Flags} <- TPids],
+ [#tpid{pid=_Pid, opts=_Flags}|_] = TPids,
+ %% io:format("ttb:p(pid(\"~w\", ~w).", [Pid, Flags]),
+ %% io:format("TTB ~w ~w~n",[R2, R1]),
+ ok.
+
+%% Sigh order is important
+setup_tps([First=#tpattern{fa={_,'_'}}|Rest], Prev) ->
+ setup_tp(First),
+ [setup_tp(TP) || TP <- lists:reverse(Prev)],
+ setup_tps(Rest, []);
+setup_tps([First=#tpattern{fa={F,_}}|Rest], Prev = [#tpattern{fa={F,_}}|_]) ->
+ setup_tps(Rest, [First|Prev]);
+setup_tps([First|Rest], Prev) ->
+ [setup_tp(TP) || TP <- lists:reverse(Prev)],
+ setup_tps(Rest, [First]);
+setup_tps([], Prev) ->
+ [setup_tp(TP) || TP <- lists:reverse(Prev)].
+
+setup_tp(#tpattern{m=M,fa={F,A}, ms=#match_spec{term=Ms}}) ->
+ ttb:tpl(M,F,A,Ms).
+
+dbg_flags(Flags) ->
+ [dbg_flag(Flag) || Flag <- Flags].
+
+dbg_flag(send) -> s;
+dbg_flag('receive') -> r;
+dbg_flag(functions) -> c;
+dbg_flag(on_spawn) -> sos;
+dbg_flag(on_link) -> sol;
+dbg_flag(on_first_spawn) -> sofs;
+dbg_flag(on_first_link) -> sofl;
+dbg_flag(events) -> p.
+
+textformat(Trace) when element(1, Trace) == trace_ts, tuple_size(Trace) >= 4 ->
+ format_trace(Trace, tuple_size(Trace)-1, element(tuple_size(Trace),Trace));
+textformat(Trace) when element(1, Trace) == drop, tuple_size(Trace) =:= 2 ->
+ io_lib:format("*** Dropped ~p messages.~n", [element(2,Trace)]);
+textformat(Trace) when element(1, Trace) == seq_trace, tuple_size(Trace) >= 3 ->
+ io_lib:format("*** Seq trace not implmented.~n", []);
+textformat(_) ->
+ "".
+
+format_trace(Trace, Size, TS0={_,_,MS}) ->
+ {_,{H,M,S}} = calendar:now_to_local_time(TS0),
+ TS = io_lib:format("~.2.0w:~.2.0w:~.2.0w:~.6.0w", [H,M,S,MS]),
+ From = element(2, Trace),
+ case element(3, Trace) of
+ 'receive' ->
+ case element(4, Trace) of
+ {dbg,ok} -> "";
+ Message ->
+ io_lib:format("~s (~100p) << ~100p ~n", [TS,From,Message])
+ end;
+ 'send' ->
+ Message = element(4, Trace),
+ To = element(5, Trace),
+ io_lib:format("~s (~100p) ~100p ! ~100p ~n", [TS,From,To,Message]);
+ call ->
+ case element(4, Trace) of
+ MFA when Size == 5 ->
+ Message = element(5, Trace),
+ io_lib:format("~s (~100p) call ~s (~100p) ~n", [TS,From,ffunc(MFA),Message]);
+ MFA ->
+ io_lib:format("~s (~100p) call ~s ~n", [TS,From,ffunc(MFA)])
+ end;
+ return_from ->
+ MFA = element(4, Trace),
+ Ret = element(5, Trace),
+ io_lib:format("~s (~100p) returned from ~s -> ~100p ~n", [TS,From,ffunc(MFA),Ret]);
+ return_to ->
+ MFA = element(4, Trace),
+ io_lib:format("~s (~100p) returning to ~s ~n", [TS,From,ffunc(MFA)]);
+ spawn when Size == 5 ->
+ Pid = element(4, Trace),
+ MFA = element(5, Trace),
+ io_lib:format("~s (~100p) spawn ~100p as ~s ~n", [TS,From,Pid,ffunc(MFA)]);
+ Op ->
+ io_lib:format("~s (~100p) ~100p ~s ~n", [TS,From,Op,ftup(Trace,4,Size)])
+ end.
+
+%%% These f* functions returns non-flat strings
+
+%% {M,F,[A1, A2, ..., AN]} -> "M:F(A1, A2, ..., AN)"
+%% {M,F,A} -> "M:F/A"
+ffunc({M,F,Argl}) when is_list(Argl) ->
+ io_lib:format("~100p:~100p(~s)", [M, F, fargs(Argl)]);
+ffunc({M,F,Arity}) ->
+ io_lib:format("~100p:~100p/~100p", [M,F,Arity]);
+ffunc(X) -> io_lib:format("~100p", [X]).
+
+%% Integer -> "Integer"
+%% [A1, A2, ..., AN] -> "A1, A2, ..., AN"
+fargs(Arity) when is_integer(Arity) -> integer_to_list(Arity);
+fargs([]) -> [];
+fargs([A]) -> io_lib:format("~100p", [A]); %% last arg
+fargs([A|Args]) -> [io_lib:format("~100p,", [A]) | fargs(Args)];
+fargs(A) -> io_lib:format("~100p", [A]). % last or only arg
+
+%% {A_1, A_2, ..., A_N} -> "A_Index A_Index+1 ... A_Size"
+ftup(Trace, Index, Index) ->
+ io_lib:format("~100p", [element(Index, Trace)]);
+ftup(Trace, Index, Size) ->
+ [io_lib:format("~100p ", [element(Index, Trace)])
+ | ftup(Trace, Index+1, Size)].
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+write_file(Frame, Filename, TraceOps, MatchSpecs, TPs) ->
+ FormatMS = fun(#match_spec{name=Id, term=T, func=F}) ->
+ io_lib:format("[{name,\"~s\"}, {term, ~w}, {func, \"~s\"}]",
+ [Id, T, F])
+ end,
+ FormatTP = fun({Module, FTPs}) ->
+ List = format_ftp(FTPs, FormatMS),
+ io_lib:format("{tp, ~w, [~s]}.~n",[Module, List])
+ end,
+ Str =
+ ["%%%\n%%% This file is generated by Observer\n",
+ "%%%\n%%% DO NOT EDIT!\n%%%\n",
+ [["{ms, ", FormatMS(Ms), "}.\n"] || Ms <- MatchSpecs],
+ "{traceopts, ", io_lib:format("~w",[TraceOps]) ,"}.\n",
+ [FormatTP(TP) || TP <- TPs]
+ ],
+ case file:write_file(Filename, list_to_binary(Str)) of
+ ok ->
+ success;
+ {error, Reason} ->
+ FailMsg = file:format_error(Reason),
+ observer_wx:create_txt_dialog(Frame, FailMsg, "Error", ?wxICON_ERROR)
+ end.
+
+format_ftp([#tpattern{fa={F,A}, ms=Ms}], FormatMS) ->
+ io_lib:format("{~w, ~w, ~s}", [F,A,FormatMS(Ms)]);
+format_ftp([#tpattern{fa={F,A}, ms=Ms}|Rest], FormatMS) ->
+ [io_lib:format("{~w, ~w, ~s},~n ", [F,A,FormatMS(Ms)]),
+ format_ftp(Rest, FormatMS)].
+
+read_settings(Filename, #state{match_specs=Ms0, def_trace_opts=TO0} = State) ->
+ case file:consult(Filename) of
+ {ok, Terms} ->
+ Ms = lists:usort(Ms0 ++ [parse_ms(MsList) || {ms, MsList} <- Terms]),
+ TOs = lists:usort(TO0 ++ proplists:get_value(traceopts, Terms, [])),
+ lists:foldl(fun parse_tp/2,
+ State#state{match_specs=Ms, def_trace_opts=TOs},
+ Terms);
+ {error, _} ->
+ observer_wx:create_txt_dialog(State#state.panel, "Could not load settings",
+ "Error", ?wxICON_ERROR),
+ State
+ end.
+
+parse_ms(Opts) ->
+ Name = proplists:get_value(name, Opts, "TracePattern"),
+ Term = proplists:get_value(term, Opts, [{'_',[],[ok]}]),
+ FunStr = proplists:get_value(term, Opts, "fun(_) -> ok end"),
+ make_ms(Name, Term, FunStr).
+
+make_ms(Name, Term, FunStr) ->
+ #match_spec{name=Name, term=Term, str=io_lib:format("~w", Term), func = FunStr}.
+
+parse_tp({tp, Mod, FAs}, State) ->
+ Patterns = [#tpattern{m=Mod,fa={F,A}, ms=parse_ms(List)} ||
+ {F,A,List} <- FAs],
+ do_add_patterns({Mod, Patterns}, State);
+parse_tp(_, State) ->
+ State.
diff --git a/lib/observer/src/observer_traceoptions_wx.erl b/lib/observer/src/observer_traceoptions_wx.erl
new file mode 100644
index 0000000000..bad05ec016
--- /dev/null
+++ b/lib/observer/src/observer_traceoptions_wx.erl
@@ -0,0 +1,572 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2011. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+
+-module(observer_traceoptions_wx).
+
+-include_lib("wx/include/wx.hrl").
+-include("observer_defs.hrl").
+
+-export([process_trace/2, trace_pattern/4]).
+
+-compile(export_all).
+
+process_trace(Parent, Default) ->
+ Dialog = wxDialog:new(Parent, ?wxID_ANY, "Process Options",
+ [{style, ?wxDEFAULT_DIALOG_STYLE bor ?wxRESIZE_BORDER}]),
+ Panel = wxPanel:new(Dialog),
+ MainSz = wxBoxSizer:new(?wxVERTICAL),
+ PanelSz = wxBoxSizer:new(?wxHORIZONTAL),
+ LeftSz = wxStaticBoxSizer:new(?wxVERTICAL, Panel, [{label, "Tracing options"}]),
+ RightSz = wxStaticBoxSizer:new(?wxVERTICAL, Panel, [{label, "Inheritance options:"}]),
+
+ FuncBox = wxCheckBox:new(Panel, ?wxID_ANY, "Trace function call", []),
+ check_box(FuncBox, lists:member(functions, Default)),
+ SendBox = wxCheckBox:new(Panel, ?wxID_ANY, "Trace send message", []),
+ check_box(SendBox, lists:member(send, Default)),
+ RecBox = wxCheckBox:new(Panel, ?wxID_ANY, "Trace receive message", []),
+ check_box(RecBox, lists:member('receive', Default)),
+ EventBox = wxCheckBox:new(Panel, ?wxID_ANY, "Trace process events", []),
+ check_box(EventBox, lists:member(events, Default)),
+
+ {SpawnBox, SpwnAllRadio, SpwnFirstRadio} =
+ optionpage_top_right(Panel, RightSz, [{flag, ?wxBOTTOM},{border, 5}], "spawn"),
+ {LinkBox, LinkAllRadio, LinkFirstRadio} =
+ optionpage_top_right(Panel, RightSz, [{flag, ?wxBOTTOM},{border, 5}], "link"),
+ SpawnBool = lists:member(on_spawn, Default) orelse lists:member(on_first_spawn, Default),
+ LinkBool = lists:member(on_link, Default) orelse lists:member(on_first_link, Default),
+ check_box(SpawnBox, SpawnBool),
+ check_box(LinkBox, LinkBool),
+ enable(SpawnBox, [SpwnAllRadio, SpwnFirstRadio]),
+ enable(LinkBox, [LinkAllRadio, LinkFirstRadio]),
+ wxRadioButton:setValue(SpwnAllRadio, lists:member(on_spawn, Default)),
+ wxRadioButton:setValue(SpwnFirstRadio, lists:member(on_first_spawn, Default)),
+ wxRadioButton:setValue(LinkAllRadio, lists:member(on_link, Default)),
+ wxRadioButton:setValue(LinkFirstRadio, lists:member(on_first_link, Default)),
+
+ wxSizer:add(LeftSz, FuncBox, []),
+ wxSizer:add(LeftSz, SendBox, []),
+ wxSizer:add(LeftSz, RecBox, []),
+ wxSizer:add(LeftSz, EventBox, []),
+ wxSizer:add(LeftSz, 150, -1),
+
+ wxSizer:add(PanelSz, LeftSz, [{flag, ?wxEXPAND}]),
+ wxSizer:add(PanelSz, RightSz,[{flag, ?wxEXPAND}]),
+ wxPanel:setSizer(Panel, PanelSz),
+ wxSizer:add(MainSz, Panel, [{flag, ?wxEXPAND}, {proportion,1}]),
+ Buttons = wxDialog:createButtonSizer(Dialog, ?wxOK bor ?wxCANCEL),
+ wxSizer:add(MainSz, Buttons, [{flag, ?wxEXPAND bor ?wxALL}, {border, 5}]),
+ wxWindow:setSizerAndFit(Dialog, MainSz),
+ wxSizer:setSizeHints(MainSz, Dialog),
+ wxCheckBox:connect(SpawnBox, command_checkbox_clicked,
+ [{callback, fun(#wx{event=#wxCommand{}},_) ->
+ enable(SpawnBox, [SpwnAllRadio, SpwnFirstRadio])
+ end}]),
+ wxCheckBox:connect(LinkBox, command_checkbox_clicked,
+ [{callback, fun(#wx{event=#wxCommand{}},_) ->
+ enable(LinkBox, [LinkAllRadio, LinkFirstRadio])
+ end}]),
+
+ Res = case wxDialog:showModal(Dialog) of
+ ?wxID_OK ->
+ All = [{SendBox, send}, {RecBox, 'receive'},
+ {FuncBox, functions}, {EventBox, events},
+ {{SpawnBox, SpwnAllRadio}, on_spawn},
+ {{SpawnBox,SpwnFirstRadio}, on_first_spawn},
+ {{LinkBox, LinkAllRadio}, on_link},
+ {{LinkBox, LinkFirstRadio}, on_first_link}],
+ Check = fun({Box, Radio}) ->
+ wxCheckBox:getValue(Box) andalso wxRadioButton:getValue(Radio);
+ (Box) ->
+ wxCheckBox:getValue(Box)
+ end,
+ Opts = [Id || {Tick, Id} <- All, Check(Tick)],
+ {ok, lists:reverse(Opts)};
+ ?wxID_CANCEL ->
+ cancel
+ end,
+ wxDialog:destroy(Dialog),
+ Res.
+
+trace_pattern(ParentPid, Parent, Node, MatchSpecs) ->
+ try
+ Module = module_selector(Parent, Node),
+ MFAs = function_selector(Parent, Node, Module),
+ MatchSpec = select_matchspec(ParentPid, Parent, MatchSpecs),
+ {Module, [#tpattern{m=M,fa={F,A},ms=MatchSpec} || {M,F,A} <- MFAs]}
+ catch cancel -> cancel
+ end.
+
+module_selector(Parent, Node) ->
+ Dialog = wxDialog:new(Parent, ?wxID_ANY, "Select Module",
+ [{style, ?wxDEFAULT_DIALOG_STYLE bor ?wxRESIZE_BORDER},
+ {size, {400, 400}}]),
+ Panel = wxPanel:new(Dialog),
+ PanelSz = wxBoxSizer:new(?wxVERTICAL),
+ MainSz = wxBoxSizer:new(?wxVERTICAL),
+
+ TxtCtrl = wxTextCtrl:new(Panel, ?wxID_ANY),
+ ListBox = wxListBox:new(Panel, ?wxID_ANY, [{style, ?wxLB_SINGLE}]),
+ wxSizer:add(PanelSz, TxtCtrl, [{flag, ?wxEXPAND}]),
+ wxSizer:add(PanelSz, ListBox, [{flag, ?wxEXPAND}, {proportion, 1}]),
+ wxPanel:setSizer(Panel, PanelSz),
+ wxSizer:add(MainSz, Panel, [{flag, ?wxEXPAND bor ?wxALL},
+ {border, 5}, {proportion, 1}]),
+ Buttons = wxDialog:createButtonSizer(Dialog, ?wxOK bor ?wxCANCEL),
+ wxSizer:add(MainSz, Buttons, [{flag, ?wxEXPAND bor ?wxALL},
+ {border, 5}, {proportion, 0}]),
+ wxWindow:setSizer(Dialog, MainSz),
+ OkId = wxDialog:getAffirmativeId(Dialog),
+ OkButt = wxWindow:findWindowById(OkId),
+ wxWindow:disable(OkButt),
+ wxWindow:setFocus(TxtCtrl),
+ %% init data
+ Modules = get_modules(Node),
+ AllModules = [{atom_to_list(X), X} || X <- Modules],
+ filter_listbox_data("", AllModules, ListBox),
+ wxTextCtrl:connect(TxtCtrl, command_text_updated,
+ [{callback, fun(#wx{event=#wxCommand{cmdString=Input}}, _) ->
+ filter_listbox_data(Input, AllModules, ListBox)
+ end}]),
+ wxListBox:connect(ListBox, command_listbox_doubleclicked,
+ [{callback, fun(_, _) -> wxDialog:endModal(Dialog, ?wxID_OK) end}]),
+ wxListBox:connect(ListBox, command_listbox_selected,
+ [{callback, fun(#wx{event=#wxCommand{commandInt=Id}}, _) ->
+ Id >= 0 andalso wxWindow:enable(OkButt)
+ end}]),
+
+ case wxDialog:showModal(Dialog) of
+ ?wxID_OK ->
+ SelId = wxListBox:getSelection(ListBox),
+ case SelId >= 0 of
+ true ->
+ Module = wxListBox:getClientData(ListBox, SelId),
+ wxDialog:destroy(Dialog),
+ Module;
+ false ->
+ wxDialog:destroy(Dialog),
+ throw(cancel)
+ end;
+ ?wxID_CANCEL ->
+ wxDialog:destroy(Dialog),
+ throw(cancel)
+ end.
+
+function_selector(Parent, Node, Module) ->
+ Dialog = wxDialog:new(Parent, ?wxID_ANY, "Trace Functions",
+ [{style, ?wxDEFAULT_DIALOG_STYLE bor ?wxRESIZE_BORDER},
+ {size, {400, 400}}]),
+
+ Panel = wxPanel:new(Dialog),
+ PanelSz = wxBoxSizer:new(?wxVERTICAL),
+ MainSz = wxBoxSizer:new(?wxVERTICAL),
+
+ TxtCtrl = wxTextCtrl:new(Panel, ?wxID_ANY),
+ ListBox = wxCheckListBox:new(Panel, ?wxID_ANY, [{style, ?wxLB_EXTENDED}]),
+ wxSizer:add(PanelSz, TxtCtrl, [{flag, ?wxEXPAND}]),
+ wxSizer:add(PanelSz, ListBox, [{flag, ?wxEXPAND}, {proportion, 1}]),
+ SelAllBtn = wxButton:new(Panel, ?wxID_ANY, [{label, "Check Visible"}]),
+ DeSelAllBtn = wxButton:new(Panel, ?wxID_ANY, [{label, "Uncheck Visible"}]),
+ ButtonSz = wxBoxSizer:new(?wxHORIZONTAL),
+ [wxSizer:add(ButtonSz, Button, []) || Button <- [SelAllBtn, DeSelAllBtn]],
+ wxSizer:add(PanelSz, ButtonSz, [{flag, ?wxEXPAND bor ?wxALL},
+ {border, 5}, {proportion, 0}]),
+ wxPanel:setSizer(Panel, PanelSz),
+ wxSizer:add(MainSz, Panel, [{flag, ?wxEXPAND bor ?wxALL},
+ {border, 5}, {proportion, 1}]),
+
+ Buttons = wxDialog:createButtonSizer(Dialog, ?wxOK bor ?wxCANCEL),
+ wxSizer:add(MainSz, Buttons, [{flag, ?wxEXPAND bor ?wxALL},
+ {border, 5}, {proportion, 0}]),
+ wxWindow:setSizer(Dialog, MainSz),
+ wxWindow:setFocus(TxtCtrl),
+ %% Init
+ Functions = observer_wx:try_rpc(Node, Module, module_info, [functions]),
+ Choices = lists:sort([{Name, Arity} || {Name, Arity} <- Functions,
+ not(erl_internal:guard_bif(Name, Arity))]),
+ ParsedChoices = parse_function_names(Choices),
+ filter_listbox_data("", ParsedChoices, ListBox, false),
+ %% Setup Event handling
+ wxTextCtrl:connect(TxtCtrl, command_text_updated,
+ [{callback,
+ fun(#wx{event=#wxCommand{cmdString=Input}}, _) ->
+ filter_listbox_data(Input, ParsedChoices, ListBox, false)
+ end}]),
+ Self = self(),
+
+ %% Sigh clientdata in checklistbox crashes on windows, wx-bug I presume.
+ %% Don't have time to investigate now, workaround file bug report later
+ GetClientData = fun(LB, N) ->
+ String = wxListBox:getString(LB, N),
+ {_, Data} = lists:keyfind(String, 1, ParsedChoices),
+ Data
+ end,
+ wxCheckListBox:connect(ListBox, command_checklistbox_toggled,
+ [{callback,
+ fun(#wx{event=#wxCommand{commandInt=N}}, _) ->
+ Self ! {ListBox, wxCheckListBox:isChecked(ListBox, N),
+ GetClientData(ListBox, N)}
+ end}]),
+ Check = fun(Id, Bool) ->
+ wxCheckListBox:check(ListBox, Id, [{check, Bool}]),
+ Self ! {ListBox, Bool, GetClientData(ListBox, Id)}
+ end,
+ wxButton:connect(SelAllBtn, command_button_clicked,
+ [{callback, fun(#wx{}, _) ->
+ Count = wxListBox:getCount(ListBox),
+ [Check(SelId, true) ||
+ SelId <- lists:seq(0, Count-1),
+ not wxCheckListBox:isChecked(ListBox, SelId)]
+ end}]),
+ wxButton:connect(DeSelAllBtn, command_button_clicked,
+ [{callback, fun(#wx{}, _) ->
+ Count = wxListBox:getCount(ListBox),
+ [Check(SelId, false) ||
+ SelId <- lists:seq(0, Count-1),
+ wxCheckListBox:isChecked(ListBox, SelId)]
+ end}]),
+ case wxDialog:showModal(Dialog) of
+ ?wxID_OK ->
+ wxDialog:destroy(Dialog),
+ case get_checked_funcs(ListBox, []) of
+ [] -> [{Module, '_', '_'}];
+ FAs ->
+ [{Module, F, A} || {F,A} <- FAs]
+ end;
+ ?wxID_CANCEL ->
+ wxDialog:destroy(Dialog),
+ throw(cancel)
+ end.
+
+get_checked_funcs(ListBox, Acc) ->
+ receive
+ {ListBox, true, FA} ->
+ get_checked_funcs(ListBox, [FA|lists:delete(FA,Acc)]);
+ {ListBox, false, FA} ->
+ get_checked_funcs(ListBox, lists:delete(FA,Acc))
+ after 0 ->
+ lists:reverse(Acc)
+ end.
+
+select_matchspec(Pid, Parent, MatchSpecs) ->
+ Dialog = wxDialog:new(Parent, ?wxID_ANY, "Trace Match Specifications",
+ [{style, ?wxDEFAULT_DIALOG_STYLE bor ?wxRESIZE_BORDER},
+ {size, {400, 400}}]),
+
+ Panel = wxPanel:new(Dialog),
+ PanelSz = wxBoxSizer:new(?wxVERTICAL),
+ MainSz = wxBoxSizer:new(?wxVERTICAL),
+ TxtSz = wxStaticBoxSizer:new(?wxVERTICAL, Panel, [{label, "Match specification:"}]),
+ BtnSz = wxBoxSizer:new(?wxHORIZONTAL),
+ SavedSz = wxStaticBoxSizer:new(?wxVERTICAL, Panel, [{label, "Saved match specifications:"}]),
+
+ TextCtrl = create_styled_txtctrl(Panel),
+ wxSizer:add(TxtSz, TextCtrl, [{flag, ?wxEXPAND}, {proportion, 1}]),
+
+ AddMsBtn = wxButton:new(Panel, ?wxID_ANY, [{label, "New"}]),
+ EditMsBtn = wxButton:new(Panel, ?wxID_ANY, [{label, "Edit"}]),
+ DelMsBtn = wxButton:new(Panel, ?wxID_ANY, [{label, "Delete"}]),
+ wxSizer:add(BtnSz, AddMsBtn),
+ wxSizer:add(BtnSz, EditMsBtn),
+ wxSizer:add(BtnSz, DelMsBtn),
+
+ ListBox = wxListBox:new(Panel, ?wxID_ANY, []),
+ wxSizer:add(SavedSz, ListBox, [{flag, ?wxEXPAND}, {proportion, 1}]),
+ wxSizer:add(PanelSz, TxtSz, [{flag, ?wxEXPAND}, {proportion, 1}]),
+ wxSizer:add(PanelSz, BtnSz),
+ wxSizer:add(PanelSz, SavedSz, [{flag, ?wxEXPAND}, {proportion, 1}]),
+
+ wxWindow:setSizer(Panel, PanelSz),
+ wxSizer:add(MainSz, Panel, [{flag, ?wxEXPAND bor ?wxALL},
+ {border, 5}, {proportion, 1}]),
+ Buttons = wxDialog:createButtonSizer(Dialog, ?wxOK bor ?wxCANCEL),
+ wxSizer:add(MainSz, Buttons, [{flag, ?wxEXPAND bor ?wxALL},
+ {border, 5}, {proportion, 0}]),
+ wxWindow:setSizer(Dialog, MainSz),
+ OkId = wxDialog:getAffirmativeId(Dialog),
+ OkButt = wxWindow:findWindowById(OkId),
+ wxWindow:disable(OkButt),
+ wxWindow:disable(EditMsBtn),
+ wxWindow:disable(DelMsBtn),
+
+ Choices = ms_names(MatchSpecs),
+ filter_listbox_data("", Choices, ListBox),
+
+ Add = fun(_,_) ->
+ case edit_ms(TextCtrl, new, Parent) of
+ Ms = #match_spec{} -> add_and_select(-1, Ms, ListBox);
+ Else -> Else
+ end
+ end,
+ Edit = fun(_,_) ->
+ SelId = wxListBox:getSelection(ListBox),
+ case SelId >= 0 of
+ true ->
+ #match_spec{name=Name} = wxListBox:getClientData(ListBox,SelId),
+ case edit_ms(TextCtrl, Name, Parent) of
+ Ms = #match_spec{} -> add_and_select(SelId, Ms, ListBox);
+ Else -> Else
+ end;
+ false ->
+ ok
+ end
+ end,
+ Del = fun(_,_) ->
+ SelId = wxListBox:getSelection(ListBox),
+ case SelId >= 0 of
+ true ->
+ wxListBox:delete(ListBox, SelId);
+ false ->
+ ok
+ end
+ end,
+ Sel = fun(#wx{event=#wxCommand{commandInt=Id}}, _) ->
+ case Id >= 0 of
+ true ->
+ wxWindow:enable(OkButt),
+ wxWindow:enable(EditMsBtn),
+ wxWindow:enable(DelMsBtn),
+ #match_spec{func=Str} = wxListBox:getClientData(ListBox,Id),
+ wxStyledTextCtrl:setText(TextCtrl, Str);
+ false ->
+ try
+ wxWindow:disable(OkButt),
+ wxWindow:disable(EditMsBtn),
+ wxWindow:disable(DelMsBtn)
+ catch _:_ -> ok
+ end
+ end
+ end,
+ wxButton:connect(AddMsBtn, command_button_clicked, [{callback,Add}]),
+ wxButton:connect(EditMsBtn, command_button_clicked, [{callback,Edit}]),
+ wxButton:connect(DelMsBtn, command_button_clicked, [{callback,Del}]),
+ wxListBox:connect(ListBox, command_listbox_selected, [{callback, Sel}]),
+ case wxDialog:showModal(Dialog) of
+ ?wxID_OK ->
+ SelId = wxListBox:getSelection(ListBox),
+ Count = wxListBox:getCount(ListBox),
+ MSs = [wxListBox:getClientData(ListBox, Id) ||
+ Id <- lists:seq(0, Count-1)],
+ Pid ! {update_ms, MSs},
+ MS = lists:nth(SelId+1, MSs),
+ wxDialog:destroy(Dialog),
+ MS;
+ ?wxID_CANCEL ->
+ wxDialog:destroy(Dialog),
+ throw(cancel)
+ end.
+
+edit_ms(TextCtrl, Label0, Parent) ->
+ Str = ensure_last_is_dot(wxStyledTextCtrl:getText(TextCtrl)),
+ try
+ MatchSpec = ms_from_string(Str),
+ Label = case Label0 == new of
+ true -> get_label(Parent);
+ _ -> Label0
+ end,
+ #match_spec{name=Label, term=MatchSpec,
+ str=io_lib:format("~w",[MatchSpec]),
+ func=Str}
+ catch
+ throw:cancel ->
+ ok;
+ throw:Error ->
+ observer_wx:create_txt_dialog(Parent, Error, "Error", ?wxICON_ERROR),
+ ok
+ end.
+
+get_label(Frame) ->
+ Dialog = wxTextEntryDialog:new(Frame, "Enter alias: "),
+ case wxDialog:showModal(Dialog) of
+ ?wxID_OK ->
+ wxTextEntryDialog:getValue(Dialog);
+ ?wxID_CANCEL ->
+ throw(cancel)
+ end.
+
+ms_from_string(Str) ->
+ try
+ Tokens = case erl_scan:string(Str) of
+ {ok, Ts, _} -> Ts;
+ {error, {SLine, SMod, SError}, _} ->
+ throw(io_lib:format("~w: ~s", [SLine,SMod:format_error(SError)]))
+ end,
+ Exprs = case erl_parse:parse_exprs(Tokens) of
+ {ok, T} -> T;
+ {error, {PLine, PMod, PError}} ->
+ throw(io_lib:format("~w: ~s", [PLine,PMod:format_error(PError)]))
+ end,
+ Term = case Exprs of
+ [{'fun', _, {clauses, Clauses}}|_] ->
+ case ms_transform:transform_from_shell(dbg,Clauses,orddict:new()) of
+ {error, [{_,[{MSLine,Mod,MSInfo}]}],_} ->
+ throw(io_lib:format("~w: ~p", [MSLine,Mod:format_error(MSInfo)]));
+ {error, _} ->
+ throw("Could not convert fun() to match spec");
+ Ms ->
+ Ms
+ end;
+ [Expr|_] ->
+ erl_parse:normalise(Expr)
+ end,
+ case erlang:match_spec_test([], Term, trace) of
+ {ok, _, _, _} -> Term;
+ {error, List} -> throw([[Error, $\n] || {_, Error} <- List])
+ end
+ catch error:_Reason ->
+ %% io:format("Bad term: ~s~n ~p in ~p~n", [Str, _Reason, erlang:get_stacktrace()]),
+ throw("Invalid term")
+ end.
+
+add_and_select(Id, MS0, ListBox) ->
+ [{Str,User}] = ms_names([MS0]),
+ Sel = case Id >= 0 of
+ true ->
+ wxListBox:setString(ListBox, Id, Str),
+ wxListBox:setClientData(ListBox, Id, User),
+ Id;
+ false ->
+ wxListBox:append(ListBox, Str, User)
+ end,
+ wxListBox:setSelection(ListBox, Sel).
+
+filter_listbox_data(Input, Data, ListBox) ->
+ filter_listbox_data(Input, Data, ListBox, true).
+
+filter_listbox_data(Input, Data, ListBox, AddClientData) ->
+ FilteredData = [X || X = {Str, _} <- Data, re:run(Str, Input) =/= nomatch],
+ wxListBox:clear(ListBox),
+ wxListBox:appendStrings(ListBox, [Str || {Str,_} <- FilteredData]),
+ AddClientData andalso
+ wx:foldl(fun({_, Term}, N) ->
+ wxListBox:setClientData(ListBox, N, Term),
+ N+1
+ end, 0, FilteredData),
+ FilteredData.
+
+get_modules(Node) ->
+ lists:sort([Module || {Module, _} <- observer_wx:try_rpc(Node, code, all_loaded, [])]).
+
+optionpage_top_right(Panel, TopRightSz, Options, Text) ->
+ Sizer = wxBoxSizer:new(?wxVERTICAL),
+ ChkBox = wxCheckBox:new(Panel, ?wxID_ANY, "Inherit on " ++ Text, []),
+ RadioSz = wxBoxSizer:new(?wxVERTICAL),
+ Radio1 = wxRadioButton:new(Panel, ?wxID_ANY, "All " ++ Text, [{style, ?wxRB_GROUP}]),
+ Radio2 = wxRadioButton:new(Panel, ?wxID_ANY, "First " ++ Text ++ " only", []),
+ wxSizer:add(Sizer, ChkBox, []),
+ wxSizer:add(RadioSz, Radio1, []),
+ wxSizer:add(RadioSz, Radio2, []),
+ wxSizer:add(Sizer, RadioSz, [{flag, ?wxLEFT},{border, 20}]),
+ wxSizer:add(TopRightSz, Sizer, Options),
+ {ChkBox, Radio1, Radio2}.
+
+
+create_styled_txtctrl(Parent) ->
+ FixedFont = observer_wx:get_attrib({font, fixed}),
+ Ed = wxStyledTextCtrl:new(Parent),
+ wxStyledTextCtrl:styleClearAll(Ed),
+ wxStyledTextCtrl:styleSetFont(Ed, ?wxSTC_STYLE_DEFAULT, FixedFont),
+ wxStyledTextCtrl:setLexer(Ed, ?wxSTC_LEX_ERLANG),
+ wxStyledTextCtrl:setMarginType(Ed, 1, ?wxSTC_MARGIN_NUMBER),
+ wxStyledTextCtrl:setSelectionMode(Ed, ?wxSTC_SEL_LINES),
+ wxStyledTextCtrl:setUseHorizontalScrollBar(Ed, false),
+
+ Styles = [{?wxSTC_ERLANG_DEFAULT, {0,0,0}},
+ {?wxSTC_ERLANG_COMMENT, {160,53,35}},
+ {?wxSTC_ERLANG_VARIABLE, {150,100,40}},
+ {?wxSTC_ERLANG_NUMBER, {5,5,100}},
+ {?wxSTC_ERLANG_KEYWORD, {130,40,172}},
+ {?wxSTC_ERLANG_STRING, {170,45,132}},
+ {?wxSTC_ERLANG_OPERATOR, {30,0,0}},
+ {?wxSTC_ERLANG_ATOM, {0,0,0}},
+ {?wxSTC_ERLANG_FUNCTION_NAME, {64,102,244}},
+ {?wxSTC_ERLANG_CHARACTER,{236,155,172}},
+ {?wxSTC_ERLANG_MACRO, {40,144,170}},
+ {?wxSTC_ERLANG_RECORD, {40,100,20}},
+ {?wxSTC_ERLANG_SEPARATOR,{0,0,0}},
+ {?wxSTC_ERLANG_NODE_NAME,{0,0,0}}],
+ SetStyle = fun({Style, Color}) ->
+ wxStyledTextCtrl:styleSetFont(Ed, Style, FixedFont),
+ wxStyledTextCtrl:styleSetForeground(Ed, Style, Color)
+ end,
+ [SetStyle(Style) || Style <- Styles],
+ wxStyledTextCtrl:setKeyWords(Ed, 0, keyWords()),
+ Ed.
+
+
+keyWords() ->
+ L = ["after","begin","case","try","cond","catch","andalso","orelse",
+ "end","fun","if","let","of","query","receive","when","bnot","not",
+ "div","rem","band","and","bor","bxor","bsl","bsr","or","xor"],
+ lists:flatten([K ++ " " || K <- L] ++ [0]).
+
+
+enable(CheckBox, Radio) ->
+ case wxCheckBox:isChecked(CheckBox) of
+ false ->
+ [wxWindow:disable(R) || R <- Radio];
+ true ->
+ [wxWindow:enable(R) || R <- Radio]
+ end.
+
+
+check_box(ChkBox, Bool) ->
+ case Bool of
+ true ->
+ wxCheckBox:set3StateValue(ChkBox, ?wxCHK_CHECKED);
+ false ->
+ ignore
+ end.
+
+parse_function_names(Choices) ->
+ StrList = [{atom_to_list(Name) ++ "/" ++ integer_to_list(Arity), Term}
+ || Term = {Name, Arity} <- Choices],
+ parse_function_names(StrList, []).
+
+parse_function_names([], Acc) ->
+ lists:reverse(Acc);
+parse_function_names([{H, Term}|T], Acc) ->
+ IsFun = re:run(H, ".*-fun-\\d*?-"),
+ IsLc = re:run(H, ".*-lc\\$\\^\\d*?/\\d*?-\\d*?-"),
+ IsLbc = re:run(H, ".*-lbc\\$\\^\\d*?/\\d*?-\\d*?-"),
+ Parsed =
+ if IsFun =/= nomatch -> "Fun: " ++ H;
+ IsLc =/= nomatch -> "List comprehension: " ++ H;
+ IsLbc =/= nomatch -> "Bit comprehension: " ++ H;
+ true ->
+ H
+ end,
+ parse_function_names(T, [{Parsed, Term} | Acc]).
+
+ms_names(MatchSpecList) ->
+ MsOrAlias = fun(#match_spec{name = A, str = M}) ->
+ case A of
+ "" -> M;
+ _ -> A ++ " " ++ M
+ end
+ end,
+ [{MsOrAlias(X), X} || X <- MatchSpecList].
+
+ensure_last_is_dot([]) ->
+ ".";
+ensure_last_is_dot(String) ->
+ case lists:last(String) =:= $. of
+ true ->
+ String;
+ false ->
+ String ++ "."
+ end.
diff --git a/lib/observer/src/observer_tv.hrl b/lib/observer/src/observer_tv.hrl
new file mode 100644
index 0000000000..05e4f928d0
--- /dev/null
+++ b/lib/observer/src/observer_tv.hrl
@@ -0,0 +1,34 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2011. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+
+-record(tab, {name,
+ id = ignore,
+ size,
+ memory=0, %% In bytes
+ owner,
+ reg_name,
+ protection = public,
+ type=set,
+ keypos=1,
+ heir=none,
+ compressed=false,
+ fixed=false,
+ %% Mnesia Info
+ storage,
+ index
+ }).
diff --git a/lib/observer/src/observer_tv_table.erl b/lib/observer/src/observer_tv_table.erl
new file mode 100644
index 0000000000..7b5cdb44b9
--- /dev/null
+++ b/lib/observer/src/observer_tv_table.erl
@@ -0,0 +1,801 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2011. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+
+-module(observer_tv_table).
+
+-export([start_link/2]).
+
+%% wx_object callbacks
+-export([init/1, handle_info/2, terminate/2, code_change/3, handle_call/3,
+ handle_event/2, handle_sync_event/3, handle_cast/2]).
+
+-export([get_table/3]).
+
+-include("observer_defs.hrl").
+-import(observer_lib, [to_str/1]).
+
+-behaviour(wx_object).
+-include_lib("wx/include/wx.hrl").
+-include("observer_tv.hrl").
+
+-define(ID_TABLE_INFO, 400).
+-define(ID_REFRESH, 401).
+-define(ID_REFRESH_INTERVAL, 402).
+-define(ID_EDIT, 403).
+-define(ID_DELETE, 404).
+-define(ID_SEARCH, 405).
+
+-define(SEARCH_ENTRY, 420).
+-define(GOTO_ENTRY, 421).
+
+-define(DEFAULT_COL_WIDTH, 150).
+
+-record(state,
+ {
+ parent,
+ frame,
+ grid,
+ status,
+ sizer,
+ search,
+ selected,
+ node=node(),
+ columns,
+ pid,
+ source,
+ tab,
+ attrs,
+ timer
+ }).
+
+-record(opt,
+ {
+ sort_key=2,
+ sort_incr=true
+ }).
+
+-record(search,
+ {enable=true, % Subwindow is enabled
+ win, % Sash Sub window obj
+ name, % name
+
+ search, % Search input ctrl
+ goto, % Goto input ctrl
+ radio, % Radio buttons
+
+ find % Search string
+ }).
+
+-record(find, {start, % start pos
+ strlen, % Found
+ found % false
+ }).
+
+start_link(Parent, Opts) ->
+ wx_object:start_link(?MODULE, [Parent, Opts], []).
+
+init([Parent, Opts]) ->
+ Source = proplists:get_value(type, Opts),
+ Table = proplists:get_value(table, Opts),
+ Node = proplists:get_value(node, Opts),
+ Title0 = atom_to_list(Table#tab.name) ++ " @ " ++ atom_to_list(Node),
+ Title = case Source of
+ ets -> "TV Ets: " ++ Title0;
+ mnesia -> "TV Mnesia: " ++ Title0
+ end,
+ Frame = wxFrame:new(Parent, ?wxID_ANY, Title, [{size, {800, 300}}]),
+ IconFile = filename:join(code:priv_dir(observer), "erlang_observer.png"),
+ Icon = wxIcon:new(IconFile, [{type,?wxBITMAP_TYPE_PNG}]),
+ wxFrame:setIcon(Frame, Icon),
+ wxIcon:destroy(Icon),
+ MenuBar = wxMenuBar:new(),
+ create_menus(MenuBar),
+ wxFrame:setMenuBar(Frame, MenuBar),
+ %% wxFrame:setAcceleratorTable(Frame, AccelTable),
+ wxMenu:connect(Frame, command_menu_selected),
+
+ StatusBar = wxFrame:createStatusBar(Frame, []),
+ try
+ TabId = table_id(Table),
+ ColumnNames = column_names(Node, Source, TabId),
+ KeyPos = key_pos(Node, Source, TabId),
+
+ Attrs = observer_lib:create_attrs(),
+
+ Self = self(),
+ Holder = spawn_link(fun() ->
+ init_table_holder(Self, Table, Source,
+ length(ColumnNames), Node, Attrs)
+ end),
+
+ Panel = wxPanel:new(Frame),
+ Sizer = wxBoxSizer:new(?wxVERTICAL),
+ Style = ?wxLC_REPORT bor ?wxLC_VIRTUAL bor ?wxLC_SINGLE_SEL bor ?wxLC_HRULES,
+ Grid = wxListCtrl:new(Panel, [{style, Style},
+ {onGetItemText,
+ fun(_, Item,Col) -> get_row(Holder, Item, Col+1) end},
+ {onGetItemAttr,
+ fun(_, Item) -> get_attr(Holder, Item) end}
+ ]),
+ wxListCtrl:connect(Grid, command_list_item_activated),
+ wxListCtrl:connect(Grid, command_list_item_selected),
+ wxListCtrl:connect(Grid, command_list_col_click),
+ wxListCtrl:connect(Grid, size, [{skip, true}]),
+ wxWindow:setFocus(Grid),
+
+ Search = search_area(Panel),
+ wxSizer:add(Sizer, Grid,
+ [{flag, ?wxEXPAND bor ?wxALL}, {proportion, 1}, {border, 5}]),
+ wxSizer:add(Sizer, Search#search.win,
+ [{flag,?wxEXPAND bor ?wxLEFT bor ?wxRIGHT bor
+ ?wxRESERVE_SPACE_EVEN_IF_HIDDEN},
+ {border, 5}]),
+ wxWindow:setSizer(Panel, Sizer),
+ wxSizer:hide(Sizer, Search#search.win),
+
+ Cols = add_columns(Grid, 0, ColumnNames),
+ wxFrame:show(Frame),
+ {Panel, #state{frame=Frame, grid=Grid, status=StatusBar, search=Search,
+ sizer = Sizer,
+ parent=Parent, columns=Cols,
+ pid=Holder, source=Source, tab=Table#tab{keypos=KeyPos},
+ attrs=Attrs}}
+ catch node_or_table_down ->
+ wxFrame:destroy(Frame),
+ stop
+ end.
+
+add_columns(Grid, Start, ColumnNames) ->
+ Li = wxListItem:new(),
+ AddListEntry = fun(Name, Col) ->
+ wxListItem:setText(Li, to_str(Name)),
+ wxListItem:setAlign(Li, ?wxLIST_FORMAT_LEFT),
+ wxListCtrl:insertColumn(Grid, Col, Li),
+ wxListCtrl:setColumnWidth(Grid, Col, ?DEFAULT_COL_WIDTH),
+ Col + 1
+ end,
+ Cols = lists:foldl(AddListEntry, Start, ColumnNames),
+ wxListItem:destroy(Li),
+ Cols.
+
+create_menus(MB) ->
+ File = wxMenu:new(),
+ wxMenu:append(File, ?ID_TABLE_INFO, "Table Information\tCtrl-I"),
+ wxMenu:append(File, ?wxID_CLOSE, "Close"),
+ wxMenuBar:append(MB, File, "File"),
+ Edit = wxMenu:new(),
+ wxMenu:append(Edit, ?ID_EDIT, "Edit Object"),
+ wxMenu:append(Edit, ?ID_DELETE, "Delete Object\tCtrl-D"),
+ wxMenu:appendSeparator(Edit),
+ wxMenu:append(Edit, ?ID_SEARCH, "Search\tCtrl-S"),
+ wxMenu:appendSeparator(Edit),
+ wxMenu:append(Edit, ?ID_REFRESH, "Refresh\tCtrl-R"),
+ wxMenu:append(Edit, ?ID_REFRESH_INTERVAL, "Refresh interval..."),
+ wxMenuBar:append(MB, Edit, "Edit"),
+ Help = wxMenu:new(),
+ wxMenu:append(Help, ?wxID_HELP, "Help"),
+ wxMenuBar:append(MB, Help, "Help"),
+ ok.
+
+search_area(Parent) ->
+ HSz = wxBoxSizer:new(?wxHORIZONTAL),
+ wxSizer:add(HSz, wxStaticText:new(Parent, ?wxID_ANY, "Find:"),
+ [{flag,?wxALIGN_CENTER_VERTICAL}]),
+ TC1 = wxTextCtrl:new(Parent, ?SEARCH_ENTRY, [{style, ?wxTE_PROCESS_ENTER}]),
+ wxSizer:add(HSz, TC1, [{proportion,3}, {flag, ?wxEXPAND}]),
+ Nbtn = wxRadioButton:new(Parent, ?wxID_ANY, "Next"),
+ wxRadioButton:setValue(Nbtn, true),
+ wxSizer:add(HSz,Nbtn,[{flag,?wxALIGN_CENTER_VERTICAL}]),
+ Pbtn = wxRadioButton:new(Parent, ?wxID_ANY, "Previous"),
+ wxSizer:add(HSz,Pbtn,[{flag,?wxALIGN_CENTER_VERTICAL}]),
+ Cbtn = wxCheckBox:new(Parent, ?wxID_ANY, "Match Case"),
+ wxSizer:add(HSz,Cbtn,[{flag,?wxALIGN_CENTER_VERTICAL}]),
+ wxSizer:add(HSz, 15,15, [{proportion,1}, {flag, ?wxEXPAND}]),
+ wxSizer:add(HSz, wxStaticText:new(Parent, ?wxID_ANY, "Goto Entry:"),
+ [{flag,?wxALIGN_CENTER_VERTICAL}]),
+ TC2 = wxTextCtrl:new(Parent, ?GOTO_ENTRY, [{style, ?wxTE_PROCESS_ENTER}]),
+ wxSizer:add(HSz, TC2, [{proportion,0}, {flag, ?wxEXPAND}]),
+ wxTextCtrl:connect(TC1, command_text_updated),
+ wxTextCtrl:connect(TC1, command_text_enter),
+ wxTextCtrl:connect(TC1, kill_focus),
+ wxTextCtrl:connect(TC2, command_text_enter),
+ wxWindow:connect(Parent, command_button_clicked),
+
+ #search{name='Search Area', win=HSz,
+ search=TC1,goto=TC2,radio={Nbtn,Pbtn,Cbtn}}.
+
+edit(Index, #state{pid=Pid, frame=Frame}) ->
+ Str = get_row(Pid, Index, all),
+ Dialog = wxTextEntryDialog:new(Frame, "Edit object:", [{value, Str}]),
+ case wxTextEntryDialog:showModal(Dialog) of
+ ?wxID_OK ->
+ New = wxTextEntryDialog:getValue(Dialog),
+ wxTextEntryDialog:destroy(Dialog),
+ case Str =:= New of
+ true -> ok;
+ false ->
+ complete_edit(Index, New, Pid)
+ end;
+ ?wxID_CANCEL ->
+ wxTextEntryDialog:destroy(Dialog)
+ end.
+
+complete_edit(Row, New0, Pid) ->
+ New = case lists:reverse(New0) of
+ [$.|_] -> New0;
+ _ -> New0 ++ "."
+ end,
+ try
+ {ok, Tokens, _} = erl_scan:string(New),
+ {ok, Term} = erl_parse:parse_term(Tokens),
+ Pid ! {edit, Row, Term}
+ catch _:{badmatch, {error, {_, _, Err}}} ->
+ self() ! {error, ["Parse error: ", Err]};
+ _Err ->
+ self() ! {error, ["Syntax error in: ", New]}
+ end.
+
+handle_event(#wx{id=?ID_REFRESH},State = #state{pid=Pid}) ->
+ Pid ! refresh,
+ {noreply, State};
+
+handle_event(#wx{event=#wxList{type=command_list_col_click, col=Col}},
+ State = #state{pid=Pid}) ->
+ Pid ! {sort, Col+1},
+ {noreply, State};
+
+handle_event(#wx{event=#wxSize{size={W,_}}}, State=#state{grid=Grid}) ->
+ wx:batch(fun() ->
+ Cols = wxListCtrl:getColumnCount(Grid),
+ Last = lists:foldl(fun(I, Last) ->
+ Last - wxListCtrl:getColumnWidth(Grid, I)
+ end, W-?LCTRL_WDECR, lists:seq(0, Cols - 2)),
+ Size = max(?DEFAULT_COL_WIDTH, Last),
+ wxListCtrl:setColumnWidth(Grid, Cols-1, Size)
+ end),
+ {noreply, State};
+
+handle_event(#wx{event=#wxList{type=command_list_item_selected, itemIndex=Index}},
+ State = #state{pid=Pid, grid=Grid, status=StatusBar}) ->
+ N = wxListCtrl:getItemCount(Grid),
+ Str = get_row(Pid, Index, all),
+ wxStatusBar:setStatusText(StatusBar, io_lib:format("Objects: ~w: ~s",[N, Str])),
+ {noreply, State#state{selected=Index}};
+
+handle_event(#wx{event=#wxList{type=command_list_item_activated, itemIndex=Index}},
+ State) ->
+ edit(Index, State),
+ {noreply, State};
+
+handle_event(#wx{id=?ID_EDIT}, State = #state{selected=undefined}) ->
+ {noreply, State};
+handle_event(#wx{id=?ID_EDIT}, State = #state{selected=Index}) ->
+ edit(Index, State),
+ {noreply, State};
+
+handle_event(#wx{id=?ID_DELETE}, State = #state{selected=undefined}) ->
+ {noreply, State};
+handle_event(#wx{id=?ID_DELETE},
+ State = #state{pid=Pid, status=StatusBar, selected=Index}) ->
+ Str = get_row(Pid, Index, all),
+ Pid ! {delete, Index},
+ wxStatusBar:setStatusText(StatusBar, io_lib:format("Deleted object: ~s",[Str])),
+ {noreply, State};
+
+handle_event(#wx{id=?wxID_CLOSE}, State) ->
+ {stop, normal, State};
+
+handle_event(Help = #wx{id=?wxID_HELP}, State = #state{parent=Parent}) ->
+ Parent ! Help,
+ {noreply, State};
+
+handle_event(#wx{id=?GOTO_ENTRY, event=#wxCommand{cmdString=Str}},
+ State = #state{grid=Grid}) ->
+ try
+ Row0 = list_to_integer(Str),
+ Row1 = min(0, Row0),
+ Row = max(wxListCtrl:getItemCount(Grid)-1,Row1),
+ wxListCtrl:ensureVisible(Grid, Row),
+ ok
+ catch _:_ -> ok
+ end,
+ {noreply, State};
+
+%% Search functionality
+handle_event(#wx{id=?ID_SEARCH},
+ State = #state{sizer=Sz, search=Search}) ->
+ wxSizer:show(Sz, Search#search.win),
+ wxWindow:setFocus(Search#search.search),
+ wxSizer:layout(Sz),
+ {noreply, State};
+handle_event(#wx{id=?SEARCH_ENTRY, event=#wxFocus{}},
+ State = #state{search=Search, pid=Pid}) ->
+ Pid ! {mark_search_hit, false},
+ {noreply, State#state{search=Search#search{find=undefined}}};
+handle_event(#wx{id=?SEARCH_ENTRY, event=#wxCommand{cmdString=""}},
+ State = #state{search=Search, pid=Pid}) ->
+ Pid ! {mark_search_hit, false},
+ {noreply, State#state{search=Search#search{find=undefined}}};
+handle_event(#wx{id=?SEARCH_ENTRY, event=#wxCommand{type=command_text_enter,cmdString=Str}},
+ State = #state{grid=Grid, pid=Pid, status=SB,
+ search=Search=#search{radio={Next0, _, Case0},
+ find=Find}})
+ when Find =/= undefined ->
+ Dir = wxRadioButton:getValue(Next0) xor wx_misc:getKeyState(?WXK_SHIFT),
+ Case = wxCheckBox:getValue(Case0),
+ Pos = if Find#find.found, Dir -> %% Forward Continuation
+ Find#find.start+1;
+ Find#find.found -> %% Backward Continuation
+ Find#find.start-1;
+ Dir -> %% Forward wrap
+ 0;
+ true -> %% Backward wrap
+ wxListCtrl:getItemCount(Grid)-1
+ end,
+ Pid ! {mark_search_hit, false},
+ case search(Pid, Str, Pos, Dir, Case) of
+ false ->
+ wxStatusBar:setStatusText(SB, "Not found"),
+ Pid ! {mark_search_hit, Find#find.start},
+ wxListCtrl:refreshItem(Grid, Find#find.start),
+ {noreply, State#state{search=Search#search{find=#find{found=false}}}};
+ Row ->
+ wxListCtrl:ensureVisible(Grid, Row),
+ wxListCtrl:refreshItem(Grid, Row),
+ Status = "Found: (Hit Enter for next, Shift-Enter for previous)",
+ wxStatusBar:setStatusText(SB, Status),
+ {noreply, State#state{search=Search#search{find=#find{start=Row, found=true}}}}
+ end;
+handle_event(#wx{id=?SEARCH_ENTRY, event=#wxCommand{cmdString=Str}},
+ State = #state{grid=Grid, pid=Pid, status=SB,
+ search=Search=#search{radio={Next0, _, Case0},
+ find=Find}}) ->
+ try
+ Dir = wxRadioButton:getValue(Next0),
+ Case = wxCheckBox:getValue(Case0),
+ Start = case Dir of
+ true -> 0;
+ false -> wxListCtrl:getItemCount(Grid)-1
+ end,
+ Cont = case Find of
+ undefined ->
+ #find{start=Start, strlen=length(Str)};
+ #find{strlen=Old} when Old < length(Str) ->
+ Find#find{start=Start, strlen=length(Str)};
+ _ ->
+ Find#find{strlen=length(Str)}
+ end,
+
+ Pid ! {mark_search_hit, false},
+ case search(Pid, Str, Cont#find.start, Dir, Case) of
+ false ->
+ wxStatusBar:setStatusText(SB, "Not found"),
+ {noreply, State};
+ Row ->
+ wxListCtrl:ensureVisible(Grid, Row),
+ wxListCtrl:refreshItem(Grid, Row),
+ Status = "Found: (Hit Enter for next, Shift-Enter for previous)",
+ wxStatusBar:setStatusText(SB, Status),
+ {noreply, State#state{search=Search#search{find=#find{start=Row, found=true}}}}
+ end
+ catch _:_ -> {noreply, State}
+ end;
+
+handle_event(#wx{id=?ID_TABLE_INFO},
+ State = #state{frame=Frame, node=Node, source=Source, tab=Table}) ->
+ observer_tv_wx:display_table_info(Frame, Node, Source, Table),
+ {noreply, State};
+
+handle_event(#wx{id=?ID_REFRESH_INTERVAL},
+ State = #state{grid=Grid, timer=Timer0}) ->
+ Timer = observer_lib:interval_dialog(Grid, Timer0, 10, 5*60),
+ {noreply, State#state{timer=Timer}};
+
+handle_event(Event, State) ->
+ io:format("~p:~p, handle event ~p\n", [?MODULE, ?LINE, Event]),
+ {noreply, State}.
+
+handle_sync_event(Event, _Obj, _State) ->
+ io:format("~p:~p, handle sync_event ~p\n", [?MODULE, ?LINE, Event]),
+ ok.
+
+handle_call(Event, From, State) ->
+ io:format("~p:~p, handle call (~p) ~p\n", [?MODULE, ?LINE, From, Event]),
+ {noreply, State}.
+
+handle_cast(Event, State) ->
+ io:format("~p:~p, handle cast ~p\n", [?MODULE, ?LINE, Event]),
+ {noreply, State}.
+
+handle_info({no_rows, N}, State = #state{grid=Grid, status=StatusBar}) ->
+ wxListCtrl:setItemCount(Grid, N),
+ wxStatusBar:setStatusText(StatusBar, io_lib:format("Objects: ~w",[N])),
+ {noreply, State};
+handle_info({new_cols, New}, State = #state{grid=Grid, columns=Cols0}) ->
+ Cols = add_columns(Grid, Cols0, New),
+ {noreply, State#state{columns=Cols}};
+handle_info({refresh, Min, Max}, State = #state{grid=Grid}) ->
+ wxListCtrl:refreshItems(Grid, Min, Max),
+ {noreply, State};
+handle_info({error, Error}, State = #state{frame=Frame}) ->
+ Dlg = wxMessageDialog:new(Frame, Error),
+ wxMessageDialog:showModal(Dlg),
+ wxMessageDialog:destroy(Dlg),
+ {noreply, State};
+
+handle_info(Event, State) ->
+ io:format("~p:~p, handle info ~p\n", [?MODULE, ?LINE, Event]),
+ {noreply, State}.
+
+terminate(_Event, #state{pid=Pid, attrs=Attrs}) ->
+ %% ListItemAttr are not auto deleted
+ #attrs{odd=Odd, deleted=D, changed=Ch, searched=S} = Attrs,
+ wxListItemAttr:destroy(Odd),
+ wxListItemAttr:destroy(D),
+ wxListItemAttr:destroy(Ch),
+ wxListItemAttr:destroy(S),
+ unlink(Pid),
+ exit(Pid, window_closed),
+ ok.
+
+code_change(_, _, State) ->
+ State.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Table holder needs to be in a separate process otherwise
+%% the callback get_row/3 may deadlock if the process do
+%% wx calls when callback is invoked.
+get_row(Table, Item, Column) ->
+ Ref = erlang:monitor(process, Table),
+ Table ! {get_row, self(), Item, Column},
+ receive
+ {'DOWN', Ref, _, _, _} -> "";
+ {Table, Res} ->
+ erlang:demonitor(Ref),
+ Res
+ end.
+
+get_attr(Table, Item) ->
+ Ref = erlang:monitor(process, Table),
+ Table ! {get_attr, self(), Item},
+ receive
+ {'DOWN', Ref, _, _, _} -> "";
+ {Table, Res} ->
+ erlang:demonitor(Ref),
+ Res
+ end.
+
+search(Table, Str, Row, Dir, Case) ->
+ Ref = erlang:monitor(process, Table),
+ Table ! {search, [Str, Row, Dir, Case]},
+ receive
+ {'DOWN', Ref, _, _, _} -> "";
+ {Table, Res} ->
+ erlang:demonitor(Ref),
+ Res
+ end.
+
+-record(holder, {node, parent, pid,
+ table=[], n=0, columns,
+ temp=[],
+ search,
+ source, tabid,
+ sort,
+ key,
+ type,
+ attrs
+ }).
+
+init_table_holder(Parent, Table, MnesiaOrEts, Cols, Node, Attrs) ->
+ TabId = case Table#tab.id of
+ ignore -> Table#tab.name;
+ Id -> Id
+ end,
+ self() ! refresh,
+ table_holder(#holder{node=Node, parent=Parent,
+ source=MnesiaOrEts, tabid=TabId, columns=Cols,
+ sort=#opt{sort_key=Table#tab.keypos, sort_incr=true},
+ type=Table#tab.type, key=Table#tab.keypos,
+ attrs=Attrs}).
+
+table_holder(S0 = #holder{parent=Parent, pid=Pid, table=Table}) ->
+ receive
+ {get_attr, From, Row} ->
+ get_attr(From, Row, S0),
+ table_holder(S0);
+ {get_row, From, Row, Col} ->
+ get_row(From, Row, Col, Table),
+ table_holder(S0);
+ {Pid, Data} ->
+ S1 = handle_new_data_chunk(Data, S0),
+ table_holder(S1);
+ {sort, Col} ->
+ table_holder(sort(Col, S0));
+ {search, Data} ->
+ table_holder(search(Data, S0));
+ {mark_search_hit, Row} ->
+ Old = S0#holder.search,
+ is_integer(Old) andalso (Parent ! {refresh, Old, Old}),
+ table_holder(S0#holder{search=Row});
+ refresh when is_pid(Pid) ->
+ %% Already getting the table...
+ %% io:format("ignoring refresh", []),
+ table_holder(S0);
+ refresh ->
+ GetTab = rpc:call(S0#holder.node, ?MODULE, get_table,
+ [self(), S0#holder.tabid, S0#holder.source]),
+ table_holder(S0#holder{pid=GetTab});
+ {delete, Row} ->
+ delete_row(Row, S0),
+ table_holder(S0);
+ {edit, Row, Term} ->
+ edit_row(Row, Term, S0),
+ table_holder(S0);
+ What ->
+ io:format("Table holder got ~p~n",[What]),
+ table_holder(S0)
+ end.
+
+handle_new_data_chunk(Data, S0 = #holder{columns=Cols, parent=Parent}) ->
+ S1 = #holder{columns=NewCols} = handle_new_data_chunk2(Data, S0),
+ case NewCols =:= Cols of
+ true -> S1;
+ false ->
+ Parent ! {new_cols, lists:seq(Cols+1, NewCols)},
+ S1
+ end.
+
+handle_new_data_chunk2('$end_of_table',
+ S0 = #holder{parent=Parent, sort=Opt,
+ key=Key,
+ table=Old, temp=New}) ->
+ Table = merge(Old, New, Key),
+ N = length(Table),
+ Parent ! {no_rows, N},
+ sort(Opt#opt.sort_key, S0#holder{n=N, pid=undefine,
+ sort=Opt#opt{sort_key = undefined},
+ table=Table, temp=[]});
+handle_new_data_chunk2(Data, S0 = #holder{columns=Cols0, source=ets, temp=Tab0}) ->
+ {Tab, Cols} = parse_ets_data(Data, Cols0, Tab0),
+ S0#holder{columns=Cols, temp=Tab};
+handle_new_data_chunk2(Data, S0 = #holder{source=mnesia, temp=Tab}) ->
+ S0#holder{temp=(Data ++ Tab)}.
+
+parse_ets_data([[Rec]|Rs], C, Tab) ->
+ parse_ets_data(Rs, max(tuple_size(Rec), C), [Rec|Tab]);
+parse_ets_data([Recs|Rs], C0, Tab0) ->
+ {Tab, Cols} = parse_ets_data(Recs, C0, Tab0),
+ parse_ets_data(Rs, Cols, Tab);
+parse_ets_data([], Cols, Tab) ->
+ {Tab, Cols}.
+
+sort(Col, S=#holder{n=N, parent=Parent, sort=Opt0, table=Table0}) ->
+ {Opt, Table} = sort(Col, Opt0, Table0),
+ Parent ! {refresh, 0, N-1},
+ S#holder{sort=Opt, table=Table}.
+
+sort(Col, Opt = #opt{sort_key=Col, sort_incr=Bool}, Table) ->
+ {Opt#opt{sort_incr=not Bool}, lists:reverse(Table)};
+sort(Col, S=#opt{sort_incr=true}, Table) ->
+ {S#opt{sort_key=Col}, keysort(Col, Table)};
+sort(Col, S=#opt{sort_incr=false}, Table) ->
+ {S#opt{sort_key=Col}, lists:reverse(keysort(Col, Table))}.
+
+keysort(Col, Table) ->
+ Sort = fun([A0|_], [B0|_]) ->
+ A = try element(Col, A0) catch _:_ -> [] end,
+ B = try element(Col, B0) catch _:_ -> [] end,
+ case A == B of
+ true -> A0 =< B0;
+ false -> A < B
+ end;
+ (A0, B0) when is_tuple(A0), is_tuple(B0) ->
+ A = try element(Col, A0) catch _:_ -> [] end,
+ B = try element(Col, B0) catch _:_ -> [] end,
+ case A == B of
+ true -> A0 =< B0;
+ false -> A < B
+ end
+ end,
+ lists:sort(Sort, Table).
+
+search([Str, Row, Dir0, CaseSens],
+ S=#holder{parent=Parent, table=Table}) ->
+ Opt = case CaseSens of
+ true -> [];
+ false -> [caseless]
+ end,
+ {ok, Re} = re:compile(Str, Opt),
+ Dir = case Dir0 of
+ true -> 1;
+ false -> -1
+ end,
+ Res = search(Row, Dir, Re, Table),
+ Parent ! {self(), Res},
+ S#holder{search=Res}.
+
+search(Row, Dir, Re, Table) ->
+ Res = try lists:nth(Row+1, Table) of
+ Term ->
+ Str = io_lib:format("~w", [Term]),
+ re:run(Str, Re)
+ catch _:_ -> no_more
+ end,
+ case Res of
+ nomatch -> search(Row+Dir, Dir, Re, Table);
+ no_more -> false;
+ {match,_} -> Row
+ end.
+
+get_row(From, Row, Col, Table) ->
+ case lists:nth(Row+1, Table) of
+ [Object|_] when Col =:= all ->
+ From ! {self(), io_lib:format("~w", [Object])};
+ [Object|_] when tuple_size(Object) >= Col ->
+ From ! {self(), io_lib:format("~w", [element(Col, Object)])};
+ _ ->
+ From ! {self(), ""}
+ end.
+
+get_attr(From, Row, #holder{attrs=Attrs, search=Row}) ->
+ What = Attrs#attrs.searched,
+ From ! {self(), What};
+get_attr(From, Row, #holder{table=Table, attrs=Attrs}) ->
+ What = case lists:nth(Row+1, Table) of
+ [_|deleted] -> Attrs#attrs.deleted;
+ [_|changed] -> Attrs#attrs.changed;
+ [_|new] -> Attrs#attrs.changed;
+ _ when (Row rem 2) > 0 ->
+ Attrs#attrs.odd;
+ _ ->
+ Attrs#attrs.even
+ end,
+ From ! {self(), What}.
+
+merge([], New, _Key) ->
+ [[N] || N <- New]; %% First time
+merge(Old, New, Key) ->
+ merge2(keysort(Key, Old), keysort(Key, New), Key).
+
+merge2([[Obj|_]|Old], [Obj|New], Key) ->
+ [[Obj]|merge2(Old, New, Key)];
+merge2([[A|_]|Old], [B|New], Key)
+ when element(Key, A) == element(Key, B) ->
+ [[B|changed]|merge2(Old, New, Key)];
+merge2([[A|_]|Old], New = [B|_], Key)
+ when element(Key, A) < element(Key, B) ->
+ [[A|deleted]|merge2(Old, New, Key)];
+merge2(Old = [[A|_]|_], [B|New], Key)
+ when element(Key, A) > element(Key, B) ->
+ [[B|new]|merge2(Old, New, Key)];
+merge2([], New, _Key) ->
+ [[N|new] || N <- New];
+merge2(Old, [], _Key) ->
+ [[O|deleted] || [O|_] <- Old].
+
+
+delete_row(Row, S0 = #holder{parent=Parent}) ->
+ case delete(Row, S0) of
+ ok ->
+ self() ! refresh;
+ {error, Err} ->
+ Parent ! {error, "Could not delete object: " ++ Err}
+ end.
+
+
+delete(Row, #holder{tabid=Id, table=Table,
+ source=Source, node=Node}) ->
+ [Object|_] = lists:nth(Row+1, Table),
+ try
+ case Source of
+ ets ->
+ true = rpc:call(Node, ets, delete_object, [Id, Object]);
+ mnesia ->
+ ok = rpc:call(Node, mnesia, dirty_delete_object, [Id, Object])
+ end,
+ ok
+ catch _:_Error ->
+ {error, "node or table is not available"}
+ end.
+
+edit_row(Row, Term, S0 = #holder{parent=Parent}) ->
+ case delete(Row, S0) of
+ ok ->
+ case insert(Term, S0) of
+ ok -> self() ! refresh;
+ Err -> Parent ! {error, Err}
+ end;
+ {error, Err} ->
+ Parent ! {error, "Could not edit object: " ++ Err}
+ end.
+
+insert(Object, #holder{tabid=Id, source=Source, node=Node}) ->
+ try
+ case Source of
+ ets ->
+ true = rpc:call(Node, ets, insert, [Id, Object]);
+ mnesia ->
+ ok = rpc:call(Node, mnesia, dirty_write, [Id, Object])
+ end,
+ ok
+ catch _:_Error ->
+ {error, "node or table is not available"}
+ end.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+get_table(Parent, Table, Module) ->
+ spawn(fun() ->
+ link(Parent),
+ get_table2(Parent, Table, Module)
+ end).
+
+get_table2(Parent, Table, Type) ->
+ Size = case Type of
+ ets -> ets:info(Table, size);
+ mnesia -> mnesia:table_info(Table, size)
+ end,
+ case Size > 0 of
+ false ->
+ Parent ! {self(), '$end_of_table'},
+ normal;
+ true when Type =:= ets ->
+ Mem = ets:info(Table, memory),
+ Average = Mem div Size,
+ NoElements = max(10, 20000 div Average),
+ get_ets_loop(Parent, ets:match(Table, '$1', NoElements));
+ true ->
+ Mem = mnesia:table_info(Table, memory),
+ Average = Mem div Size,
+ NoElements = max(10, 20000 div Average),
+ Ms = [{'$1', [], ['$1']}],
+ Get = fun() ->
+ get_mnesia_loop(Parent, mnesia:select(Table, Ms, NoElements, read))
+ end,
+ %% Not a transaction, we don't want to grab locks when inspecting the table
+ mnesia:async_dirty(Get)
+ end.
+
+get_ets_loop(Parent, '$end_of_table') ->
+ Parent ! {self(), '$end_of_table'};
+get_ets_loop(Parent, {Match, Cont}) ->
+ Parent ! {self(), Match},
+ get_ets_loop(Parent, ets:match(Cont)).
+
+get_mnesia_loop(Parent, '$end_of_table') ->
+ Parent ! {self(), '$end_of_table'};
+get_mnesia_loop(Parent, {Match, Cont}) ->
+ Parent ! {self(), Match},
+ get_ets_loop(Parent, mnesia:select(Cont)).
+
+column_names(Node, Type, Table) ->
+ case Type of
+ ets -> [1, 2];
+ mnesia ->
+ Attrs = rpc:call(Node, mnesia, table_info, [Table, attributes]),
+ is_list(Attrs) orelse throw(node_or_table_down),
+ ["Record Name"|Attrs]
+ end.
+
+table_id(#tab{id=ignore, name=Name}) -> Name;
+table_id(#tab{id=Id}) -> Id.
+
+key_pos(_, mnesia, _) -> 2;
+key_pos(Node, ets, TabId) ->
+ KeyPos = rpc:call(Node, ets, info, [TabId, keypos]),
+ is_integer(KeyPos) orelse throw(node_or_table_down),
+ KeyPos.
diff --git a/lib/observer/src/observer_tv_wx.erl b/lib/observer/src/observer_tv_wx.erl
new file mode 100644
index 0000000000..ded03fadb1
--- /dev/null
+++ b/lib/observer/src/observer_tv_wx.erl
@@ -0,0 +1,475 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2011. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+-module(observer_tv_wx).
+
+-export([start_link/2, display_table_info/4]).
+
+%% wx_object callbacks
+-export([init/1, handle_info/2, terminate/2, code_change/3, handle_call/3,
+ handle_event/2, handle_sync_event/3, handle_cast/2]).
+
+-export([get_table_list/1]). %% RPC called move to runtime tools?
+
+-behaviour(wx_object).
+-include_lib("wx/include/wx.hrl").
+-include("observer_defs.hrl").
+-include("observer_tv.hrl").
+
+-define(GRID, 500).
+-define(ID_REFRESH, 401).
+-define(ID_REFRESH_INTERVAL, 402).
+-define(ID_ETS, 403).
+-define(ID_MNESIA, 404).
+-define(ID_UNREADABLE, 405).
+-define(ID_SYSTEM_TABLES, 406).
+-define(ID_TABLE_INFO, 407).
+
+-record(opt, {type=ets,
+ sys_hidden=true,
+ unread_hidden=true,
+ sort_key=2,
+ sort_incr=true
+ }).
+
+-record(state,
+ {
+ parent,
+ grid,
+ node=node(),
+ opt=#opt{},
+ selected,
+ tabs,
+ timer
+ }).
+
+start_link(Notebook, Parent) ->
+ wx_object:start_link(?MODULE, [Notebook, Parent], []).
+
+init([Notebook, Parent]) ->
+ Panel = wxPanel:new(Notebook),
+ Sizer = wxBoxSizer:new(?wxVERTICAL),
+ Style = ?wxLC_REPORT bor ?wxLC_SINGLE_SEL bor ?wxLC_HRULES,
+ Grid = wxListCtrl:new(Panel, [{winid, ?GRID}, {style, Style}]),
+ wxSizer:add(Sizer, Grid, [{flag, ?wxEXPAND bor ?wxALL},
+ {proportion, 1}, {border, 5}]),
+ wxWindow:setSizer(Panel, Sizer),
+ Li = wxListItem:new(),
+ AddListEntry = fun({Name, Align, DefSize}, Col) ->
+ wxListItem:setText(Li, Name),
+ wxListItem:setAlign(Li, Align),
+ wxListCtrl:insertColumn(Grid, Col, Li),
+ wxListCtrl:setColumnWidth(Grid, Col, DefSize),
+ Col + 1
+ end,
+ ListItems = [{"Table Name", ?wxLIST_FORMAT_LEFT, 200},
+ {"Table Id", ?wxLIST_FORMAT_RIGHT, 100},
+ {"Objects", ?wxLIST_FORMAT_RIGHT, 100},
+ {"Size (kB)", ?wxLIST_FORMAT_RIGHT, 100},
+ {"Owner Pid", ?wxLIST_FORMAT_CENTER, 150},
+ {"Owner Name", ?wxLIST_FORMAT_LEFT, 200}
+ ],
+ lists:foldl(AddListEntry, 0, ListItems),
+ wxListItem:destroy(Li),
+
+ wxListCtrl:connect(Grid, command_list_item_activated),
+ wxListCtrl:connect(Grid, command_list_item_selected),
+ wxListCtrl:connect(Grid, command_list_col_click),
+ wxListCtrl:connect(Grid, size, [{skip, true}]),
+
+ wxWindow:setFocus(Grid),
+ Timer = observer_lib:start_timer(10),
+ {Panel, #state{grid=Grid, parent=Parent, timer=Timer}}.
+
+handle_event(#wx{id=?ID_REFRESH},
+ State = #state{node=Node, grid=Grid, opt=Opt}) ->
+ Tables = get_tables(Node, Opt),
+ Tabs = update_grid(Grid, Opt, Tables),
+ {noreply, State#state{tabs=Tabs}};
+
+handle_event(#wx{event=#wxList{type=command_list_col_click, col=Col}},
+ State = #state{node=Node, grid=Grid,
+ opt=Opt0=#opt{sort_key=Key, sort_incr=Bool}}) ->
+ Opt = case Col+2 of
+ Key -> Opt0#opt{sort_incr=not Bool};
+ NewKey -> Opt0#opt{sort_key=NewKey}
+ end,
+ Tables = get_tables(Node, Opt),
+ Tabs = update_grid(Grid, Opt, Tables),
+ wxWindow:setFocus(Grid),
+ {noreply, State#state{opt=Opt, tabs=Tabs}};
+
+handle_event(#wx{id=Id}, State = #state{node=Node, grid=Grid, opt=Opt0})
+ when Id >= ?ID_ETS, Id =< ?ID_SYSTEM_TABLES ->
+ Opt = case Id of
+ ?ID_ETS -> Opt0#opt{type=ets};
+ ?ID_MNESIA -> Opt0#opt{type=mnesia};
+ ?ID_UNREADABLE -> Opt0#opt{unread_hidden= not Opt0#opt.unread_hidden};
+ ?ID_SYSTEM_TABLES -> Opt0#opt{sys_hidden= not Opt0#opt.sys_hidden}
+ end,
+ Tables = get_tables(Node, Opt),
+ Tabs = update_grid(Grid, Opt, Tables),
+ wxWindow:setFocus(Grid),
+ {noreply, State#state{opt=Opt, tabs=Tabs}};
+
+handle_event(#wx{event=#wxSize{size={W,_}}}, State=#state{grid=Grid}) ->
+ wx:batch(fun() ->
+ Cols = wxListCtrl:getColumnCount(Grid),
+ Last = lists:foldl(fun(I, Last) ->
+ Last - wxListCtrl:getColumnWidth(Grid, I)
+ end, W-?LCTRL_WDECR, lists:seq(0, Cols - 2)),
+ Size = max(200, Last),
+ wxListCtrl:setColumnWidth(Grid, Cols-1, Size)
+ end),
+ {noreply, State};
+
+handle_event(#wx{obj=Grid, event=#wxList{type=command_list_item_activated,
+ itemIndex=Index}},
+ State=#state{grid=Grid, node=Node, opt=#opt{type=Type}, tabs=Tabs}) ->
+ Table = lists:nth(Index+1, Tabs),
+ case Table#tab.protection of
+ private ->
+ self() ! {error, "Table has 'private' protection and can not be read"};
+ _ ->
+ observer_tv_table:start_link(Grid, [{node,Node}, {type,Type}, {table,Table}])
+ end,
+ {noreply, State};
+
+handle_event(#wx{event=#wxList{type=command_list_item_selected, itemIndex=Index}},
+ State) ->
+ {noreply, State#state{selected=Index}};
+
+handle_event(#wx{id=?ID_TABLE_INFO},
+ State = #state{grid=Grid, node=Node, opt=#opt{type=Type}, tabs=Tabs, selected=Sel}) ->
+ case Sel of
+ undefined ->
+ {noreply, State};
+ R when is_integer(R) ->
+ Table = lists:nth(Sel+1, Tabs),
+ display_table_info(Grid, Node, Type, Table),
+ {noreply, State}
+ end;
+
+handle_event(#wx{id=?ID_REFRESH_INTERVAL},
+ State = #state{grid=Grid, timer=Timer0}) ->
+ Timer = observer_lib:interval_dialog(Grid, Timer0, 10, 5*60),
+ {noreply, State#state{timer=Timer}};
+
+handle_event(Event, State) ->
+ io:format("~p:~p, handle event ~p\n", [?MODULE, ?LINE, Event]),
+ {noreply, State}.
+
+handle_sync_event(_Event, _Obj, _State) ->
+ ok.
+
+handle_call(_Event, _From, State) ->
+ {noreply, State}.
+
+handle_cast(_Event, State) ->
+ {noreply, State}.
+
+handle_info(refresh_interval, State = #state{node=Node, grid=Grid, opt=Opt}) ->
+ Tables = get_tables(Node, Opt),
+ Tabs = update_grid(Grid, Opt, Tables),
+ {noreply, State#state{tabs=Tabs}};
+
+handle_info({active, Node}, State = #state{parent=Parent, grid=Grid, opt=Opt,
+ timer=Timer0}) ->
+ Tables = get_tables(Node, Opt),
+ Tabs = update_grid(Grid, Opt, Tables),
+ wxWindow:setFocus(Grid),
+ create_menus(Parent, Opt),
+ Timer = observer_lib:start_timer(Timer0),
+ {noreply, State#state{node=Node, tabs=Tabs, timer=Timer}};
+
+handle_info(not_active, State = #state{timer = Timer0}) ->
+ Timer = observer_lib:stop_timer(Timer0),
+ {noreply, State#state{timer=Timer}};
+
+handle_info({node, Node}, State = #state{grid=Grid, opt=Opt}) ->
+ Tables = get_tables(Node, Opt),
+ Tabs = update_grid(Grid, Opt, Tables),
+ wxWindow:setFocus(Grid),
+ {noreply, State#state{node=Node, tabs=Tabs}};
+
+handle_info({error, Error}, State) ->
+ handle_error(Error),
+ {noreply, State};
+
+handle_info(_Event, State) ->
+ {noreply, State}.
+
+terminate(_Event, _State) ->
+ ok.
+
+code_change(_, _, State) ->
+ State.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+create_menus(Parent, #opt{sys_hidden=Sys, unread_hidden=UnR, type=Type}) ->
+ MenuEntries = [{"View",
+ [#create_menu{id = ?ID_TABLE_INFO, text = "Table information\tCtrl-I"},
+ separator,
+ #create_menu{id = ?ID_ETS, text = "&Ets Tables",
+ type=radio, check=Type==ets},
+ #create_menu{id = ?ID_MNESIA, text = "&Mnesia Tables",
+ type=radio, check=Type==mnesia},
+ separator,
+ #create_menu{id = ?ID_UNREADABLE, text = "View &Unreadable Tables",
+ type=check, check=not UnR},
+ #create_menu{id = ?ID_SYSTEM_TABLES, text = "View &System Tables",
+ type=check, check=not Sys},
+ separator,
+ #create_menu{id = ?ID_REFRESH, text = "Refresh\tCtrl-R"},
+ #create_menu{id = ?ID_REFRESH_INTERVAL, text = "Refresh Interval..."}
+ ]}],
+ observer_wx:create_menus(Parent, MenuEntries).
+
+get_tables(Node, Opt) ->
+ case rpc:call(Node, ?MODULE, get_table_list, [Opt]) of
+ {badrpc, Error} ->
+ self() ! {error, Error},
+ [];
+ {error, Error} ->
+ self() ! {error, Error},
+ [];
+ Result ->
+ Result
+ end.
+
+get_table_list(#opt{type=ets, unread_hidden=HideUnread, sys_hidden=HideSys}) ->
+ Info = fun(Id, Acc) ->
+ try
+ TabId = case ets:info(Id, named_table) of
+ true -> ignore;
+ false -> Id
+ end,
+ Name = ets:info(Id, name),
+ Protection = ets:info(Id, protection),
+ ignore(HideUnread andalso Protection == private, unreadable),
+ Owner = ets:info(Id, owner),
+ RegName = case catch process_info(Owner, registered_name) of
+ [] -> ignore;
+ {registered_name, ProcName} -> ProcName
+ end,
+ ignore(HideSys andalso ordsets:is_element(RegName, sys_processes()), system_tab),
+ ignore(HideSys andalso ordsets:is_element(Name, sys_tables()), system_tab),
+ ignore((RegName == mnesia_monitor)
+ andalso Name /= schema
+ andalso is_atom((catch mnesia:table_info(Name, where_to_read))), mnesia_tab),
+ Memory = ets:info(Id, memory) * erlang:system_info(wordsize),
+ Tab = #tab{name = Name,
+ id = TabId,
+ protection = Protection,
+ owner = Owner,
+ size = ets:info(Id, size),
+ reg_name = RegName,
+ type = ets:info(Id, type),
+ keypos = ets:info(Id, keypos),
+ heir = ets:info(Id, heir),
+ memory = Memory,
+ compressed = ets:info(Id, compressed),
+ fixed = ets:info(Id, fixed)
+ },
+ [Tab|Acc]
+ catch _:_What ->
+ %% io:format("Skipped ~p: ~p ~n",[Id, _What]),
+ Acc
+ end
+ end,
+ lists:foldl(Info, [], ets:all());
+get_table_list(#opt{type=mnesia, sys_hidden=HideSys}) ->
+ Owner = ets:info(schema, owner),
+ Owner /= undefined orelse
+ throw({error, "Mnesia is not running on: " ++ atom_to_list(node())}),
+ {registered_name, RegName} = process_info(Owner, registered_name),
+ Info = fun(Id, Acc) ->
+ try
+ Name = Id,
+ ignore(HideSys andalso ordsets:is_element(Name, mnesia_tables()), system_tab),
+ ignore(Name =:= schema, mnesia_tab),
+ Storage = mnesia:table_info(Id, storage_type),
+ Tab0 = #tab{name = Name,
+ owner = Owner,
+ size = mnesia:table_info(Id, size),
+ reg_name = RegName,
+ type = mnesia:table_info(Id, type),
+ keypos = 2,
+ memory = mnesia:table_info(Id, memory) * erlang:system_info(wordsize),
+ storage = Storage,
+ index = mnesia:table_info(Id, index)
+ },
+ Tab = if Storage == disc_only_copies ->
+ Tab0#tab{fixed = element(2, dets:info(Id, safe_fixed)) /= []};
+ (Storage == ram_copies) orelse
+ (Storage == disc_copies) ->
+ Tab0#tab{fixed = ets:info(Id, fixed),
+ compressed = ets:info(Id, compressed)};
+ true -> Tab0
+ end,
+ [Tab|Acc]
+ catch _:_What ->
+ %% io:format("Skipped ~p: ~p ~n",[Id, _What]),
+ Acc
+ end
+ end,
+ lists:foldl(Info, [], mnesia:system_info(tables)).
+
+display_table_info(Parent0, Node, Source, Table) ->
+ Parent = observer_lib:get_wx_parent(Parent0),
+ Title = "Table Info: " ++ atom_to_list(Table#tab.name),
+ Frame = wxMiniFrame:new(Parent, ?wxID_ANY, Title,
+ [{style, ?wxSYSTEM_MENU bor ?wxCAPTION
+ bor ?wxCLOSE_BOX bor ?wxRESIZE_BORDER}]),
+
+ IdInfo = {"Identification and Owner",
+ [{"Name", Table#tab.name},
+ {"Id", case Table#tab.id of
+ ignore -> Table#tab.name;
+ Id -> Id
+ end},
+ {"Named table", Table#tab.id == ignore},
+ {"Owner", Table#tab.owner},
+ {"Owner Name", case Table#tab.reg_name of
+ ignore -> "-";
+ Id -> Id
+ end},
+ {"Heir", Table#tab.heir},
+ {"Node", Node}]},
+ MnesiaSettings = case Source of
+ ets -> [];
+ mnesia ->
+ [{"Local storage type", case Table#tab.storage of
+ unknown -> "Not available";
+ ST -> ST
+ end},
+ {"Index positions", list_to_strings(Table#tab.index)}]
+ end,
+ Settings = {"Settings",
+ [{"Source", Source},
+ {"Key Position", Table#tab.keypos},
+ {"Table Type", Table#tab.type},
+ {"Protection Mode", Table#tab.protection},
+ {"Fixed", Table#tab.fixed}
+ | MnesiaSettings ]},
+ Memory = {"Memory Usage",
+ [{"Number of objects", Table#tab.size},
+ {"Memory allocated", {bytes, Table#tab.memory}},
+ {"Compressed", Table#tab.compressed}]},
+
+ {_, Sizer, _} = observer_lib:display_info(Frame, [IdInfo,Settings,Memory]),
+ wxSizer:setSizeHints(Sizer, Frame),
+ wxFrame:center(Frame),
+ wxFrame:show(Frame).
+
+list_to_strings([]) -> "None";
+list_to_strings([A]) -> integer_to_list(A);
+list_to_strings([A,B]) ->
+ integer_to_list(A) ++ " ," ++ list_to_strings(B).
+
+sys_tables() ->
+ [ac_tab, asn1,
+ cdv_dump_index_table, cdv_menu_table, cdv_decode_heap_table,
+ cell_id, cell_pos, clist,
+ cover_internal_data_table, cover_collected_remote_data_table, cover_binary_code_table,
+ code, code_names, cookies,
+ corba_policy, corba_policy_associations,
+ dets, dets_owners, dets_registry,
+ disk_log_names, disk_log_pids,
+ eprof, erl_atom_cache, erl_epmd_nodes,
+ etop_accum_tab, etop_tr,
+ ets_coverage_data,
+ file_io_servers,
+ gs_mapping, gs_names, gstk_db,
+ gstk_grid_cellid, gstk_grid_cellpos, gstk_grid_id,
+ httpd,
+ id,
+ ign_req_index, ign_requests,
+ index,
+ inet_cache, inet_db, inet_hosts,
+ 'InitialReferences',
+ int_db,
+ interpreter_includedirs_macros,
+ ir_WstringDef,
+ lmcounter, locks,
+% mnesia_decision,
+ mnesia_gvar, mnesia_stats,
+% mnesia_transient_decision,
+ pg2_table,
+ queue,
+ schema,
+ shell_records,
+ snmp_agent_table, snmp_local_db2, snmp_mib_data, snmp_note_store, snmp_symbolic_ets,
+ tkFun, tkLink, tkPriv,
+ ttb, ttb_history_table,
+ udp_fds, udp_pids
+ ].
+
+sys_processes() ->
+ [auth, code_server, global_name_server, inet_db,
+ mnesia_recover, net_kernel, timer_server, wxe_master].
+
+mnesia_tables() ->
+ [ir_AliasDef, ir_ArrayDef, ir_AttributeDef, ir_ConstantDef,
+ ir_Contained, ir_Container, ir_EnumDef, ir_ExceptionDef,
+ ir_IDLType, ir_IRObject, ir_InterfaceDef, ir_ModuleDef,
+ ir_ORB, ir_OperationDef, ir_PrimitiveDef, ir_Repository,
+ ir_SequenceDef, ir_StringDef, ir_StructDef, ir_TypedefDef,
+ ir_UnionDef, logTable, logTransferTable, mesh_meas,
+ mesh_type, mnesia_clist, orber_CosNaming,
+ orber_objkeys, user
+ ].
+
+handle_error(Foo) ->
+ Str = io_lib:format("ERROR: ~s~n",[Foo]),
+ observer_lib:display_info_dialog(Str).
+
+update_grid(Grid, Opt, Tables) ->
+ wx:batch(fun() -> update_grid2(Grid, Opt, Tables) end).
+update_grid2(Grid, #opt{sort_key=Sort,sort_incr=Dir}, Tables) ->
+ wxListCtrl:deleteAllItems(Grid),
+ Update =
+ fun(#tab{name = Name, id = Id, owner = Owner, size = Size, memory = Memory,
+ protection = Protection, reg_name = RegName}, Row) ->
+ _Item = wxListCtrl:insertItem(Grid, Row, ""),
+ if (Row rem 2) =:= 0 ->
+ wxListCtrl:setItemBackgroundColour(Grid, Row, ?BG_EVEN);
+ true -> ignore
+ end,
+ if Protection == private ->
+ wxListCtrl:setItemTextColour(Grid, Row, {200,130,50});
+ true -> ignore
+ end,
+
+ lists:foreach(fun({_, ignore}) -> ignore;
+ ({Col, Val}) ->
+ wxListCtrl:setItem(Grid, Row, Col, observer_lib:to_str(Val))
+ end,
+ [{0,Name}, {1,Id}, {2,Size}, {3, Memory div 1024},
+ {4,Owner}, {5,RegName}]),
+ Row + 1
+ end,
+ ProcInfo = case Dir of
+ false -> lists:reverse(lists:keysort(Sort, Tables));
+ true -> lists:keysort(Sort, Tables)
+ end,
+ lists:foldl(Update, 0, ProcInfo),
+ ProcInfo.
+
+ignore(true, Reason) -> throw(Reason);
+ignore(_,_ ) -> ok.
diff --git a/lib/observer/src/observer_wx.erl b/lib/observer/src/observer_wx.erl
new file mode 100644
index 0000000000..f9dec1ab1b
--- /dev/null
+++ b/lib/observer/src/observer_wx.erl
@@ -0,0 +1,537 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2011. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+-module(observer_wx).
+
+-behaviour(wx_object).
+
+-export([start/0]).
+-export([create_menus/2, get_attrib/1, get_tracer/0,
+ create_txt_dialog/4, try_rpc/4, return_to_localnode/2]).
+
+-export([init/1, handle_event/2, handle_cast/2, terminate/2, code_change/3,
+ handle_call/3, handle_info/2, check_page_title/1]).
+
+%% Includes
+-include_lib("wx/include/wx.hrl").
+
+-include("observer_defs.hrl").
+
+%% Defines
+
+-define(ID_PING, 1).
+-define(ID_CONNECT, 2).
+-define(ID_NOTEBOOK, 3).
+
+-define(FIRST_NODES_MENU_ID, 1000).
+-define(LAST_NODES_MENU_ID, 2000).
+
+-define(TRACE_STR, "Trace Overview").
+
+%% Records
+-record(state,
+ {frame,
+ menubar,
+ menus = [],
+ status_bar,
+ notebook,
+ main_panel,
+ pro_panel,
+ tv_panel,
+ sys_panel,
+ trace_panel,
+ active_tab,
+ node,
+ nodes
+ }).
+
+start() ->
+ wx_object:start(?MODULE, [], []).
+
+create_menus(Object, Menus) when is_list(Menus) ->
+ wx_object:call(Object, {create_menus, Menus}).
+
+get_attrib(What) ->
+ wx_object:call(observer, {get_attrib, What}).
+
+get_tracer() ->
+ wx_object:call(observer, get_tracer).
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+init(_Args) ->
+ register(observer, self()),
+ wx:new(),
+ catch wxSystemOptions:setOption("mac.listctrl.always_use_generic", 1),
+ Frame = wxFrame:new(wx:null(), ?wxID_ANY, "Observer",
+ [{size, {1000, 500}}, {style, ?wxDEFAULT_FRAME_STYLE}]),
+ IconFile = filename:join(code:priv_dir(observer), "erlang_observer.png"),
+ Icon = wxIcon:new(IconFile, [{type,?wxBITMAP_TYPE_PNG}]),
+ wxFrame:setIcon(Frame, Icon),
+ wxIcon:destroy(Icon),
+
+ State = #state{frame = Frame},
+ UpdState = setup(State),
+ net_kernel:monitor_nodes(true),
+ process_flag(trap_exit, true),
+ {Frame, UpdState}.
+
+setup(#state{frame = Frame} = State) ->
+ %% Setup Menubar & Menus
+ MenuBar = wxMenuBar:new(),
+
+ {Nodes, NodeMenus} = get_nodes(),
+ DefMenus = default_menus(NodeMenus),
+ observer_lib:create_menus(DefMenus, MenuBar, default),
+
+ wxFrame:setMenuBar(Frame, MenuBar),
+ StatusBar = wxFrame:createStatusBar(Frame, []),
+ wxFrame:setTitle(Frame, atom_to_list(node())),
+ wxStatusBar:setStatusText(StatusBar, atom_to_list(node())),
+
+ %% Setup panels
+ Panel = wxPanel:new(Frame, []),
+ Notebook = wxNotebook:new(Panel, ?ID_NOTEBOOK, [{style, ?wxBK_DEFAULT}]),
+
+ %% System Panel
+ SysPanel = observer_sys_wx:start_link(Notebook, self()),
+ wxNotebook:addPage(Notebook, SysPanel, "System", []),
+
+ %% Setup sizer create early to get it when window shows
+ MainSizer = wxBoxSizer:new(?wxVERTICAL),
+
+ wxSizer:add(MainSizer, Notebook, [{proportion, 1}, {flag, ?wxEXPAND}]),
+ wxPanel:setSizer(Panel, MainSizer),
+
+ wxNotebook:connect(Notebook, command_notebook_page_changing),
+ wxFrame:connect(Frame, close_window, [{skip, true}]),
+ wxMenu:connect(Frame, command_menu_selected),
+ wxFrame:show(Frame),
+
+ %% I postpone the creation of the other tabs so they can query/use
+ %% the window size
+
+ %% Process Panel
+ ProPanel = observer_pro_wx:start_link(Notebook, self()),
+ wxNotebook:addPage(Notebook, ProPanel, "Processes", []),
+
+ %% Table Viewer Panel
+ TVPanel = observer_tv_wx:start_link(Notebook, self()),
+ wxNotebook:addPage(Notebook, TVPanel, "Table Viewer", []),
+
+ %% Trace Viewer Panel
+ TracePanel = observer_trace_wx:start_link(Notebook, self()),
+ wxNotebook:addPage(Notebook, TracePanel, ?TRACE_STR, []),
+
+ %% Force redraw (window needs it)
+ wxWindow:refresh(Panel),
+
+ SysPid = wx_object:get_pid(SysPanel),
+ SysPid ! {active, node()},
+ UpdState = State#state{main_panel = Panel,
+ notebook = Notebook,
+ menubar = MenuBar,
+ status_bar = StatusBar,
+ sys_panel = SysPanel,
+ pro_panel = ProPanel,
+ tv_panel = TVPanel,
+ trace_panel = TracePanel,
+ active_tab = SysPid,
+ node = node(),
+ nodes = Nodes
+ },
+ %% Create resources which we don't want to duplicate
+ SysFont = wxSystemSettings:getFont(?wxSYS_DEFAULT_GUI_FONT),
+ SysFontSize = wxFont:getPointSize(SysFont),
+ Modern = wxFont:new(SysFontSize, ?wxFONTFAMILY_MODERN, ?wxFONTSTYLE_NORMAL, ?wxFONTWEIGHT_NORMAL),
+ put({font, modern}, Modern),
+ put({font, fixed}, Modern),
+ UpdState.
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%%Callbacks
+handle_event(#wx{event=#wxNotebook{type=command_notebook_page_changing}},
+ #state{active_tab=Previous, node=Node} = State) ->
+ Pid = get_active_pid(State),
+ Previous ! not_active,
+ Pid ! {active, Node},
+ {noreply, State#state{active_tab=Pid}};
+
+handle_event(#wx{event = #wxClose{}}, State) ->
+ {stop, normal, State};
+
+handle_event(#wx{id = ?wxID_EXIT, event = #wxCommand{type = command_menu_selected}}, State) ->
+ {stop, normal, State};
+
+handle_event(#wx{id = ?wxID_HELP, event = #wxCommand{type = command_menu_selected}}, State) ->
+ External = "http://www.erlang.org/doc/apps/observer/index.html",
+ Internal = filename:join([code:lib_dir(observer),"doc", "html", "index.html"]),
+ Help = case filelib:is_file(Internal) of
+ true -> Internal;
+ false -> External
+ end,
+ wx_misc:launchDefaultBrowser(Help) orelse
+ create_txt_dialog(State#state.frame, "Could not launch browser: ~n " ++ Help,
+ "Error", ?wxICON_ERROR),
+ {noreply, State};
+
+handle_event(#wx{id = ?wxID_ABOUT, event = #wxCommand{type = command_menu_selected}},
+ State = #state{frame=Frame}) ->
+ AboutString = "Observe an erlang system\n"
+ "Authors: Olle Mattson & Magnus Eriksson & Dan Gudmundsson",
+ Style = [{style, ?wxOK bor ?wxSTAY_ON_TOP},
+ {caption, "About"}],
+ wxMessageDialog:showModal(wxMessageDialog:new(Frame, AboutString, Style)),
+ {noreply, State};
+
+
+handle_event(#wx{id = ?ID_CONNECT, event = #wxCommand{type = command_menu_selected}},
+ #state{frame = Frame} = State) ->
+ UpdState = case create_connect_dialog(connect, State) of
+ cancel ->
+ State;
+ {value, [], _, _} ->
+ create_txt_dialog(Frame, "Node must have a name",
+ "Error", ?wxICON_ERROR),
+ State;
+ {value, NodeName, LongOrShort, Cookie} -> %Shortname,
+ try
+ case connect(list_to_atom(NodeName), LongOrShort, list_to_atom(Cookie)) of
+ {ok, set_cookie} ->
+ change_node_view(node(), State);
+ {error, set_cookie} ->
+ create_txt_dialog(Frame, "Could not set cookie",
+ "Error", ?wxICON_ERROR),
+ State;
+ {error, net_kernel, _Reason} ->
+ create_txt_dialog(Frame, "Could not enable node",
+ "Error", ?wxICON_ERROR),
+ State
+ end
+ catch _:_ ->
+ create_txt_dialog(Frame, "Could not enable node",
+ "Error", ?wxICON_ERROR),
+ State
+ end
+ end,
+ {noreply, UpdState};
+
+handle_event(#wx{id = ?ID_PING, event = #wxCommand{type = command_menu_selected}},
+ #state{frame = Frame} = State) ->
+ UpdState = case create_connect_dialog(ping, State) of
+ cancel -> State;
+ {value, Value} when is_list(Value) ->
+ try
+ Node = list_to_atom(Value),
+ case net_adm:ping(Node) of
+ pang ->
+ create_txt_dialog(Frame, "Connect failed", "Pang", ?wxICON_EXCLAMATION),
+ State;
+ pong ->
+ change_node_view(Node, State)
+ end
+ catch _:_ ->
+ create_txt_dialog(Frame, "Connect failed", "Pang", ?wxICON_EXCLAMATION),
+ State
+ end
+ end,
+ {noreply, UpdState};
+
+handle_event(#wx{id = Id, event = #wxCommand{type = command_menu_selected}}, State)
+ when Id > ?FIRST_NODES_MENU_ID, Id < ?LAST_NODES_MENU_ID ->
+
+ Node = lists:nth(Id - ?FIRST_NODES_MENU_ID, State#state.nodes),
+ UpdState = change_node_view(Node, State),
+ {noreply, UpdState};
+
+handle_event(Event, State) ->
+ Pid = get_active_pid(State),
+ Pid ! Event,
+ {noreply, State}.
+
+handle_cast(_Cast, State) ->
+ {noreply, State}.
+
+handle_call({create_menus, TabMenus}, _From,
+ State = #state{menubar=MenuBar, menus=PrevTabMenus}) ->
+ wx:batch(fun() ->
+ clean_menus(PrevTabMenus, MenuBar),
+ observer_lib:create_menus(TabMenus, MenuBar, plugin)
+ end),
+ {reply, ok, State#state{menus=TabMenus}};
+
+handle_call({get_attrib, Attrib}, _From, State) ->
+ {reply, get(Attrib), State};
+
+handle_call(get_tracer, _From, State=#state{trace_panel=TraceP}) ->
+ {reply, TraceP, State};
+
+handle_call(_Msg, _From, State) ->
+ {reply, ok, State}.
+
+handle_info({nodeup, _Node}, State) ->
+ State2 = update_node_list(State),
+ {noreply, State2};
+
+handle_info({nodedown, Node},
+ #state{frame = Frame} = State) ->
+ State2 = case Node =:= State#state.node of
+ true ->
+ change_node_view(node(), State);
+ false ->
+ State
+ end,
+ State3 = update_node_list(State2),
+ Msg = ["Node down: " | atom_to_list(Node)],
+ create_txt_dialog(Frame, Msg, "Node down", ?wxICON_EXCLAMATION),
+ {noreply, State3};
+
+handle_info(_Info, State) ->
+ {noreply, State}.
+
+terminate(_Reason, #state{frame = Frame}) ->
+ wxFrame:destroy(Frame),
+ ok.
+
+code_change(_, _, State) ->
+ {stop, not_yet_implemented, State}.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+try_rpc(Node, Mod, Func, Args) ->
+ case
+ rpc:call(Node, Mod, Func, Args) of
+ {badrpc, Reason} ->
+ error_logger:error_report([{node, Node},
+ {call, {Mod, Func, Args}},
+ {reason, {badrpc, Reason}}]),
+ error({badrpc, Reason});
+ Res ->
+ Res
+ end.
+
+return_to_localnode(Frame, Node) ->
+ case node() =/= Node of
+ true ->
+ create_txt_dialog(Frame, "Error occured on remote node",
+ "Error", ?wxICON_ERROR),
+ disconnect_node(Node);
+ false ->
+ ok
+ end.
+
+create_txt_dialog(Frame, Msg, Title, Style) ->
+ MD = wxMessageDialog:new(Frame, Msg, [{style, Style}]),
+ wxMessageDialog:setTitle(MD, Title),
+ wxDialog:showModal(MD),
+ wxDialog:destroy(MD).
+
+connect(NodeName, 0, Cookie) ->
+ connect2(NodeName, shortnames, Cookie);
+connect(NodeName, 1, Cookie) ->
+ connect2(NodeName, longnames, Cookie).
+
+connect2(NodeName, Opts, Cookie) ->
+ case net_adm:names() of
+ {ok, _} -> %% Epmd is running
+ ok;
+ {error, address} ->
+ Epmd = os:find_executable("epmd"),
+ os:cmd(Epmd)
+ end,
+ case net_kernel:start([NodeName, Opts]) of
+ {ok, _} ->
+ case is_alive() of
+ true ->
+ erlang:set_cookie(node(), Cookie),
+ {ok, set_cookie};
+ false ->
+ {error, set_cookie}
+ end;
+ {error, Reason} ->
+ {error, net_kernel, Reason}
+ end.
+
+change_node_view(Node, State = #state{pro_panel=Pro, sys_panel=Sys, tv_panel=Tv}) ->
+ lists:foreach(fun(Pid) -> wx_object:get_pid(Pid) ! {node, Node} end,
+ [Pro, Sys, Tv]),
+ StatusText = ["Observer - " | atom_to_list(Node)],
+ wxFrame:setTitle(State#state.frame, StatusText),
+ wxStatusBar:setStatusText(State#state.status_bar, StatusText),
+ State#state{node = Node}.
+
+check_page_title(Notebook) ->
+ Selection = wxNotebook:getSelection(Notebook),
+ wxNotebook:getPageText(Notebook, Selection).
+
+get_active_pid(#state{notebook=Notebook, pro_panel=Pro, sys_panel=Sys, tv_panel=Tv, trace_panel=Trace}) ->
+ Panel = case check_page_title(Notebook) of
+ "Processes" -> Pro;
+ "System" -> Sys;
+ "Table Viewer" -> Tv;
+ ?TRACE_STR -> Trace
+ end,
+ wx_object:get_pid(Panel).
+
+create_connect_dialog(ping, #state{frame = Frame}) ->
+ Dialog = wxTextEntryDialog:new(Frame, "Connect to node"),
+ case wxDialog:showModal(Dialog) of
+ ?wxID_OK ->
+ Value = wxTextEntryDialog:getValue(Dialog),
+ wxDialog:destroy(Dialog),
+ {value, Value};
+ ?wxID_CANCEL ->
+ wxDialog:destroy(Dialog),
+ cancel
+ end;
+create_connect_dialog(connect, #state{frame = Frame}) ->
+ Dialog = wxDialog:new(Frame, ?wxID_ANY, "Distribute node "),
+
+ VSizer = wxBoxSizer:new(?wxVERTICAL),
+ RadioBoxSizer = wxBoxSizer:new(?wxHORIZONTAL),
+
+ Choices = ["Short name", "Long name"],
+ RadioBox = wxRadioBox:new(Dialog, 1, "",
+ ?wxDefaultPosition,
+ ?wxDefaultSize,
+ Choices,
+ [{majorDim, 2},
+ {style, ?wxHORIZONTAL}]),
+
+ NameText = wxStaticText:new(Dialog, ?wxID_ANY, "Node name: "),
+ NameCtrl = wxTextCtrl:new(Dialog, ?wxID_ANY, [{size, {200, 25}}]),
+ wxTextCtrl:setValue(NameCtrl, "observer"),
+ CookieText = wxStaticText:new(Dialog, ?wxID_ANY, "Secret cookie: "),
+ CookieCtrl = wxTextCtrl:new(Dialog, ?wxID_ANY,
+ [{size, {200, 25}}, {style, ?wxTE_PASSWORD}]),
+
+ BtnSizer = wxDialog:createStdDialogButtonSizer(Dialog, ?wxID_DEFAULT),
+ Flags = [{flag, ?wxEXPAND bor ?wxALL}, {border, 5}],
+ wxSizer:add(RadioBoxSizer, RadioBox, Flags),
+
+ wxSizer:add(VSizer, RadioBoxSizer, Flags),
+ wxSizer:addSpacer(VSizer, 10),
+ wxSizer:add(VSizer, NameText),
+ wxSizer:add(VSizer, NameCtrl, Flags),
+ wxSizer:addSpacer(VSizer, 10),
+ wxSizer:add(VSizer, CookieText),
+ wxSizer:add(VSizer, CookieCtrl, Flags),
+ wxSizer:addSpacer(VSizer, 10),
+ wxSizer:add(VSizer, BtnSizer, [{flag, ?wxALIGN_LEFT}]),
+
+ wxWindow:setSizer(Dialog, VSizer),
+ CookiePath = filename:join(os:getenv("HOME"), ".erlang.cookie"),
+ DefaultCookie = case filelib:is_file(CookiePath) of
+ true ->
+ {ok, Bin} = file:read_file(CookiePath),
+ binary_to_list(Bin);
+ false ->
+ ""
+ end,
+ wxTextCtrl:setValue(CookieCtrl, DefaultCookie),
+ case wxDialog:showModal(Dialog) of
+ ?wxID_OK ->
+ NameValue = wxTextCtrl:getValue(NameCtrl),
+ NameLngthValue = wxRadioBox:getSelection(RadioBox),
+ CookieValue = wxTextCtrl:getValue(CookieCtrl),
+ wxDialog:destroy(Dialog),
+ {value, NameValue, NameLngthValue, CookieValue};
+ ?wxID_CANCEL ->
+ wxDialog:destroy(Dialog),
+ cancel
+ end.
+
+default_menus(NodesMenuItems) ->
+ Quit = #create_menu{id = ?wxID_EXIT, text = "Quit"},
+ About = #create_menu{id = ?wxID_ABOUT, text = "About"},
+ Help = #create_menu{id = ?wxID_HELP},
+ NodeMenu = case erlang:is_alive() of
+ true -> {"Nodes", NodesMenuItems ++
+ [#create_menu{id = ?ID_PING, text = "Connect Node"}]};
+ false -> {"Nodes", NodesMenuItems ++
+ [#create_menu{id = ?ID_CONNECT, text = "Enable distribution"}]}
+ end,
+ case os:type() =:= {unix, darwin} of
+ false ->
+ FileMenu = {"File", [Quit]},
+ HelpMenu = {"Help", [About,Help]},
+ [FileMenu, NodeMenu, HelpMenu];
+ true ->
+ %% On Mac quit and about will be moved to the "default' place
+ %% automagicly, so just add them to a menu that always exist.
+ %% But not to the help menu for some reason
+ {Tag, Menus} = NodeMenu,
+ [{Tag, Menus ++ [Quit,About]}, {"&Help", [Help]}]
+ end.
+
+clean_menus(Menus, MenuBar) ->
+ remove_menu_items(Menus, MenuBar).
+
+remove_menu_items([{MenuStr = "File", Menus}|Rest], MenuBar) ->
+ MenuId = wxMenuBar:findMenu(MenuBar, MenuStr),
+ Menu = wxMenuBar:getMenu(MenuBar, MenuId),
+ Items = [wxMenu:findItem(Menu, Tag) || #create_menu{text=Tag} <- Menus],
+ [wxMenu:delete(Menu, MItem) || MItem <- Items],
+ case os:type() =:= {unix, darwin} of
+ true ->
+ wxMenuBar:remove(MenuBar, MenuId),
+ wxMenu:destroy(Menu);
+ false ->
+ ignore
+ end,
+ remove_menu_items(Rest, MenuBar);
+remove_menu_items([{"Nodes", _}|_], _MB) ->
+ ok;
+remove_menu_items([{Tag, _Menus}|Rest], MenuBar) ->
+ MenuId = wxMenuBar:findMenu(MenuBar, Tag),
+ Menu = wxMenuBar:getMenu(MenuBar, MenuId),
+ wxMenuBar:remove(MenuBar, MenuId),
+ Items = wxMenu:getMenuItems(Menu),
+ [wxMenu:'Destroy'(Menu, Item) || Item <- Items],
+ wxMenu:destroy(Menu),
+ remove_menu_items(Rest, MenuBar);
+remove_menu_items([], _MB) ->
+ ok.
+
+get_nodes() ->
+ Nodes = [node()| nodes()],
+ {_, Menues} =
+ lists:foldl(fun(Node, {Id, Acc}) when Id < ?LAST_NODES_MENU_ID ->
+ {Id + 1, [#create_menu{id=Id + ?FIRST_NODES_MENU_ID,
+ text=atom_to_list(Node)} | Acc]}
+ end, {1, []}, Nodes),
+ {Nodes, lists:reverse(Menues)}.
+
+update_node_list(State = #state{menubar=MenuBar}) ->
+ {Nodes, NodesMenuItems} = get_nodes(),
+ NodeMenuId = wxMenuBar:findMenu(MenuBar, "Nodes"),
+ NodeMenu = wxMenuBar:getMenu(MenuBar, NodeMenuId),
+ wx:foreach(fun(Item) -> wxMenu:'Destroy'(NodeMenu, Item) end,
+ wxMenu:getMenuItems(NodeMenu)),
+
+ Index = wx:foldl(fun(Record, Index) ->
+ observer_lib:create_menu_item(Record, NodeMenu, Index)
+ end, 0, NodesMenuItems),
+
+ Dist = case erlang:is_alive() of
+ true -> #create_menu{id = ?ID_PING, text = "Connect node"};
+ false -> #create_menu{id = ?ID_CONNECT, text = "Enable distribution"}
+ end,
+ observer_lib:create_menu_item(Dist, NodeMenu, Index),
+ State#state{nodes = Nodes}.
diff --git a/lib/observer/src/ttb.erl b/lib/observer/src/ttb.erl
index 221b71df6a..61fd6d1787 100644
--- a/lib/observer/src/ttb.erl
+++ b/lib/observer/src/ttb.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2002-2009. All Rights Reserved.
+%% Copyright Ericsson AB 2002-2011. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -18,9 +18,11 @@
%%
-module(ttb).
-author('[email protected]').
+-author('[email protected]').
%% API
--export([tracer/0,tracer/1,tracer/2,p/2,stop/0,stop/1]).
+-export([tracer/0,tracer/1,tracer/2,p/2,stop/0,stop/1,start_trace/4]).
+-export([get_et_handler/0]).
-export([tp/2, tp/3, tp/4, ctp/0, ctp/1, ctp/2, ctp/3, tpl/2, tpl/3, tpl/4,
ctpl/0, ctpl/1, ctpl/2, ctpl/3, ctpg/0, ctpg/1, ctpg/2, ctpg/3]).
-export([seq_trigger_ms/0,seq_trigger_ms/1]).
@@ -34,24 +36,38 @@
-include_lib("kernel/include/file.hrl").
-define(meta_time,5000).
+-define(fetch_time, 10000).
-define(history_table,ttb_history_table).
-define(seq_trace_flags,[send,'receive',print,timestamp]).
--define(upload_dir,"ttb_upload").
+-define(upload_dir(Logname),"ttb_upload_"++Logname).
+-define(last_config, "ttb_last_config").
+-define(partial_dir, "ttb_partial_result").
-ifdef(debug).
--define(get_status,;get_status -> erlang:display(dict:to_list(NodeInfo)),loop(NodeInfo)).
+-define(get_status,;get_status -> erlang:display(dict:to_list(NodeInfo),loop(NodeInfo, TraceInfo)).
-else.
-define(get_status,).
-endif.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%% Shortcut
+start_trace(Nodes, Patterns, {Procs, Flags}, Options) ->
+ {ok, _} = tracer(Nodes, Options),
+ [{ok, _} = apply(?MODULE, tpl, tuple_to_list(Args)) || Args <- Patterns],
+ {ok, _} = p(Procs, Flags).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%% Open a trace port on all given nodes and create the meta data file
tracer() -> tracer(node()).
+tracer(shell) -> tracer(node(), shell);
+tracer(dbg) -> tracer(node(), {shell, only});
tracer(Nodes) -> tracer(Nodes,[]).
tracer(Nodes,Opt) ->
- start(),
- store(tracer,[Nodes,Opt]),
{PI,Client,Traci} = opt(Opt),
- do_tracer(Nodes,PI,Client,Traci).
+ %%We use initial Traci as SessionInfo for loop/2
+ Pid = start(Traci),
+ store(tracer,[Nodes,Opt]),
+ do_tracer(Nodes,PI,Client,[{ttb_control, Pid}|Traci]).
do_tracer(Nodes0,PI,Client,Traci) ->
Nodes = nods(Nodes0),
@@ -59,24 +75,41 @@ do_tracer(Nodes0,PI,Client,Traci) ->
do_tracer(Clients,PI,Traci).
do_tracer(Clients,PI,Traci) ->
- {ClientSucc,Succ} =
+ Shell = proplists:get_value(shell, Traci, false),
+ DefShell = fun(Trace) -> dbg:dhandler(Trace, standard_io) end,
+ {ClientSucc,Succ} =
lists:foldl(
- fun({N,{local,File},TF},{CS,S}) ->
- [_Sname,Host] = string:tokens(atom_to_list(N),"@"),
+ fun({N,{local,File},TF},{CS,S}) ->
+ {TF2, FileInfo, ShellOutput} =
+ case Shell of
+ only -> {none, shell_only, DefShell};
+ true -> {TF, {file,File}, DefShell};
+ {only,Fun} -> {none, shell_only, Fun};
+ Fun when is_function(Fun) -> {TF, {file,File}, Fun};
+ _ -> {TF, {file,File}, false}
+ end,
+ Host = case N of
+ nonode@nohost ->
+ {ok, H} = inet:gethostname(),
+ H;
+ _ ->
+ [_,H] = string:tokens(atom_to_list(N),"@"),
+ H
+ end,
case catch dbg:tracer(N,port,dbg:trace_port(ip,0)) of
{ok,N} ->
{ok,Port} = dbg:trace_port_control(N,get_listen_port),
{ok,T} = dbg:get_tracer(N),
rpc:call(N,seq_trace,set_system_tracer,[T]),
dbg:trace_client(ip,{Host,Port},
- {fun ip_to_file/2,{file,File}}),
- {[{N,{local,File,Port},TF}|CS], [N|S]};
+ {fun ip_to_file/2,{FileInfo, ShellOutput}}),
+ {[{N,{local,File,Port},TF2}|CS], [N|S]};
Other ->
display_warning(N,{cannot_open_ip_trace_port,
Host,
Other}),
{CS, S}
- end;
+ end;
({N,C,_}=Client,{CS,S}) ->
case catch dbg:tracer(N,port,dbg:trace_port(file,C)) of
{ok,N} ->
@@ -98,17 +131,54 @@ do_tracer(Clients,PI,Traci) ->
{ok,Succ}
end.
+opt(Opt) when is_list(Opt) ->
+ opt(Opt,{true,?MODULE,[]});
opt(Opt) ->
- opt(Opt,{true,?MODULE,[]}).
+ opt([Opt]).
opt([{process_info,PI}|O],{_,Client,Traci}) ->
opt(O,{PI,Client,Traci});
opt([{file,Client}|O],{PI,_,Traci}) ->
- opt(O,{PI,Client,Traci});
+ opt(O,{PI,Client,[{logfile,get_logname(Client)}|Traci]});
opt([{handler,Handler}|O],{PI,Client,Traci}) ->
opt(O,{PI,Client,[{handler,Handler}|Traci]});
+opt([{timer, {MSec, StopOpts}}|O],{PI,Client,Traci}) ->
+ opt(O,{PI,Client,[{timer,{MSec, StopOpts}}|Traci]});
+opt([{timer, MSec}|O],{PI,Client,Traci}) ->
+ opt(O,{PI,Client,[{timer,{MSec, []}}|Traci]});
+opt([{overload_check, {MSec,M,F}}|O],{PI,Client,Traci}) ->
+ opt(O,{PI,Client,[{overload_check,{MSec,M,F}}|Traci]});
+opt([shell|O],{PI,Client,Traci}) ->
+ opt(O,{PI,Client,[{shell, true}|Traci]});
+opt([{shell,Type}|O],{PI,Client,Traci}) ->
+ opt(O,{PI,Client,[{shell, Type}|Traci]});
+opt([resume|O],{PI,Client,Traci}) ->
+ opt(O,{PI,Client,[{resume, {true, ?fetch_time}}|Traci]});
+opt([{resume,MSec}|O],{PI,Client,Traci}) ->
+ opt(O,{PI,Client,[{resume, {true, MSec}}|Traci]});
+opt([{flush,MSec}|O],{PI,Client,Traci}) ->
+ opt(O,{PI,Client,[{flush, MSec}|Traci]});
opt([],Opt) ->
- Opt.
+ ensure_opt(Opt).
+
+ensure_opt({PI,Client,Traci}) ->
+ case {proplists:get_value(flush, Traci), Client} of
+ {undefined, _} -> ok;
+ {_, {local, _}} -> exit(flush_unsupported_with_ip_trace_port);
+ {_,_} -> ok
+ end,
+ NeedIpTracer = proplists:get_value(shell, Traci, false) /= false,
+ case {NeedIpTracer, Client} of
+ {false, _} -> {PI, Client, Traci};
+ {true, ?MODULE} -> {PI, {local, ?MODULE}, Traci};
+ {true, {local, File}} -> {PI, {local, File}, Traci};
+ {true, _} -> exit(local_client_required_on_shell_tracing)
+ end.
+
+get_logname({local, F}) -> get_logname(F);
+get_logname({wrap, F}) -> filename:basename(F);
+get_logname({wrap, F, _, _}) -> filename:basename(F);
+get_logname(F) -> filename:basename(F).
nods(all) ->
Nodes1 = remove_active([node()|nodes()]),
@@ -205,17 +275,29 @@ run_history([H|T]) ->
ok -> run_history(T);
{error,not_found} -> {error,{not_found,H}}
end;
+
+run_history(all) ->
+ CurrentHist = ets:tab2list(?history_table),
+ ets:delete_all_objects(?history_table),
+ [run_printed(MFA,true) || {_, MFA} <- CurrentHist];
+run_history(all_silent) ->
+ CurrentHist = ets:tab2list(?history_table),
+ ets:delete_all_objects(?history_table),
+ [run_printed(MFA,false) || {_, MFA} <- CurrentHist];
run_history([]) ->
ok;
run_history(N) ->
case catch ets:lookup(?history_table,N) of
[{N,{M,F,A}}] ->
- print_func(M,F,A),
- R = apply(M,F,A),
- print_result(R);
+ run_printed({M,F,A},true);
_ ->
{error, not_found}
end.
+
+run_printed({M,F,A},Verbose) ->
+ Verbose andalso print_func(M,F,A),
+ R = apply(M,F,A),
+ Verbose andalso print_result(R).
write_config(ConfigFile,all) ->
write_config(ConfigFile,['_']);
@@ -223,6 +305,8 @@ write_config(ConfigFile,Config) ->
write_config(ConfigFile,Config,[]).
write_config(ConfigFile,all,Opt) ->
write_config(ConfigFile,['_'],Opt);
+write_config(ConfigFile,Config,Opt) when not(is_list(Opt)) ->
+ write_config(ConfigFile,Config,[Opt]);
write_config(ConfigFile,Nums,Opt) when is_list(Nums), is_integer(hd(Nums));
Nums=:=['_'] ->
F = fun(N) -> ets:select(?history_table,
@@ -313,6 +397,7 @@ arg_list([A1|A],Acc) ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%% Set trace flags on processes
p(Procs0,Flags0) ->
+ ensure_no_overloaded_nodes(),
store(p,[Procs0,Flags0]),
no_store_p(Procs0,Flags0).
no_store_p(Procs0,Flags0) ->
@@ -327,11 +412,12 @@ no_store_p(Procs0,Flags0) ->
{error,Reason} ->
display_warning(P,Reason),
{PMatched,Ps}
- end
+ end
end,{[],[]},Procs) of
{[],[]} -> {error, no_match};
{SuccMatched,Succ} ->
no_store_write_trace_info(flags,{Succ,Flags}),
+ ?MODULE ! trace_started,
{ok,SuccMatched}
end
end.
@@ -339,7 +425,7 @@ no_store_p(Procs0,Flags0) ->
transform_flags([clear]) ->
[clear];
transform_flags(Flags) ->
- dbg:transform_flags(Flags).
+ dbg:transform_flags([timestamp | Flags]).
procs(Procs) when is_list(Procs) ->
@@ -365,24 +451,30 @@ proc({global,Name}) ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%% Trace pattern
tp(A,B) ->
- store(tp,[A,B]),
- dbg:tp(A,B).
+ ensure_no_overloaded_nodes(),
+ store(tp,[A,ms(B)]),
+ dbg:tp(A,ms(B)).
tp(A,B,C) ->
- store(tp,[A,B,C]),
- dbg:tp(A,B,C).
+ ensure_no_overloaded_nodes(),
+ store(tp,[A,B,ms(C)]),
+ dbg:tp(A,B,ms(C)).
tp(A,B,C,D) ->
- store(tp,[A,B,C,D]),
- dbg:tp(A,B,C,D).
+ ensure_no_overloaded_nodes(),
+ store(tp,[A,B,C,ms(D)]),
+ dbg:tp(A,B,C,ms(D)).
tpl(A,B) ->
- store(tpl,[A,B]),
- dbg:tpl(A,B).
+ ensure_no_overloaded_nodes(),
+ store(tpl,[A,ms(B)]),
+ dbg:tpl(A,ms(B)).
tpl(A,B,C) ->
- store(tpl,[A,B,C]),
- dbg:tpl(A,B,C).
+ ensure_no_overloaded_nodes(),
+ store(tpl,[A,B,ms(C)]),
+ dbg:tpl(A,B,ms(C)).
tpl(A,B,C,D) ->
- store(tpl,[A,B,C,D]),
- dbg:tpl(A,B,C,D).
+ ensure_no_overloaded_nodes(),
+ store(tpl,[A,B,C,ms(D)]),
+ dbg:tpl(A,B,C,ms(D)).
ctp() ->
store(ctp,[]),
@@ -423,6 +515,56 @@ ctpg(A,B,C) ->
store(ctpg,[A,B,C]),
dbg:ctpg(A,B,C).
+ms(return) ->
+ [{'_',[],[{return_trace}]}];
+ms(caller) ->
+ [{'_',[],[{message,{caller}}]}];
+ms({codestr, FunStr}) ->
+ {ok, MS} = string2ms(FunStr),
+ MS;
+ms(Other) ->
+ Other.
+
+ensure_no_overloaded_nodes() ->
+ Overloaded = case whereis(?MODULE) of
+ undefined ->
+ [];
+ _ ->
+ ?MODULE ! {get_overloaded, self()},
+ receive {overloaded,O} -> O end
+ end,
+ case Overloaded of
+ [] -> ok;
+ Overloaded -> exit({error, overload_protection_active, Overloaded})
+ end.
+
+-spec string2ms(string()) -> {ok, list()} | {error, fun_format}.
+string2ms(FunStr) ->
+ case erl_scan:string(fix_dot(FunStr)) of
+ {ok, Tokens, _} ->
+ case erl_parse:parse_exprs(Tokens) of
+ {ok, [Expression]} ->
+ case Expression of
+ {_, _, {clauses, Clauses}} ->
+ {ok, ms_transform:transform_from_shell(dbg, Clauses, [])};
+ _ ->
+ {error, fun_format}
+ end;
+ _ ->
+ {error, fun_format}
+ end;
+ _ ->{error, fun_format}
+ end.
+
+-spec fix_dot(string()) -> string().
+fix_dot(FunStr) ->
+ [H | Rest] = lists:reverse(FunStr),
+ case H of
+ $. ->
+ FunStr;
+ H ->
+ lists:reverse([$., H | Rest])
+ end.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%% Support for sequential trace
@@ -457,66 +599,114 @@ no_store_write_trace_info(Key,What) ->
%%% Stop tracing on all nodes
stop() ->
stop([]).
-stop(Opts) ->
+stop(Opts) when is_list(Opts) ->
Fetch = stop_opts(Opts),
- case whereis(?MODULE) of
- undefined -> ok;
- Pid when is_pid(Pid) ->
- ?MODULE ! {stop,Fetch,self()},
- receive {?MODULE,stopped} -> ok end
+ Result =
+ case whereis(?MODULE) of
+ undefined -> ok;
+ Pid when is_pid(Pid) ->
+ ?MODULE ! {stop,Fetch,self()},
+ receive {?MODULE,R} -> R end
+ end,
+ case {Fetch, Result} of
+ {nofetch, _} ->
+ ok;
+ {_, {stopped, _}} ->
+ %% Printout moved out of the ttb loop to avoid occasional deadlock
+ io:format("Stored logs in ~s~n", [element(2, Result)]);
+ {_, _} ->
+ ok
end,
- stopped.
+ stop_return(Result,Opts);
+stop(Opts) ->
+ stop([Opts]).
stop_opts(Opts) ->
- case lists:member(format,Opts) of
- true ->
- format; % format implies fetch
- false ->
- case lists:member(fetch,Opts) of
- true -> fetch;
- false -> nofetch
- end
+ FetchDir = proplists:get_value(fetch_dir, Opts),
+ ensure_fetch_dir(FetchDir),
+ FormatData = case proplists:get_value(format, Opts) of
+ undefined -> false;
+ true -> {format, []};
+ FOpts -> {format, FOpts}
+ end,
+ case {FormatData, lists:member(return_fetch_dir, Opts)} of
+ {false, true} ->
+ {fetch, FetchDir}; % if we specify return_fetch_dir, the data should be fetched
+ {false, false} ->
+ case lists:member(nofetch,Opts) of
+ false -> {fetch, FetchDir};
+ true -> nofetch
+ end;
+ {FormatData, _} ->
+ {FormatData, FetchDir}
+ end.
+
+ensure_fetch_dir(undefined) -> ok;
+ensure_fetch_dir(Dir) ->
+ case filelib:is_file(Dir) of
+ true ->
+ throw({error, exists, Dir});
+ false ->
+ ok
+ end.
+
+stop_return(R,Opts) ->
+ case {lists:member(return_fetch_dir,Opts),R} of
+ {true,_} ->
+ R;
+ {false,{stopped,_}} ->
+ stopped;
+ {false,_} ->
+ %% Anything other than 'stopped' would not be bw compatible...
+ stopped
end.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%% Process implementation
-start() ->
+start(SessionInfo) ->
case whereis(?MODULE) of
undefined ->
Parent = self(),
- Pid = spawn(fun() -> init(Parent) end),
- receive {started,Pid} -> ok end;
+ Pid = spawn(fun() -> init(Parent, SessionInfo) end),
+ receive {started,Pid} -> ok end,
+ Pid;
Pid when is_pid(Pid) ->
- ok
+ Pid
end.
-
-init(Parent) ->
+init(Parent, SessionInfo) ->
register(?MODULE,self()),
ets:new(?history_table,[ordered_set,named_table,public]),
Parent ! {started,self()},
- loop(dict:new()).
+ NewSessionInfo = [{partials, 0}, {dead_nodes, []} | SessionInfo],
+ try_send_flush_tick(NewSessionInfo),
+ loop(dict:new(), NewSessionInfo).
-loop(NodeInfo) ->
+loop(NodeInfo, SessionInfo) ->
receive
{init_node,Node,MetaFile,PI,Traci} ->
erlang:monitor_node(Node,true),
- MetaPid =
+ {AbsoluteMetaFile, MetaPid} =
case rpc:call(Node,
observer_backend,
ttb_init_node,
[MetaFile,PI,Traci]) of
- {ok,MP} ->
- MP;
+ {ok,MF,MP} ->
+ {MF,MP};
{badrpc,nodedown} ->
%% We will get a nodedown message
- undefined
+ {MetaFile,undefined}
end,
- loop(dict:store(Node,{MetaFile,MetaPid},NodeInfo));
+ loop(dict:store(Node,{AbsoluteMetaFile,MetaPid},NodeInfo), SessionInfo);
+ {ip_to_file_trace_port,Port,Sender} ->
+ Ports = proplists:get_value(ip_to_file_trace_ports, SessionInfo, []),
+ NewSessionInfo = [{ip_to_file_trace_ports,[Port|Ports]}|SessionInfo],
+ Sender ! {?MODULE,ok},
+ loop(NodeInfo, NewSessionInfo);
{get_nodes,Sender} ->
Sender ! {?MODULE,dict:fetch_keys(NodeInfo)},
- loop(NodeInfo);
+ loop(NodeInfo, SessionInfo);
{write_trace_info,Key,What} ->
dict:fold(fun(Node,{_MetaFile,MetaPid},_) ->
rpc:call(Node,observer_backend,
@@ -524,55 +714,136 @@ loop(NodeInfo) ->
end,
ok,
NodeInfo),
- loop(NodeInfo);
+ loop(NodeInfo, SessionInfo);
{nodedown,Node} ->
- loop(dict:erase(Node,NodeInfo));
+ NewState = make_node_dead(Node, NodeInfo, SessionInfo),
+ loop(dict:erase(Node,NodeInfo), NewState);
+ {noderesumed,Node,Reporter} ->
+ {MetaFile, CurrentSuffix, NewState} = make_node_alive(Node, SessionInfo),
+ fetch_partial_result(Node, MetaFile, CurrentSuffix),
+ spawn(fun() -> resume_trace(Reporter) end),
+ loop(NodeInfo, NewState);
+ {timeout, StopOpts} ->
+ spawn(?MODULE, stop, [StopOpts]),
+ loop(NodeInfo, SessionInfo);
+ {node_overloaded, Node} ->
+ io:format("Overload check activated on node: ~p.~n", [Node]),
+ {Overloaded, SI} = {proplists:get_value(overloaded, SessionInfo, []),
+ lists:keydelete(overloaded, 1, SessionInfo)},
+ loop(NodeInfo, [{overloaded, [Node|Overloaded]} | SI]);
+ {get_overloaded, Pid} ->
+ Pid ! {overloaded,proplists:get_value(overloaded, SessionInfo, [])},
+ loop(NodeInfo, SessionInfo);
+ trace_started ->
+ case proplists:get_value(timer, SessionInfo) of
+ undefined -> ok;
+ {MSec, StopOpts} -> erlang:send_after(MSec, self(), {timeout, StopOpts})
+ end,
+ loop(NodeInfo, SessionInfo);
+ flush_timeout ->
+ [ dbg:flush_trace_port(Node) || Node <- dict:fetch_keys(NodeInfo) ],
+ try_send_flush_tick(SessionInfo),
+ loop(NodeInfo, SessionInfo);
{stop,nofetch,Sender} ->
- dict:fold(
- fun(Node,{_,MetaPid},_) ->
- rpc:call(Node,observer_backend,ttb_stop,[MetaPid])
- end,
- ok,
- NodeInfo),
- dbg:stop_clear(),
- ets:delete(?history_table),
- Sender ! {?MODULE,stopped};
- {stop,FetchOrFormat,Sender} ->
- Localhost = host(node()),
- Dir = ?upload_dir++ts(),
- file:make_dir(Dir),
- %% The nodes are traversed twice here because
- %% the meta tracing in observer_backend must be
- %% stopped before dbg is stopped, and dbg must
- %% be stopped before the trace logs are moved orelse
- %% windows complains.
- AllNodesAndMeta =
- dict:fold(
- fun(Node,{MetaFile,MetaPid},Nodes) ->
- rpc:call(Node,observer_backend,ttb_stop,[MetaPid]),
- [{Node,MetaFile}|Nodes]
- end,
- [],
- NodeInfo),
- dbg:stop_clear(),
- AllNodes =
- lists:map(
- fun({Node,MetaFile}) ->
- spawn(fun() -> fetch(Localhost,Dir,Node,MetaFile) end),
- Node
+ do_stop(nofetch, Sender, NodeInfo, SessionInfo);
+ {stop,FetchSpec,Sender} ->
+ case proplists:get_value(shell, SessionInfo, false) of
+ only -> do_stop(nofetch, Sender, NodeInfo, SessionInfo);
+ _ -> do_stop(FetchSpec, Sender, NodeInfo, SessionInfo)
+ end
+ end.
+
+do_stop(nofetch, Sender, NodeInfo, SessionInfo) ->
+ write_config(?last_config, all),
+ dict:fold(
+ fun(Node,{_,MetaPid},_) ->
+ rpc:call(Node,observer_backend,ttb_stop,[MetaPid])
+ end,
+ ok,
+ NodeInfo),
+ stop_ip_to_file_trace_ports(SessionInfo),
+ dbg:stop_clear(),
+ ets:delete(?history_table),
+ Sender ! {?MODULE, stopped};
+
+do_stop({FetchOrFormat, UserDir}, Sender, NodeInfo, SessionInfo) ->
+ write_config(?last_config, all),
+ Localhost = host(node()),
+ Dir = get_fetch_dir(UserDir, proplists:get_value(logfile, SessionInfo)),
+ file:make_dir(Dir),
+ %% The nodes are traversed twice here because
+ %% the meta tracing in observer_backend must be
+ %% stopped before dbg is stopped, and dbg must
+ %% be stopped before the trace logs are moved orelse
+ %% windows complains.
+ AllNodesAndMeta =
+ dict:fold(
+ fun(Node,{MetaFile,MetaPid},Nodes) ->
+ rpc:call(Node,observer_backend,ttb_stop,[MetaPid]),
+ [{Node,MetaFile}|Nodes]
+ end,
+ [],
+ NodeInfo),
+ stop_ip_to_file_trace_ports(SessionInfo),
+ dbg:stop_clear(),
+ AllNodes =
+ lists:map(
+ fun({Node,MetaFile}) ->
+ spawn(fun() -> fetch_report(Localhost,Dir,Node,MetaFile) end),
+ Node
+ end,
+ AllNodesAndMeta),
+ ets:delete(?history_table),
+ wait_for_fetch(AllNodes),
+ copy_partials(Dir, proplists:get_value(partials, SessionInfo)),
+ Absname = filename:absname(Dir),
+ case FetchOrFormat of
+ fetch -> ok;
+ {format, Opts} -> format(Dir, Opts)
+ end,
+ Sender ! {?MODULE,{stopped,Absname}}.
+
+stop_ip_to_file_trace_ports(SessionInfo) ->
+ lists:foreach(fun(Port) ->
+ case lists:member(Port,erlang:ports()) of
+ true ->
+ dbg:deliver_and_flush(Port),
+ erlang:port_close(Port);
+ false ->
+ ok
+ end
end,
- AllNodesAndMeta),
- ets:delete(?history_table),
- wait_for_fetch(AllNodes),
- io:format("Stored logs in ~s~n",[filename:absname(Dir)]),
- case FetchOrFormat of
- format -> format(Dir);
- fetch -> ok
- end,
- Sender ! {?MODULE,stopped}
- ?get_status
+ proplists:get_value(ip_to_file_trace_ports,SessionInfo,[])).
+
+
+make_node_dead(Node, NodeInfo, SessionInfo) ->
+ {MetaFile,_} = dict:fetch(Node, NodeInfo),
+ NewDeadNodes = [{Node, MetaFile} | proplists:get_value(dead_nodes, SessionInfo)],
+ [{dead_nodes, NewDeadNodes} | lists:keydelete(dead_nodes, 1, SessionInfo)].
+
+make_node_alive(Node, SessionInfo) ->
+ DeadNodes = proplists:get_value(dead_nodes, SessionInfo),
+ Partials = proplists:get_value(partials, SessionInfo),
+ {value, {_, MetaFile}, Dn2} = lists:keytake(Node, 1, DeadNodes),
+ SessionInfo2 = lists:keyreplace(dead_nodes, 1, SessionInfo, {dead_nodes, Dn2}),
+ {MetaFile, Partials + 1, lists:keyreplace(partials, 1, SessionInfo2, {partials, Partials + 1})}.
+
+try_send_flush_tick(State) ->
+ case proplists:get_value(flush, State) of
+ undefined ->
+ ok;
+ MSec ->
+ erlang:send_after(MSec, self(), flush_timeout)
end.
+get_fetch_dir(undefined,undefined) -> ?upload_dir(?MODULE_STRING) ++ ts();
+get_fetch_dir(undefined,Logname) -> ?upload_dir(Logname) ++ ts();
+get_fetch_dir(Dir,_) -> Dir.
+
+resume_trace(Reporter) ->
+ ?MODULE:run_history(all_silent),
+ Reporter ! trace_resumed.
+
get_nodes() ->
?MODULE ! {get_nodes,self()},
receive {?MODULE,Nodes} -> Nodes end.
@@ -582,19 +853,40 @@ ts() ->
io_lib:format("-~4.4.0w~2.2.0w~2.2.0w-~2.2.0w~2.2.0w~2.2.0w",
[Y,M,D,H,Min,S]).
+copy_partials(_, 0) ->
+ ok;
+copy_partials(Dir, Num) ->
+ PartialDir = ?partial_dir ++ integer_to_list(Num),
+ file:rename(PartialDir, filename:join(Dir,PartialDir)),
+ copy_partials(Dir, Num - 1).
+
+fetch_partial_result(Node,MetaFile,Current) ->
+ DirName = ?partial_dir ++ integer_to_list(Current),
+ case file:list_dir(DirName) of
+ {error, enoent} ->
+ ok;
+ {ok, Files} ->
+ [ file:delete(filename:join(DirName, File)) || File <- Files ],
+ file:del_dir(DirName)
+ end,
+ file:make_dir(DirName),
+ fetch(host(node()), DirName, Node, MetaFile).
+fetch_report(Localhost, Dir, Node, MetaFile) ->
+ fetch(Localhost,Dir,Node,MetaFile),
+ ?MODULE ! {fetch_complete,Node}.
fetch(Localhost,Dir,Node,MetaFile) ->
- case host(Node) of
- Localhost -> % same host, just move the files
- Files = rpc:call(Node,observer_backend,ttb_get_filenames,[MetaFile]),
+ case (host(Node) == Localhost) orelse is_local(MetaFile) of
+ true -> % same host, just move the files
+ Files = get_filenames(Node,MetaFile),
lists:foreach(
- fun(File0) ->
- File = filename:join(Dir,filename:basename(File0)),
- file:rename(File0,File)
- end,
- Files);
- _Otherhost ->
+ fun(File0) ->
+ Dest = filename:join(Dir,filename:basename(File0)),
+ file:rename(File0, Dest)
+ end,
+ Files);
+ false ->
{ok, LSock} = gen_tcp:listen(0, [binary,{packet,2},{active,false}]),
{ok,Port} = inet:port(LSock),
rpc:cast(Node,observer_backend,ttb_fetch,
@@ -603,8 +895,17 @@ fetch(Localhost,Dir,Node,MetaFile) ->
receive_files(Dir,Sock,undefined),
ok = gen_tcp:close(LSock),
ok = gen_tcp:close(Sock)
- end,
- ?MODULE ! {fetch_complete,Node}.
+ end.
+
+is_local({local, _, _}) ->
+ true;
+is_local(_) ->
+ false.
+
+get_filenames(_N, {local,F,_}) ->
+ observer_backend:ttb_get_filenames(F);
+get_filenames(N, F) ->
+ rpc:call(N, observer_backend,ttb_get_filenames,[F]).
receive_files(Dir,Sock,Fd) ->
case gen_tcp:recv(Sock, 0) of
@@ -646,9 +947,16 @@ wait_for_fetch(Nodes) ->
%%% - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
write_info(Nodes,PI,Traci) ->
- lists:foreach(fun({N,{local,C,_},F}) ->
- MetaFile = F ++ ".ti",
- file:delete(MetaFile),
+ {ok, Cwd} = file:get_cwd(),
+ lists:foreach(fun({N,{local,C,_},F}) ->
+ MetaFile = case F of
+ none ->
+ none;
+ F ->
+ AbsFile = filename:join(Cwd, F) ++ ".ti",
+ file:delete(AbsFile),
+ AbsFile
+ end,
Traci1 = [{node,N},{file,C}|Traci],
{ok,Port} = dbg:get_tracer(N),
?MODULE !
@@ -662,38 +970,35 @@ write_info(Nodes,PI,Traci) ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%% Format binary trace logs
+get_et_handler() ->
+ {fun ttb_et:handler/4, initial}.
+
format(Files) ->
format(Files,[]).
format(Files,Opt) ->
- {Out,Handler} = format_opt(Opt),
+ {Out,Handler,DisableSort} = format_opt(Opt),
ets:new(?MODULE,[named_table]),
- format(Files,Out,Handler).
-format(File,Out,Handler) when is_list(File), is_integer(hd(File)) ->
+ format(Files,Out,Handler, DisableSort).
+format(File,Out,Handler,DisableSort) when is_list(File), is_integer(hd(File)) ->
Files =
case filelib:is_dir(File) of
true -> % will merge all files in the directory
- MetaFiles = filelib:wildcard(filename:join(File,"*.ti")),
- lists:map(fun(M) ->
- Sub = string:left(M,length(M)-3),
- case filelib:is_file(Sub) of
- true -> Sub;
- false -> Sub++".*.wrp"
- end
- end,
- MetaFiles);
+ List = filelib:wildcard(filename:join(File, ?partial_dir++"*")),
+ lists:append(collect_files([File | List]));
false -> % format one file
[File]
end,
- format(Files,Out,Handler);
-format(Files,Out,Handler) when is_list(Files), is_list(hd(Files)) ->
+ format(Files,Out,Handler,DisableSort);
+format(Files,Out,Handler,DisableSort) when is_list(Files), is_list(hd(Files)) ->
StopDbg = case whereis(dbg) of
undefined -> true;
_ -> false
end,
- Details = lists:foldl(fun(File,Acc) -> [prepare(File,Handler)|Acc] end,
+ Details = lists:foldl(fun(File,Acc) -> [prepare(File)|Acc] end,
[],Files),
Fd = get_fd(Out),
- R = do_format(Fd,Details),
+ RealHandler = get_handler(Handler, Files),
+ R = do_format(Fd,Details,DisableSort,RealHandler),
file:close(Fd),
ets:delete(?MODULE),
case StopDbg of
@@ -702,7 +1007,30 @@ format(Files,Out,Handler) when is_list(Files), is_list(hd(Files)) ->
end,
R.
-prepare(File,Handler) ->
+collect_files(Dirs) ->
+ lists:map(fun(Dir) ->
+ MetaFiles = filelib:wildcard(filename:join(Dir,"*.ti")),
+ lists:map(fun(M) ->
+ Sub = string:left(M,length(M)-3),
+ case filelib:is_file(Sub) of
+ true -> Sub;
+ false -> Sub++".*.wrp"
+ end
+ end,
+ MetaFiles)
+ end, Dirs).
+
+get_handler(undefined, Files) ->
+ %%We retrieve traci from the first available file
+ {Traci, _} = read_traci(hd(Files)),
+ case dict:find(handler, Traci) of
+ error -> {fun defaulthandler/4, initial};
+ {ok, [Handler]} -> Handler
+ end;
+get_handler(Handler, _) ->
+ Handler.
+
+prepare(File) ->
{Traci,Proci} = read_traci(File),
Node = get_node(Traci),
lists:foreach(fun({Pid,PI}) ->
@@ -714,19 +1042,21 @@ prepare(File,Handler) ->
ets:insert(?MODULE,{Pid,PI,Node})
end,Proci),
FileOrWrap = get_file(File,Traci),
- Handler1 = get_handler(Handler,Traci),
- {FileOrWrap,Traci,Handler1}.
+ {FileOrWrap,Traci}.
-format_opt(Opt) ->
+format_opt(Opt) when is_list(Opt) ->
Out = case lists:keysearch(out,1,Opt) of
{value,{out,O}} -> O;
_ -> standard_io
end,
Handler = case lists:keysearch(handler,1,Opt) of
- {value,{handler,H}} -> H;
- _ -> undefined
+ {value,{handler,H}} -> H;
+ _ -> undefined
end,
- {Out,Handler}.
+ DisableSort = proplists:get_value(disable_sort, Opt, false),
+ {Out,Handler,DisableSort};
+format_opt(Opt) ->
+ format_opt([Opt]).
read_traci(File) ->
@@ -800,75 +1130,61 @@ check_client(Client,File) when is_tuple(Client),element(2,Client)==wrap ->
check_exists(File) ->
case file:read_file_info(File) of
{ok,#file_info{type=regular}} -> File;
- _ ->
+ _ ->
exit({error,no_file})
end.
-
-get_handler(Handler,Traci) ->
- case Handler of
- undefined ->
- case dict:find(handler,Traci) of
- {ok,[H]} -> H;
- error -> undefined
- end;
- _ ->
- Handler
- end.
-do_format(Fd,Details) ->
- Clients = lists:foldl(fun({FileOrWrap,Traci,Handler},Acc) ->
- [start_client(FileOrWrap,Traci,Handler)
- |Acc]
+do_format(Fd,Details,DisableSort,Handler) ->
+ Clients = lists:foldl(fun({FileOrWrap,Traci},Acc) ->
+ [start_client(FileOrWrap,Traci)|Acc]
end,[],Details),
- init_collector(Fd,Clients).
-
-
-start_client(FileOrWrap,Traci,et) ->
- dbg:trace_client(file, FileOrWrap,
- {fun handler/2,
- {dict:to_list(Traci),{{ttb_et,handler},initial}}});
-start_client(FileOrWrap,Traci,undefined) ->
- dbg:trace_client(file, FileOrWrap,
- {fun handler/2,
- {dict:to_list(Traci),{fun defaulthandler/4,initial}}});
-start_client(FileOrWrap,Traci,Handler) ->
- dbg:trace_client(file, FileOrWrap,
- {fun handler/2, {dict:to_list(Traci),Handler}}).
-
-handler(Trace,State) ->
- %% State here is only used for the initial state. The accumulated
- %% State is maintained by collector!!!
- receive
- {get,Collector} -> Collector ! {self(),{Trace,State}};
+ init_collector(Fd,Clients,DisableSort,Handler).
+
+start_client(FileOrWrap,Traci) ->
+ dbg:trace_client(file, FileOrWrap,
+ {fun handler/2, dict:to_list(Traci)}).
+
+handler(Trace,Traci) ->
+ %%We return our own Traci so that it not necesarry to look it up
+ %%This may take time if something huge has been written to it
+ receive
+ {get,Collector} -> Collector ! {self(),{Trace,Traci}};
done -> ok
end,
- State.
+ Traci.
-handler1(Trace,{Fd,{Traci,{Fun,State}}}) when is_function(Fun) ->
- {Traci,{Fun,Fun(Fd,Trace,Traci,State)}};
-handler1(Trace,{Fd,{Traci,{{M,F},State}}}) when is_atom(M), is_atom(F) ->
- {Traci,{{M,F},M:F(Fd,Trace,Traci,State)}}.
+%%Used to handle common state (the same for all clients)
+handler2(Trace,{Fd,Traci,{Fun,State}}) when is_function(Fun) ->
+ {Fun, Fun(Fd, Trace, Traci, State)};
+handler2(Trace,{Fd,Traci,{{M,F},State}}) when is_atom(M), is_atom(F) ->
+ {{M,F}, M:F(Fd, Trace, Traci, State)}.
defaulthandler(Fd,Trace,_Traci,initial) ->
dbg:dhandler(Trace,Fd);
defaulthandler(_Fd,Trace,_Traci,State) ->
dbg:dhandler(Trace,State).
-init_collector(Fd,Clients) ->
+init_collector(Fd,Clients,DisableSort,Handler) ->
Collected = get_first(Clients),
- collector(Fd,sort(Collected)).
+ case DisableSort of
+ true -> collector(Fd,Collected, DisableSort, Handler);
+ false -> collector(Fd,sort(Collected), DisableSort, Handler)
+ end.
-collector(Fd,[{_,{Client,{Trace,State}}}|Rest]) ->
+collector(Fd,[{_,{Client,{Trace,Traci}}} |Rest], DisableSort, CommonState) ->
Trace1 = update_procinfo(Trace),
- State1 = handler1(Trace1,{Fd,State}),
- case get_next(Client,State1) of
- end_of_trace ->
- handler1(end_of_trace,{Fd,State1}),
- collector(Fd,Rest);
- Next -> collector(Fd,sort([Next|Rest]))
+ CommonState2 = handler2(Trace1, {Fd, Traci, CommonState}),
+ case get_next(Client) of
+ end_of_trace ->
+ collector(Fd,Rest,DisableSort, CommonState2);
+ Next -> case DisableSort of
+ false -> collector(Fd,sort([Next|Rest]), DisableSort, CommonState2);
+ true -> collector(Fd,[Next|Rest], DisableSort, CommonState2)
+ end
end;
-collector(_Fd,[]) ->
+collector(Fd,[], _, CommonState) ->
+ handler2(end_of_trace, {Fd, end_of_trace, CommonState}),
ok.
update_procinfo({drop,_N}=Trace) ->
@@ -895,7 +1211,7 @@ update_procinfo(Trace) ->
ProcInfo = get_procinfo(Pid),
setelement(2,Trace,ProcInfo).
-get_procinfo(Pid) when is_pid(Pid) ->
+get_procinfo(Pid) when is_pid(Pid); is_port(Pid) ->
case ets:lookup(?MODULE,Pid) of
[PI] -> PI;
[] -> Pid
@@ -913,21 +1229,21 @@ get_procinfo({Name,Node}) when is_atom(Name) ->
get_first([Client|Clients]) ->
Client ! {get,self()},
- receive
- {Client,{end_of_trace,_}} ->
+ receive
+ {Client,{end_of_trace,_}} ->
get_first(Clients);
- {Client,{Trace,_State}}=Next ->
+ {Client,{Trace,_}}=Next ->
[{timestamp(Trace),Next}|get_first(Clients)]
end;
get_first([]) -> [].
-get_next(Client,State) when is_pid(Client) ->
+get_next(Client) when is_pid(Client) ->
Client ! {get,self()},
- receive
- {Client,{end_of_trace,_}} ->
+ receive
+ {Client,{end_of_trace,_}} ->
end_of_trace;
- {Client,{Trace,_OldState}} ->
- {timestamp(Trace),{Client,{Trace,State}}} % inserting new state!!
+ {Client,{Trace, Traci}} ->
+ {timestamp(Trace),{Client,{Trace,Traci}}}
end.
sort(List) ->
@@ -971,19 +1287,37 @@ display_warning(Item,Warning) ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%% Trace client which reads an IP port and puts data directly to a file.
%%% This is used when tracing remote nodes with no file system.
-ip_to_file(Trace,{file,File}) ->
+ip_to_file({metadata,_,_},{shell_only, _} = State) ->
+ State;
+ip_to_file(Trace, {shell_only, Fun} = State) ->
+ Fun(Trace),
+ State;
+ip_to_file(Trace,{{file,File}, ShellOutput}) ->
Fun = dbg:trace_port(file,File), %File can be a filename or a wrap spec
Port = Fun(),
- ip_to_file(Trace,Port);
-ip_to_file({metadata,MetaFile,MetaData},Port) ->
+ %% Store the port so it can be properly closed
+ ?MODULE ! {ip_to_file_trace_port, Port, self()},
+ receive {?MODULE,ok} -> ok end,
+ case Trace of
+ {metadata, _, _} -> ok;
+ Trace -> show_trace(Trace, ShellOutput)
+ end,
+ ip_to_file(Trace,{Port,ShellOutput});
+ip_to_file({metadata,MetaFile,MetaData},State) ->
{ok,MetaFd} = file:open(MetaFile,[write,raw,append]),
file:write(MetaFd,MetaData),
file:close(MetaFd),
- Port;
-ip_to_file(Trace,Port) ->
+ State;
+ip_to_file(Trace,{Port, ShellOutput}) ->
+ show_trace(Trace, ShellOutput),
B = term_to_binary(Trace),
erlang:port_command(Port,B),
- Port.
+ {Port, ShellOutput}.
+
+show_trace(Trace, Fun) when is_function(Fun) ->
+ Fun(Trace);
+show_trace(_, _) ->
+ ok.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%% For debugging
@@ -996,5 +1330,3 @@ dump_ti(<<>>,Acc) ->
dump_ti(B,Acc) ->
{Term,Rest} = get_term(B),
dump_ti(Rest,[Term|Acc]).
-
-
diff --git a/lib/observer/test/Makefile b/lib/observer/test/Makefile
index 6073e6ea00..bf99f07081 100644
--- a/lib/observer/test/Makefile
+++ b/lib/observer/test/Makefile
@@ -22,7 +22,10 @@ MODULES = \
observer_SUITE \
crashdump_viewer_SUITE \
etop_SUITE \
+ ttb_helper \
ttb_SUITE \
+ client \
+ server \
crashdump_helper
ERL_FILES= $(MODULES:%=%.erl)
diff --git a/lib/observer/test/client.erl b/lib/observer/test/client.erl
new file mode 100644
index 0000000000..90b72d3f8f
--- /dev/null
+++ b/lib/observer/test/client.erl
@@ -0,0 +1,28 @@
+-module(client).
+-compile(export_all).
+
+init(Node) ->
+ application:start(runtime_tools),
+ net_kernel:connect_node(Node).
+
+init() ->
+ init(server_node()).
+
+restart() ->
+ init:restart().
+
+server_node() ->
+ {ok,HostName} = inet:gethostname(),
+ list_to_atom("server@" ++ HostName).
+
+get() ->
+ erlang:send({server,server_node()}, {get,self()}),
+ receive Data -> Data
+ after 1000 -> no_reply
+ end.
+
+put(Thing) ->
+ erlang:send({server,server_node()}, {put,self(),Thing}),
+ receive ok -> timer:sleep(2), ok
+ after 1000 -> no_reply
+ end.
diff --git a/lib/observer/test/crashdump_helper.erl b/lib/observer/test/crashdump_helper.erl
index d1c65f97e8..520fcdfd0d 100644
--- a/lib/observer/test/crashdump_helper.erl
+++ b/lib/observer/test/crashdump_helper.erl
@@ -19,7 +19,7 @@
-module(crashdump_helper).
-export([n1_proc/2,remote_proc/2]).
--compile(r12).
+-compile(r13).
-include("test_server.hrl").
n1_proc(N2,Creator) ->
diff --git a/lib/observer/test/crashdump_viewer_SUITE.erl b/lib/observer/test/crashdump_viewer_SUITE.erl
index fdc4a2f1ff..79ece7edf5 100644
--- a/lib/observer/test/crashdump_viewer_SUITE.erl
+++ b/lib/observer/test/crashdump_viewer_SUITE.erl
@@ -70,7 +70,7 @@ init_per_suite(Config) when is_list(Config) ->
application:start(inets), % will be using the http client later
httpc:set_options([{ipfamily,inet6fb4}]),
DataDir = ?config(data_dir,Config),
- Rels = [R || R <- [r12b,r13b], ?t:is_release_available(R)] ++ [current],
+ Rels = [R || R <- [r13b,r14b], ?t:is_release_available(R)] ++ [current],
io:format("Creating crash dumps for the following releases: ~p", [Rels]),
AllDumps = create_dumps(DataDir,Rels),
?t:timetrap_cancel(Dog),
@@ -722,7 +722,8 @@ dump_prefix(Rel) ->
r11b -> "r11b_dump.";
r12b -> "r12b_dump.";
r13b -> "r13b_dump.";
- current -> "r14b_dump."
+ r14b -> "r14b_dump.";
+ current -> "r15b_dump."
end.
compat_rel(Rel) ->
@@ -733,5 +734,6 @@ compat_rel(Rel) ->
r11b -> "+R11 ";
r12b -> "+R12 ";
r13b -> "+R13 ";
+ r14b -> "+R13 ";
current -> ""
end.
diff --git a/lib/observer/test/server.erl b/lib/observer/test/server.erl
new file mode 100644
index 0000000000..f6d3542c96
--- /dev/null
+++ b/lib/observer/test/server.erl
@@ -0,0 +1,44 @@
+-module(server).
+-compile(export_all).
+
+start() ->
+ application:start(runtime_tools),
+ Pid = spawn(?MODULE,loop,[[], 0]),
+ register(server,Pid).
+
+stop() ->
+ case lists:member(server, registered()) of
+ true ->
+ server ! stop;
+ false ->
+ ok
+ end.
+
+loop(Data, Num) ->
+ receive
+ {put,From,Ting} -> timer:sleep(2),
+ received(From,Ting),
+ From ! ok,
+ loop([Ting|Data], Num+1);
+ {get,From} -> From ! Data,
+ loop(Data, Num+1);
+ stop -> stopped;
+ clear -> loop([], Num+1);
+ {cnt, From} -> From ! Num,
+ loop(Data, Num)
+ end.
+
+counter() ->
+ server ! {cnt, self()},
+ receive
+ Num ->
+ Num
+ end.
+
+received(From, Thing) ->
+ case Thing of
+ never_send_this_atom ->
+ loop(Thing, 0);
+ _ ->
+ {return, 27, Thing, From}
+ end.
diff --git a/lib/observer/test/ttb_SUITE.erl b/lib/observer/test/ttb_SUITE.erl
index 24b4a22aa9..695d41b48a 100644
--- a/lib/observer/test/ttb_SUITE.erl
+++ b/lib/observer/test/ttb_SUITE.erl
@@ -1,7 +1,7 @@
-%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2002-2011. All Rights Reserved.
+%%
+%% Copyright Ericsson AB 2002-2010. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -33,12 +33,34 @@
-include_lib("test_server/include/test_server.hrl").
-define(default_timeout, ?t:minutes(1)).
+-define(OUTPUT, "handler_output").
+-define(FNAME, "temptest").
+-define(DIRNAME, "ddtemp").
-init_per_testcase(_Case, Config) ->
- ttb:stop(),
+init_per_testcase(Case, Config) ->
?line Dog=test_server:timetrap(?default_timeout),
+ ttb:stop(),
+ rm(?OUTPUT),
+ [rm(Upload) || Upload<-filelib:wildcard("ttb_upload*")],
+ rm(?DIRNAME),
+ [rm(At) || At <- filelib:wildcard("*@*")],
+ rm("ttb_last_config"),
+ %% Workaround for bug(?) in test_server - if the test case fails
+ %% with a timetrap timeout, then end_per_testcase will run with
+ %% faulty group_leader - which in turn makes test_server:stop_node
+ %% hang (stop_node is called by most of the cleanup functions).
+ %% Therefore we do the cleanup before each testcase instead - this
+ %% is obviously not 100% correct, but it will at least make sure
+ %% that the nodes which are to be started in a test case at are
+ %% terminated.
+ try apply(?MODULE,Case,[cleanup,Config])
+ catch error:undef -> ok
+ end,
[{watchdog, Dog}|Config].
-end_per_testcase(_Case, Config) ->
+end_per_testcase(Case, Config) ->
+ %% try apply(?MODULE,Case,[cleanup,Config])
+ %% catch error:undef -> ok
+ %% end,
Dog=?config(watchdog, Config),
?t:timetrap_cancel(Dog),
ok.
@@ -49,12 +71,31 @@ all() ->
[file, file_no_pi, file_fetch, wrap, wrap_merge,
wrap_merge_fetch_format, write_config1, write_config2,
write_config3, history, write_trace_info, seq_trace,
- diskless, otp_4967_1, otp_4967_2].
+ diskless, diskless_wrap, otp_4967_1, otp_4967_2,
+ fetch_when_no_option_given, basic_ttb_run_ip_port, basic_ttb_run_file_port,
+ return_fetch_dir_implies_fetch, logfile_name_in_fetch_dir, upload_to_my_logdir,
+ upload_to_my_existing_logdir, fetch_with_options_not_as_list,
+ error_when_formatting_multiple_files_4393, format_on_trace_stop,
+ trace_to_remote_files_on_localhost_with_different_pwd,
+ trace_to_local_files_on_localhost_with_different_pwd,
+ trace_to_remote_files_on_localhost_with_different_pwd_abs,
+ changing_cwd_on_control_node, changing_cwd_on_remote_node,
+ changing_cwd_on_control_node_with_local_trace,
+ one_command_trace_setup, dbg_style_fetch, shell_tracing_init,
+ only_one_state_for_format_handler, only_one_state_with_default_format_handler,
+ only_one_state_with_initial_format_handler, run_trace_with_shortcut1,
+ run_trace_with_shortcut2, run_trace_with_shortcut3, run_trace_with_shortcut4,
+ cant_specify_local_and_flush, trace_sorted_by_default,disable_sorting,
+ trace_resumed_after_node_restart, trace_resumed_after_node_restart_ip,
+ trace_resumed_after_node_restart_wrap,
+ trace_resumed_after_node_restart_wrap_mult
+].
groups() ->
[].
init_per_suite(Config) ->
+ clean_priv_dir(Config),
Config.
end_per_suite(_Config) ->
@@ -76,7 +117,7 @@ file(Config) when is_list(Config) ->
?line {ok,OtherNode} = ?t:start_node(node2,slave,[]),
?line c:nl(?MODULE),
?line S = self(),
- ?line Privdir=?config(priv_dir, Config),
+ ?line Privdir=priv_dir(Config),
?line File = filename:join(Privdir,"file"),
?line {ok,[Node]} =
ttb:tracer(Node,[{file, File},
@@ -92,18 +133,20 @@ file(Config) when is_list(Config) ->
?line {ok,[{matched,_,1},{matched,_,1}]} = ttb:tp(?MODULE,foo,[]),
?line ?MODULE:foo(),
?line rpc:call(OtherNode,?MODULE,foo,[]),
- ?line ttb:stop(),
- ?line ?t:stop_node(OtherNode),
+ ?line ttb:stop([nofetch]),
?line ok = ttb:format(filename:join(Privdir,atom_to_list(Node)++"-file")),
?line ok = ttb:format(filename:join(Privdir,
atom_to_list(OtherNode)++"-file")),
- ?line [{trace,{S,_,Node},call,{?MODULE,foo,[]}},
+ ?line [{trace_ts,{S,_,Node},call,{?MODULE,foo,[]},{_,_,_}},
end_of_trace,
- {trace,{_,_,OtherNode},call,{?MODULE,foo,[]}},
+ {trace_ts,{_,_,OtherNode},call,{?MODULE,foo,[]},{_,_,_}},
end_of_trace] = flush(),
ok.
+file(cleanup,_Config) ->
+ ?line ?t:stop_node(ttb_helper:get_node(node2)).
+
file_no_pi(suite) ->
[];
file_no_pi(doc) ->
@@ -113,7 +156,7 @@ file_no_pi(Config) when is_list(Config) ->
?line {ok,OtherNode} = ?t:start_node(node2,slave,[]),
?line c:nl(?MODULE),
?line S = self(),
- ?line Privdir=?config(priv_dir, Config),
+ ?line Privdir=priv_dir(Config),
?line File = filename:join(Privdir,"file"),
?line {ok,[_,_]} =
ttb:tracer([Node,OtherNode],[{file, File},
@@ -123,20 +166,23 @@ file_no_pi(Config) when is_list(Config) ->
?line {ok,[{matched,_,1},{matched,_,1}]} = ttb:tp(?MODULE,foo,[]),
?line ?MODULE:foo(),
?line rpc:call(OtherNode,?MODULE,foo,[]),
- ?line ttb:stop(),
- ?line ?t:stop_node(OtherNode),
+ ?line ttb:stop([nofetch]),
?line ok = ttb:format(filename:join(Privdir,atom_to_list(Node)++"-file")),
?line ok = ttb:format(filename:join(Privdir,
atom_to_list(OtherNode)++"-file")),
- ?line [{trace,LocalProc,call,{?MODULE,foo,[]}},
+ ?line [{trace_ts,LocalProc,call,{?MODULE,foo,[]}, {_,_,_}},
end_of_trace,
- {trace,RemoteProc,call,{?MODULE,foo,[]}},
+ {trace_ts,RemoteProc,call,{?MODULE,foo,[]},{_,_,_}},
end_of_trace] = flush(),
?line true = is_pid(LocalProc),
?line true = is_pid(RemoteProc),
ok.
+file_no_pi(cleanup,_Config) ->
+ ?line ?t:stop_node(ttb_helper:get_node(node2)).
+
+
file_fetch(suite) ->
[];
file_fetch(doc) ->
@@ -146,7 +192,7 @@ file_fetch(Config) when is_list(Config) ->
?line {ok,OtherNode} = ?t:start_node(node2,slave,[]),
?line c:nl(?MODULE),
?line S = self(),
- ?line Privdir=?config(priv_dir, Config),
+ ?line Privdir=priv_dir(Config),
?line ThisDir = filename:join(Privdir,this),
?line ok = file:make_dir(ThisDir),
?line OtherDir = filename:join(Privdir,other),
@@ -170,12 +216,11 @@ file_fetch(Config) when is_list(Config) ->
?line ?MODULE:foo(),
?line rpc:call(OtherNode,?MODULE,foo,[]),
?line ?t:capture_start(),
- ?line ttb:stop([fetch]),
+ ?line ttb:stop([return_fetch_dir]),
?line ?t:capture_stop(),
?line [StoreString] = ?t:capture_get(),
?line UploadDir =
lists:last(string:tokens(lists:flatten(StoreString),"$ \n")),
- ?line ?t:stop_node(OtherNode),
%% check that files are no longer in original directories...
?line ok = check_gone(ThisDir,atom_to_list(Node)++"-file_fetch"),
@@ -194,14 +239,18 @@ file_fetch(Config) when is_list(Config) ->
?line ok = ttb:format(filename:join(UploadDir,
atom_to_list(OtherNode)++"-file_fetch")),
- ?line [{trace,{S,_,Node},call,{?MODULE,foo,[]}},
+ ?line [{trace_ts,{S,_,Node},call,{?MODULE,foo,[]},{_,_,_}},
end_of_trace,
- {trace,{_,_,OtherNode},call,{?MODULE,foo,[]}},
+ {trace_ts,{_,_,OtherNode},call,{?MODULE,foo,[]},{_,_,_}},
end_of_trace] = flush(),
?line ok = file:set_cwd(Cwd),
ok.
+file_fetch(cleanup,_Config) ->
+ ?line ?t:stop_node(ttb_helper:get_node(node2)).
+
+
wrap(suite) ->
[];
wrap(doc) ->
@@ -211,7 +260,7 @@ wrap(Config) when is_list(Config) ->
?line {ok,OtherNode} = ?t:start_node(node2,slave,[]),
?line c:nl(?MODULE),
?line S = self(),
- ?line Privdir=?config(priv_dir, Config),
+ ?line Privdir=priv_dir(Config),
?line File = filename:join(Privdir,"wrap"),
?line {ok,[_,_]} =
ttb:tracer([Node,OtherNode],[{file, {wrap,File,200,3}},
@@ -224,19 +273,18 @@ wrap(Config) when is_list(Config) ->
?line rpc:call(OtherNode,?MODULE,foo,[]),
?line ?MODULE:foo(),
?line rpc:call(OtherNode,?MODULE,foo,[]),
- ?line ttb:stop(),
- ?line ?t:stop_node(OtherNode),
+ ?line ttb:stop([nofetch]),
?line ok = ttb:format(filename:join(Privdir,
atom_to_list(Node)++"-wrap.*.wrp")),
- ?line [{trace,{S,_,Node},call,{?MODULE,foo,[]}},
- {trace,{S,_,Node},call,{?MODULE,foo,[]}},
- {trace,{S,_,Node},call,{?MODULE,foo,[]}},
+ ?line [{trace_ts,{S,_,Node},call,{?MODULE,foo,[]},{_,_,_}},
+ {trace_ts,{S,_,Node},call,{?MODULE,foo,[]},{_,_,_}},
+ {trace_ts,{S,_,Node},call,{?MODULE,foo,[]},{_,_,_}},
end_of_trace] = flush(),
?line ok = ttb:format(filename:join(Privdir,
atom_to_list(OtherNode)++"-wrap.*.wrp")),
- ?line [{trace,{_,_,OtherNode},call,{?MODULE,foo,[]}},
- {trace,{_,_,OtherNode},call,{?MODULE,foo,[]}},
- {trace,{_,_,OtherNode},call,{?MODULE,foo,[]}},
+ ?line [{trace_ts,{_,_,OtherNode},call,{?MODULE,foo,[]},{_,_,_}},
+ {trace_ts,{_,_,OtherNode},call,{?MODULE,foo,[]},{_,_,_}},
+ {trace_ts,{_,_,OtherNode},call,{?MODULE,foo,[]},{_,_,_}},
end_of_trace] = flush(),
%% Check that merge does not crash even if the timestamp flag is not on.
@@ -244,17 +292,19 @@ wrap(Config) when is_list(Config) ->
[filename:join(Privdir,
atom_to_list(Node)++"-wrap.*.wrp"),
filename:join(Privdir,
- atom_to_list(OtherNode)++"-wrap.*.wrp")]),
- ?line [{trace,{S,_,Node},call,{?MODULE,foo,[]}},
- {trace,{S,_,Node},call,{?MODULE,foo,[]}},
- {trace,{S,_,Node},call,{?MODULE,foo,[]}},
- end_of_trace,
- {trace,{_,_,OtherNode},call,{?MODULE,foo,[]}},
- {trace,{_,_,OtherNode},call,{?MODULE,foo,[]}},
- {trace,{_,_,OtherNode},call,{?MODULE,foo,[]}},
+ atom_to_list(OtherNode)++"-wrap.*.wrp")],[{disable_sort,true}]),
+ ?line [{trace_ts,{S,_,Node},call,{?MODULE,foo,[]},{_,_,_}},
+ {trace_ts,{S,_,Node},call,{?MODULE,foo,[]},{_,_,_}},
+ {trace_ts,{S,_,Node},call,{?MODULE,foo,[]},{_,_,_}},
+ {trace_ts,{_,_,OtherNode},call,{?MODULE,foo,[]},{_,_,_}},
+ {trace_ts,{_,_,OtherNode},call,{?MODULE,foo,[]},{_,_,_}},
+ {trace_ts,{_,_,OtherNode},call,{?MODULE,foo,[]},{_,_,_}},
end_of_trace] = flush(),
ok.
+wrap(cleanup,_Config) ->
+ ?line ?t:stop_node(ttb_helper:get_node(node2)).
+
wrap_merge(suite) ->
[];
wrap_merge(doc) ->
@@ -264,7 +314,7 @@ wrap_merge(Config) when is_list(Config) ->
?line {ok,OtherNode} = ?t:start_node(node2,slave,[]),
?line c:nl(?MODULE),
?line S = self(),
- ?line Privdir=?config(priv_dir, Config),
+ ?line Privdir=priv_dir(Config),
?line File = filename:join(Privdir,"wrap_merge"),
?line {ok,[_,_]} =
ttb:tracer([Node,OtherNode],[{file, {wrap,File,200,3}},
@@ -277,8 +327,7 @@ wrap_merge(Config) when is_list(Config) ->
?line rpc:call(OtherNode,?MODULE,foo,[]),
?line ?MODULE:foo(),
?line rpc:call(OtherNode,?MODULE,foo,[]),
- ?line ttb:stop(),
- ?line ?t:stop_node(OtherNode),
+ ?line ttb:stop([nofetch]),
?line ok = ttb:format(
[filename:join(Privdir,
atom_to_list(Node)++"-wrap_merge.*.wrp"),
@@ -289,11 +338,13 @@ wrap_merge(Config) when is_list(Config) ->
{trace_ts,{S,_,Node},call,{?MODULE,foo,[]},_},
{trace_ts,_,call,{?MODULE,foo,[]},_},
{trace_ts,{S,_,Node},call,{?MODULE,foo,[]},_},
- end_of_trace,
{trace_ts,{_,_,OtherNode},call,{?MODULE,foo,[]},_},
end_of_trace] = flush(),
ok.
+wrap_merge(cleanup,_Config) ->
+ ?line ?t:stop_node(ttb_helper:get_node(node2)).
+
wrap_merge_fetch_format(suite) ->
[];
@@ -304,7 +355,7 @@ wrap_merge_fetch_format(Config) when is_list(Config) ->
?line {ok,OtherNode} = ?t:start_node(node2,slave,[]),
?line c:nl(?MODULE),
?line S = self(),
- ?line Privdir=?config(priv_dir, Config),
+ ?line Privdir=priv_dir(Config),
?line File = filename:join(Privdir,"wrap_merge_fetch_format"),
%% I'm setting priv_dir as cwd, so ttb_upload directory is created there
@@ -324,19 +375,19 @@ wrap_merge_fetch_format(Config) when is_list(Config) ->
?line ?MODULE:foo(),
?line rpc:call(OtherNode,?MODULE,foo,[]),
?line ttb:stop([format]),
- ?line ?t:stop_node(OtherNode),
?line [{trace_ts,{S,_,Node},call,{?MODULE,foo,[]},_},
{trace_ts,{_,_,OtherNode},call,{?MODULE,foo,[]},_},
{trace_ts,{S,_,Node},call,{?MODULE,foo,[]},_},
{trace_ts,{_,_,OtherNode},call,{?MODULE,foo,[]},_},
{trace_ts,{S,_,Node},call,{?MODULE,foo,[]},_},
- end_of_trace,
{trace_ts,{_,_,OtherNode},call,{?MODULE,foo,[]},_},
end_of_trace] = flush(),
?line ok = file:set_cwd(Cwd),
ok.
+wrap_merge_fetch_format(cleanup,_Config) ->
+ ?line ?t:stop_node(ttb_helper:get_node(node2)).
write_config1(suite) ->
[];
@@ -348,7 +399,7 @@ write_config1(Config) when is_list(Config) ->
?line c:nl(?MODULE),
?line S = self(),
- ?line Privdir=?config(priv_dir, Config),
+ ?line Privdir=priv_dir(Config),
?line File = filename:join(Privdir,"write_config1"),
?line ok = ttb:write_config(File,
[{ttb,tracer,[[Node,OtherNode],
@@ -360,16 +411,14 @@ write_config1(Config) when is_list(Config) ->
?line ok = ttb:run_config(File),
?line ?MODULE:foo(),
?line rpc:call(OtherNode,?MODULE,foo,[]),
- ?line ttb:stop(),
- ?line ?t:stop_node(OtherNode),
+ ?line ttb:stop([nofetch]),
?line ok = ttb:format(
[filename:join(Privdir,
atom_to_list(Node)++"-write_config1"),
filename:join(Privdir,
atom_to_list(OtherNode)++"-write_config1")]),
- ?line [{trace,{S,_,Node},call,{?MODULE,foo,[]}},
- end_of_trace,
- {trace,Other,call,{?MODULE,foo,[]}},
+ ?line [{trace_ts,{S,_,Node},call,{?MODULE,foo,[]},{_,_,_}},
+ {trace_ts,Other,call,{?MODULE,foo,[]},{_,_,_}},
end_of_trace] = flush(),
case metatest(Other,OtherNode,Privdir,"-write_config1.ti") of
@@ -388,6 +437,10 @@ write_config1(Config) when is_list(Config) ->
end,
ok.
+
+write_config1(cleanup,_Config) ->
+ ?line ?t:stop_node(ttb_helper:get_node(node2)).
+
write_config2(suite) ->
[];
write_config2(doc) ->
@@ -397,7 +450,7 @@ write_config2(Config) when is_list(Config) ->
?line {ok,OtherNode} = ?t:start_node(node2,slave,[]),
?line c:nl(?MODULE),
?line S = self(),
- ?line Privdir=?config(priv_dir, Config),
+ ?line Privdir=priv_dir(Config),
?line File = filename:join(Privdir,"write_config2"),
?line {ok,[_,_]} =
ttb:tracer([Node,OtherNode],[{file, File},
@@ -410,16 +463,14 @@ write_config2(Config) when is_list(Config) ->
?line ok = ttb:run_config(File),
?line ?MODULE:foo(),
?line rpc:call(OtherNode,?MODULE,foo,[]),
- ?line ttb:stop(),
- ?line ?t:stop_node(OtherNode),
+ ?line ttb:stop([nofetch]),
?line ok = ttb:format(
[filename:join(Privdir,
atom_to_list(Node)++"-write_config2"),
filename:join(Privdir,
atom_to_list(OtherNode)++"-write_config2")]),
- ?line [{trace,{S,_,Node},call,{?MODULE,foo,[]}},
- end_of_trace,
- {trace,Other,call,{?MODULE,foo,[]}},
+ ?line [{trace_ts,{S,_,Node},call,{?MODULE,foo,[]},{_,_,_}},
+ {trace_ts,Other,call,{?MODULE,foo,[]},{_,_,_}},
end_of_trace] = flush(),
case metatest(Other,OtherNode,Privdir,"-write_config2.ti") of
@@ -438,6 +489,10 @@ write_config2(Config) when is_list(Config) ->
end,
ok.
+write_config2(cleanup,_Config) ->
+ ?line ?t:stop_node(ttb_helper:get_node(node2)).
+
+
write_config3(suite) ->
[];
write_config3(doc) ->
@@ -447,7 +502,7 @@ write_config3(Config) when is_list(Config) ->
?line {ok,OtherNode} = ?t:start_node(node2,slave,[]),
?line c:nl(?MODULE),
?line S = self(),
- ?line Privdir=?config(priv_dir, Config),
+ ?line Privdir=priv_dir(Config),
?line File = filename:join(Privdir,"write_config3"),
?line {ok,[_,_]} =
ttb:tracer([Node,OtherNode],[{file, File},
@@ -455,18 +510,18 @@ write_config3(Config) when is_list(Config) ->
?line {ok,[{all,[{matched,_,_},{matched,_,_}]}]} = ttb:p(all,call),
?line {ok,[{matched,_,1},{matched,_,1}]} = ttb:tp(?MODULE,foo,[]),
?line ok = ttb:write_config(File,[1,2]),
- ?line ttb:stop(),
+ ?line ttb:stop([nofetch]),
?line [_,_] = ttb:list_config(File),
?line ok = ttb:run_config(File),
?line ?MODULE:foo(),
?line rpc:call(OtherNode,?MODULE,foo,[]),
- ?line ttb:stop(),
+ ?line ttb:stop([nofetch]),
?line ok = ttb:format(
[filename:join(Privdir,
atom_to_list(Node)++"-write_config3"),
filename:join(Privdir,
atom_to_list(OtherNode)++"-write_config3")]),
- ?line [] = flush(), %foo is not traced
+ ?line [end_of_trace] = flush(), %foo is not traced
?line ok = ttb:write_config(File,[{ttb,tp,[?MODULE,foo,[]]}],
[append]),
@@ -474,16 +529,14 @@ write_config3(Config) when is_list(Config) ->
?line ok = ttb:run_config(File),
?line ?MODULE:foo(),
?line rpc:call(OtherNode,?MODULE,foo,[]),
- ?line ttb:stop(),
- ?line ?t:stop_node(OtherNode),
+ ?line ttb:stop([nofetch]),
?line ok = ttb:format(
[filename:join(Privdir,
atom_to_list(Node)++"-write_config3"),
filename:join(Privdir,
atom_to_list(OtherNode)++"-write_config3")]),
- ?line [{trace,{S,_,Node},call,{?MODULE,foo,[]}},
- end_of_trace,
- {trace,Other,call,{?MODULE,foo,[]}},
+ ?line [{trace_ts,{S,_,Node},call,{?MODULE,foo,[]},{_,_,_}},
+ {trace_ts,Other,call,{?MODULE,foo,[]},{_,_,_}},
end_of_trace] = flush(),
case metatest(Other,OtherNode,Privdir,"-write_config3.ti") of
@@ -502,6 +555,10 @@ write_config3(Config) when is_list(Config) ->
end,
ok.
+write_config3(cleanup,_Config) ->
+ ?line ?t:stop_node(ttb_helper:get_node(node2)).
+
+
history(suite) ->
[];
@@ -514,7 +571,7 @@ history(Config) when is_list(Config) ->
?line S = self(),
?line Nodes = [Node,OtherNode],
- ?line Privdir=?config(priv_dir, Config),
+ ?line Privdir=priv_dir(Config),
?line File = filename:join(Privdir,"history"),
?line StartOpts = [{file, File},
{handler,{fun myhandler/4, S}}],
@@ -531,15 +588,16 @@ history(Config) when is_list(Config) ->
?line ?MODULE:foo(),
?line ok = ttb:run_history([3,4]),
?line ?MODULE:foo(),
- ?line ttb:stop(),
- ?line ?t:stop_node(OtherNode),
+ ?line ttb:stop([nofetch]),
?line ok = ttb:format(
[filename:join(Privdir,atom_to_list(Node)++"-history"),
filename:join(Privdir,atom_to_list(OtherNode)++"-history")]),
- ?line [{trace,{S,_,Node},call,{?MODULE,foo,[]}},
+ ?line [{trace_ts,{S,_,Node},call,{?MODULE,foo,[]},{_,_,_}},
end_of_trace] = flush(),
ok.
-
+
+history(cleanup,_Config) ->
+ ?line ?t:stop_node(ttb_helper:get_node(node2)).
write_trace_info(suite) ->
@@ -551,7 +609,7 @@ write_trace_info(Config) when is_list(Config) ->
?line {ok,OtherNode} = ?t:start_node(node2,slave,[]),
?line c:nl(?MODULE),
?line S = self(),
- ?line Privdir=?config(priv_dir, Config),
+ ?line Privdir=priv_dir(Config),
?line File = filename:join(Privdir,"write_trace_info"),
?line {ok,[_,_]} =
ttb:tracer([Node,OtherNode],[{file, File},
@@ -561,20 +619,21 @@ write_trace_info(Config) when is_list(Config) ->
?line ok = ttb:write_trace_info(mytraceinfo,fun() -> node() end),
?line ?MODULE:foo(),
?line rpc:call(OtherNode,?MODULE,foo,[]),
- ?line ttb:stop(),
- ?line ?t:stop_node(OtherNode),
+ ?line ttb:stop([nofetch]),
?line ok = ttb:format(
[filename:join(Privdir,atom_to_list(Node)++"-write_trace_info"),
filename:join(Privdir,
atom_to_list(OtherNode)++"-write_trace_info")],
[{handler,{fun otherhandler/4,S}}]),
- ?line [{{trace,{S,_,Node},call,{?MODULE,foo,[]}},[Node]},
- {end_of_trace,[Node]},
- {{trace,{_,_,OtherNode},call,{?MODULE,foo,[]}},[OtherNode]},
- {end_of_trace,[OtherNode]}] = flush(),
+ ?line [{{trace_ts,{S,_,Node},call,{?MODULE,foo,[]},{_,_,_}},[Node]},
+ {{trace_ts,{_,_,OtherNode},call,{?MODULE,foo,[]},{_,_,_}},[OtherNode]},
+ end_of_trace] = flush(),
ok.
+write_trace_info(cleanup,_Config) ->
+ ?line ?t:stop_node(ttb_helper:get_node(node2)).
+
seq_trace(suite) ->
[];
@@ -583,7 +642,7 @@ seq_trace(doc) ->
seq_trace(Config) when is_list(Config) ->
?line S = self(),
- ?line Privdir=?config(priv_dir, Config),
+ ?line Privdir=priv_dir(Config),
?line File = filename:join(Privdir,"seq_trace"),
?line {ok,[Node]} = ttb:tracer(node(),[{file,File},
{handler,{fun myhandler/4, S}}]),
@@ -593,10 +652,10 @@ seq_trace(Config) when is_list(Config) ->
?line Start = spawn(fun() -> seq() end),
?line timer:sleep(300),
- ?line ttb:stop(),
+ ?line ttb:stop([nofetch]),
?line ok = ttb:format(
[filename:join(Privdir,atom_to_list(Node)++"-seq_trace")]),
- ?line [{trace,StartProc,call,{?MODULE,seq,[]}},
+ ?line [{trace_ts,StartProc,call,{?MODULE,seq,[]},{_,_,_}},
{seq_trace,0,{send,{0,1},StartProc,P1Proc,{Start,P2}}},
{seq_trace,0,{send,{1,2},P1Proc,P2Proc,{P1,Start}}},
{seq_trace,0,{send,{2,3},P2Proc,StartProc,{P2,P1}}},
@@ -650,7 +709,7 @@ diskless(Config) when is_list(Config) ->
?line {ok,RemoteNode} = ?t:start_node(node2,slave,[]),
?line c:nl(?MODULE),
?line S = self(),
- ?line Privdir=?config(priv_dir, Config),
+ ?line Privdir=priv_dir(Config),
?line File = filename:join(Privdir,"diskless"),
?line {ok,[RemoteNode]} =
ttb:tracer([RemoteNode],[{file, {local, File}},
@@ -660,15 +719,45 @@ diskless(Config) when is_list(Config) ->
?line rpc:call(RemoteNode,?MODULE,foo,[]),
?line timer:sleep(500), % needed for the IP port to flush
- ?line ttb:stop(),
- ?line ?t:stop_node(RemoteNode),
+ ?line ttb:stop([nofetch]),
?line ok = ttb:format(filename:join(Privdir,
atom_to_list(RemoteNode)++"-diskless")),
- ?line [{trace,{_,_,RemoteNode},call,{?MODULE,foo,[]}},
+ ?line [{trace_ts,{_,_,RemoteNode},call,{?MODULE,foo,[]},{_,_,_}},
+ end_of_trace] = flush(),
+ ok.
+
+diskless(cleanup,_Config) ->
+ ?line ?t:stop_node(ttb_helper:get_node(node2)).
+
+diskless_wrap(suite) ->
+ [];
+diskless_wrap(doc) ->
+ ["Start tracing on diskless remote node, save to local wrapped file"];
+diskless_wrap(Config) when is_list(Config) ->
+ ?line {ok,RemoteNode} = ?t:start_node(node2,slave,[]),
+ ?line c:nl(?MODULE),
+ ?line S = self(),
+ ?line Privdir=priv_dir(Config),
+ ?line File = filename:join(Privdir,"diskless"),
+ ?line {ok,[RemoteNode]} =
+ ttb:tracer([RemoteNode],[{file, {local, {wrap,File,200,3}}},
+ {handler,{fun myhandler/4, S}}]),
+ ?line {ok,[{all,[{matched,RemoteNode,_}]}]} = ttb:p(all,call),
+ ?line {ok,[{matched,RemoteNode,1}]} = ttb:tp(?MODULE,foo,[]),
+
+ ?line rpc:call(RemoteNode,?MODULE,foo,[]),
+ ?line timer:sleep(500), % needed for the IP port to flush
+ ?line ttb:stop([nofetch]),
+ ?line ok = ttb:format(filename:join(Privdir,
+ atom_to_list(RemoteNode)++"-diskless.*.wrp")),
+
+ ?line [{trace_ts,{_,_,RemoteNode},call,{?MODULE,foo,[]},{_,_,_}},
end_of_trace] = flush(),
ok.
+diskless_wrap(cleanup,_Config) ->
+ ?line ?t:stop_node(ttb_helper:get_node(node2)).
otp_4967_1(suite) ->
[];
@@ -688,7 +777,7 @@ otp_4967_2(doc) ->
["OTP-4967: Trace message sent to {Name, Node}"];
otp_4967_2(Config) when is_list(Config) ->
io:format("1: ~p",[now()]),
- ?line Privdir = ?config(priv_dir,Config),
+ ?line Privdir = priv_dir(Config),
io:format("2: ~p",[now()]),
?line File = filename:join(Privdir,"otp_4967"),
io:format("3: ~p",[now()]),
@@ -715,19 +804,41 @@ otp_4967_2(Config) when is_list(Config) ->
io:format("11: ~p",[now()]),
?line true = lists:member(heihopp,Msgs), % the heihopp message itself
io:format("13: ~p",[now()]),
- ?line {value,{trace,_,send,heihopp,{_,otp_4967,Node}}} =
+ ?line {value,{trace_ts,_,send,heihopp,{_,otp_4967,Node},{_,_,_}}} =
lists:keysearch(heihopp,4,Msgs), % trace trace of the heihopp message
io:format("14: ~p",[now()]),
?line end_of_trace = lists:last(Msgs), % end of the trace
ok.
-
-
myhandler(_Fd,Trace,_,Relay) ->
Relay ! Trace,
Relay.
+simple_call_handler() ->
+ {fun(A, {trace_ts, _, call, _, _} ,_,_) -> io:format(A, "ok.~n", []);
+ (_, end_of_trace, _, _) -> ok end, []}.
+
+marking_call_handler() ->
+ {fun(_, _, _, initial) -> file:write_file("HANDLER_OK", []);
+ (_,_,_,_) -> ok end, initial}.
+
+counter_call_handler() ->
+ {fun(_, {trace_ts, _, call, _, _} ,_,State) -> State + 1;
+ (A, end_of_trace, _, State) -> io:format(A,"~p.~n", [State]) end, 0}.
+
+ret_caller_call_handler() ->
+ {fun(A, {trace_ts, _, call, _, _, _} ,_,_) -> io:format(A, "ok.~n", []);
+ (A, {trace_ts, _, return_from, _, _, _}, _, _) -> io:format(A, "ok.~n", []);
+ (_, _, _, _) -> ok end, []}.
+
+node_call_handler() ->
+ {fun(A, {trace_ts, {_,_,Node}, call, _, _} ,_,_) -> io:format(A, "~p.~n", [Node]);
+ (_, end_of_trace, _, _) -> ok end, []}.
+
+otherhandler(_Fd,_,end_of_trace,Relay) ->
+ Relay ! end_of_trace,
+ Relay;
otherhandler(_Fd,Trace,TI,Relay) ->
{value,{mytraceinfo,I}} = lists:keysearch(mytraceinfo,1,TI),
Relay ! {Trace,I},
@@ -794,3 +905,630 @@ check_gone(Dir,File) ->
false ->
ok
end.
+
+start_client_and_server() ->
+ ?line {ok,ClientNode} = ?t:start_node(client,slave,[]),
+ ?line ok = ttb_helper:c(code, add_paths, [code:get_path()]),
+ ?line {ok,ServerNode} = ?t:start_node(server,slave,[]),
+ ?line ok = ttb_helper:s(code, add_paths, [code:get_path()]),
+ ?line ttb_helper:clear(),
+ {ServerNode, ClientNode}.
+
+stop_client_and_server() ->
+ ClientNode = ttb_helper:get_node(client),
+ ServerNode = ttb_helper:get_node(server),
+ erlang:monitor_node(ClientNode,true),
+ erlang:monitor_node(ServerNode,true),
+ ?line ?t:stop_node(ClientNode),
+ ?line ?t:stop_node(ServerNode),
+ wait_for_client_and_server_stop(ClientNode,ServerNode).
+
+wait_for_client_and_server_stop(undefined,undefined) ->
+ ok;
+wait_for_client_and_server_stop(ClientNode,ServerNode) ->
+ receive
+ {nodedown,ClientNode} ->
+ erlang:monitor_node(ClientNode,false),
+ wait_for_client_and_server_stop(undefined,ServerNode);
+ {nodedown,ServerNode} ->
+ erlang:monitor_node(ServerNode,false),
+ wait_for_client_and_server_stop(ClientNode,undefined)
+ end.
+
+begin_trace(ServerNode, ClientNode, Dest) ->
+ ?line {ok, _} =
+ ttb:tracer([ServerNode,ClientNode],[{file, Dest}]),
+ ?line ttb:p(all, call),
+ ?line ttb:tp(server, received, []),
+ ?line ttb:tp(client, put, []),
+ ?line ttb:tp(client, get, []).
+
+begin_trace_local(ServerNode, ClientNode, Dest) ->
+ ?line {ok, _} =
+ ttb:tracer([ServerNode,ClientNode],[{file, Dest}]),
+ ?line ttb:p(all, call),
+ ?line ttb:tpl(server, received, []),
+ ?line ttb:tpl(client, put, []),
+ ?line ttb:tpl(client, get, []).
+
+check_size(N, Dest, Output, ServerNode, ClientNode) ->
+ ?line begin_trace(ServerNode, ClientNode, Dest),
+ ?line case Dest of
+ {local, _} ->
+ ?line ttb_helper:msgs_ip(N);
+ _ ->
+ ?line ttb_helper:msgs(N)
+ end,
+ ?line {_, D} = ttb:stop([fetch, return_fetch_dir]),
+ ?line ttb:format(D, [{out, Output}, {handler, simple_call_handler()}]),
+ ?line {ok, Ret} = file:consult(Output),
+ ?line true = (N + 1 == length(Ret)).
+
+fetch_when_no_option_given(suite) ->
+ [];
+fetch_when_no_option_given(doc) ->
+ ["Fetch when no option given"];
+fetch_when_no_option_given(Config) when is_list(Config) ->
+ ?line {ServerNode, ClientNode} = start_client_and_server(),
+ ?line {ok, Privdir} = file:get_cwd(),
+ ?line [] = filelib:wildcard(filename:join(Privdir,"ttb_upload_temptest*")),
+ begin_trace(ServerNode, ClientNode, ?FNAME),
+ ?line ttb_helper:msgs(4),
+ ?line stopped = ttb:stop(),
+ ?line [_] = filelib:wildcard(filename:join(Privdir,"ttb_upload_temptest*")).
+
+fetch_when_no_option_given(cleanup,_Config) ->
+ ?line stop_client_and_server().
+
+
+basic_ttb_run_ip_port(suite) ->
+ [];
+basic_ttb_run_ip_port(doc) ->
+ ["Basic ttb run ip port"];
+basic_ttb_run_ip_port(Config) when is_list(Config) ->
+ ?line {ServerNode, ClientNode} = start_client_and_server(),
+ ?line check_size(1, {local, ?FNAME}, ?OUTPUT, ServerNode, ClientNode),
+ ?line check_size(2, {local, ?FNAME}, ?OUTPUT, ServerNode, ClientNode),
+ ?line check_size(10, {local, ?FNAME}, ?OUTPUT, ServerNode, ClientNode).
+basic_ttb_run_ip_port(cleanup,_Config) ->
+ ?line stop_client_and_server().
+
+basic_ttb_run_file_port(suite) ->
+ [];
+basic_ttb_run_file_port(doc) ->
+ ["Basic ttb run file port"];
+basic_ttb_run_file_port(Config) when is_list(Config) ->
+ ?line {ServerNode, ClientNode} = start_client_and_server(),
+ ?line check_size(1, ?FNAME, ?OUTPUT, ServerNode, ClientNode),
+ ?line check_size(2, ?FNAME, ?OUTPUT, ServerNode, ClientNode),
+ ?line check_size(10, ?FNAME, ?OUTPUT, ServerNode, ClientNode).
+basic_ttb_run_file_port(cleanup,_Config) ->
+ ?line stop_client_and_server().
+
+return_fetch_dir_implies_fetch(suite) ->
+ [];
+return_fetch_dir_implies_fetch(doc) ->
+ ["Return_fetch_dir implies fetch"];
+return_fetch_dir_implies_fetch(Config) when is_list(Config) ->
+ ?line {ServerNode, ClientNode} = start_client_and_server(),
+ ?line begin_trace(ServerNode, ClientNode, ?FNAME),
+ ?line ttb_helper:msgs(2),
+ ?line {_,_} = ttb:stop([return_fetch_dir]).
+return_fetch_dir_implies_fetch(cleanup,_Config) ->
+ ?line stop_client_and_server().
+
+logfile_name_in_fetch_dir(suite) ->
+ [];
+logfile_name_in_fetch_dir(doc) ->
+ ["Logfile name in fetch dir"];
+logfile_name_in_fetch_dir(Config) when is_list(Config) ->
+ ?line {ServerNode, ClientNode} = start_client_and_server(),
+ ?line begin_trace(ServerNode, ClientNode, {local, ?FNAME}),
+ ?line {_,Dir} = ttb:stop([return_fetch_dir]),
+ ?line P1 = lists:nth(3, string:tokens(filename:basename(Dir), "_")),
+ ?line P2 = hd(string:tokens(P1, "-")),
+ ?line _File = P2.
+logfile_name_in_fetch_dir(cleanup,_Config) ->
+ ?line stop_client_and_server().
+
+upload_to_my_logdir(suite) ->
+ [];
+upload_to_my_logdir(doc) ->
+ ["Upload to my logdir"];
+upload_to_my_logdir(Config) when is_list(Config) ->
+ ?line {ServerNode, ClientNode} = start_client_and_server(),
+ ?line {ok, _} =
+ ttb:tracer([ServerNode,ClientNode],[{file, ?FNAME}]),
+ ?line {stopped,_} = ttb:stop([return_fetch_dir, {fetch_dir, ?DIRNAME}]),
+ ?line true = filelib:is_file(?DIRNAME),
+ ?line [] = filelib:wildcard("ttb_upload_"++?FNAME).
+upload_to_my_logdir(cleanup,_Config) ->
+ ?line stop_client_and_server().
+
+upload_to_my_existing_logdir(suite) ->
+ [];
+upload_to_my_existing_logdir(doc) ->
+ ["Upload to my existing logdir"];
+upload_to_my_existing_logdir(Config) when is_list(Config) ->
+ ?line {ServerNode, ClientNode} = start_client_and_server(),
+ ?line ok = file:make_dir(?DIRNAME),
+ ?line {ok, _} =
+ ttb:tracer([ServerNode,ClientNode],[{file, ?FNAME}]),
+ ?line {error,_,_} = (catch ttb:stop([return_fetch_dir, {fetch_dir, ?DIRNAME}])),
+ ?line {stopped,_} = ttb:stop(return_fetch_dir).
+upload_to_my_existing_logdir(cleanup,_Config) ->
+ ?line stop_client_and_server().
+
+fetch_with_options_not_as_list(suite) ->
+ [];
+fetch_with_options_not_as_list(doc) ->
+ ["Fetch with options not as list"];
+fetch_with_options_not_as_list(Config) when is_list(Config) ->
+ ?line {ServerNode, ClientNode} = start_client_and_server(),
+ ?line {ok, _} =
+ ttb:tracer([ServerNode,ClientNode],[{file, ?FNAME}]),
+ ?line {stopped, D} = ttb:stop(return_fetch_dir),
+ ?line false = filelib:is_file(?OUTPUT),
+ ?line ttb:format(D, {out, ?OUTPUT}),
+ ?line true = filelib:is_file(?OUTPUT).
+fetch_with_options_not_as_list(cleanup,_Config) ->
+ ?line stop_client_and_server().
+
+error_when_formatting_multiple_files_4393(suite) ->
+ [];
+error_when_formatting_multiple_files_4393(doc) ->
+ ["Error when formatting multiple files"];
+error_when_formatting_multiple_files_4393(Config) when is_list(Config) ->
+ ?line {ServerNode, ClientNode} = start_client_and_server(),
+ ?line begin_trace(ServerNode, ClientNode, ?FNAME),
+ ?line ttb_helper:msgs(2),
+ ?line {_, Dir} = ttb:stop(return_fetch_dir),
+ ?line Files = [filename:join(Dir, atom_to_list(ServerNode) ++ "-" ++ ?FNAME),
+ filename:join(Dir, atom_to_list(ClientNode) ++ "-" ++ ?FNAME)],
+ ?line ok = ttb:format(Files).
+error_when_formatting_multiple_files_4393(cleanup,_Config) ->
+ ?line stop_client_and_server().
+
+format_on_trace_stop(suite) ->
+ [];
+format_on_trace_stop(doc) ->
+ ["Format on trace stop"];
+format_on_trace_stop(Config) when is_list(Config) ->
+ ?line {ServerNode, ClientNode} = start_client_and_server(),
+ ?line begin_trace(ServerNode, ClientNode, {local, ?FNAME}),
+ ?line ttb_helper:msgs_ip(2),
+ ?line file:delete("HANDLER_OK"),
+ ?line {_,_} = ttb:stop([fetch, return_fetch_dir, {format, {handler, marking_call_handler()}}]),
+ ?line true = filelib:is_file("HANDLER_OK"),
+ ?line ok = file:delete("HANDLER_OK").
+format_on_trace_stop(cleanup,_Config) ->
+ ?line stop_client_and_server().
+
+%% The following three tests are for the issue "fixes fetch fail when nodes on the same host
+%% have different cwd"
+trace_to_remote_files_on_localhost_with_different_pwd(suite) ->
+ [];
+trace_to_remote_files_on_localhost_with_different_pwd(doc) ->
+ ["Trace to remote files on localhost with different pwd"];
+trace_to_remote_files_on_localhost_with_different_pwd(Config) when is_list(Config) ->
+ ?line {ok, OldDir} = file:get_cwd(),
+ ?line ok = file:set_cwd(".."),
+ ?line {ServerNode, ClientNode} = start_client_and_server(),
+ ?line check_size(2, ?FNAME, ?OUTPUT, ServerNode, ClientNode),
+ ?line ok = file:set_cwd(OldDir).
+trace_to_remote_files_on_localhost_with_different_pwd(cleanup,_Config) ->
+ ?line stop_client_and_server().
+
+trace_to_local_files_on_localhost_with_different_pwd(suite) ->
+ [];
+trace_to_local_files_on_localhost_with_different_pwd(doc) ->
+ ["Trace to local files on localhost with different pwd"];
+trace_to_local_files_on_localhost_with_different_pwd(Config) when is_list(Config) ->
+ ?line {ok, OldDir} = file:get_cwd(),
+ ?line ok = file:set_cwd(".."),
+ ?line {ServerNode, ClientNode} = start_client_and_server(),
+ ?line check_size(2, {local, ?FNAME}, ?OUTPUT, ServerNode, ClientNode),
+ ?line ok = file:set_cwd(OldDir).
+trace_to_local_files_on_localhost_with_different_pwd(cleanup,_Config) ->
+ ?line stop_client_and_server().
+
+trace_to_remote_files_on_localhost_with_different_pwd_abs(suite) ->
+ [];
+trace_to_remote_files_on_localhost_with_different_pwd_abs(doc) ->
+ ["Trace to remote files on localhost with different pwd abs"];
+trace_to_remote_files_on_localhost_with_different_pwd_abs(Config) when is_list(Config) ->
+ ?line {ok, OldDir} = file:get_cwd(),
+ ?line ok = file:set_cwd(".."),
+ ?line {ok, Path} = file:get_cwd(),
+ ?line {ServerNode, ClientNode} = start_client_and_server(),
+ ?line File = filename:join(Path, ?FNAME),
+ ?line check_size(2, File, ?OUTPUT, ServerNode, ClientNode),
+ ?line ok = file:set_cwd(OldDir).
+trace_to_remote_files_on_localhost_with_different_pwd_abs(cleanup,_Config) ->
+ ?line stop_client_and_server().
+
+%% Trace is not affected by changes of cwd on control node or remote nodes during tracing
+%% (three tests)
+changing_cwd_on_control_node(suite) ->
+ [];
+changing_cwd_on_control_node(doc) ->
+ ["Changing cwd on control node during tracing is safe"];
+changing_cwd_on_control_node(Config) when is_list(Config) ->
+ ?line {ok, OldDir} = file:get_cwd(),
+ ?line {ServerNode, ClientNode} = start_client_and_server(),
+ ?line begin_trace(ServerNode, ClientNode, ?FNAME),
+ ?line NumMsgs = 3,
+ ?line ttb_helper:msgs(NumMsgs),
+ ?line ok = file:set_cwd(".."),
+ ?line ttb_helper:msgs(NumMsgs),
+ ?line {_, D} = ttb:stop([fetch, return_fetch_dir]),
+ ?line ttb:format(D, [{out, ?OUTPUT}, {handler, simple_call_handler()}]),
+ ?line {ok, Ret} = file:consult(?OUTPUT),
+ ?line true = (2*(NumMsgs + 1) == length(Ret)),
+ ?line ok = file:set_cwd(OldDir).
+changing_cwd_on_control_node(cleanup,_Config) ->
+ ?line stop_client_and_server().
+
+changing_cwd_on_control_node_with_local_trace(suite) ->
+ [];
+changing_cwd_on_control_node_with_local_trace(doc) ->
+ ["Changing cwd on control node during local tracing is safe"];
+changing_cwd_on_control_node_with_local_trace(Config) when is_list(Config) ->
+ ?line {ok, OldDir} = file:get_cwd(),
+ ?line {ServerNode, ClientNode} = start_client_and_server(),
+ ?line begin_trace(ServerNode, ClientNode, {local, ?FNAME}),
+ ?line NumMsgs = 3,
+ ?line ttb_helper:msgs_ip(NumMsgs),
+ ?line ok = file:set_cwd(".."),
+ ?line ttb_helper:msgs_ip(NumMsgs),
+ ?line {_, D} = ttb:stop([fetch, return_fetch_dir]),
+ ?line ttb:format(D, [{out, ?OUTPUT}, {handler, simple_call_handler()}]),
+ ?line {ok, Ret} = file:consult(?OUTPUT),
+ ?line true = (2*(NumMsgs + 1) == length(Ret)),
+ ?line ok = file:set_cwd(OldDir).
+changing_cwd_on_control_node_with_local_trace(cleanup,_Config) ->
+ ?line stop_client_and_server().
+
+changing_cwd_on_remote_node(suite) ->
+ [];
+changing_cwd_on_remote_node(doc) ->
+ ["Changing cwd on remote node during tracing is safe"];
+changing_cwd_on_remote_node(Config) when is_list(Config) ->
+ ?line {ServerNode, ClientNode} = start_client_and_server(),
+ ?line begin_trace(ServerNode, ClientNode, ?FNAME),
+ ?line NumMsgs = 2,
+ ?line ttb_helper:msgs(NumMsgs),
+ ?line ok = rpc:call(ClientNode, file, set_cwd, [".."]),
+ ?line ttb_helper:msgs(NumMsgs),
+ ?line {_, D} = ttb:stop([fetch, return_fetch_dir]),
+ ?line ttb:format(D, [{out, ?OUTPUT}, {handler, simple_call_handler()}]),
+ ?line {ok, Ret} = file:consult(?OUTPUT),
+ ?line true = (2*(NumMsgs + 1) == length(Ret)).
+changing_cwd_on_remote_node(cleanup,_Config) ->
+ ?line stop_client_and_server().
+
+one_command_trace_setup(suite) ->
+ [];
+one_command_trace_setup(doc) ->
+ ["One command trace setup"];
+one_command_trace_setup(Config) when is_list(Config) ->
+ ?line {ServerNode, ClientNode} = start_client_and_server(),
+ ?line ttb:start_trace([ClientNode, ServerNode],
+ [{server, received, '_', []},
+ {client, put, 1, []},
+ {client, get, '_', []}],
+ {all, call},
+ [{file, ?FNAME}]),
+ ?line ttb_helper:msgs(2),
+ ?line {_, D} = ttb:stop(return_fetch_dir),
+ ?line ttb:format(D, [{out, ?OUTPUT}, {handler, simple_call_handler()}]),
+ ?line {ok, Ret} = file:consult(?OUTPUT),
+ ?line 5 = length(Ret).
+one_command_trace_setup(cleanup,_Config) ->
+ ?line stop_client_and_server().
+
+dbg_style_fetch(suite) ->
+ [];
+dbg_style_fetch(doc) ->
+ ["Dbg style fetch"];
+dbg_style_fetch(Config) when is_list(Config) ->
+ ?line {ServerNode, ClientNode} = start_client_and_server(),
+ ?line DirSize = length(element(2, file:list_dir("."))),
+ ?line ttb:start_trace([ClientNode, ServerNode],
+ [{server, received, '_', []},
+ {client, put, 1, []},
+ {client, get, '_', []}],
+ {all, call},
+ [{shell, only}]),
+ ?line DirSize = length(element(2, file:list_dir("."))),
+ ?line ttb_helper:msgs(2),
+ ?line DirSize = length(element(2, file:list_dir("."))),
+ ?line stopped, ttb:stop(format),
+ %%+1 -> ttb_last_trace
+ ?line true = (DirSize + 1 == length(element(2, file:list_dir(".")))),
+ ?line {ok,[{all, [{matched,_,_}, {matched,_,_}]}]} =
+ ttb:start_trace([ClientNode, ServerNode],
+ [{server, received, '_', []},
+ {client, put, 1, []},
+ {client, get, '_', []}],
+ {all, call},
+ [{shell, only}]),
+ ?line ttb:stop().
+dbg_style_fetch(cleanup,_Config) ->
+ ?line stop_client_and_server().
+
+shell_tracing_init(suite) ->
+ [];
+shell_tracing_init(doc) ->
+ ["Shell tracing init"];
+shell_tracing_init(Config) when is_list(Config) ->
+ ?line {ServerNode, ClientNode} = start_client_and_server(),
+ ?line ttb:tracer([ClientNode, ServerNode], shell),
+ ?line ttb:stop(),
+ ?line ttb:tracer([ClientNode, ServerNode],
+ [{file, {local, ?FNAME}}, shell]),
+ ?line ttb:stop(),
+ ?line local_client_required_on_shell_tracing =
+ try ttb:tracer([ClientNode, ServerNode],[{file, ?FNAME}, shell])
+ catch
+ exit:local_client_required_on_shell_tracing ->
+ local_client_required_on_shell_tracing
+ end.
+shell_tracing_init(cleanup,_Config) ->
+ ?line stop_client_and_server().
+
+only_one_state_for_format_handler(suite) ->
+ [];
+only_one_state_for_format_handler(doc) ->
+ ["Only one state for format handler"];
+only_one_state_for_format_handler(Config) when is_list(Config) ->
+ ?line {ServerNode, ClientNode} = start_client_and_server(),
+ ?line begin_trace_local(ServerNode, ClientNode, ?FNAME),
+ ?line ttb_helper:msgs(2),
+ ?line {_, D} = ttb:stop([return_fetch_dir]),
+ ?line ttb:format(D, [{out, ?OUTPUT}, {handler, counter_call_handler()}]),
+ ?line {ok, Ret} = file:consult(?OUTPUT),
+ ?line [5] = Ret.
+only_one_state_for_format_handler(cleanup,_Config) ->
+ ?line stop_client_and_server().
+
+only_one_state_with_default_format_handler(suite) ->
+ [];
+only_one_state_with_default_format_handler(doc) ->
+ ["Only one state with default format handler"];
+only_one_state_with_default_format_handler(Config) when is_list(Config) ->
+ ?line {ServerNode, ClientNode} = start_client_and_server(),
+ ?line begin_trace_local(ServerNode, ClientNode, ?FNAME),
+ ?line ttb_helper:msgs(2),
+ ?line {_, D} = ttb:stop([return_fetch_dir]),
+ ?line ttb:format(D, [{out, ?OUTPUT}]),
+ ?line true = filelib:is_file(?OUTPUT).
+only_one_state_with_default_format_handler(cleanup,_Config) ->
+ ?line stop_client_and_server().
+
+only_one_state_with_initial_format_handler(suite) ->
+ [];
+only_one_state_with_initial_format_handler(doc) ->
+ ["Only one state with initial format handler"];
+only_one_state_with_initial_format_handler(Config) when is_list(Config) ->
+ ?line {ServerNode, ClientNode} = start_client_and_server(),
+ ?line {ok, _} =
+ ttb:tracer([ServerNode,ClientNode],[{file, ?FNAME}, {handler, counter_call_handler()}]),
+ ?line ttb:p(all, call),
+ ?line ttb:tpl(server, received, []),
+ ?line ttb:tpl(client, put, []),
+ ?line ttb:tpl(client, get, []),
+ ?line ttb_helper:msgs(2),
+ ?line {_, D} = ttb:stop([return_fetch_dir]),
+ ?line ttb:format(D, [{out, ?OUTPUT}]),
+ ?line {ok, Ret} = file:consult(?OUTPUT),
+ ?line [5] = Ret.
+only_one_state_with_initial_format_handler(cleanup,_Config) ->
+ ?line stop_client_and_server().
+
+run_trace_with_shortcut(Shortcut, Ret, F) ->
+ ?line {ServerNode, ClientNode} = start_client_and_server(),
+ ?line {ok, _} =
+ ttb:tracer([ServerNode,ClientNode],[{file, ?FNAME}]),
+ ?line ttb:p(all, call),
+ ?line ttb:F(client, put, Shortcut),
+ ?line ttb_helper:msgs(2),
+ ?line {_, D} = ttb:stop([return_fetch_dir]),
+ ?line ttb:format(D, [{out, ?OUTPUT}, {handler, ret_caller_call_handler()}]),
+ ?line {ok, Ret} =file:consult(?OUTPUT),
+ ?line stop_client_and_server().
+
+fun_for(return) ->
+ {codestr, "fun(_) -> return_trace() end"};
+fun_for(msg_false) ->
+ {codestr, "fun(_) -> message(false) end"}.
+
+run_trace_with_shortcut1(suite) ->
+ [];
+run_trace_with_shortcut1(doc) ->
+ ["Run trace with shortcut 1"];
+run_trace_with_shortcut1(Config) when is_list(Config) ->
+ ?line run_trace_with_shortcut(caller, [ok,ok], tp),
+ ?line run_trace_with_shortcut(caller, [ok,ok], tpl).
+run_trace_with_shortcut1(cleanup,_Config) ->
+ ?line stop_client_and_server().
+
+run_trace_with_shortcut2(suite) ->
+ [];
+run_trace_with_shortcut2(doc) ->
+ ["Run trace with shortcut 2"];
+run_trace_with_shortcut2(Config) when is_list(Config) ->
+ ?line run_trace_with_shortcut(return, [ok,ok], tp),
+ ?line run_trace_with_shortcut(return, [ok,ok], tpl).
+run_trace_with_shortcut2(cleanup,_Config) ->
+ ?line stop_client_and_server().
+
+run_trace_with_shortcut3(suite) ->
+ [];
+run_trace_with_shortcut3(doc) ->
+ ["Run trace with shortcut 3"];
+run_trace_with_shortcut3(Config) when is_list(Config) ->
+ ?line run_trace_with_shortcut(fun_for(return), [ok,ok], tp),
+ ?line run_trace_with_shortcut(fun_for(return), [ok,ok], tpl).
+run_trace_with_shortcut3(cleanup,_Config) ->
+ ?line stop_client_and_server().
+
+run_trace_with_shortcut4(suite) ->
+ [];
+run_trace_with_shortcut4(doc) ->
+ ["Run trace with shortcut 4"];
+run_trace_with_shortcut4(Config) when is_list(Config) ->
+ ?line run_trace_with_shortcut(fun_for(msg_false), [], tp),
+ ?line run_trace_with_shortcut(fun_for(msg_false), [], tpl).
+run_trace_with_shortcut4(cleanup,_Config) ->
+ ?line stop_client_and_server().
+
+cant_specify_local_and_flush(suite) ->
+ [];
+cant_specify_local_and_flush(doc) ->
+ ["Can't specify local and flush"];
+cant_specify_local_and_flush(Config) when is_list(Config) ->
+ ?line {ServerNode, ClientNode} = start_client_and_server(),
+ ?line flush_unsupported_with_ip_trace_port =
+ try ttb:tracer([ServerNode, ClientNode],
+ [{flush, 1000}, {file, {local, ?FNAME}}])
+ catch
+ exit:flush_unsupported_with_ip_trace_port ->
+ flush_unsupported_with_ip_trace_port
+ end.
+cant_specify_local_and_flush(cleanup,_Config) ->
+ ?line stop_client_and_server().
+
+trace_sorted_by_default(suite) ->
+ [];
+trace_sorted_by_default(doc) ->
+ ["Trace sorted by default"];
+trace_sorted_by_default(Config) when is_list(Config) ->
+ ?line {ServerNode, ClientNode} = start_client_and_server(),
+ ?line begin_trace_local(ServerNode, ClientNode, ?FILE),
+ ?line ttb_helper:msgs(2),
+ ?line {_, D} = ttb:stop([return_fetch_dir]),
+ ?line ttb:format(D, [{out, ?OUTPUT}, {handler, node_call_handler()}, {disable_sort, false}]),
+ {ok, Ret} = file:consult(?OUTPUT),
+ ?line [ClientNode,ServerNode,ClientNode,ServerNode,ServerNode] = Ret.
+trace_sorted_by_default(cleanup,_Config) ->
+ ?line stop_client_and_server().
+
+disable_sorting(suite) ->
+ [];
+disable_sorting(doc) ->
+ ["Disable sorting"];
+disable_sorting(Config) when is_list(Config) ->
+ ?line {ServerNode, ClientNode} = start_client_and_server(),
+ ?line begin_trace_local(ServerNode, ClientNode, ?FILE),
+ ?line ttb_helper:msgs(2),
+ ?line {_, D} = ttb:stop([return_fetch_dir]),
+ ?line ttb:format(D, [{out, ?OUTPUT}, {handler, node_call_handler()}, {disable_sort, true}]),
+ {ok, Ret} = file:consult(?OUTPUT),
+ ?line [ClientNode,ClientNode,ServerNode,ServerNode,ServerNode] = Ret.
+disable_sorting(cleanup,_Config) ->
+ ?line stop_client_and_server().
+
+%% -----------------------------------------------------------------------------
+%% tests for autoresume of tracing
+%% -----------------------------------------------------------------------------
+
+trace_resumed_after_node_restart(suite) ->
+ [];
+trace_resumed_after_node_restart(doc) ->
+ ["Test trace resumed after node restart, trace to files on remote node."];
+trace_resumed_after_node_restart(Config) when is_list(Config) ->
+ ?line {ServerNode, ClientNode} = start_client_and_server(),
+ ?line begin_trace_with_resume(ServerNode, ClientNode, ?FNAME),
+ ?line logic(2,6,file).
+trace_resumed_after_node_restart(cleanup,_Config) ->
+ ?line stop_client_and_server().
+
+trace_resumed_after_node_restart_ip(suite) ->
+ [];
+trace_resumed_after_node_restart_ip(doc) ->
+ ["Test trace resumed after node restart, trace via tcp/ip to local node."];
+trace_resumed_after_node_restart_ip(Config) when is_list(Config) ->
+ ?line {ServerNode, ClientNode} = start_client_and_server(),
+ ?line begin_trace_with_resume(ServerNode, ClientNode, {local, ?FNAME}),
+ ?line logic(2,6,local).
+trace_resumed_after_node_restart_ip(cleanup,_Config) ->
+ ?line stop_client_and_server().
+
+trace_resumed_after_node_restart_wrap(suite) ->
+ [];
+trace_resumed_after_node_restart_wrap(doc) ->
+ ["Test trace resumed after node restart, wrap option."];
+trace_resumed_after_node_restart_wrap(Config) when is_list(Config) ->
+ ?line {ServerNode, ClientNode} = start_client_and_server(),
+ ?line begin_trace_with_resume(ServerNode, ClientNode, {wrap, ?FNAME, 10, 4}),
+ ?line logic(1,4,file).
+trace_resumed_after_node_restart_wrap(cleanup,_Config) ->
+ ?line stop_client_and_server().
+
+trace_resumed_after_node_restart_wrap_mult(suite) ->
+ [];
+trace_resumed_after_node_restart_wrap_mult(doc) ->
+ ["Test trace resumed after node restart, wrap option, multiple files."];
+trace_resumed_after_node_restart_wrap_mult(Config) when is_list(Config) ->
+ ?line {ServerNode, ClientNode} = start_client_and_server(),
+ ?line begin_trace_with_resume(ServerNode, ClientNode, {wrap, ?FNAME, 10, 4}),
+ ?line logic(20,8,file).
+trace_resumed_after_node_restart_wrap_mult(cleanup,_Config) ->
+ ?line stop_client_and_server().
+
+logic(N, M, TracingType) ->
+ helper_msgs(N, TracingType),
+ ?t:stop_node(ttb_helper:get_node(client)),
+ timer:sleep(2500),
+ ?line {ok,_ClientNode} = ?t:start_node(client,slave,[]),
+ ?line ok = ttb_helper:c(code, add_paths, [code:get_path()]),
+ ?line ttb_helper:c(client, init, []),
+ ?line helper_msgs(N, TracingType),
+ ?line {_, D} = ttb:stop([return_fetch_dir]),
+ ?line ttb:format(D, [{out, ?OUTPUT}, {handler, ret_caller_call_handler2()}]),
+ ?line {ok, Ret} = file:consult(?OUTPUT),
+ ?line M = length(Ret).
+
+begin_trace_with_resume(ServerNode, ClientNode, Dest) ->
+ ?line {ok, _} = ttb:tracer([ServerNode,ClientNode], [{file, Dest}, resume]),
+ ?line ttb:p(all, [call, timestamp]),
+ ?line ttb:tp(server, received, []),
+ ?line ttb:tp(client, put, []),
+ ?line ttb:tp(client, get, []).
+
+ret_caller_call_handler2() ->
+ {fun(A, {trace_ts, _, call, _, _} ,_,_) -> io:format(A, "ok.~n", []);
+ (_, _, _, _) -> ok end, []}.
+
+helper_msgs(N, TracingType) ->
+ case TracingType of
+ local ->
+ ttb_helper:msgs_ip(N);
+ _ ->
+ ttb_helper:msgs(N)
+ end.
+
+priv_dir(Conf) ->
+ %% Due to problem with long paths on windows => creating a new
+ %% priv_dir under data_dir
+ Dir = filename:absname(filename:join(?config(data_dir, Conf),priv_dir)),
+ filelib:ensure_dir(filename:join(Dir,"*")),
+ Dir.
+
+clean_priv_dir(Config) ->
+ PrivDir = priv_dir(Config),
+ case filelib:is_dir(PrivDir) of
+ true -> rm(PrivDir);
+ false -> ok
+ end.
+
+rm(This) ->
+ case filelib:is_dir(This) of
+ true ->
+ {ok,Files} = file:list_dir(This),
+ [rm(filename:join(This,F)) || F <- Files],
+ file:del_dir(This);
+ false ->
+ file:delete(This)
+ end.
diff --git a/lib/observer/test/ttb_helper.erl b/lib/observer/test/ttb_helper.erl
new file mode 100644
index 0000000000..76b06cd3ce
--- /dev/null
+++ b/lib/observer/test/ttb_helper.erl
@@ -0,0 +1,157 @@
+-module(ttb_helper). %%Nodes control
+-compile(export_all).
+
+%%API
+%%get() -> client:get()
+%%put(X) -> client:put(X)
+%%msgs(N) -> N times client:put(test_msg)
+%%clear() -> restart server
+%%ensure_running() / stop() -> start/stop nodes
+%%get_node(atom) -> return atom@hostname
+
+-define(NODE_CMD(Name),
+ "erl -sname " ++ atom_to_list(Name) ++
+ " -pa .. -pa . -detached -run ttb_helper send_ok").
+-define(REG_NAME, nc_testing).
+
+new_fun() ->
+ fun(_, end_of_trace, _, Dict) -> io:format("~p~n", [dict:to_list(Dict)]);
+ (_, T, _, Dict) -> case element(2, T) of
+ {Pid, _, _} ->
+ dict:update_counter(Pid, 1, Dict);
+ Pid ->
+ dict:update_counter(Pid, 1, Dict)
+ end
+ end.
+
+new_fun_2() ->
+ fun(_, end_of_trace, _, Dict) -> io:format("~p~n", [dict:to_list(Dict)]);
+ (_, T, _, Dict) -> case element(2, T) of
+ {_, Name, _} when is_atom(Name)->
+ dict:update_counter(Name, 1, Dict);
+ Pid ->
+ dict:update_counter(Pid, 1, Dict)
+ end
+
+ end.
+
+
+ensure_running() ->
+ try_start_node(server),
+ try_start_node(client),
+ clear().
+
+try_start_node(Node) ->
+ global:unregister_name(?REG_NAME),
+ global:register_name(?REG_NAME, self()),
+ global:sync(),
+ N = get_node(Node),
+ case net_adm:ping(N) of
+ pong ->
+ io:format("Node ~p already running~n", [N]);
+ _ ->
+ io:format("Starting node ~p... ~p ", [Node, os:cmd(?NODE_CMD(Node))]),
+ recv()
+ end.
+
+clear() ->
+ s(server, stop, []),
+ init().
+
+stop() ->
+ s(init, stop, []),
+ c(init, stop, []).
+
+msgs(N) ->
+ [c(client, put, [test_msg]) || _ <- lists:seq(1, N)],
+ s(server, received, [a,b]),
+ [dbg:flush_trace_port(Node) || Node <- [get_node(client), get_node(server)]].
+
+msgs_ip(N) ->
+ [c(client, put, [test_msg]) || _ <- lists:seq(1, N)],
+ s(server, received, [a,b]),
+ timer:sleep(200). %% allow trace messages to arrive over tcp/ip
+
+run() ->
+ ttb({local, "A"}),
+ msgs(2),
+ c(erlang, whereis, [ttbt]).
+
+get() -> c(client, get, []).
+put(Thing) -> c(client, put, [Thing]).
+
+get_node(Node) ->
+ {ok, Host} = inet:gethostname(),
+ list_to_atom(atom_to_list(Node) ++ "@" ++ Host).
+
+trace_setup() ->
+ ttb:p(all, call),
+ ttb:tp(server, received, []),
+ ttb:tp(client, put, []),
+ ttb:tp(client, get, []).
+
+ttb() -> ttb("A").
+ttb(File) ->
+ ttb:tracer([get_node(client), get_node(server)], [{file, File}, resume]),
+ ttb:p(all, [call, timestamp]),
+ ttb:tp(client, put, []),
+ ttb:tp(client, get, []),
+ ttb:tp(server, received, []).
+
+tc() ->
+ TC = example_config_gen:create_trace_case("dummy comment"),
+ Patterns = example_config_gen:create_pattern(client, put, 1, return),
+ Flags = example_config_gen:create_flags(all, call),
+ Merge = example_config_gen:create_merge_conf(show_handler(), "dummy merge comment"),
+ Merge2 = example_config_gen:create_merge_conf(undefined, "dummy merge comment"),
+ TC2 = example_config_gen:add_pattern(Patterns, TC),
+ TC3 = example_config_gen:add_flags(Flags, TC2),
+ TC4 = example_config_gen:add_merge_conf(Merge, TC3),
+ TC5 = example_config_gen:add_merge_conf(Merge2, TC4),
+ example_config_gen:add_nodes([get_node(client), get_node(server)], TC5).
+
+
+show(X) ->
+ io:format(user, "Showing: ~p~n", [X]).
+
+state_handler() ->
+ {fun(_,_,I,S) -> io:format(user, "Got from ~p: ~p~n", [I,S]), S+1 end, 0}.
+
+show_handler() ->
+ {fun(A,B,_,_) -> io:format(A, "~p~n", [B]) end, []}.
+
+opts() ->
+ [[get_node(client), get_node(server)],
+ [{server, received, '_', []},
+ {client, put, '_', []},
+ {client, get, '_', []}],
+ {all, call},
+ [{file, "TEST"}]].
+
+overload_check(check) ->
+ true;
+overload_check(_) ->
+ ok.
+%%%Internal
+s(M, F, A) -> rpc:call(get_node(server), M, F, A).
+c(M, F, A) -> rpc:call(get_node(client), M, F, A).
+
+send_ok() ->
+ pong = net_adm:ping(get_node(test)),
+ global:sync(),
+ global:send(?REG_NAME, node()).
+
+init() ->
+ True = s(server, start, []),
+ io:format("ok1: ~p~n", [True]),
+ true = c(client, init, [get_node(server)]).
+
+recv() ->
+ receive
+ Node ->
+ io:format("Node ~p ready.~n", [Node]),
+ ok
+ after 5000 ->
+ io:format("Startup failed~n",[]),
+ throw(startup_failed)
+ end.
diff --git a/lib/odbc/c_src/Makefile.in b/lib/odbc/c_src/Makefile.in
index ed3eeb1d42..dda896bcd2 100644
--- a/lib/odbc/c_src/Makefile.in
+++ b/lib/odbc/c_src/Makefile.in
@@ -89,9 +89,10 @@ TARGET_FLAGS = @TARGET_FLAGS@
# ----------------------------------------------------
# Targets
# ----------------------------------------------------
+_create_dirs := $(shell mkdir -p $(OBJ_DIR) $(BIN_DIR))
ifdef EXE_TARGET
-opt debug: create_dirs $(EXE_TARGET)
+opt debug: $(EXE_TARGET)
else
opt debug:
endif
@@ -119,10 +120,6 @@ endif
$(OBJ_DIR)/odbcserver.o: odbcserver.c
$(CC) $(CFLAGS) $(INCLUDES) $(TARGET_FLAGS) -o $@ -c odbcserver.c
-create_dirs:
- $(INSTALL_DIR) $(OBJ_DIR)
- $(INSTALL_DIR) $(BIN_DIR)
-
# ----------------------------------------------------
# Release Target
# ----------------------------------------------------
diff --git a/lib/odbc/doc/src/Makefile b/lib/odbc/doc/src/Makefile
index e2f09733d0..3e648d854d 100644
--- a/lib/odbc/doc/src/Makefile
+++ b/lib/odbc/doc/src/Makefile
@@ -29,14 +29,6 @@ VSN=$(ODBC_VSN)
APPLICATION=odbc
# ----------------------------------------------------
-# Include dependency
-# ----------------------------------------------------
-
-ifndef DOCSUPPORT
-include make.dep
-endif
-
-# ----------------------------------------------------
# Release directory specification
# ----------------------------------------------------
RELSYSDIR = $(RELEASE_PATH)/lib/$(APPLICATION)-$(VSN)
@@ -89,32 +81,10 @@ EXTRA_FILES = $(DEFAULT_GIF_FILES) \
MAN3_FILES = $(XML_REF3_FILES:%.xml=$(MAN3DIR)/%.3)
-ifdef DOCSUPPORT
-
HTML_REF_MAN_FILE = $(HTMLDIR)/index.html
TOP_PDF_FILE = $(PDFDIR)/$(APPLICATION)-$(VSN).pdf
-else
-
-TEX_FILES_BOOK = \
- $(BOOK_FILES:%.xml=%.tex)
-TEX_FILES_REF_MAN = $(XML_REF3_FILES:%.xml=%.tex) \
- $(XML_APPLICATION_FILES:%.xml=%.tex)
-TEX_FILES_USERS_GUIDE = \
- $(XML_CHAPTER_FILES:%.xml=%.tex)
-
-TOP_PDF_FILE = $(APPLICATION)-$(VSN).pdf
-TOP_PS_FILE = $(APPLICATION)-$(VSN).ps
-
-$(TOP_PDF_FILE): book.dvi ../../vsn.mk
- $(DVI2PS) $(DVIPS_FLAGS) -f $< | $(DISTILL) $(DISTILL_FLAGS) > $@
-
-$(TOP_PS_FILE): book.dvi ../../vsn.mk
- $(DVI2PS) $(DVIPS_FLAGS) -f $< > $@
-
-endif
-
# ----------------------------------------------------
# FLAGS
# ----------------------------------------------------
@@ -128,8 +98,6 @@ DVIPS_FLAGS +=
$(HTMLDIR)/%.gif: %.gif # Copy them to ../html
$(INSTALL_DATA) $< $@
-ifdef DOCSUPPORT
-
docs: pdf html man
$(TOP_PDF_FILE): $(XML_FILES)
@@ -144,32 +112,6 @@ clean clean_docs:
rm -f $(TOP_PDF_FILE) $(TOP_PDF_FILE:%.pdf=%.fo)
rm -f errs core *~
-else
-
-ifeq ($(DOCTYPE),pdf)
-docs: pdf
-else
-ifeq ($(DOCTYPE),ps)
-docs: ps
-else
-docs: html gifs man
-endif
-endif
-
-pdf: $(TOP_PDF_FILE)
-
-ps: $(TOP_PS_FILE)
-
-html: $(HTML_FILES)
-
-clean clean_docs clean_tex:
- rm -f $(TEX_FILES_USERS_GUIDE) $(TEX_FILES_REF_MAN) $(TEX_FILES_BOOK)
- rm -f $(HTML_FILES) $(MAN3_FILES)
- rm -f $(TOP_PDF_FILE) $(TOP_PS_FILE)
- rm -f errs core *~ *xmls_output *xmls_errs $(LATEX_CLEAN)
-
-endif
-
man: $(MAN3_FILES)
gifs: $(GIF_FILES:%=$(HTMLDIR)/%) # We depend just to copy them to ../html
@@ -182,8 +124,6 @@ debug opt:
# ----------------------------------------------------
include $(ERL_TOP)/make/otp_release_targets.mk
-ifdef DOCSUPPORT
-
release_docs_spec: docs
$(INSTALL_DIR) $(RELSYSDIR)/doc/pdf
$(INSTALL_DATA) $(TOP_PDF_FILE) $(RELSYSDIR)/doc/pdf
@@ -193,32 +133,5 @@ release_docs_spec: docs
$(INSTALL_DATA) $(INFO_FILE) $(RELSYSDIR)
$(INSTALL_DIR) $(RELEASE_PATH)/man/man3
$(INSTALL_DATA) $(MAN3DIR)/* $(RELEASE_PATH)/man/man3
-else
-
-ifeq ($(DOCTYPE),pdf)
-release_docs_spec: pdf
- $(INSTALL_DIR) $(RELEASE_PATH)/pdf
- $(INSTALL_DATA) $(TOP_PDF_FILE) $(RELEASE_PATH)/pdf
-else
-ifeq ($(DOCTYPE),ps)
-release_docs_spec: ps
- $(INSTALL_DIR) $(RELEASE_PATH)/ps
- $(INSTALL_DATA) $(TOP_PS_FILE) $(RELEASE_PATH)/ps
-else
-release_docs_spec: docs
- $(INSTALL_DIR) $(RELSYSDIR)/doc/html
- $(INSTALL_DATA) $(GIF_FILES) $(EXTRA_FILES) $(HTML_FILES) \
- $(RELSYSDIR)/doc/html
- $(INSTALL_DATA) $(INFO_FILE) $(RELSYSDIR)
- $(INSTALL_DIR) $(RELEASE_PATH)/man/man3
- $(INSTALL_DATA) $(MAN3_FILES) $(RELEASE_PATH)/man/man3
-endif
-endif
-
-endif
release_spec:
-
-
-
-
diff --git a/lib/odbc/doc/src/make.dep b/lib/odbc/doc/src/make.dep
deleted file mode 100644
index d62e8dd8f0..0000000000
--- a/lib/odbc/doc/src/make.dep
+++ /dev/null
@@ -1,27 +0,0 @@
-# ----------------------------------------------------
-# >>>> Do not edit this file <<<<
-# This file was automaticly generated by
-# /home/otp/bin/docdepend
-# ----------------------------------------------------
-
-
-# ----------------------------------------------------
-# TeX files that the DVI file depend on
-# ----------------------------------------------------
-
-book.dvi: book.tex databases.tex error_handling.tex \
- getting_started.tex introduction.tex odbc.tex \
- part.tex ref_man.tex
-
-# ----------------------------------------------------
-# Source inlined when transforming from source to LaTeX
-# ----------------------------------------------------
-
-book.tex: ref_man.xml
-
-# ----------------------------------------------------
-# Pictures that the DVI file depend on
-# ----------------------------------------------------
-
-book.dvi: odbc_app_arc.ps
-
diff --git a/lib/odbc/src/odbc.appup.src b/lib/odbc/src/odbc.appup.src
index f3a3af8c29..853323da09 100644
--- a/lib/odbc/src/odbc.appup.src
+++ b/lib/odbc/src/odbc.appup.src
@@ -1,10 +1,12 @@
%% -*- erlang -*-
{"%VSN%",
[
+ {"2.10.11", [{restart_application, odbc}]},
{"2.10.10", [{restart_application, odbc}]},
{"2.10.9", [{restart_application, odbc}]}
],
[
+ {"2.10.11", [{restart_application, odbc}]},
{"2.10.10", [{restart_application, odbc}]},
{"2.10.9", [{restart_application, odbc}]}
]}.
diff --git a/lib/odbc/src/odbc.erl b/lib/odbc/src/odbc.erl
index 68497292db..36afd1abcf 100644
--- a/lib/odbc/src/odbc.erl
+++ b/lib/odbc/src/odbc.erl
@@ -748,6 +748,9 @@ handle_info({'DOWN', _Ref, _Type, _Process, normal}, State) ->
handle_info({'DOWN', _Ref, _Type, _Process, timeout}, State) ->
{stop, normal, State#state{reply_to = undefined}};
+
+handle_info({'DOWN', _Ref, _Type, _Process, shutdown}, State) ->
+ {stop, normal, State#state{reply_to = undefined}};
handle_info({'DOWN', _Ref, _Type, Process, Reason}, State) ->
{stop, {stopped, {'EXIT', Process, Reason}},
diff --git a/lib/orber/COSS/CosNaming/Makefile b/lib/orber/COSS/CosNaming/Makefile
index d3deec7600..d4b2079036 100644
--- a/lib/orber/COSS/CosNaming/Makefile
+++ b/lib/orber/COSS/CosNaming/Makefile
@@ -113,7 +113,7 @@ debug:
@${MAKE} TYPE=debug
clean:
- rm -f $(TARGET_FILES) $(GEN_FILES) $(APP_TARGET)
+ rm -f $(TARGET_FILES) $(GEN_FILES) $(APP_TARGET) IDL-GENERATED
rm -f errs core *~
$(APP_TARGET): $(APP_SRC)
@@ -124,13 +124,15 @@ docs:
# ----------------------------------------------------
# Special Build Targets
# ----------------------------------------------------
-$(GEN_FILES): cos_naming_ext.idl cos_naming.idl
+IDL-GENERATED: cos_naming_ext.idl cos_naming.idl
erlc $(ERL_IDL_FLAGS) +'{this,"CosNaming::NamingContext"}' \
+'{this,"CosNaming::NamingContextExt"}' cos_naming_ext.idl
erlc $(ERL_IDL_FLAGS) +'{this,"CosNaming::NamingContext"}' cos_naming.idl
+ >IDL-GENERATED
-# echo "ic:gen(cos_naming, [{this, \"CosNaming::NamingContext\"}]), halt()."| $(ERL) $(ERL_IDL_FLAGS)
+$(GEN_FILES): IDL-GENERATED
+$(TARGET_FILES): IDL-GENERATED
# ----------------------------------------------------
# Release Target
diff --git a/lib/orber/doc/src/Makefile b/lib/orber/doc/src/Makefile
index b8e26d5ba3..8a555cb408 100644
--- a/lib/orber/doc/src/Makefile
+++ b/lib/orber/doc/src/Makefile
@@ -28,14 +28,6 @@ VSN=$(ORBER_VSN)
APPLICATION=orber
# ----------------------------------------------------
-# Include dependency
-# ----------------------------------------------------
-
-ifndef DOCSUPPORT
-include make.dep
-endif
-
-# ----------------------------------------------------
# Release directory specification
# ----------------------------------------------------
RELSYSDIR = $(RELEASE_PATH)/lib/$(APPLICATION)-$(VSN)
@@ -128,32 +120,10 @@ EXTRA_FILES = summary.html.src \
MAN3_FILES = $(XML_REF3_FILES:%.xml=$(MAN3DIR)/%.3)
-ifdef DOCSUPPORT
-
HTML_REF_MAN_FILE = $(HTMLDIR)/index.html
TOP_PDF_FILE = $(PDFDIR)/$(APPLICATION)-$(VSN).pdf
-else
-
-TEX_FILES_BOOK = \
- $(BOOK_FILES:%.xml=%.tex)
-TEX_FILES_REF_MAN = $(XML_REF3_FILES:%.xml=%.tex) \
- $(XML_APPLICATION_FILES:%.xml=%.tex)
-TEX_FILES_USERS_GUIDE = \
- $(XML_CHAPTER_FILES:%.xml=%.tex)
-
-TOP_PDF_FILE = $(APPLICATION)-$(VSN).pdf
-TOP_PS_FILE = $(APPLICATION)-$(VSN).ps
-
-$(TOP_PDF_FILE): book.dvi ../../vsn.mk
- $(DVI2PS) $(DVIPS_FLAGS) -f $< | $(DISTILL) $(DISTILL_FLAGS) > $@
-
-$(TOP_PS_FILE): book.dvi ../../vsn.mk
- $(DVI2PS) $(DVIPS_FLAGS) -f $< > $@
-
-endif
-
# ----------------------------------------------------
# FLAGS
# ----------------------------------------------------
@@ -167,8 +137,6 @@ $(HTMLDIR)/%.gif: %.gif
$(INSTALL_DATA) $< $@
-ifdef DOCSUPPORT
-
docs: pdf html man
$(TOP_PDF_FILE): $(XML_FILES)
@@ -184,35 +152,6 @@ clean clean_docs:
rm -f errs core *~
rm -f $(JD_HTML) $(JD_PACK)
-else
-
-ifeq ($(DOCTYPE),pdf)
-docs: pdf
-else
-ifeq ($(DOCTYPE),ps)
-docs: ps
-else
-docs: html gifs man
-endif
-endif
-
-pdf: $(TOP_PDF_FILE)
-
-ps: $(TOP_PS_FILE)
-
-html: $(HTML_FILES) $(INTERNAL_HTML_FILES)
-
-clean clean_docs clean_tex:
- rm -f $(TEX_FILES_USERS_GUIDE) $(TEX_FILES_REF_MAN) $(TEX_FILES_BOOK)
- rm -f $(HTMLDIR)/*
- rm -f $(MAN3DIR)/*
- rm -f $(TOP_PDF_FILE) $(TOP_PS_FILE)
- rm -f errs core *~ *xmls_output *xmls_errs $(LATEX_CLEAN)
- rm -f $(JD_HTML) $(JD_PACK)
-
-endif
-
-
man: $(MAN3_FILES)
gifs: $(GIF_FILES:%=$(HTMLDIR)/%)
@@ -224,9 +163,6 @@ debug opt:
# ----------------------------------------------------
include $(ERL_TOP)/make/otp_release_targets.mk
-
-ifdef DOCSUPPORT
-
release_docs_spec: docs
$(INSTALL_DIR) $(RELSYSDIR)/doc/pdf
$(INSTALL_DATA) $(TOP_PDF_FILE) $(RELSYSDIR)/doc/pdf
@@ -236,30 +172,5 @@ release_docs_spec: docs
$(INSTALL_DATA) $(INFO_FILE) $(RELSYSDIR)
$(INSTALL_DIR) $(RELEASE_PATH)/man/man3
$(INSTALL_DATA) $(MAN3DIR)/* $(RELEASE_PATH)/man/man3
-else
-
-ifeq ($(DOCTYPE),pdf)
-release_docs_spec: pdf
- $(INSTALL_DIR) $(RELEASE_PATH)/pdf
- $(INSTALL_DATA) $(TOP_PDF_FILE) $(RELEASE_PATH)/pdf
-else
-ifeq ($(DOCTYPE),ps)
-release_docs_spec: ps
- $(INSTALL_DIR) $(RELEASE_PATH)/ps
- $(INSTALL_DATA) $(TOP_PS_FILE) $(RELEASE_PATH)/ps
-else
-release_docs_spec: docs
- $(INSTALL_DIR) $(RELSYSDIR)/doc/html
- $(INSTALL_DATA) $(GIF_FILES) $(EXTRA_FILES) $(HTML_FILES) \
- $(RELSYSDIR)/doc/html
- $(INSTALL_DATA) $(INFO_FILE) $(RELSYSDIR)
- $(INSTALL_DIR) $(RELEASE_PATH)/man/man3
- $(INSTALL_DATA) $(MAN3_FILES) $(RELEASE_PATH)/man/man3
-
-endif
-endif
-
-endif
release_spec:
-
diff --git a/lib/orber/doc/src/Orber/ignore_config_record.inf b/lib/orber/doc/src/Orber/ignore_config_record.inf
deleted file mode 100644
index 0a5053eba3..0000000000
--- a/lib/orber/doc/src/Orber/ignore_config_record.inf
+++ /dev/null
@@ -1 +0,0 @@
-This file makes clearmake use the -T switch for this subdirectory
diff --git a/lib/orber/doc/src/make.dep b/lib/orber/doc/src/make.dep
deleted file mode 100644
index cf5aad747d..0000000000
--- a/lib/orber/doc/src/make.dep
+++ /dev/null
@@ -1,62 +0,0 @@
-# ----------------------------------------------------
-# >>>> Do not edit this file <<<<
-# This file was automaticly generated by
-# /home/otp/bin/docdepend
-# ----------------------------------------------------
-
-
-# ----------------------------------------------------
-# TeX files that the DVI file depend on
-# ----------------------------------------------------
-
-book.dvi: CosNaming.tex CosNaming_BindingIterator.tex \
- CosNaming_NamingContext.tex CosNaming_NamingContextExt.tex \
- Module_Interface.tex any.tex book.tex ch_contents.tex \
- ch_debugging.tex ch_exceptions.tex \
- ch_idl_to_erlang_mapping.tex ch_ifr.tex ch_install.tex \
- ch_interceptors.tex ch_introduction.tex ch_naming_service.tex \
- ch_orber_kernel.tex ch_orberweb.tex ch_security.tex \
- ch_stubs.tex corba.tex corba_object.tex example_part.tex \
- fixed.tex interceptors.tex intro_part.tex \
- lname.tex lname_component.tex orber.tex orber_acl.tex \
- orber_diagnostics.tex orber_ifr.tex orber_tc.tex \
- ref_man.tex tools_debugging_part.tex
-
-# ----------------------------------------------------
-# Source inlined when transforming from source to LaTeX
-# ----------------------------------------------------
-
-book.tex: ref_man.xml
-
-ch_contents.tex: ../../../../system/doc/definitions/term.defs
-
-ch_idl_to_erlang_mapping.tex: ../../../../system/doc/definitions/term.defs
-
-ch_install.tex: ../../../../system/doc/definitions/term.defs
-
-ch_introduction.tex: ../../../../system/doc/definitions/term.defs
-
-ch_naming_service.tex: ../../../../system/doc/definitions/term.defs
-
-ch_orber_kernel.tex: ../../../../system/doc/definitions/term.defs
-
-orber_ifr.tex: ../../../../system/doc/definitions/term.defs
-
-# ----------------------------------------------------
-# Pictures that the DVI file depend on
-# ----------------------------------------------------
-
-book.dvi: firewall_nat.ps
-
-book.dvi: interceptor_operations.ps
-
-book.dvi: dependent.ps orbs.ps
-
-book.dvi: name.ps
-
-book.dvi: iiop.ps theORB.ps
-
-book.dvi: dataframe1.ps dataframe2.ps dataframe3.ps \
- dataframe4.ps dataframe5.ps dataframe6.ps \
- dataframe7.ps dataframe8.ps menuframe.ps
-
diff --git a/lib/orber/examples/Stack/Makefile b/lib/orber/examples/Stack/Makefile
index 6e7f292a04..215e57fcbe 100644
--- a/lib/orber/examples/Stack/Makefile
+++ b/lib/orber/examples/Stack/Makefile
@@ -64,6 +64,8 @@ HRL_FILES=
ERL_FILES= $(MODULES:%=%.erl)
+GEN_FILES = $(GEN_ERL_MODULES:%=%.erl) $(GEN_HRL_FILES)
+
JAVA_CLASSES = \
StackClient
@@ -94,16 +96,20 @@ ERL_COMPILE_FLAGS += \
debug opt: $(TARGET_FILES)
clean:
- rm -f $(TARGET_FILES) $(GEN_ERL_MODULES:%=%.erl) $(GEN_HRL_FILES) $(CLASS_FILES)
+ rm -f $(TARGET_FILES) $(GEN_ERL_MODULES:%=%.erl) $(GEN_HRL_FILES) $(CLASS_FILES) IDL-GENERATED
rm -f errs core *~
docs:
test: $(TEST_TARGET_FILES)
-
-$(GEN_ERL_MODULES:%=%.erl) $(GEN_HRL_FILES): stack.idl
+IDL-GENERATED: stack.idl
erlc $(ERL_IDL_FLAGS) stack.idl
+ >IDL-GENERATED
+
+$(GEN_FILES): IDL-GENERATED
+
+$(TARGET_FILES): IDL-GENERATED
# ----------------------------------------------------
# Release Target
diff --git a/lib/orber/priv/Makefile b/lib/orber/priv/Makefile
index 2847727035..2847727035 100755..100644
--- a/lib/orber/priv/Makefile
+++ b/lib/orber/priv/Makefile
diff --git a/lib/orber/priv/blank.html b/lib/orber/priv/blank.html
index 44e86908a0..44e86908a0 100755..100644
--- a/lib/orber/priv/blank.html
+++ b/lib/orber/priv/blank.html
diff --git a/lib/orber/priv/info_frames.html b/lib/orber/priv/info_frames.html
index 75456a67a4..75456a67a4 100755..100644
--- a/lib/orber/priv/info_frames.html
+++ b/lib/orber/priv/info_frames.html
diff --git a/lib/orber/priv/main_frame.html b/lib/orber/priv/main_frame.html
index 056a92812e..056a92812e 100755..100644
--- a/lib/orber/priv/main_frame.html
+++ b/lib/orber/priv/main_frame.html
diff --git a/lib/orber/priv/orber.tool b/lib/orber/priv/orber.tool
index 910a7d7e45..910a7d7e45 100755..100644
--- a/lib/orber/priv/orber.tool
+++ b/lib/orber/priv/orber.tool
diff --git a/lib/orber/priv/orber_help.txt b/lib/orber/priv/orber_help.txt
index a6580dc30a..a6580dc30a 100755..100644
--- a/lib/orber/priv/orber_help.txt
+++ b/lib/orber/priv/orber_help.txt
diff --git a/lib/orber/priv/start_info.html b/lib/orber/priv/start_info.html
index 0ad521c90a..0ad521c90a 100755..100644
--- a/lib/orber/priv/start_info.html
+++ b/lib/orber/priv/start_info.html
diff --git a/lib/orber/src/Makefile b/lib/orber/src/Makefile
index ccc449333c..e812e22b46 100644
--- a/lib/orber/src/Makefile
+++ b/lib/orber/src/Makefile
@@ -212,7 +212,7 @@ debug:
opt: $(TARGET_FILES) $(APP_TARGET) $(APPUP_TARGET)
clean:
- rm -f $(TARGET_FILES) $(GEN_FILES) $(APP_TARGET) $(APPUP_TARGET)
+ rm -f $(TARGET_FILES) $(GEN_FILES) $(APP_TARGET) $(APPUP_TARGET) IDL-GENERATED
rm -f errs core *~
$(APP_TARGET): $(APP_SRC) ../vsn.mk
@@ -227,15 +227,14 @@ docs:
# Special Build Targets
# ----------------------------------------------------
-$(GEN_ERL_FILES1) $(GEN_HRL_FILES1): $(ERL_TOP)/lib/ic/include/erlang.idl
+IDL-GENERATED: $(ERL_TOP)/lib/ic/include/erlang.idl CORBA.idl OrberIFR.idl
erlc $(ERL_IDL_FLAGS) $(ERL_TOP)/lib/ic/include/erlang.idl
-
-$(GEN_ERL_FILES2) $(GEN_HRL_FILES2): CORBA.idl
erlc $(ERL_IDL_FLAGS) CORBA.idl
+ erlc $(ERL_IDL_FLAGS) +'{this,"Orber::IFR"}' OrberIFR.idl
+ >IDL-GENERATED
-$(GEN_ERL_FILES3) $(GEN_HRL_FILES3): OrberIFR.idl
- erlc $(ERL_IDL_FLAGS) +'{this,"Orber::IFR"}' \
- OrberIFR.idl
+$(GEN_ERL_FILES): IDL-GENERATED
+$(TARGET_FILES): IDL-GENERATED
$(GEN_ASN_ERL) $(GEN_ASN_HRL): OrberCSIv2.asn1 OrberCSIv2.set.asn
erlc $(ERL_COMPILE_FLAGS) $(ASN_FLAGS) +'{inline,"OrberCSIv2"}' OrberCSIv2.set.asn
diff --git a/lib/orber/src/corba.erl b/lib/orber/src/corba.erl
index ecec768544..989e84f581 100644
--- a/lib/orber/src/corba.erl
+++ b/lib/orber/src/corba.erl
@@ -947,7 +947,7 @@ handle_cast2(M, F, A, InternalState, State, Ctx) ->
{noreply, {InternalState, NewState}}
end.
-handle_exit(InternalState, State, {undef, [{M, F, _}|_]} = Reason,
+handle_exit(InternalState, State, {undef, [{M, F, _, _}|_]} = Reason,
OnewayOp, {M, F}, A) ->
case catch check_exports(M:module_info(exports), F) of
{'EXIT',{undef,_}} ->
@@ -979,7 +979,7 @@ handle_exit(InternalState, State, {undef, [{M, F, _}|_]} = Reason,
#'OBJ_ADAPTER'{minor=(?ORBER_VMCID bor 4),
completion_status=?COMPLETED_MAYBE})
end;
-handle_exit(InternalState, State, {undef, [{M2, F2, A2}|_]} = Reason,
+handle_exit(InternalState, State, {undef, [{M2, F2, A2, _}|_]} = Reason,
OnewayOp, {M, F}, A) ->
case catch check_exports(M2:module_info(exports), F2) of
{'EXIT',{undef,_}} ->
diff --git a/lib/orber/src/orber_diagnostics.erl b/lib/orber/src/orber_diagnostics.erl
index c12dbfa896..c115d79524 100644
--- a/lib/orber/src/orber_diagnostics.erl
+++ b/lib/orber/src/orber_diagnostics.erl
@@ -130,10 +130,10 @@ missing_modules_helper([[Mod, Type]|T], ErrorsFound) when Type == ?IFR_StructDef
end;
missing_modules_helper([[Mod, Type]|T], ErrorsFound) when Type == ?IFR_InterfaceDef ->
case catch Mod:oe_get_interface() of
- {'EXIT', {undef,[{Mod, _, _}|_]}} ->
+ {'EXIT', {undef,[{Mod, _, _, _}|_]}} ->
io:format("Missing (Interface): ~p~n", [Mod]),
missing_modules_helper(T, ErrorsFound + 1);
- {'EXIT', {undef,[{OtherMod, _, _}|_]}} ->
+ {'EXIT', {undef,[{OtherMod, _, _, _}|_]}} ->
io:format("Missing (Inherited by the ~p Interface): ~p~n",
[Mod, OtherMod]),
missing_modules_helper(T, ErrorsFound + 1);
diff --git a/lib/orber/src/orber_ifr.erl b/lib/orber/src/orber_ifr.erl
index e56672be93..9631a268e4 100644
--- a/lib/orber/src/orber_ifr.erl
+++ b/lib/orber/src/orber_ifr.erl
@@ -500,7 +500,7 @@ get_tc(Id, Type) ->
case catch Module:tc() of
{'EXIT', Reason} ->
case Reason of
- {undef,[{Module, tc,[]}|_]} ->
+ {undef,[{Module, tc,[],_}|_]} ->
orber:dbg("[~p] ~p:get_tc(~p);~nMissing ~p:tc()~n",
[?LINE, ?MODULE, Id, Module], ?DEBUG_LEVEL),
corba:raise(#'UNKNOWN'{minor=(?ORBER_VMCID bor 1),
diff --git a/lib/orber/test/Makefile b/lib/orber/test/Makefile
index b682bcf24b..996d0d1874 100644
--- a/lib/orber/test/Makefile
+++ b/lib/orber/test/Makefile
@@ -184,31 +184,17 @@ docs:
# Special Targets
# ----------------------------------------------------
-#
-# Each IDL file produces many target files so no pattern
-# rule can be used.
-#
-TGT_ORBER = \
- $(GEN_HRL_ORBER:%=$(IDLOUTDIR)/%) \
- $(GEN_MOD_ORBER:%=$(IDLOUTDIR)/%.erl)
-TGT_IIOP = \
- $(GEN_HRL_IIOP:%=$(IDLOUTDIR)/%) \
- $(GEN_MOD_IIOP:%=$(IDLOUTDIR)/%.erl)
-
-TGT_TEST_SERVER = \
- $(GEN_HRL_TEST_SERVER:%=$(IDLOUTDIR)/%) \
- $(GEN_MOD_TEST_SERVER:%=$(IDLOUTDIR)/%.erl)
-
-$(TGT_ORBER): orber_test.idl
+IDL-GENERATED: orber_test.idl iiop_test.idl orber_test_server.idl
erlc $(ERL_IDL_FLAGS) -o$(IDLOUTDIR) orber_test.idl
-
-$(TGT_IIOP): iiop_test.idl
erlc $(ERL_IDL_FLAGS) -o$(IDLOUTDIR) \
+'{preproc_flags,"-I../COSS/CosNaming"}' iiop_test.idl
-
-$(TGT_TEST_SERVER): orber_test_server.idl
erlc $(ERL_IDL_FLAGS) -o$(IDLOUTDIR) \
+'{cfgfile,"orber_test_server.cfg"}' orber_test_server.idl
+ >IDL-GENERATED
+
+$(GEN_FILES): IDL-GENERATED
+
+$(TARGET_FILES): IDL-GENERATED
# ----------------------------------------------------
# Release Targets
diff --git a/lib/orber/test/csiv2_SUITE.erl b/lib/orber/test/csiv2_SUITE.erl
index 95cd8c56b3..406a8ea693 100644
--- a/lib/orber/test/csiv2_SUITE.erl
+++ b/lib/orber/test/csiv2_SUITE.erl
@@ -696,7 +696,6 @@ ssl_client_peercert_api(_Config) ->
?match({ok,_,_}, orber_test_lib:js_node(Options)),
crypto:start(),
ssl:start(),
- ssl:seed("testing"),
SSLOptions = orber_test_lib:get_options(ssl, server),
{ok, LSock} = ?match({ok, _}, ssl:listen(0, SSLOptions)),
{ok, {_Address, LPort}} = ?match({ok, {_, _}}, ssl:sockname(LSock)),
@@ -857,8 +856,7 @@ fake_server_ORB(Type, Port, Options, Action, Data) ->
start_ssl(ssl) ->
crypto:start(),
- ssl:start(),
- ssl:seed("testing");
+ ssl:start();
start_ssl(_) ->
ok.
diff --git a/lib/orber/test/multi_ORB_SUITE.erl b/lib/orber/test/multi_ORB_SUITE.erl
index 608fb23f3e..b9453663c3 100644
--- a/lib/orber/test/multi_ORB_SUITE.erl
+++ b/lib/orber/test/multi_ORB_SUITE.erl
@@ -1683,7 +1683,6 @@ ssl_reconfigure(ExtraSSLOptions) ->
{ip_address, IP}|ExtraSSLOptions])),
orber_test_lib:remote_apply(ServerNode, ssl, start, []),
orber_test_lib:remote_apply(ServerNode, crypto, start, []),
- orber_test_lib:remote_apply(ServerNode, ssl, seed, ["testing"]),
?match(ok, orber_test_lib:remote_apply(ServerNode, orber_test_lib,
install_test_data,
[ssl])),
@@ -1713,7 +1712,6 @@ ssl_reconfigure(ExtraSSLOptions) ->
[ssl])),
orber_test_lib:remote_apply(ClientNode, ssl, start, []),
orber_test_lib:remote_apply(ServerNode, crypto, start, []),
- orber_test_lib:remote_apply(ClientNode, ssl, seed, ["testing"]),
Obj = ?match(#'IOP_IOR'{},
orber_test_lib:remote_apply(ClientNode, corba,
string_to_object, ["corbaname:iiop:1.1@"++Loopback++":5648/NameService#mamba",
diff --git a/lib/orber/test/orber_test_lib.erl b/lib/orber/test/orber_test_lib.erl
index ffc13d0e3c..903ab1d771 100644
--- a/lib/orber/test/orber_test_lib.erl
+++ b/lib/orber/test/orber_test_lib.erl
@@ -296,8 +296,7 @@ slave_sup() ->
start_ssl(true, Node) ->
rpc:call(Node, ssl, start, []),
- rpc:call(Node, crypto, start, []),
- rpc:call(Node, ssl, seed, ["testing"]);
+ rpc:call(Node, crypto, start, []);
start_ssl(_, _) ->
ok.
diff --git a/lib/orber/vsn.mk b/lib/orber/vsn.mk
index 29b21e8e01..0eac1e1410 100644
--- a/lib/orber/vsn.mk
+++ b/lib/orber/vsn.mk
@@ -1,3 +1,3 @@
-ORBER_VSN = 3.6.22
+ORBER_VSN = 3.6.23
diff --git a/lib/os_mon/c_src/Makefile.in b/lib/os_mon/c_src/Makefile.in
index 1a371eb380..b81d3f564b 100644
--- a/lib/os_mon/c_src/Makefile.in
+++ b/lib/os_mon/c_src/Makefile.in
@@ -82,13 +82,9 @@ ALL_CFLAGS = @CFLAGS@ @DEFS@ $(CFLAGS)
# Targets
# ----------------------------------------------------
-debug opt: $(OBJDIR) $(BINDIR) $(TARGET_FILES)
+_create_dirs := $(shell mkdir -p $(OBJDIR) $(BINDIR))
-$(OBJDIR):
- -@mkdir -p $(OBJDIR)
-
-$(BINDIR):
- -@mkdir -p $(BINDIR)
+debug opt: $(TARGET_FILES)
clean:
rm -f $(TARGET_FILES)
diff --git a/lib/os_mon/doc/src/make.dep b/lib/os_mon/doc/src/make.dep
deleted file mode 100644
index b657f2e036..0000000000
--- a/lib/os_mon/doc/src/make.dep
+++ /dev/null
@@ -1,21 +0,0 @@
-# ----------------------------------------------------
-# >>>> Do not edit this file <<<<
-# This file was automaticly generated by
-# /home/otp/bin/docdepend
-# ----------------------------------------------------
-
-
-# ----------------------------------------------------
-# TeX files that the DVI file depend on
-# ----------------------------------------------------
-
-book.dvi: book.tex cpu_sup.tex disksup.tex memsup.tex \
- nteventlog.tex os_mon.tex os_mon_mib.tex os_sup.tex \
- ref_man.tex
-
-# ----------------------------------------------------
-# Source inlined when transforming from source to LaTeX
-# ----------------------------------------------------
-
-book.tex: ref_man.xml
-
diff --git a/lib/os_mon/mibs/Makefile b/lib/os_mon/mibs/Makefile
index cbbc337491..a361fef378 100644
--- a/lib/os_mon/mibs/Makefile
+++ b/lib/os_mon/mibs/Makefile
@@ -78,6 +78,9 @@ $(SNMP_BIN_TARGET_DIR)/OTP-MIB.bin: $(ERL_TOP)/lib/$(OTP_MIBDIR)/mibs/OTP-MI
v1/%.mib.v1: %.mib
$(ERL_TOP)/lib/snmp/bin/snmp-v2tov1 -o $@ $<
+$(SNMP_BIN_TARGET_DIR)/OTP-OS-MON-MIB.bin: \
+ $(SNMP_BIN_TARGET_DIR)/OTP-REG.bin \
+ $(SNMP_BIN_TARGET_DIR)/OTP-MIB.bin \
# ----------------------------------------------------
# Release Target
diff --git a/lib/os_mon/src/os_mon_mib.erl b/lib/os_mon/src/os_mon_mib.erl
index a4ce274a16..c972913b03 100644
--- a/lib/os_mon/src/os_mon_mib.erl
+++ b/lib/os_mon/src/os_mon_mib.erl
@@ -65,11 +65,11 @@
%% Shadow argument macros
-define(loadShadowArgs,
{loadTable, string, record_info(fields, loadTable), 5000,
- {os_mon_mib, update_load_table}}).
+ fun os_mon_mib:update_load_table/0}).
-define(diskShadowArgs,
{diskTable, {integer, integer}, record_info(fields, diskTable), 5000,
- {os_mon_mib, update_disk_table}}).
+ fun os_mon_mib:update_disk_table/0}).
%% Misc
-record(diskAlloc, {diskDescr, diskId}).
diff --git a/lib/os_mon/test/os_mon_mib_SUITE.erl b/lib/os_mon/test/os_mon_mib_SUITE.erl
index 4bd256a3f7..a137efc441 100644
--- a/lib/os_mon/test/os_mon_mib_SUITE.erl
+++ b/lib/os_mon/test/os_mon_mib_SUITE.erl
@@ -718,7 +718,7 @@ del_dir(Dir) ->
{ok, Files} = file:list_dir(Dir),
FullPathFiles = lists:map(fun(File) -> filename:join(Dir, File) end,
Files),
- lists:foreach({file, delete}, FullPathFiles),
+ lists:foreach(fun file:delete/1, FullPathFiles),
file:del_dir(Dir).
%%---------------------------------------------------------------------
diff --git a/lib/otp_mibs/doc/src/make.dep b/lib/otp_mibs/doc/src/make.dep
deleted file mode 100644
index 2885155315..0000000000
--- a/lib/otp_mibs/doc/src/make.dep
+++ /dev/null
@@ -1,20 +0,0 @@
-# ----------------------------------------------------
-# >>>> Do not edit this file <<<<
-# This file was automaticly generated by
-# /home/otp/bin/docdepend
-# ----------------------------------------------------
-
-
-# ----------------------------------------------------
-# TeX files that the DVI file depend on
-# ----------------------------------------------------
-
-book.dvi: book.tex introduction.tex mibs.tex otp_mib.tex \
- part.tex ref_man.tex
-
-# ----------------------------------------------------
-# Source inlined when transforming from source to LaTeX
-# ----------------------------------------------------
-
-book.tex: ref_man.xml
-
diff --git a/lib/otp_mibs/src/otp_mib.erl b/lib/otp_mibs/src/otp_mib.erl
index e8b0e51b91..1b0211df02 100644
--- a/lib/otp_mibs/src/otp_mib.erl
+++ b/lib/otp_mibs/src/otp_mib.erl
@@ -48,11 +48,11 @@
%% Shadow argument macros
-define(erlNodeShadowArgs,
{erlNodeTable, integer, record_info(fields, erlNodeTable), 5000,
- {otp_mib, update_erl_node_table}}).
+ fun otp_mib:update_erl_node_table/0}).
-define(applShadowArgs,
{applTable, {integer, integer}, record_info(fields, applTable),
- 5000, {otp_mib, update_appl_table}}).
+ 5000, fun otp_mib:update_appl_table/0}).
%% Misc
-record(erlNodeAlloc, {nodeName, nodeId}).
diff --git a/lib/parsetools/doc/src/make.dep b/lib/parsetools/doc/src/make.dep
deleted file mode 100644
index 3a09ecdedd..0000000000
--- a/lib/parsetools/doc/src/make.dep
+++ /dev/null
@@ -1,21 +0,0 @@
-# ----------------------------------------------------
-# >>>> Do not edit this file <<<<
-# This file was automaticly generated by
-# /home/otp/bin/docdepend
-# ----------------------------------------------------
-
-
-# ----------------------------------------------------
-# TeX files that the DVI file depend on
-# ----------------------------------------------------
-
-book.dvi: book.tex leex.tex ref_man.tex yecc.tex
-
-# ----------------------------------------------------
-# Source inlined when transforming from source to LaTeX
-# ----------------------------------------------------
-
-book.tex: ref_man.xml
-
-ref_man.tex: ../../../../system/doc/definitions/term.defs
-
diff --git a/lib/parsetools/include/yeccpre.hrl b/lib/parsetools/include/yeccpre.hrl
index 80a3afbdb6..3672394fc5 100644
--- a/lib/parsetools/include/yeccpre.hrl
+++ b/lib/parsetools/include/yeccpre.hrl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2010. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2011. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -28,10 +28,11 @@ parse(Tokens) ->
-spec parse_and_scan({function() | {atom(), atom()}, [_]}
| {atom(), atom(), [_]}) -> yecc_ret().
-parse_and_scan({F, A}) -> % Fun or {M, F}
+parse_and_scan({F, A}) ->
yeccpars0([], {{F, A}, no_line}, 0, [], []);
parse_and_scan({M, F, A}) ->
- yeccpars0([], {{{M, F}, A}, no_line}, 0, [], []).
+ Arity = length(A),
+ yeccpars0([], {{fun M:F/Arity, A}, no_line}, 0, [], []).
-spec format_error(any()) -> [char() | list()].
format_error(Message) ->
@@ -67,7 +68,7 @@ yeccpars0(Tokens, Tzr, State, States, Vstack) ->
Error
end.
-yecc_error_type(function_clause, [{?MODULE,F,ArityOrArgs} | _]) ->
+yecc_error_type(function_clause, [{?MODULE,F,ArityOrArgs,_} | _]) ->
case atom_to_list(F) of
"yeccgoto_" ++ SymbolL ->
{ok,[{atom,_,Symbol}],_} = erl_scan:string(SymbolL),
diff --git a/lib/parsetools/src/yeccparser.erl b/lib/parsetools/src/yeccparser.erl
index 63127802ee..e4b8b06db5 100644
--- a/lib/parsetools/src/yeccparser.erl
+++ b/lib/parsetools/src/yeccparser.erl
@@ -17,7 +17,7 @@ line_of(Token) ->
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2010. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2011. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -83,7 +83,7 @@ yeccpars0(Tokens, Tzr, State, States, Vstack) ->
Error
end.
-yecc_error_type(function_clause, [{?MODULE,F,ArityOrArgs} | _]) ->
+yecc_error_type(function_clause, [{?MODULE,F,ArityOrArgs,_} | _]) ->
case atom_to_list(F) of
"yeccgoto_" ++ SymbolL ->
{ok,[{atom,_,Symbol}],_} = erl_scan:string(SymbolL),
diff --git a/lib/parsetools/test/yecc_SUITE.erl b/lib/parsetools/test/yecc_SUITE.erl
index a5f66b48e9..3d26adf1be 100644
--- a/lib/parsetools/test/yecc_SUITE.erl
+++ b/lib/parsetools/test/yecc_SUITE.erl
@@ -1197,7 +1197,7 @@ yeccpre(Config) when is_list(Config) ->
catch error: error ->
ok
end,
- try parse_and_scan({{yecc_test, scan}, [exit]})
+ try parse_and_scan({fun yecc_test:scan/1, [exit]})
catch exit: exit ->
ok
end,
@@ -1650,10 +1650,11 @@ yeccpre_v1_2() ->
parse(Tokens) ->
yeccpars0(Tokens, false).
-parse_and_scan({F, A}) -> % Fun or {M, F}
+parse_and_scan({F, A}) ->
yeccpars0([], {F, A});
parse_and_scan({M, F, A}) ->
- yeccpars0([], {{M, F}, A}).
+ Arity = length(A),
+ yeccpars0([], {fun M:F/Arity, A}).
format_error(Message) ->
case io_lib:deep_char_list(Message) of
diff --git a/lib/percept/doc/src/make.dep b/lib/percept/doc/src/make.dep
deleted file mode 100644
index df16cffd4f..0000000000
--- a/lib/percept/doc/src/make.dep
+++ /dev/null
@@ -1,34 +0,0 @@
-# ----------------------------------------------------
-# >>>> Do not edit this file <<<<
-# This file was automaticly generated by
-# /home/otp/bin/docdepend
-# ----------------------------------------------------
-
-
-# ----------------------------------------------------
-# TeX files that the DVI file depend on
-# ----------------------------------------------------
-
-book.dvi: book.tex egd.tex egd_ug.tex part.tex percept.tex \
- percept_profile.tex percept_ug.tex ref_man.tex
-
-# ----------------------------------------------------
-# Source inlined when transforming from source to LaTeX
-# ----------------------------------------------------
-
-book.tex: ref_man.xml
-
-egd_ug.tex: img.erl img_esi.erl
-
-percept_ug.tex: sorter.erl
-
-# ----------------------------------------------------
-# Pictures that the DVI file depend on
-# ----------------------------------------------------
-
-book.dvi: img_esi_result.ps test1.ps test2.ps test3.ps \
- test4.ps
-
-book.dvi: percept_compare.ps percept_overview.ps percept_processes.ps \
- percept_processinfo.ps
-
diff --git a/lib/percept/doc/src/part_notes.xml b/lib/percept/doc/src/part_notes.xml
index 4965e67640..4965e67640 100755..100644
--- a/lib/percept/doc/src/part_notes.xml
+++ b/lib/percept/doc/src/part_notes.xml
diff --git a/lib/percept/test/percept_SUITE_data/ipc-dist.dat b/lib/percept/test/percept_SUITE_data/ipc-dist.dat
index 14ab6c0c5d..14ab6c0c5d 100755..100644
--- a/lib/percept/test/percept_SUITE_data/ipc-dist.dat
+++ b/lib/percept/test/percept_SUITE_data/ipc-dist.dat
Binary files differ
diff --git a/lib/pman/doc/src/make.dep b/lib/pman/doc/src/make.dep
deleted file mode 100644
index 2f6a8a06cd..0000000000
--- a/lib/pman/doc/src/make.dep
+++ /dev/null
@@ -1,26 +0,0 @@
-# ----------------------------------------------------
-# >>>> Do not edit this file <<<<
-# This file was automaticly generated by
-# /home/otp/bin/docdepend
-# ----------------------------------------------------
-
-
-# ----------------------------------------------------
-# TeX files that the DVI file depend on
-# ----------------------------------------------------
-
-book.dvi: book.tex part.tex pman.tex pman_chapter.tex \
- ref_man.tex
-
-# ----------------------------------------------------
-# Source inlined when transforming from source to LaTeX
-# ----------------------------------------------------
-
-book.tex: ref_man.xml
-
-# ----------------------------------------------------
-# Pictures that the DVI file depend on
-# ----------------------------------------------------
-
-book.dvi: main_window.ps options.ps trace.ps
-
diff --git a/lib/public_key/.gitignore b/lib/public_key/.gitignore
new file mode 100644
index 0000000000..db24906676
--- /dev/null
+++ b/lib/public_key/.gitignore
@@ -0,0 +1,7 @@
+# public_key
+
+/lib/public_key/asn1/*.asn1db
+/lib/public_key/asn1/*.erl
+/lib/public_key/asn1/*.hrl
+/lib/public_key/include/OTP-PUB-KEY.hrl
+/lib/public_key/include/PKCS-FRAME.hrl
diff --git a/lib/public_key/asn1/DSS.asn1 b/lib/public_key/asn1/DSS.asn1
index 77aca3808b..77aca3808b 100755..100644
--- a/lib/public_key/asn1/DSS.asn1
+++ b/lib/public_key/asn1/DSS.asn1
diff --git a/lib/public_key/asn1/InformationFramework.asn1 b/lib/public_key/asn1/InformationFramework.asn1
new file mode 100644
index 0000000000..40fbd11a2a
--- /dev/null
+++ b/lib/public_key/asn1/InformationFramework.asn1
@@ -0,0 +1,682 @@
+InformationFramework {joint-iso-itu-t ds(5) module(1) informationFramework(1)
+ 6} DEFINITIONS ::=
+BEGIN
+
+-- EXPORTS All
+-- The types and values defined in this module are exported for use in the other ASN.1 modules contained
+-- within the Directory Specifications, and for the use of other applications which will use them to access
+-- Directory services. Other applications may use them for their own purposes, but this will not constrain
+-- extensions and modifications needed to maintain or improve the Directory service.
+IMPORTS
+ -- from ITU-T Rec. X.501 | ISO/IEC 9594-2
+ directoryAbstractService, id-ar, id-at, id-mr, id-nf, id-oa, id-oc,
+ id-sc, selectedAttributeTypes, serviceAdministration
+ FROM UsefulDefinitions {joint-iso-itu-t ds(5) module(1)
+ usefulDefinitions(0) 6}
+ SearchRule
+ FROM ServiceAdministration serviceAdministration
+ -- from ITU-T Rec. X.511 | ISO/IEC 9594-3
+ TypeAndContextAssertion
+ FROM DirectoryAbstractService directoryAbstractService
+ -- from ITU-T Rec. X.520 | ISO/IEC 9594-6
+ booleanMatch, commonName, generalizedTimeMatch, generalizedTimeOrderingMatch,
+ integerFirstComponentMatch, integerMatch, integerOrderingMatch,
+ objectIdentifierFirstComponentMatch, UnboundedDirectoryString
+ FROM SelectedAttributeTypes selectedAttributeTypes;
+
+-- attribute data types
+Attribute{ATTRIBUTE:SupportedAttributes} ::= SEQUENCE {
+ type ATTRIBUTE.&id({SupportedAttributes}),
+ values
+ SET SIZE (0..MAX) OF ATTRIBUTE.&Type({SupportedAttributes}{@type}),
+ valuesWithContext
+ SET SIZE (1..MAX) OF
+ SEQUENCE {value ATTRIBUTE.&Type({SupportedAttributes}{@type}),
+ contextList SET SIZE (1..MAX) OF Context} OPTIONAL
+}
+
+AttributeType ::= ATTRIBUTE.&id
+
+AttributeValue ::= ATTRIBUTE.&Type
+
+Context ::= SEQUENCE {
+ contextType CONTEXT.&id({SupportedContexts}),
+ contextValues
+ SET SIZE (1..MAX) OF CONTEXT.&Type({SupportedContexts}{@contextType}),
+ fallback BOOLEAN DEFAULT FALSE
+}
+
+AttributeValueAssertion ::= SEQUENCE {
+ type ATTRIBUTE.&id({SupportedAttributes}),
+ assertion
+ ATTRIBUTE.&equality-match.&AssertionType
+ ({SupportedAttributes}{@type}),
+ assertedContexts
+ CHOICE {allContexts [0] NULL,
+ selectedContexts [1] SET SIZE (1..MAX) OF ContextAssertion
+ } OPTIONAL
+}
+
+ContextAssertion ::= SEQUENCE {
+ contextType CONTEXT.&id({SupportedContexts}),
+ contextValues
+ SET SIZE (1..MAX) OF
+ CONTEXT.&Assertion({SupportedContexts}{@contextType})
+}
+
+AttributeTypeAssertion ::= SEQUENCE {
+ type ATTRIBUTE.&id({SupportedAttributes}),
+ assertedContexts SEQUENCE SIZE (1..MAX) OF ContextAssertion OPTIONAL
+}
+
+-- Definition of the following information object set is deferred, perhaps to standardized
+-- profiles or to protocol implementation conformance statements. The set is required to
+-- specify a table constraint on the values component of Attribute, the value component
+-- of AttributeTypeAndValue, and the assertion component of AttributeValueAssertion.
+SupportedAttributes ATTRIBUTE ::=
+ {objectClass | aliasedEntryName, ...}
+
+-- Definition of the following information object set is deferred, perhaps to standardized
+-- profiles or to protocol implementation conformance statements. The set is required to
+-- specify a table constraint on the context specifications
+SupportedContexts CONTEXT ::=
+ {...}
+
+-- naming data types
+Name ::= CHOICE { -- only one possibility for now --rdnSequence RDNSequence
+}
+
+RDNSequence ::= SEQUENCE OF RelativeDistinguishedName
+
+DistinguishedName ::= RDNSequence
+
+RelativeDistinguishedName ::=
+ SET SIZE (1..MAX) OF AttributeTypeAndDistinguishedValue
+
+AttributeTypeAndDistinguishedValue ::= SEQUENCE {
+ type ATTRIBUTE.&id({SupportedAttributes}),
+ value ATTRIBUTE.&Type({SupportedAttributes}{@type}),
+ primaryDistinguished BOOLEAN DEFAULT TRUE,
+ valuesWithContext
+ SET SIZE (1..MAX) OF
+ SEQUENCE {distingAttrValue
+ [0] ATTRIBUTE.&Type({SupportedAttributes}{@type})
+ OPTIONAL,
+ contextList SET SIZE (1..MAX) OF Context} OPTIONAL
+}
+
+-- subtree data types
+SubtreeSpecification ::= SEQUENCE {
+ base [0] LocalName DEFAULT {},
+ COMPONENTS OF ChopSpecification,
+ specificationFilter [4] Refinement OPTIONAL
+}
+
+-- empty sequence specifies whole administrative area
+LocalName ::= RDNSequence
+
+ChopSpecification ::= SEQUENCE {
+ specificExclusions
+ [1] SET SIZE (1..MAX) OF
+ CHOICE {chopBefore [0] LocalName,
+ chopAfter [1] LocalName} OPTIONAL,
+ minimum [2] BaseDistance DEFAULT 0,
+ maximum [3] BaseDistance OPTIONAL
+}
+
+BaseDistance ::= INTEGER(0..MAX)
+
+Refinement ::= CHOICE {
+ item [0] OBJECT-CLASS.&id,
+ and [1] SET SIZE (1..MAX) OF Refinement,
+ or [2] SET SIZE (1..MAX) OF Refinement,
+ not [3] Refinement
+}
+
+-- OBJECT-CLASS information object class specification
+OBJECT-CLASS ::= CLASS {
+ &Superclasses OBJECT-CLASS OPTIONAL,
+ &kind ObjectClassKind DEFAULT structural,
+ &MandatoryAttributes ATTRIBUTE OPTIONAL,
+ &OptionalAttributes ATTRIBUTE OPTIONAL,
+ &id OBJECT IDENTIFIER UNIQUE
+}
+WITH SYNTAX {
+ [SUBCLASS OF &Superclasses]
+ [KIND &kind]
+ [MUST CONTAIN &MandatoryAttributes]
+ [MAY CONTAIN &OptionalAttributes]
+ ID &id
+}
+
+ObjectClassKind ::= ENUMERATED {abstract(0), structural(1), auxiliary(2)}
+
+-- object classes
+top OBJECT-CLASS ::= {
+ KIND abstract
+ MUST CONTAIN {objectClass}
+ ID id-oc-top
+}
+
+alias OBJECT-CLASS ::= {
+ SUBCLASS OF {top}
+ MUST CONTAIN {aliasedEntryName}
+ ID id-oc-alias
+}
+
+parent OBJECT-CLASS ::= {KIND abstract
+ ID id-oc-parent
+}
+
+child OBJECT-CLASS ::= {KIND auxiliary
+ ID id-oc-child
+}
+
+-- ATTRIBUTE information object class specification
+ATTRIBUTE ::= CLASS {
+ &derivation ATTRIBUTE OPTIONAL,
+ &Type OPTIONAL, -- either &Type or &derivation required
+ &equality-match MATCHING-RULE OPTIONAL,
+ &ordering-match MATCHING-RULE OPTIONAL,
+ &substrings-match MATCHING-RULE OPTIONAL,
+ &single-valued BOOLEAN DEFAULT FALSE,
+ &collective BOOLEAN DEFAULT FALSE,
+ &dummy BOOLEAN DEFAULT FALSE,
+ -- operational extensions
+ &no-user-modification BOOLEAN DEFAULT FALSE,
+ &usage AttributeUsage DEFAULT userApplications,
+ &id OBJECT IDENTIFIER UNIQUE
+}
+WITH SYNTAX {
+ [SUBTYPE OF &derivation]
+ [WITH SYNTAX &Type]
+ [EQUALITY MATCHING RULE &equality-match]
+ [ORDERING MATCHING RULE &ordering-match]
+ [SUBSTRINGS MATCHING RULE &substrings-match]
+ [SINGLE VALUE &single-valued]
+ [COLLECTIVE &collective]
+ [DUMMY &dummy]
+ [NO USER MODIFICATION &no-user-modification]
+ [USAGE &usage]
+ ID &id
+}
+
+AttributeUsage ::= ENUMERATED {
+ userApplications(0), directoryOperation(1), distributedOperation(2),
+ dSAOperation(3)}
+
+-- attributes
+objectClass ATTRIBUTE ::= {
+ WITH SYNTAX OBJECT IDENTIFIER
+ EQUALITY MATCHING RULE objectIdentifierMatch
+ ID id-at-objectClass
+}
+
+aliasedEntryName ATTRIBUTE ::= {
+ WITH SYNTAX DistinguishedName
+ EQUALITY MATCHING RULE distinguishedNameMatch
+ SINGLE VALUE TRUE
+ ID id-at-aliasedEntryName
+}
+
+-- MATCHING-RULE information object class specification
+MATCHING-RULE ::= CLASS {
+ &ParentMatchingRules MATCHING-RULE OPTIONAL,
+ &AssertionType OPTIONAL,
+ &uniqueMatchIndicator ATTRIBUTE OPTIONAL,
+ &id OBJECT IDENTIFIER UNIQUE
+}
+WITH SYNTAX {
+ [PARENT &ParentMatchingRules]
+ [SYNTAX &AssertionType]
+ [UNIQUE-MATCH-INDICATOR &uniqueMatchIndicator]
+ ID &id
+}
+
+-- matching rules
+objectIdentifierMatch MATCHING-RULE ::= {
+ SYNTAX OBJECT IDENTIFIER
+ ID id-mr-objectIdentifierMatch
+}
+
+distinguishedNameMatch MATCHING-RULE ::= {
+ SYNTAX DistinguishedName
+ ID id-mr-distinguishedNameMatch
+}
+
+MAPPING-BASED-MATCHING{SelectedBy, BOOLEAN:combinable, MappingResult,
+ OBJECT IDENTIFIER:matchingRule} ::= CLASS {
+ &selectBy SelectedBy OPTIONAL,
+ &ApplicableTo ATTRIBUTE,
+ &subtypesIncluded BOOLEAN DEFAULT TRUE,
+ &combinable BOOLEAN(combinable),
+ &mappingResults MappingResult OPTIONAL,
+ &userControl BOOLEAN DEFAULT FALSE,
+ &exclusive BOOLEAN DEFAULT TRUE,
+ &matching-rule MATCHING-RULE.&id(matchingRule),
+ &id OBJECT IDENTIFIER UNIQUE
+}
+WITH SYNTAX {
+ [SELECT BY &selectBy]
+ APPLICABLE TO &ApplicableTo
+ [SUBTYPES INCLUDED &subtypesIncluded]
+ COMBINABLE &combinable
+ [MAPPING RESULTS &mappingResults]
+ [USER CONTROL &userControl]
+ [EXCLUSIVE &exclusive]
+ MATCHING RULE &matching-rule
+ ID &id
+}
+
+-- NAME-FORM information object class specification
+NAME-FORM ::= CLASS {
+ &namedObjectClass OBJECT-CLASS,
+ &MandatoryAttributes ATTRIBUTE,
+ &OptionalAttributes ATTRIBUTE OPTIONAL,
+ &id OBJECT IDENTIFIER UNIQUE
+}
+WITH SYNTAX {
+ NAMES &namedObjectClass
+ WITH ATTRIBUTES &MandatoryAttributes
+ [AND OPTIONALLY &OptionalAttributes]
+ ID &id
+}
+
+-- STRUCTURE-RULE class and DIT structure rule data types
+DITStructureRule ::= SEQUENCE {
+ ruleIdentifier RuleIdentifier,
+ -- shall be unique within the scope of the subschema
+ nameForm NAME-FORM.&id,
+ superiorStructureRules SET SIZE (1..MAX) OF RuleIdentifier OPTIONAL
+}
+
+RuleIdentifier ::= INTEGER
+
+STRUCTURE-RULE ::= CLASS {
+ &nameForm NAME-FORM,
+ &SuperiorStructureRules STRUCTURE-RULE OPTIONAL,
+ &id RuleIdentifier
+}
+WITH SYNTAX {
+ NAME FORM &nameForm
+ [SUPERIOR RULES &SuperiorStructureRules]
+ ID &id
+}
+
+-- DIT content rule data type and CONTENT-RULE class
+DITContentRule ::= SEQUENCE {
+ structuralObjectClass OBJECT-CLASS.&id,
+ auxiliaries SET SIZE (1..MAX) OF OBJECT-CLASS.&id OPTIONAL,
+ mandatory [1] SET SIZE (1..MAX) OF ATTRIBUTE.&id OPTIONAL,
+ optional [2] SET SIZE (1..MAX) OF ATTRIBUTE.&id OPTIONAL,
+ precluded [3] SET SIZE (1..MAX) OF ATTRIBUTE.&id OPTIONAL
+}
+
+CONTENT-RULE ::= CLASS {
+ &structuralClass OBJECT-CLASS.&id UNIQUE,
+ &Auxiliaries OBJECT-CLASS OPTIONAL,
+ &Mandatory ATTRIBUTE OPTIONAL,
+ &Optional ATTRIBUTE OPTIONAL,
+ &Precluded ATTRIBUTE OPTIONAL
+}
+WITH SYNTAX {
+ STRUCTURAL OBJECT-CLASS &structuralClass
+ [AUXILIARY OBJECT-CLASSES &Auxiliaries]
+ [MUST CONTAIN &Mandatory]
+ [MAY CONTAIN &Optional]
+ [MUST-NOT CONTAIN &Precluded]
+}
+
+CONTEXT ::= CLASS {
+ &Type ,
+ &DefaultValue OPTIONAL,
+ &Assertion OPTIONAL,
+ &absentMatch BOOLEAN DEFAULT TRUE,
+ &id OBJECT IDENTIFIER UNIQUE
+}
+WITH SYNTAX {
+ WITH SYNTAX &Type
+ [DEFAULT-VALUE &DefaultValue]
+ [ASSERTED AS &Assertion]
+ [ABSENT-MATCH &absentMatch]
+ ID &id
+}
+
+DITContextUse ::= SEQUENCE {
+ attributeType ATTRIBUTE.&id,
+ mandatoryContexts [1] SET SIZE (1..MAX) OF CONTEXT.&id OPTIONAL,
+ optionalContexts [2] SET SIZE (1..MAX) OF CONTEXT.&id OPTIONAL
+}
+
+DIT-CONTEXT-USE-RULE ::= CLASS {
+ &attributeType ATTRIBUTE.&id UNIQUE,
+ &Mandatory CONTEXT OPTIONAL,
+ &Optional CONTEXT OPTIONAL
+}
+WITH SYNTAX {
+ ATTRIBUTE TYPE &attributeType
+ [MANDATORY CONTEXTS &Mandatory]
+ [OPTIONAL CONTEXTS &Optional]
+}
+
+FRIENDS ::= CLASS {
+ &anchor ATTRIBUTE.&id UNIQUE,
+ &Friends ATTRIBUTE
+}WITH SYNTAX {ANCHOR &anchor
+ FRIENDS &Friends
+}
+
+-- system schema information objects
+-- object classes
+subentry OBJECT-CLASS ::= {
+ SUBCLASS OF {top}
+ KIND structural
+ MUST CONTAIN {commonName | subtreeSpecification}
+ ID id-sc-subentry
+}
+
+subentryNameForm NAME-FORM ::= {
+ NAMES subentry
+ WITH ATTRIBUTES {commonName}
+ ID id-nf-subentryNameForm
+}
+
+subtreeSpecification ATTRIBUTE ::= {
+ WITH SYNTAX SubtreeSpecification
+ USAGE directoryOperation
+ ID id-oa-subtreeSpecification
+}
+
+administrativeRole ATTRIBUTE ::= {
+ WITH SYNTAX OBJECT-CLASS.&id
+ EQUALITY MATCHING RULE objectIdentifierMatch
+ USAGE directoryOperation
+ ID id-oa-administrativeRole
+}
+
+createTimestamp ATTRIBUTE ::= {
+ WITH SYNTAX GeneralizedTime
+ -- as per 46.3 b) or c) of ITU-T Rec. X.680 | ISO/IEC 8824-1
+ EQUALITY MATCHING RULE generalizedTimeMatch
+ ORDERING MATCHING RULE generalizedTimeOrderingMatch
+ SINGLE VALUE TRUE
+ NO USER MODIFICATION TRUE
+ USAGE directoryOperation
+ ID id-oa-createTimestamp
+}
+
+modifyTimestamp ATTRIBUTE ::= {
+ WITH SYNTAX GeneralizedTime
+ -- as per 46.3 b) or c) of ITU-T Rec. X.680 | ISO/IEC 8824-1
+ EQUALITY MATCHING RULE generalizedTimeMatch
+ ORDERING MATCHING RULE generalizedTimeOrderingMatch
+ SINGLE VALUE TRUE
+ NO USER MODIFICATION TRUE
+ USAGE directoryOperation
+ ID id-oa-modifyTimestamp
+}
+
+subschemaTimestamp ATTRIBUTE ::= {
+ WITH SYNTAX GeneralizedTime
+ -- as per 46.3 b) or c) of ITU-T Rec. X.680 | ISO/IEC 8824-1
+ EQUALITY MATCHING RULE generalizedTimeMatch
+ ORDERING MATCHING RULE generalizedTimeOrderingMatch
+ SINGLE VALUE TRUE
+ NO USER MODIFICATION TRUE
+ USAGE directoryOperation
+ ID id-oa-subschemaTimestamp
+}
+
+creatorsName ATTRIBUTE ::= {
+ WITH SYNTAX DistinguishedName
+ EQUALITY MATCHING RULE distinguishedNameMatch
+ SINGLE VALUE TRUE
+ NO USER MODIFICATION TRUE
+ USAGE directoryOperation
+ ID id-oa-creatorsName
+}
+
+modifiersName ATTRIBUTE ::= {
+ WITH SYNTAX DistinguishedName
+ EQUALITY MATCHING RULE distinguishedNameMatch
+ SINGLE VALUE TRUE
+ NO USER MODIFICATION TRUE
+ USAGE directoryOperation
+ ID id-oa-modifiersName
+}
+
+subschemaSubentryList ATTRIBUTE ::= {
+ WITH SYNTAX DistinguishedName
+ EQUALITY MATCHING RULE distinguishedNameMatch
+ SINGLE VALUE TRUE
+ NO USER MODIFICATION TRUE
+ USAGE directoryOperation
+ ID id-oa-subschemaSubentryList
+}
+
+accessControlSubentryList ATTRIBUTE ::= {
+ WITH SYNTAX DistinguishedName
+ EQUALITY MATCHING RULE distinguishedNameMatch
+ NO USER MODIFICATION TRUE
+ USAGE directoryOperation
+ ID id-oa-accessControlSubentryList
+}
+
+collectiveAttributeSubentryList ATTRIBUTE ::= {
+ WITH SYNTAX DistinguishedName
+ EQUALITY MATCHING RULE distinguishedNameMatch
+ NO USER MODIFICATION TRUE
+ USAGE directoryOperation
+ ID id-oa-collectiveAttributeSubentryList
+}
+
+contextDefaultSubentryList ATTRIBUTE ::= {
+ WITH SYNTAX DistinguishedName
+ EQUALITY MATCHING RULE distinguishedNameMatch
+ NO USER MODIFICATION TRUE
+ USAGE directoryOperation
+ ID id-oa-contextDefaultSubentryList
+}
+
+serviceAdminSubentryList ATTRIBUTE ::= {
+ WITH SYNTAX DistinguishedName
+ EQUALITY MATCHING RULE distinguishedNameMatch
+ NO USER MODIFICATION TRUE
+ USAGE directoryOperation
+ ID id-oa-serviceAdminSubentryList
+}
+
+hasSubordinates ATTRIBUTE ::= {
+ WITH SYNTAX BOOLEAN
+ EQUALITY MATCHING RULE booleanMatch
+ SINGLE VALUE TRUE
+ NO USER MODIFICATION TRUE
+ USAGE directoryOperation
+ ID id-oa-hasSubordinates
+}
+
+accessControlSubentry OBJECT-CLASS ::= {
+ KIND auxiliary
+ ID id-sc-accessControlSubentry
+}
+
+collectiveAttributeSubentry OBJECT-CLASS ::= {
+ KIND auxiliary
+ ID id-sc-collectiveAttributeSubentry
+}
+
+collectiveExclusions ATTRIBUTE ::= {
+ WITH SYNTAX OBJECT IDENTIFIER
+ EQUALITY MATCHING RULE objectIdentifierMatch
+ USAGE directoryOperation
+ ID id-oa-collectiveExclusions
+}
+
+contextAssertionSubentry OBJECT-CLASS ::= {
+ KIND auxiliary
+ MUST CONTAIN {contextAssertionDefaults}
+ ID id-sc-contextAssertionSubentry
+}
+
+contextAssertionDefaults ATTRIBUTE ::= {
+ WITH SYNTAX TypeAndContextAssertion
+ EQUALITY MATCHING RULE objectIdentifierFirstComponentMatch
+ USAGE directoryOperation
+ ID id-oa-contextAssertionDefault
+}
+
+serviceAdminSubentry OBJECT-CLASS ::= {
+ KIND auxiliary
+ MUST CONTAIN {searchRules}
+ ID id-sc-serviceAdminSubentry
+}
+
+searchRules ATTRIBUTE ::= {
+ WITH SYNTAX SearchRuleDescription
+ EQUALITY MATCHING RULE integerFirstComponentMatch
+ USAGE directoryOperation
+ ID id-oa-searchRules
+}
+
+SearchRuleDescription ::= SEQUENCE {
+ COMPONENTS OF SearchRule,
+ name [28] SET SIZE (1..MAX) OF UnboundedDirectoryString OPTIONAL,
+ description [29] UnboundedDirectoryString OPTIONAL
+}
+
+hierarchyLevel ATTRIBUTE ::= {
+ WITH SYNTAX HierarchyLevel
+ EQUALITY MATCHING RULE integerMatch
+ ORDERING MATCHING RULE integerOrderingMatch
+ SINGLE VALUE TRUE
+ NO USER MODIFICATION TRUE
+ USAGE directoryOperation
+ ID id-oa-hierarchyLevel
+}
+
+HierarchyLevel ::= INTEGER
+
+hierarchyBelow ATTRIBUTE ::= {
+ WITH SYNTAX HierarchyBelow
+ EQUALITY MATCHING RULE booleanMatch
+ SINGLE VALUE TRUE
+ NO USER MODIFICATION TRUE
+ USAGE directoryOperation
+ ID id-oa-hierarchyBelow
+}
+
+HierarchyBelow ::= BOOLEAN
+
+hierarchyParent ATTRIBUTE ::= {
+ WITH SYNTAX DistinguishedName
+ EQUALITY MATCHING RULE distinguishedNameMatch
+ SINGLE VALUE TRUE
+ USAGE directoryOperation
+ ID id-oa-hierarchyParent
+}
+
+hierarchyTop ATTRIBUTE ::= {
+ WITH SYNTAX DistinguishedName
+ EQUALITY MATCHING RULE distinguishedNameMatch
+ SINGLE VALUE TRUE
+ USAGE directoryOperation
+ ID id-oa-hierarchyTop
+}
+
+-- object identifier assignments
+-- object classes
+id-oc-top OBJECT IDENTIFIER ::=
+ {id-oc 0}
+
+id-oc-alias OBJECT IDENTIFIER ::= {id-oc 1}
+
+id-oc-parent OBJECT IDENTIFIER ::= {id-oc 28}
+
+id-oc-child OBJECT IDENTIFIER ::= {id-oc 29}
+
+-- attributes
+id-at-objectClass OBJECT IDENTIFIER ::= {id-at 0}
+
+id-at-aliasedEntryName OBJECT IDENTIFIER ::= {id-at 1}
+
+-- matching rules
+id-mr-objectIdentifierMatch OBJECT IDENTIFIER ::= {id-mr 0}
+
+id-mr-distinguishedNameMatch OBJECT IDENTIFIER ::= {id-mr 1}
+
+-- operational attributes
+id-oa-excludeAllCollectiveAttributes OBJECT IDENTIFIER ::=
+ {id-oa 0}
+
+id-oa-createTimestamp OBJECT IDENTIFIER ::= {id-oa 1}
+
+id-oa-modifyTimestamp OBJECT IDENTIFIER ::= {id-oa 2}
+
+id-oa-creatorsName OBJECT IDENTIFIER ::= {id-oa 3}
+
+id-oa-modifiersName OBJECT IDENTIFIER ::= {id-oa 4}
+
+id-oa-administrativeRole OBJECT IDENTIFIER ::= {id-oa 5}
+
+id-oa-subtreeSpecification OBJECT IDENTIFIER ::= {id-oa 6}
+
+id-oa-collectiveExclusions OBJECT IDENTIFIER ::= {id-oa 7}
+
+id-oa-subschemaTimestamp OBJECT IDENTIFIER ::= {id-oa 8}
+
+id-oa-hasSubordinates OBJECT IDENTIFIER ::= {id-oa 9}
+
+id-oa-subschemaSubentryList OBJECT IDENTIFIER ::= {id-oa 10}
+
+id-oa-accessControlSubentryList OBJECT IDENTIFIER ::= {id-oa 11}
+
+id-oa-collectiveAttributeSubentryList OBJECT IDENTIFIER ::= {id-oa 12}
+
+id-oa-contextDefaultSubentryList OBJECT IDENTIFIER ::= {id-oa 13}
+
+id-oa-contextAssertionDefault OBJECT IDENTIFIER ::= {id-oa 14}
+
+id-oa-serviceAdminSubentryList OBJECT IDENTIFIER ::= {id-oa 15}
+
+id-oa-searchRules OBJECT IDENTIFIER ::= {id-oa 16}
+
+id-oa-hierarchyLevel OBJECT IDENTIFIER ::= {id-oa 17}
+
+id-oa-hierarchyBelow OBJECT IDENTIFIER ::= {id-oa 18}
+
+id-oa-hierarchyParent OBJECT IDENTIFIER ::= {id-oa 19}
+
+id-oa-hierarchyTop OBJECT IDENTIFIER ::= {id-oa 20}
+
+-- subentry classes
+id-sc-subentry OBJECT IDENTIFIER ::= {id-sc 0}
+
+id-sc-accessControlSubentry OBJECT IDENTIFIER ::= {id-sc 1}
+
+id-sc-collectiveAttributeSubentry OBJECT IDENTIFIER ::= {id-sc 2}
+
+id-sc-contextAssertionSubentry OBJECT IDENTIFIER ::= {id-sc 3}
+
+id-sc-serviceAdminSubentry OBJECT IDENTIFIER ::= {id-sc 4}
+
+-- Name forms
+id-nf-subentryNameForm OBJECT IDENTIFIER ::= {id-nf 16}
+
+-- administrative roles
+id-ar-autonomousArea OBJECT IDENTIFIER ::= {id-ar 1}
+
+id-ar-accessControlSpecificArea OBJECT IDENTIFIER ::= {id-ar 2}
+
+id-ar-accessControlInnerArea OBJECT IDENTIFIER ::= {id-ar 3}
+
+id-ar-subschemaAdminSpecificArea OBJECT IDENTIFIER ::= {id-ar 4}
+
+id-ar-collectiveAttributeSpecificArea OBJECT IDENTIFIER ::= {id-ar 5}
+
+id-ar-collectiveAttributeInnerArea OBJECT IDENTIFIER ::= {id-ar 6}
+
+id-ar-contextDefaultSpecificArea OBJECT IDENTIFIER ::= {id-ar 7}
+
+id-ar-serviceSpecificArea OBJECT IDENTIFIER ::= {id-ar 8}
+
+END -- InformationFramework
diff --git a/lib/public_key/asn1/Makefile b/lib/public_key/asn1/Makefile
index 94abec083c..2ce1168349 100644
--- a/lib/public_key/asn1/Makefile
+++ b/lib/public_key/asn1/Makefile
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2008-2010. All Rights Reserved.
+# Copyright Ericsson AB 2008-2011. All Rights Reserved.
#
# The contents of this file are subject to the Erlang Public License,
# Version 1.1, (the "License"); you may not use this file except in
@@ -38,12 +38,12 @@ RELSYSDIR = $(RELEASE_PATH)/lib/public_key-$(VSN)
.SUFFIXES: .asn1
.PRECIOUS: %.erl
-ASN_TOP = OTP-PUB-KEY
+ASN_TOP = OTP-PUB-KEY PKCS-FRAME
ASN_MODULES = PKIX1Explicit88 PKIX1Implicit88 PKIX1Algorithms88 \
- PKIXAttributeCertificate PKCS-1 PKCS-3 OTP-PKIX
+ PKIXAttributeCertificate PKCS-1 PKCS-3 PKCS-8 InformationFramework PKCS5v2-0 OTP-PKIX
ASN_ASNS = $(ASN_MODULES:%=%.asn1)
-ASN_ERLS = $(ASN_TOP).erl
-ASN_HRLS = $(ASN_TOP).hrl
+ASN_ERLS = $(ASN_TOP:%=%.erl)
+ASN_HRLS = $(ASN_TOP:%=%.hrl)
ASN_CONFIGS = OTP-PUB-KEY.asn1config
ASN_DBS = $(ASN_MODULES:%=%.asn1db) OTP-PUB-KEY.asn1db
ASN_TABLES = $(ASN_MODULES:%=%.table)
@@ -65,7 +65,7 @@ EBIN = ../ebin
EXTRA_ERLC_FLAGS =
ERL_COMPILE_FLAGS += $(EXTRA_ERLC_FLAGS)
-ASN_FLAGS = -bber_bin +der +compact_bit_string +optimize +noobj +asn1config +inline
+ASN_FLAGS = -bber_bin +der +compact_bit_string +optimize +noobj +asn1config +inline +nif
# ----------------------------------------------------
# Targets
@@ -79,11 +79,11 @@ clean:
docs:
-%.erl: %.set.asn
+%.erl %.hrl: %.set.asn
erlc $(ASN_FLAGS) $<
-$(HRL_FILES): $(ASN_HRLS)
- cp -p $(ASN_HRLS) $(INCLUDE)
+$(INCLUDE)/%.hrl: %.hrl
+ cp -p $< $@
# ----------------------------------------------------
# Release Target
@@ -113,3 +113,9 @@ OTP-PUB-KEY.asn1db: PKIX1Algorithms88.asn1 \
PKCS-1.asn1\
PKCS-3.asn1\
OTP-PKIX.asn1
+
+$(EBIN)/PKCS-FRAME.beam: PKCS-FRAME.erl PKCS-FRAME.hrl
+PKCS-FRAME.erl PKCS-FRAME.hrl: PKCS-FRAME.asn1db
+PKCS-FRAME.asn1db: PKCS-8.asn1\
+ InformationFramework.asn1\
+ PKCS5v2-0.asn1 \ No newline at end of file
diff --git a/lib/public_key/asn1/PKCS-1.asn1 b/lib/public_key/asn1/PKCS-1.asn1
index b06f5efa9d..b06f5efa9d 100755..100644
--- a/lib/public_key/asn1/PKCS-1.asn1
+++ b/lib/public_key/asn1/PKCS-1.asn1
diff --git a/lib/public_key/asn1/PKCS-8.asn1 b/lib/public_key/asn1/PKCS-8.asn1
new file mode 100644
index 0000000000..7413519b57
--- /dev/null
+++ b/lib/public_key/asn1/PKCS-8.asn1
@@ -0,0 +1,83 @@
+PKCS-8 {iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) pkcs-8(8)
+ modules(1) pkcs-8(1)}
+
+-- $Revision: 1.5 $
+
+-- This module has been checked for conformance with the ASN.1
+-- standard by the OSS ASN.1 Tools
+
+DEFINITIONS IMPLICIT TAGS ::=
+
+BEGIN
+
+-- EXPORTS All --
+-- All types and values defined in this module is exported for use in other
+-- ASN.1 modules.
+
+IMPORTS
+
+-- informationFramework
+-- FROM UsefulDefinitions {joint-iso-itu-t(2) ds(5) module(1)
+-- usefulDefinitions(0) 3}
+
+Attribute
+-- FROM InformationFramework informationFramework
+ FROM InformationFramework;
+
+-- This import is really unnecessary since ALGORITHM-IDENTIFIER is defined as a
+-- TYPE-IDENTIFIER
+-- Renome this import and replace all occurences of ALGORITHM-IDENTIFIER with
+-- TYPE-IDENTIFIER as a workaround for weaknesses in the ASN.1 compiler
+--AlgorithmIdentifier, ALGORITHM-IDENTIFIER
+-- FROM PKCS5v2-0 {iso(1) member-body(2) us(840) rsadsi(113549)
+-- pkcs(1) pkcs-5(5) modules(16) pkcs-5(1)};
+
+-- Inlined from PKCS5v2-0 since it is the only thing imported from that module
+-- AlgorithmIdentifier { ALGORITHM-IDENTIFIER:InfoObjectSet } ::=
+AlgorithmIdentifier { TYPE-IDENTIFIER:InfoObjectSet } ::=
+SEQUENCE {
+-- algorithm ALGORITHM-IDENTIFIER.&id({InfoObjectSet}),
+ algorithm TYPE-IDENTIFIER.&id({InfoObjectSet}),
+-- parameters ALGORITHM-IDENTIFIER.&Type({InfoObjectSet}
+ parameters TYPE-IDENTIFIER.&Type({InfoObjectSet}
+ {@algorithm}) OPTIONAL }
+
+-- Private-key information syntax
+
+PrivateKeyInfo ::= SEQUENCE {
+ version Version,
+-- privateKeyAlgorithm AlgorithmIdentifier {{PrivateKeyAlgorithms}},
+ privateKeyAlgorithm AlgorithmIdentifier {{...}},
+ privateKey PrivateKey,
+ attributes [0] Attributes OPTIONAL }
+
+Version ::= INTEGER {v1(0)} (v1,...)
+
+PrivateKey ::= OCTET STRING
+
+-- Attributes ::= SET OF Attribute
+Attributes ::= SET OF Attribute {{...}}
+
+-- Encrypted private-key information syntax
+
+EncryptedPrivateKeyInfo ::= SEQUENCE {
+-- encryptionAlgorithm AlgorithmIdentifier {{KeyEncryptionAlgorithms}},
+ encryptionAlgorithm AlgorithmIdentifier {{...}},
+ encryptedData EncryptedData
+}
+
+EncryptedData ::= OCTET STRING
+
+-- PrivateKeyAlgorithms ALGORITHM-IDENTIFIER ::= {
+PrivateKeyAlgorithms TYPE-IDENTIFIER ::= {
+ ... -- For local profiles
+}
+
+-- KeyEncryptionAlgorithms ALGORITHM-IDENTIFIER ::= {
+KeyEncryptionAlgorithms TYPE-IDENTIFIER ::= {
+ ... -- For local profiles
+}
+
+END
+
+
diff --git a/lib/public_key/asn1/PKCS-FRAME.set.asn b/lib/public_key/asn1/PKCS-FRAME.set.asn
new file mode 100644
index 0000000000..a0777ff260
--- /dev/null
+++ b/lib/public_key/asn1/PKCS-FRAME.set.asn
@@ -0,0 +1,3 @@
+PKCS-8.asn1
+InformationFramework.asn1
+PKCS5v2-0.asn1
diff --git a/lib/public_key/asn1/PKCS5v2-0.asn1 b/lib/public_key/asn1/PKCS5v2-0.asn1
new file mode 100644
index 0000000000..fe7e16c7fa
--- /dev/null
+++ b/lib/public_key/asn1/PKCS5v2-0.asn1
@@ -0,0 +1,142 @@
+-- PKCS #5 v2.0 ASN.1 Module
+-- Revised March 25, 1999
+
+-- This module has been checked for conformance with the
+-- ASN.1 standard by the OSS ASN.1 Tools
+
+PKCS5v2-0 {iso(1) member-body(2) us(840) rsadsi(113549)
+ pkcs(1) pkcs-5(5) modules(16) pkcs5v2-0(1)}
+
+DEFINITIONS ::= BEGIN
+
+-- Basic object identifiers
+
+rsadsi OBJECT IDENTIFIER ::=
+ {iso(1) member-body(2) us(840) 113549}
+pkcs OBJECT IDENTIFIER ::= {rsadsi 1}
+pkcs-5 OBJECT IDENTIFIER ::= {pkcs 5}
+
+-- Basic types and classes
+
+AlgorithmIdentifier { TYPE-IDENTIFIER:InfoObjectSet } ::=
+SEQUENCE {
+ algorithm TYPE-IDENTIFIER.&id({InfoObjectSet}),
+ parameters TYPE-IDENTIFIER.&Type({InfoObjectSet}
+ {@algorithm}) OPTIONAL }
+
+--ALGORITHM-IDENTIFIER ::= TYPE-IDENTIFIER
+
+-- PBKDF2
+
+-- PBKDF2Algorithms ALGORITHM-IDENTIFIER ::=
+-- { {PBKDF2-params IDENTIFIED BY id-PBKDF2}, ...}
+
+id-PBKDF2 OBJECT IDENTIFIER ::= {pkcs-5 12}
+
+-- algid-hmacWithSHA1 AlgorithmIdentifier {{PBKDF2-PRFs}} ::=
+-- {algorithm id-hmacWithSHA1, parameters NULL : NULL}
+
+PBKDF2-params ::= SEQUENCE {
+ salt CHOICE {
+ specified OCTET STRING,
+ otherSource AlgorithmIdentifier {{PBKDF2-SaltSources}}
+ },
+ iterationCount INTEGER (1..MAX),
+ keyLength INTEGER (1..MAX) OPTIONAL,
+ prf AlgorithmIdentifier {{PBKDF2-PRFs}} DEFAULT
+{algorithm id-hmacWithSHA1, parameters NULL : NULL}}
+-- algid-hmacWithSHA1 }
+
+PBKDF2-SaltSources TYPE-IDENTIFIER ::= { ... }
+
+PBKDF2-PRFs TYPE-IDENTIFIER ::=
+ { {NULL IDENTIFIED BY id-hmacWithSHA1}, ... }
+
+ -- PBES1
+
+PBES1Algorithms TYPE-IDENTIFIER ::=
+ { {PBEParameter IDENTIFIED BY pbeWithMD2AndDES-CBC} |
+ {PBEParameter IDENTIFIED BY pbeWithMD2AndRC2-CBC} |
+ {PBEParameter IDENTIFIED BY pbeWithMD5AndDES-CBC} |
+ {PBEParameter IDENTIFIED BY pbeWithMD5AndRC2-CBC} |
+ {PBEParameter IDENTIFIED BY pbeWithSHA1AndDES-CBC} |
+ {PBEParameter IDENTIFIED BY pbeWithSHA1AndRC2-CBC}, ...}
+
+pbeWithMD2AndDES-CBC OBJECT IDENTIFIER ::= {pkcs-5 1}
+pbeWithMD2AndRC2-CBC OBJECT IDENTIFIER ::= {pkcs-5 4}
+pbeWithMD5AndDES-CBC OBJECT IDENTIFIER ::= {pkcs-5 3}
+pbeWithMD5AndRC2-CBC OBJECT IDENTIFIER ::= {pkcs-5 6}
+pbeWithSHA1AndDES-CBC OBJECT IDENTIFIER ::= {pkcs-5 10}
+pbeWithSHA1AndRC2-CBC OBJECT IDENTIFIER ::= {pkcs-5 11}
+
+PBEParameter ::= SEQUENCE {
+ salt OCTET STRING (SIZE(8)),
+ iterationCount INTEGER }
+
+-- PBES2
+
+PBES2Algorithms TYPE-IDENTIFIER ::=
+ { {PBES2-params IDENTIFIED BY id-PBES2}, ...}
+
+id-PBES2 OBJECT IDENTIFIER ::= {pkcs-5 13}
+
+PBES2-params ::= SEQUENCE {
+ keyDerivationFunc AlgorithmIdentifier {{PBES2-KDFs}},
+ encryptionScheme AlgorithmIdentifier {{PBES2-Encs}} }
+
+PBES2-KDFs TYPE-IDENTIFIER ::=
+ { {PBKDF2-params IDENTIFIED BY id-PBKDF2}, ... }
+
+PBES2-Encs TYPE-IDENTIFIER ::= { ... }
+
+-- PBMAC1
+
+PBMAC1Algorithms TYPE-IDENTIFIER ::=
+ { {PBMAC1-params IDENTIFIED BY id-PBMAC1}, ...}
+
+id-PBMAC1 OBJECT IDENTIFIER ::= {pkcs-5 14}
+
+PBMAC1-params ::= SEQUENCE {
+ keyDerivationFunc AlgorithmIdentifier {{PBMAC1-KDFs}},
+ messageAuthScheme AlgorithmIdentifier {{PBMAC1-MACs}} }
+
+PBMAC1-KDFs TYPE-IDENTIFIER ::=
+ { {PBKDF2-params IDENTIFIED BY id-PBKDF2}, ... }
+
+PBMAC1-MACs TYPE-IDENTIFIER ::= { ... }
+
+-- Supporting techniques
+
+digestAlgorithm OBJECT IDENTIFIER ::= {rsadsi 2}
+encryptionAlgorithm OBJECT IDENTIFIER ::= {rsadsi 3}
+
+SupportingAlgorithms TYPE-IDENTIFIER ::=
+ { {NULL IDENTIFIED BY id-hmacWithSHA1} |
+ {OCTET STRING (SIZE(8)) IDENTIFIED BY desCBC} |
+ {OCTET STRING (SIZE(8)) IDENTIFIED BY des-EDE3-CBC} |
+ {RC2-CBC-Parameter IDENTIFIED BY rc2CBC} |
+ {RC5-CBC-Parameters IDENTIFIED BY rc5-CBC-PAD}, ... }
+
+id-hmacWithSHA1 OBJECT IDENTIFIER ::= {digestAlgorithm 7}
+
+desCBC OBJECT IDENTIFIER ::=
+ {iso(1) identified-organization(3) oiw(14) secsig(3)
+ algorithms(2) 7} -- from OIW
+
+des-EDE3-CBC OBJECT IDENTIFIER ::= {encryptionAlgorithm 7}
+
+rc2CBC OBJECT IDENTIFIER ::= {encryptionAlgorithm 2}
+
+RC2-CBC-Parameter ::= SEQUENCE {
+ rc2ParameterVersion INTEGER OPTIONAL,
+ iv OCTET STRING (SIZE(8)) }
+
+rc5-CBC-PAD OBJECT IDENTIFIER ::= {encryptionAlgorithm 9}
+
+RC5-CBC-Parameters ::= SEQUENCE {
+ version INTEGER {v1-0(16)}, -- (v1-0),
+ rounds INTEGER (8..127),
+ blockSizeInBits INTEGER (64 | 128),
+ iv OCTET STRING OPTIONAL }
+
+END
diff --git a/lib/public_key/doc/src/Makefile b/lib/public_key/doc/src/Makefile
index afb17399da..9616a96195 100644
--- a/lib/public_key/doc/src/Makefile
+++ b/lib/public_key/doc/src/Makefile
@@ -29,14 +29,6 @@ VSN=$(PUBLIC_KEY_VSN)
APPLICATION=public_key
# ----------------------------------------------------
-# Include dependency
-# ----------------------------------------------------
-
-ifndef DOCSUPPORT
-include make.dep
-endif
-
-# ----------------------------------------------------
# Release directory specification
# ----------------------------------------------------
RELSYSDIR = $(RELEASE_PATH)/lib/$(APPLICATION)-$(VSN)
@@ -79,33 +71,10 @@ EXTRA_FILES = \
MAN3_FILES = $(XML_REF3_FILES:%.xml=$(MAN3DIR)/%.3)
-ifdef DOCSUPPORT
-
HTML_REF_MAN_FILE = $(HTMLDIR)/index.html
TOP_PDF_FILE = $(PDFDIR)/$(APPLICATION)-$(VSN).pdf
-else
-
-TEX_FILES_BOOK = \
- $(BOOK_FILES:%.xml=%.tex)
-TEX_FILES_REF_MAN = $(XML_REF3_FILES:%.xml=%.tex) \
- $(XML_APPLICATION_FILES:%.xml=%.tex)
-TEX_FILES_USERS_GUIDE = \
- $(XML_PART_FILES:%.xml=%.tex) \
- $(XML_CHAPTER_FILES:%.xml=%.tex)
-
-TOP_PDF_FILE = public_key-$(VSN).pdf
-TOP_PS_FILE = public_key-$(VSN).ps
-
-$(TOP_PDF_FILE): book.dvi ../../vsn.mk
- $(DVI2PS) $(DVIPS_FLAGS) -f $< | $(DISTILL) $(DISTILL_FLAGS) > $@
-
-$(TOP_PS_FILE): book.dvi ../../vsn.mk
- $(DVI2PS) $(DVIPS_FLAGS) -f $< > $@
-
-endif
-
# ----------------------------------------------------
# FLAGS
# ----------------------------------------------------
@@ -118,8 +87,6 @@ DVIPS_FLAGS +=
$(HTMLDIR)/%.gif: %.gif
$(INSTALL_DATA) $< $@
-ifdef DOCSUPPORT
-
docs: pdf html man
$(TOP_PDF_FILE): $(XML_FILES)
@@ -134,33 +101,6 @@ clean clean_docs:
rm -f $(TOP_PDF_FILE) $(TOP_PDF_FILE:%.pdf=%.fo)
rm -f errs core *~
-else
-
-ifeq ($(DOCTYPE),pdf)
-docs: pdf
-else
-ifeq ($(DOCTYPE),ps)
-docs: ps
-else
-docs: html gifs man
-endif
-endif
-
-pdf: $(TOP_PDF_FILE)
-
-ps: $(TOP_PS_FILE)
-
-html: $(HTML_FILES)
-
-clean clean_docs clean_tex:
- rm -f $(TEX_FILES_USERS_GUIDE) $(TEX_FILES_REF_MAN) $(TEX_FILES_BOOK)
- rm -f $(HTML_FILES) $(MAN3_FILES)
- rm -f $(TOP_PDF_FILE) $(TOP_PS_FILE)
- rm -f errs core *~ min_head.gif \
- $(LATEX_CLEAN)
-
-endif
-
man: $(MAN3_FILES)
gifs: $(GIF_FILES:%=$(HTMLDIR)/%)
@@ -173,8 +113,6 @@ debug opt:
# ----------------------------------------------------
include $(ERL_TOP)/make/otp_release_targets.mk
-ifdef DOCSUPPORT
-
release_docs_spec: docs
$(INSTALL_DIR) $(RELSYSDIR)/doc/pdf
$(INSTALL_DATA) $(TOP_PDF_FILE) $(RELSYSDIR)/doc/pdf
@@ -184,30 +122,6 @@ release_docs_spec: docs
$(INSTALL_DATA) $(INFO_FILE) $(RELSYSDIR)
$(INSTALL_DIR) $(RELEASE_PATH)/man/man3
$(INSTALL_DATA) $(MAN3DIR)/* $(RELEASE_PATH)/man/man3
-else
-
-ifeq ($(DOCTYPE),pdf)
-release_docs_spec: pdf
- $(INSTALL_DIR) $(RELEASE_PATH)/pdf
- $(INSTALL_DATA) $(TOP_PDF_FILE) $(RELEASE_PATH)/pdf
-else
-ifeq ($(DOCTYPE),ps)
-release_docs_spec: ps
- $(INSTALL_DIR) $(RELEASE_PATH)/ps
- $(INSTALL_DATA) $(TOP_PS_FILE) $(RELEASE_PATH)/ps
-else
-release_docs_spec: docs
- $(INSTALL_DIR) $(RELSYSDIR)/doc/html
- $(INSTALL_DATA) $(GIF_FILES) $(EXTRA_FILES) $(HTML_FILES) \
- $(RELSYSDIR)/doc/html
- $(INSTALL_DATA) $(INFO_FILE) $(RELSYSDIR)
- $(INSTALL_DIR) $(RELEASE_PATH)/man/man3
- $(INSTALL_DATA) $(MAN3_FILES) $(RELEASE_PATH)/man/man3
-endif
-endif
-
-endif
-
release_spec:
info:
diff --git a/lib/public_key/doc/src/introduction.xml b/lib/public_key/doc/src/introduction.xml
index 8cf11ee10e..a21fcf3576 100644
--- a/lib/public_key/doc/src/introduction.xml
+++ b/lib/public_key/doc/src/introduction.xml
@@ -48,5 +48,13 @@
of the concepts of using public keys.</p>
</section>
+ <section>
+ <title>Performance tips</title>
+ <p>The public_key decode and encode functions will try to use the nifs
+ which are in the asn1 compilers runtime modules if they can be found.
+ So for the best performance you want to have the asn1 application in the
+ path of your system. </p>
+ </section>
+
</chapter>
diff --git a/lib/public_key/doc/src/make.dep b/lib/public_key/doc/src/make.dep
deleted file mode 100644
index 2675556f1b..0000000000
--- a/lib/public_key/doc/src/make.dep
+++ /dev/null
@@ -1,21 +0,0 @@
-# ----------------------------------------------------
-# >>>> Do not edit this file <<<<
-# This file was automaticly generated by
-# /home/otp/bin/docdepend
-# ----------------------------------------------------
-
-
-# ----------------------------------------------------
-# TeX files that the DVI file depend on
-# ----------------------------------------------------
-
-book.dvi: book.tex cert_records.tex introduction.tex \
- part.tex public_key.tex public_key_records.tex \
- ref_man.tex
-
-# ----------------------------------------------------
-# Source inlined when transforming from source to LaTeX
-# ----------------------------------------------------
-
-book.tex: ref_man.xml
-
diff --git a/lib/public_key/doc/src/public_key.xml b/lib/public_key/doc/src/public_key.xml
index 9a3832c68b..821e7a2300 100644
--- a/lib/public_key/doc/src/public_key.xml
+++ b/lib/public_key/doc/src/public_key.xml
@@ -61,11 +61,14 @@
<p><code>string = [bytes()]</code></p>
<p><code>pki_asn1_type() = 'Certificate' | 'RSAPrivateKey'| 'RSAPublicKey'
- 'DSAPrivateKey' | 'DSAPublicKey' | 'DHParameter' | 'SubjectPublicKeyInfo'</code></p>
+ 'DSAPrivateKey' | 'DSAPublicKey' | 'DHParameter' | 'SubjectPublicKeyInfo'| 'PrivateKeyInfo'</code></p>
<p><code>pem_entry () = {pki_asn1_type(), binary(), %% DER or encrypted DER
- not_encrypted | {"DES-CBC" | "DES-EDE3-CBC", crypto:rand_bytes(8)}}.</code></p>
-
+ not_encrypted | cipher_info()} </code></p>
+
+ <p><code>cipher_info() = {"RC2-CBC | "DES-CBC" | "DES-EDE3-CBC", crypto:rand_bytes(8)} |
+ 'PBES2-params'} </code></p>
+
<p><code>rsa_public_key() = #'RSAPublicKey'{}</code></p>
<p><code>rsa_private_key() = #'RSAPrivateKey'{} </code></p>
@@ -118,7 +121,8 @@
<funcs>
<func>
- <name>decrypt_private(CipherText, Key [, Options]) -> binary()</name>
+ <name>decrypt_private(CipherText, Key) -> binary()</name>
+ <name>decrypt_private(CipherText, Key, Options) -> binary()</name>
<fsummary>Public key decryption.</fsummary>
<type>
<v>CipherText = binary()</v>
@@ -131,7 +135,8 @@
</func>
<func>
- <name>decrypt_public(CipherText, Key [, Options]) - > binary()</name>
+ <name>decrypt_public(CipherText, Key) - > binary()</name>
+ <name>decrypt_public(CipherText, Key, Options) - > binary()</name>
<fsummary></fsummary>
<type>
<v>CipherText = binary()</v>
@@ -198,7 +203,8 @@
</func>
<func>
- <name>pem_entry_decode(PemEntry [, Password]) -> term()</name>
+ <name>pem_entry_decode(PemEntry) -> term()</name>
+ <name>pem_entry_decode(PemEntry, Password) -> term()</name>
<fsummary>Decodes a pem entry.</fsummary>
<type>
<v> PemEntry = pem_entry() </v>
@@ -213,7 +219,8 @@
</func>
<func>
- <name>pem_entry_encode(Asn1Type, Entity [,{CipherInfo, Password}]) -> pem_entry()</name>
+ <name>pem_entry_encode(Asn1Type, Entity) -> pem_entry()</name>
+ <name>pem_entry_encode(Asn1Type, Entity, {CipherInfo, Password}) -> pem_entry()</name>
<fsummary> Creates a pem entry that can be fed to pem_encode/1.</fsummary>
<type>
<v>Asn1Type = pki_asn1_type()</v>
@@ -224,7 +231,7 @@
dsa_public_key() and this function will create the appropriate
'SubjectPublicKeyInfo' entry.
</d>
- <v>CipherInfo = {"DES-CBC" | "DES-EDE3-CBC", crypto:rand_bytes(8)}</v>
+ <v>CipherInfo = cipher_info()</v>
<v>Password = string()</v>
</type>
<desc>
diff --git a/lib/public_key/include/public_key.hrl b/lib/public_key/include/public_key.hrl
index 5f97d80f7e..2475295974 100644
--- a/lib/public_key/include/public_key.hrl
+++ b/lib/public_key/include/public_key.hrl
@@ -23,6 +23,7 @@
-define(public_key, true).
-include("OTP-PUB-KEY.hrl").
+-include("PKCS-FRAME.hrl").
-record('SubjectPublicKeyInfoAlgorithm', {
algorithm,
diff --git a/lib/public_key/src/Makefile b/lib/public_key/src/Makefile
index 5a24b02d2a..062c495a65 100644
--- a/lib/public_key/src/Makefile
+++ b/lib/public_key/src/Makefile
@@ -42,10 +42,11 @@ MODULES = \
public_key \
pubkey_pem \
pubkey_ssh \
+ pubkey_pbe \
pubkey_cert \
- pubkey_cert_records
+ pubkey_cert_records
-HRL_FILES = $(INCLUDE)/public_key.hrl
+HRL_FILES = $(INCLUDE)/public_key.hrl
INTERNAL_HRL_FILES =
@@ -109,4 +110,3 @@ release_spec: opt
$(INSTALL_DATA) $(TARGET_FILES) $(APP_TARGET) $(APPUP_TARGET) $(RELSYSDIR)/ebin
release_docs_spec:
-
diff --git a/lib/public_key/src/pubkey_pbe.erl b/lib/public_key/src/pubkey_pbe.erl
new file mode 100644
index 0000000000..43f6c42f10
--- /dev/null
+++ b/lib/public_key/src/pubkey_pbe.erl
@@ -0,0 +1,213 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2011-2011. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+%% Description: Implements Password Based Encryption PKCS-5, RFC-2898
+
+-module(pubkey_pbe).
+
+-include("public_key.hrl").
+
+-export([encode/4, decode/4, decrypt_parameters/1]).
+-export([pbdkdf1/4, pbdkdf2/6]).
+
+-define(DEFAULT_SHA_MAC_KEYLEN, 20).
+-define(ASN1_OCTET_STR_TAG, 4).
+-define(IV_LEN, 8).
+
+%%====================================================================
+%% Internal application API
+%%====================================================================
+
+%%--------------------------------------------------------------------
+-spec encode(binary(), string(), string(), term()) -> binary().
+%%
+%% Description: Performs password based encoding
+%%--------------------------------------------------------------------
+encode(Data, Password, "DES-CBC" = Cipher, KeyDevParams) ->
+ {Key, IV} = password_to_key_and_iv(Password, Cipher, KeyDevParams),
+ crypto:des_cbc_encrypt(Key, IV, Data);
+
+encode(Data, Password, "DES-EDE3-CBC" = Cipher, KeyDevParams) ->
+ {Key, IV} = password_to_key_and_iv(Password, Cipher, KeyDevParams),
+ <<Key1:8/binary, Key2:8/binary, Key3:8/binary>> = Key,
+ crypto:des_ede3_cbc_encrypt(Key1, Key2, Key3, IV, Data);
+
+encode(Data, Password, "RC2-CBC" = Cipher, KeyDevParams) ->
+ {Key, IV} = password_to_key_and_iv(Password, Cipher, KeyDevParams),
+ crypto:rc2_cbc_encrypt(Key, IV, Data).
+%%--------------------------------------------------------------------
+-spec decode(binary(), string(), string(), term()) -> binary().
+%%
+%% Description: Performs password based decoding
+%%--------------------------------------------------------------------
+decode(Data, Password,"DES-CBC"= Cipher, KeyDevParams) ->
+ {Key, IV} = password_to_key_and_iv(Password, Cipher, KeyDevParams),
+ crypto:des_cbc_decrypt(Key, IV, Data);
+
+decode(Data, Password,"DES-EDE3-CBC" = Cipher, KeyDevParams) ->
+ {Key, IV} = password_to_key_and_iv(Password, Cipher, KeyDevParams),
+ <<Key1:8/binary, Key2:8/binary, Key3:8/binary>> = Key,
+ crypto:des_ede3_cbc_decrypt(Key1, Key2, Key3, IV, Data);
+
+decode(Data, Password,"RC2-CBC"= Cipher, KeyDevParams) ->
+ {Key, IV} = password_to_key_and_iv(Password, Cipher, KeyDevParams),
+ crypto:rc2_cbc_decrypt(Key, IV, Data).
+
+%%--------------------------------------------------------------------
+-spec pbdkdf1(string(), iodata(), integer(), atom()) -> binary().
+%%
+%% Description: Implements password based decryption key derive function 1.
+%% Exported mainly for testing purposes.
+%%--------------------------------------------------------------------
+pbdkdf1(_, _, 0, Acc) ->
+ Acc;
+pbdkdf1(Password, Salt, Count, Hash) ->
+ Result = crypto:Hash([Password, Salt]),
+ do_pbdkdf1(Result, Count-1, Result, Hash).
+
+%%--------------------------------------------------------------------
+-spec pbdkdf2(string(), iodata(), integer(), integer(), fun(), integer())
+ -> binary().
+%%
+%% Description: Implements password based decryption key derive function 2.
+%% Exported mainly for testing purposes.
+%%--------------------------------------------------------------------
+pbdkdf2(Password, Salt, Count, DerivedKeyLen, Prf, PrfOutputLen)->
+ NumBlocks = ceiling(DerivedKeyLen / PrfOutputLen),
+ NumLastBlockOctets = DerivedKeyLen - (NumBlocks - 1) * PrfOutputLen ,
+ blocks(NumBlocks, NumLastBlockOctets, 1, Password, Salt,
+ Count, Prf, PrfOutputLen, <<>>).
+%%--------------------------------------------------------------------
+-spec decrypt_parameters(#'EncryptedPrivateKeyInfo_encryptionAlgorithm'{}) ->
+ {Cipher::string(), #'PBES2-params'{}}.
+%%
+%% Description: Performs ANS1-decoding of encryption parameters.
+%%--------------------------------------------------------------------
+decrypt_parameters(#'EncryptedPrivateKeyInfo_encryptionAlgorithm'{
+ algorithm = Oid, parameters = Param}) ->
+ decrypt_parameters(Oid, Param).
+
+%%--------------------------------------------------------------------
+%%% Internal functions
+%%--------------------------------------------------------------------
+password_to_key_and_iv(Password, _, #'PBES2-params'{} = Params) ->
+ {Salt, ItrCount, KeyLen, PseudoRandomFunction, PseudoOtputLen, IV} =
+ key_derivation_params(Params),
+ <<Key:KeyLen/binary, _/binary>> =
+ pbdkdf2(Password, Salt, ItrCount, KeyLen, PseudoRandomFunction, PseudoOtputLen),
+ {Key, IV};
+password_to_key_and_iv(Password, Cipher, Salt) ->
+ KeyLen = derived_key_length(Cipher, undefined),
+ <<Key:KeyLen/binary, _/binary>> =
+ pem_encrypt(<<>>, Password, Salt, ceiling(KeyLen div 16), <<>>, md5),
+ %% Old PEM encryption does not use standard encryption method
+ %% pbdkdf1 and uses then salt as IV
+ {Key, Salt}.
+
+pem_encrypt(_, _, _, 0, Acc, _) ->
+ Acc;
+pem_encrypt(Prev, Password, Salt, Count, Acc, Hash) ->
+ Result = crypto:Hash([Prev, Password, Salt]),
+ pem_encrypt(Result, Password, Salt, Count-1 , <<Acc/binary, Result/binary>>, Hash).
+
+do_pbdkdf1(_, 0, Acc, _) ->
+ Acc;
+do_pbdkdf1(Prev, Count, Acc, Hash) ->
+ Result = crypto:Hash(Prev),
+ do_pbdkdf1(Result, Count-1 , <<Result/binary, Acc/binary>>, Hash).
+
+iv(#'PBES2-params_encryptionScheme'{algorithm = Algo,
+ parameters = ASNIV}) when (Algo == ?'desCBC') or
+ (Algo == ?'des-EDE3-CBC') ->
+ %% This is an so called open ASN1-type that in this
+ %% case will be an octet-string of length 8
+ <<?ASN1_OCTET_STR_TAG, ?IV_LEN, IV:?IV_LEN/binary>> = ASNIV,
+ IV;
+iv(#'PBES2-params_encryptionScheme'{algorithm = ?'rc2CBC',
+ parameters = ASN1IV}) ->
+ {ok, #'RC2-CBC-Parameter'{iv = IV}} = 'PKCS-FRAME':decode('RC2-CBC-Parameter', ASN1IV),
+ iolist_to_binary(IV).
+
+blocks(1, N, Index, Password, Salt, Count, Prf, PrfLen, Acc) ->
+ <<XorSum:N/binary, _/binary>> = xor_sum(Password, Salt, Count, Index, Prf, PrfLen),
+ <<Acc/binary, XorSum/binary>>;
+blocks(NumBlocks, N, Index, Password, Salt, Count, Prf, PrfLen, Acc) ->
+ XorSum = xor_sum(Password, Salt, Count, Index, Prf, PrfLen),
+ blocks(NumBlocks -1, N, Index +1, Password, Salt, Count, Prf,
+ PrfLen, <<Acc/binary, XorSum/binary>>).
+
+xor_sum(Password, Salt, Count, Index, Prf, PrfLen) ->
+ Result = Prf(Password, [Salt,<<Index:32/unsigned-big-integer>>], PrfLen),
+ do_xor_sum(Prf, PrfLen, Result, Password, Count-1, Result).
+
+do_xor_sum(_, _, _, _, 0, Acc) ->
+ Acc;
+do_xor_sum(Prf, PrfLen, Prev, Password, Count, Acc)->
+ Result = Prf(Password, Prev, PrfLen),
+ do_xor_sum(Prf, PrfLen, Result, Password, Count-1, crypto:exor(Acc, Result)).
+
+decrypt_parameters(?'id-PBES2', DekParams) ->
+ {ok, Params} = 'PKCS-FRAME':decode('PBES2-params', DekParams),
+ {cipher(Params#'PBES2-params'.encryptionScheme), Params}.
+
+key_derivation_params(#'PBES2-params'{keyDerivationFunc = KeyDerivationFunc,
+ encryptionScheme = EncScheme}) ->
+ #'PBES2-params_keyDerivationFunc'{algorithm = ?'id-PBKDF2',
+ parameters =
+ #'PBKDF2-params'{salt = {specified, OctetSalt},
+ iterationCount = Count,
+ keyLength = Length,
+ prf = Prf}} = KeyDerivationFunc,
+ #'PBES2-params_encryptionScheme'{algorithm = Algo} = EncScheme,
+ {PseudoRandomFunction, PseudoOtputLen} = pseudo_random_function(Prf),
+ KeyLen = derived_key_length(Algo, Length),
+ {OctetSalt, Count, KeyLen,
+ PseudoRandomFunction, PseudoOtputLen, iv(EncScheme)}.
+
+%% This function currently matches a tuple that ougth to be the value
+%% ?'id-hmacWithSHA1, but we need some kind of ASN1-fix for this.
+pseudo_random_function(#'PBKDF2-params_prf'{algorithm =
+ {_,_, _,'id-hmacWithSHA1'}}) ->
+ {fun crypto:sha_mac/3, pseudo_output_length(?'id-hmacWithSHA1')};
+pseudo_random_function(#'PBKDF2-params_prf'{algorithm = ?'id-hmacWithSHA1'}) ->
+ {fun crypto:sha_mac/3, pseudo_output_length(?'id-hmacWithSHA1')}.
+
+pseudo_output_length(?'id-hmacWithSHA1') ->
+ ?DEFAULT_SHA_MAC_KEYLEN.
+
+derived_key_length(_, Len) when is_integer(Len) ->
+ Len;
+derived_key_length(Cipher,_) when (Cipher == ?'desCBC') or
+ (Cipher == "DES-CBC") ->
+ 8;
+derived_key_length(Cipher,_) when (Cipher == ?'rc2CBC') or
+ (Cipher == "RC2-CBC") ->
+ 16;
+derived_key_length(Cipher,_) when (Cipher == ?'des-EDE3-CBC') or
+ (Cipher == "DES-EDE3-CBC") ->
+ 24.
+
+cipher(#'PBES2-params_encryptionScheme'{algorithm = ?'desCBC'}) ->
+ "DES-CBC";
+cipher(#'PBES2-params_encryptionScheme'{algorithm = ?'des-EDE3-CBC'}) ->
+ "DES-EDE3-CBC";
+cipher(#'PBES2-params_encryptionScheme'{algorithm = ?'rc2CBC'}) ->
+ "RC2-CBC".
+
+ceiling(Float) ->
+ erlang:round(Float + 0.5).
diff --git a/lib/public_key/src/pubkey_pem.erl b/lib/public_key/src/pubkey_pem.erl
index c26815bc04..910473d629 100644
--- a/lib/public_key/src/pubkey_pem.erl
+++ b/lib/public_key/src/pubkey_pem.erl
@@ -43,8 +43,6 @@
-include("public_key.hrl").
-export([encode/1, decode/1, decipher/2, cipher/3]).
-%% Backwards compatibility
--export([decode_key/2]).
-define(ENCODED_LINE_LENGTH, 64).
@@ -69,23 +67,23 @@ encode(PemEntries) ->
encode_pem_entries(PemEntries).
%%--------------------------------------------------------------------
--spec decipher({pki_asn1_type(), DerEncrypted::binary(),{Cipher :: string(),
- Salt :: binary()}},
+-spec decipher({pki_asn1_type(), DerEncrypted::binary(),
+ {Cipher :: string(), Salt :: iodata() | #'PBES2-params'{}}},
string()) -> Der::binary().
%%
%% Description: Deciphers a decrypted pem entry.
%%--------------------------------------------------------------------
-decipher({_, DecryptDer, {Cipher,Salt}}, Password) ->
- decode_key(DecryptDer, Password, Cipher, Salt).
+decipher({_, DecryptDer, {Cipher, KeyDevParams}}, Password) ->
+ pubkey_pbe:decode(DecryptDer, Password, Cipher, KeyDevParams).
%%--------------------------------------------------------------------
--spec cipher(Der::binary(),{Cipher :: string(), Salt :: binary()} ,
+-spec cipher(Der::binary(), {Cipher :: string(), Salt :: iodata() | #'PBES2-params'{}} ,
string()) -> binary().
%%
%% Description: Ciphers a PEM entry
%%--------------------------------------------------------------------
-cipher(Der, {Cipher,Salt}, Password)->
- encode_key(Der, Password, Cipher, Salt).
+cipher(Der, {Cipher, KeyDevParams}, Password)->
+ pubkey_pbe:encode(Der, Password, Cipher, KeyDevParams).
%%--------------------------------------------------------------------
%%% Internal functions
@@ -127,8 +125,20 @@ decode_pem_entry(Start, Lines) ->
Type = asn1_type(Start),
Cs = erlang:iolist_to_binary(Lines),
Decoded = base64:mime_decode(Cs),
- {Type, Decoded, not_encrypted}.
-
+ case Type of
+ 'EncryptedPrivateKeyInfo'->
+ decode_encrypted_private_keyinfo(Decoded);
+ _ ->
+ {Type, Decoded, not_encrypted}
+ end.
+
+decode_encrypted_private_keyinfo(Der) ->
+ #'EncryptedPrivateKeyInfo'{encryptionAlgorithm = AlgorithmInfo,
+ encryptedData = Data} =
+ public_key:der_decode('EncryptedPrivateKeyInfo', Der),
+ DecryptParams = pubkey_pbe:decrypt_parameters(AlgorithmInfo),
+ {'PrivateKeyInfo', iolist_to_binary(Data), DecryptParams}.
+
split_bin(Bin) ->
split_bin(0, Bin).
@@ -160,37 +170,6 @@ join_entry([<<"-----END ", _/binary>>| Lines], Entry) ->
join_entry([Line | Lines], Entry) ->
join_entry(Lines, [Line | Entry]).
-decode_key(Data, Password, "DES-CBC", Salt) ->
- Key = password_to_key(Password, Salt, 8),
- IV = Salt,
- crypto:des_cbc_decrypt(Key, IV, Data);
-decode_key(Data, Password, "DES-EDE3-CBC", Salt) ->
- Key = password_to_key(Password, Salt, 24),
- IV = Salt,
- <<Key1:8/binary, Key2:8/binary, Key3:8/binary>> = Key,
- crypto:des_ede3_cbc_decrypt(Key1, Key2, Key3, IV, Data).
-
-encode_key(Data, Password, "DES-CBC", Salt) ->
- Key = password_to_key(Password, Salt, 8),
- IV = Salt,
- crypto:des_cbc_encrypt(Key, IV, Data);
-encode_key(Data, Password, "DES-EDE3-CBC", Salt) ->
- Key = password_to_key(Password, Salt, 24),
- IV = Salt,
- <<Key1:8/binary, Key2:8/binary, Key3:8/binary>> = Key,
- crypto:des_ede3_cbc_encrypt(Key1, Key2, Key3, IV, Data).
-
-password_to_key(Data, Salt, KeyLen) ->
- <<Key:KeyLen/binary, _/binary>> =
- password_to_key(<<>>, Data, Salt, KeyLen, <<>>),
- Key.
-
-password_to_key(_, _, _, Len, Acc) when Len =< 0 ->
- Acc;
-password_to_key(Prev, Data, Salt, Len, Acc) ->
- M = crypto:md5([Prev, Data, Salt]),
- password_to_key(M, Data, Salt, Len - size(M), <<Acc/binary, M/binary>>).
-
unhex(S) ->
unhex(S, []).
@@ -228,6 +207,10 @@ pem_end(<<"-----BEGIN DSA PRIVATE KEY-----">>) ->
<<"-----END DSA PRIVATE KEY-----">>;
pem_end(<<"-----BEGIN DH PARAMETERS-----">>) ->
<<"-----END DH PARAMETERS-----">>;
+pem_end(<<"-----BEGIN PRIVATE KEY-----">>) ->
+ <<"-----END PRIVATE KEY-----">>;
+pem_end(<<"-----BEGIN ENCRYPTED PRIVATE KEY-----">>) ->
+ <<"-----END ENCRYPTED PRIVATE KEY-----">>;
pem_end(_) ->
undefined.
@@ -242,18 +225,14 @@ asn1_type(<<"-----BEGIN PUBLIC KEY-----">>) ->
asn1_type(<<"-----BEGIN DSA PRIVATE KEY-----">>) ->
'DSAPrivateKey';
asn1_type(<<"-----BEGIN DH PARAMETERS-----">>) ->
- 'DHParameter'.
+ 'DHParameter';
+asn1_type(<<"-----BEGIN PRIVATE KEY-----">>) ->
+ 'PrivateKeyInfo';
+asn1_type(<<"-----BEGIN ENCRYPTED PRIVATE KEY-----">>) ->
+ 'EncryptedPrivateKeyInfo'.
pem_decrypt() ->
<<"Proc-Type: 4,ENCRYPTED">>.
pem_decrypt_info(Cipher, Salt) ->
io_lib:format("DEK-Info: ~s,~s", [Cipher, lists:flatten(hexify(Salt))]).
-
-%%--------------------------------------------------------------------
-%%% Deprecated
-%%--------------------------------------------------------------------
-decode_key({_Type, Bin, not_encrypted}, _) ->
- Bin;
-decode_key({_Type, Bin, {Chipher,Salt}}, Password) ->
- decode_key(Bin, Password, Chipher, Salt).
diff --git a/lib/public_key/src/public_key.app.src b/lib/public_key/src/public_key.app.src
index 1963bd05d4..4cc81ea573 100644
--- a/lib/public_key/src/public_key.app.src
+++ b/lib/public_key/src/public_key.app.src
@@ -3,10 +3,12 @@
{vsn, "%VSN%"},
{modules, [ public_key,
pubkey_pem,
+ pubkey_pbe,
pubkey_ssh,
pubkey_cert,
pubkey_cert_records,
- 'OTP-PUB-KEY'
+ 'OTP-PUB-KEY',
+ 'PKCS-FRAME'
]},
{applications, [crypto, kernel, stdlib]},
{registered, []},
diff --git a/lib/public_key/src/public_key.appup.src b/lib/public_key/src/public_key.appup.src
index 4986801dad..2945fb1213 100644
--- a/lib/public_key/src/public_key.appup.src
+++ b/lib/public_key/src/public_key.appup.src
@@ -1,70 +1,16 @@
%% -*- erlang -*-
{"%VSN%",
[
- {"0.11",
- [
- {update, public_key, soft, soft_purge, soft_purge, []},
- {update, pubkey_pem, soft, soft_purge, soft_purge, []},
- {add_module, pubkey_ssh, soft, soft_purge, soft_purge},
- {update, pubkey_cert, soft, soft_purge, soft_purge, []},
- {update, pubkey_cert_records, soft, soft_purge, soft_purge, []}
- ]
- },
-
- {"0.10",
- [
- {update, public_key, soft, soft_purge, soft_purge, []},
- {update, pubkey_pem, soft, soft_purge, soft_purge, []},
- {update, pubkey_cert_records, soft, soft_purge, soft_purge, []}
- ]
- },
- {"0.9",
- [
- {update, public_key, soft, soft_purge, soft_purge, []},
- {update, pubkey_cert, soft, soft_purge, soft_purge, []}
- ]
- },
- {"0.8",
- [
- {update, 'OTP-PUB-KEY', soft, soft_purge, soft_purge, []},
- {update, public_key, soft, soft_purge, soft_purge, []},
- {update, pubkey_pem, soft, soft_purge, soft_purge, []},
- {update, pubkey_cert_records, soft, soft_purge, soft_purge, []},
- {update, pubkey_cert, soft, soft_purge, soft_purge, []}
- ]
- }
+ {"0.13", [{restart_application, public_key}]},
+ {"0.11", [{restart_application, public_key}]},
+ {"0.10", [{restart_application, public_key}]},
+ {"0.9", [{restart_application, public_key}]},
+ {"0.8", [{restart_application, public_key}]}
],
[
- {"0.11",
- [
- {update, public_key, soft, soft_purge, soft_purge, []},
- {update, pubkey_pem, soft, soft_purge, soft_purge, []},
- {delete_module, pubkey_ssh, soft, soft_purge, soft_purge},
- {update, pubkey_cert, soft, soft_purge, soft_purge, []},
- {update, pubkey_cert_records, soft, soft_purge, soft_purge, []}
- ]
- },
-
- {"0.10",
- [
- {update, public_key, soft, soft_purge, soft_purge, []},
- {update, pubkey_pem, soft, soft_purge, soft_purge, []},
- {update, pubkey_cert_records, soft, soft_purge, soft_purge, []}
- ]
- },
- {"0.9",
- [
- {update, public_key, soft, soft_purge, soft_purge, []},
- {update, pubkey_cert, soft, soft_purge, soft_purge, []}
- ]
- },
- {"0.8",
- [
- {update, 'OTP-PUB-KEY', soft, soft_purge, soft_purge, []},
- {update, public_key, soft, soft_purge, soft_purge, []},
- {update, pubkey_pem, soft, soft_purge, soft_purge, []},
- {update, pubkey_cert_records, soft, soft_purge, soft_purge, []},
- {update, pubkey_cert, soft, soft_purge, soft_purge, []}
- ]
- }
+ {"0.13", [{restart_application, public_key}]},
+ {"0.11", [{restart_application, public_key}]},
+ {"0.10", [{restart_application, public_key}]},
+ {"0.9", [{restart_application, public_key}]},
+ {"0.8", [{restart_application, public_key}]}
]}.
diff --git a/lib/public_key/src/public_key.erl b/lib/public_key/src/public_key.erl
index 33fcce2c44..753322b46d 100644
--- a/lib/public_key/src/public_key.erl
+++ b/lib/public_key/src/public_key.erl
@@ -45,13 +45,6 @@
ssh_decode/2, ssh_encode/2
]).
-%% Deprecated
--export([decode_private_key/1, decode_private_key/2, pem_to_der/1]).
-
--deprecated({pem_to_der, 1, next_major_release}).
--deprecated({decode_private_key, 1, next_major_release}).
--deprecated({decode_private_key, 2, next_major_release}).
-
-type rsa_padding() :: 'rsa_pkcs1_padding' | 'rsa_pkcs1_oaep_padding'
| 'rsa_no_padding'.
-type public_crypt_options() :: [{rsa_pad, rsa_padding()}].
@@ -104,22 +97,23 @@ pem_entry_decode({Asn1Type, Der, not_encrypted}) when is_atom(Asn1Type),
pem_entry_decode({Asn1Type, Der, not_encrypted}, _) when is_atom(Asn1Type),
is_binary(Der) ->
der_decode(Asn1Type, Der);
+pem_entry_decode({Asn1Type, CryptDer, {Cipher, #'PBES2-params'{}}} = PemEntry,
+ Password) when is_atom(Asn1Type) andalso
+ is_binary(CryptDer) andalso
+ is_list(Cipher) ->
+ do_pem_entry_decode(PemEntry, Password);
pem_entry_decode({Asn1Type, CryptDer, {Cipher, Salt}} = PemEntry,
- Password) when is_atom(Asn1Type),
- is_binary(CryptDer),
- is_list(Cipher),
- is_binary(Salt),
- erlang:byte_size(Salt) == 8
- ->
- Der = pubkey_pem:decipher(PemEntry, Password),
- der_decode(Asn1Type, Der).
+ Password) when is_atom(Asn1Type) andalso
+ is_binary(CryptDer) andalso
+ is_list(Cipher) andalso
+ is_binary(Salt) andalso
+ erlang:byte_size(Salt) == 8 ->
+ do_pem_entry_decode(PemEntry, Password).
%%--------------------------------------------------------------------
-spec pem_entry_encode(pki_asn1_type(), term()) -> pem_entry().
--spec pem_entry_encode(pki_asn1_type(), term(),
- {{Cipher :: string(), Salt :: binary()}, string()}) ->
- pem_entry().
-%
+-spec pem_entry_encode(pki_asn1_type(), term(), term()) -> pem_entry().
+%%
%% Description: Creates a pem entry that can be feed to pem_encode/1.
%%--------------------------------------------------------------------
pem_entry_encode('SubjectPublicKeyInfo', Entity=#'RSAPublicKey'{}) ->
@@ -137,21 +131,36 @@ pem_entry_encode('SubjectPublicKeyInfo',
pem_entry_encode(Asn1Type, Entity) when is_atom(Asn1Type) ->
Der = der_encode(Asn1Type, Entity),
{Asn1Type, Der, not_encrypted}.
-pem_entry_encode(Asn1Type, Entity,
- {{Cipher, Salt}= CipherInfo, Password}) when is_atom(Asn1Type),
- is_list(Cipher),
- is_binary(Salt),
- erlang:byte_size(Salt) == 8,
- is_list(Password)->
- Der = der_encode(Asn1Type, Entity),
- DecryptDer = pubkey_pem:cipher(Der, CipherInfo, Password),
- {Asn1Type, DecryptDer, CipherInfo}.
-
+pem_entry_encode(Asn1Type, Entity, {{Cipher, #'PBES2-params'{}} = CipherInfo,
+ Password}) when is_atom(Asn1Type) andalso
+ is_list(Password) andalso
+ is_list(Cipher) ->
+ do_pem_entry_encode(Asn1Type, Entity, CipherInfo, Password);
+
+pem_entry_encode(Asn1Type, Entity, {{Cipher, Salt} = CipherInfo,
+ Password}) when is_atom(Asn1Type) andalso
+ is_list(Password) andalso
+ is_list(Cipher) andalso
+ is_binary(Salt) andalso
+ erlang:byte_size(Salt) == 8 ->
+ do_pem_entry_encode(Asn1Type, Entity, CipherInfo, Password).
+
%%--------------------------------------------------------------------
-spec der_decode(asn1_type(), Der::binary()) -> term().
%%
%% Description: Decodes a public key asn1 der encoded entity.
%%--------------------------------------------------------------------
+der_decode(Asn1Type, Der) when (Asn1Type == 'PrivateKeyInfo') or
+ (Asn1Type == 'EncryptedPrivateKeyInfo')
+ andalso is_binary(Der) ->
+ try
+ {ok, Decoded} = 'PKCS-FRAME':decode(Asn1Type, Der),
+ Decoded
+ catch
+ error:{badmatch, {error, _}} = Error ->
+ erlang:error(Error)
+ end;
+
der_decode(Asn1Type, Der) when is_atom(Asn1Type), is_binary(Der) ->
try
{ok, Decoded} = 'OTP-PUB-KEY':decode(Asn1Type, Der),
@@ -166,6 +175,16 @@ der_decode(Asn1Type, Der) when is_atom(Asn1Type), is_binary(Der) ->
%%
%% Description: Encodes a public key entity with asn1 DER encoding.
%%--------------------------------------------------------------------
+der_encode(Asn1Type, Entity) when (Asn1Type == 'PrivateKeyInfo') or
+ (Asn1Type == 'EncryptedPrivateKeyInfo') ->
+ try
+ {ok, Encoded} = 'PKCS-FRAME':encode(Asn1Type, Entity),
+ iolist_to_binary(Encoded)
+ catch
+ error:{badmatch, {error, _}} = Error ->
+ erlang:error(Error)
+ end;
+
der_encode(Asn1Type, Entity) when is_atom(Asn1Type) ->
try
{ok, Encoded} = 'OTP-PUB-KEY':encode(Asn1Type, Entity),
@@ -535,6 +554,14 @@ ssh_encode(Entries, Type) when is_list(Entries),
%%--------------------------------------------------------------------
%%% Internal functions
%%--------------------------------------------------------------------
+do_pem_entry_encode(Asn1Type, Entity, CipherInfo, Password) ->
+ Der = der_encode(Asn1Type, Entity),
+ DecryptDer = pubkey_pem:cipher(Der, CipherInfo, Password),
+ {Asn1Type, DecryptDer, CipherInfo}.
+
+do_pem_entry_decode({Asn1Type,_, _} = PemEntry, Password) ->
+ Der = pubkey_pem:decipher(PemEntry, Password),
+ der_decode(Asn1Type, Der).
encrypt_public(PlainText, N, E, Options)->
Padding = proplists:get_value(rsa_pad, Options, rsa_pkcs1_padding),
@@ -632,20 +659,3 @@ validate(DerCert, #path_validation_state{working_issuer_name = Issuer,
sized_binary(Binary) ->
Size = size(Binary),
<<?UINT32(Size), Binary/binary>>.
-
-%%--------------------------------------------------------------------
-%%% Deprecated functions
-%%--------------------------------------------------------------------
-pem_to_der(CertSource) ->
- {ok, Bin} = file:read_file(CertSource),
- {ok, pubkey_pem:decode(Bin)}.
-
-decode_private_key(KeyInfo) ->
- decode_private_key(KeyInfo, no_passwd).
-
-decode_private_key(KeyInfo = {'RSAPrivateKey', _, _}, Password) ->
- DerEncoded = pubkey_pem:decode_key(KeyInfo, Password),
- 'OTP-PUB-KEY':decode('RSAPrivateKey', DerEncoded);
-decode_private_key(KeyInfo = {'DSAPrivateKey', _, _}, Password) ->
- DerEncoded = pubkey_pem:decode_key(KeyInfo, Password),
- 'OTP-PUB-KEY':decode('DSAPrivateKey', DerEncoded).
diff --git a/lib/public_key/test/Makefile b/lib/public_key/test/Makefile
index 6889ae9a8a..b7f91981a5 100644
--- a/lib/public_key/test/Makefile
+++ b/lib/public_key/test/Makefile
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2008-2010. All Rights Reserved.
+# Copyright Ericsson AB 2008-2011. All Rights Reserved.
#
# The contents of this file are subject to the Erlang Public License,
# Version 1.1, (the "License"); you may not use this file except in
@@ -30,6 +30,7 @@ INCLUDES= -I. -I ../include
MODULES= \
erl_make_certs \
public_key_SUITE \
+ pbe_SUITE \
pkits_SUITE
ERL_FILES= $(MODULES:%=%.erl)
diff --git a/lib/public_key/test/pbe_SUITE.erl b/lib/public_key/test/pbe_SUITE.erl
new file mode 100644
index 0000000000..380a67db7b
--- /dev/null
+++ b/lib/public_key/test/pbe_SUITE.erl
@@ -0,0 +1,259 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2011-2011. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+-module(pbe_SUITE).
+
+-include_lib("test_server/include/test_server.hrl").
+-include_lib("public_key/include/public_key.hrl").
+
+%% Note: This directive should only be used in test suites.
+-compile(export_all).
+%% Test server callback functions
+%%--------------------------------------------------------------------
+%% Function: init_per_suite(Config) -> Config
+%% Config - [tuple()]
+%% A list of key/value pairs, holding the test case configuration.
+%% Description: Initialization before the whole suite
+%%
+%% Note: This function is free to add any key/value pairs to the Config
+%% variable, but should NOT alter/remove any existing entries.
+%%--------------------------------------------------------------------
+init_per_suite(Config) ->
+ try crypto:start() of
+ ok ->
+ Config
+ catch _:_ ->
+ {skip, "Crypto did not start"}
+ end.
+%%--------------------------------------------------------------------
+%% Function: end_per_suite(Config) -> _
+%% Config - [tuple()]
+%% A list of key/value pairs, holding the test case configuration.
+%% Description: Cleanup after the whole suite
+%%--------------------------------------------------------------------
+end_per_suite(_Config) ->
+ application:stop(crypto).
+
+%%--------------------------------------------------------------------
+%% Function: init_per_testcase(TestCase, Config) -> Config
+%% Case - atom()
+%% Name of the test case that is about to be run.
+%% Config - [tuple()]
+%% A list of key/value pairs, holding the test case configuration.
+%%
+%% Description: Initialization before each test case
+%%
+%% Note: This function is free to add any key/value pairs to the Config
+%% variable, but should NOT alter/remove any existing entries.
+%% Description: Initialization before each test case
+%%--------------------------------------------------------------------
+init_per_testcase(_TestCase, Config) ->
+ Config.
+
+%%--------------------------------------------------------------------
+%% Function: end_per_testcase(TestCase, Config) -> _
+%% Case - atom()
+%% Name of the test case that is about to be run.
+%% Config - [tuple()]
+%% A list of key/value pairs, holding the test case configuration.
+%% Description: Cleanup after each test case
+%%--------------------------------------------------------------------
+end_per_testcase(_TestCase, _Config) ->
+ ok.
+
+%%--------------------------------------------------------------------
+%% Function: all(Clause) -> TestCases
+%% Clause - atom() - suite | doc
+%% TestCases - [Case]
+%% Case - atom()
+%% Name of a test case.
+%% Description: Returns a list of all test cases in this test suite
+%%--------------------------------------------------------------------
+suite() -> [{ct_hooks,[ts_install_cth]}].
+
+all() ->
+ [
+ pbdkdf1,
+ pbdkdf2,
+ encrypted_private_key_info].
+
+groups() ->
+ [].
+
+init_per_group(_GroupName, Config) ->
+ Config.
+
+end_per_group(_GroupName, Config) ->
+ Config.
+
+
+%% Test cases starts here.
+%%--------------------------------------------------------------------
+pbdkdf1(doc) ->
+ ["Test with PKCS #5 PBKDF1 Test Vectors"];
+pbdkdf1(Config) when is_list(Config) ->
+ %%Password = "password"
+ %% = (0x)70617373776F7264
+ %%Salt = (0x)78578E5A5D63CB06
+ %%Count = 1000
+ %%kLen = 16
+ %%Key = PBKDF1(Password, Salt, Count, kLen)
+ %%= (0x)DC19847E05C64D2FAF10EBFB4A3D2A20
+
+ Password = "password",
+ Salt = <<16#78,16#57,16#8E,16#5A,16#5D,16#63,16#CB,16#06>>,
+ Count = 1000,
+
+ <<16#DC, 16#19, 16#84, 16#7E,
+ 16#05, 16#C6, 16#4D, 16#2F,
+ 16#AF, 16#10, 16#EB, 16#FB,
+ 16#4A, 16#3D, 16#2A, 16#20, _/binary>> =
+ pubkey_pbe:pbdkdf1(Password, Salt, Count, sha).
+
+pbdkdf2(doc) ->
+ ["Test with PKCS #5 PBKDF2 Test Vectors"];
+pbdkdf2(Config) when is_list(Config) ->
+ %% Input:
+ %% P = "password" (8 octets)
+ %% S = "salt" (4 octets)
+ %% c = 1
+ %% dkLen = 20
+
+ %% Output:
+ %% DK = 0c 60 c8 0f 96 1f 0e 71
+ %% f3 a9 b5 24 af 60 12 06
+ %% 2f e0 37 a6 (20 octets)
+
+ <<16#0c, 16#60, 16#c8, 16#0f, 16#96, 16#1f, 16#0e, 16#71,
+ 16#f3, 16#a9, 16#b5, 16#24, 16#af, 16#60, 16#12, 16#06,
+ 16#2f, 16#e0, 16#37, 16#a6>> = pubkey_pbe:pbdkdf2("password", "salt", 1, 20, fun crypto:sha_mac/3, 20),
+
+ %% Input:
+ %% P = "password" (8 octets)
+ %% S = "salt" (4 octets)
+ %% c = 2
+ %% dkLen = 20
+
+ %% Output:
+ %% DK = ea 6c 01 4d c7 2d 6f 8c
+ %% cd 1e d9 2a ce 1d 41 f0
+ %% d8 de 89 57 (20 octets)
+
+ <<16#ea, 16#6c, 16#01, 16#4d, 16#c7, 16#2d, 16#6f, 16#8c,
+ 16#cd, 16#1e, 16#d9, 16#2a, 16#ce, 16#1d, 16#41, 16#f0,
+ 16#d8, 16#de, 16#89, 16#57>> =
+ pubkey_pbe:pbdkdf2("password", "salt", 2, 20, fun crypto:sha_mac/3, 20),
+
+ %% Input:
+ %% P = "password" (8 octets)
+ %% S = "salt" (4 octets)
+ %% c = 4096
+ %% dkLen = 20
+
+ %% Output:
+ %% DK = 4b 00 79 01 b7 65 48 9a
+ %% be ad 49 d9 26 f7 21 d0
+ %% 65 a4 29 c1 (20 octets)
+
+ <<16#4b, 16#00, 16#79, 16#01, 16#b7, 16#65, 16#48, 16#9a,
+ 16#be, 16#ad, 16#49, 16#d9, 16#26, 16#f7, 16#21, 16#d0,
+ 16#65, 16#a4, 16#29, 16#c1>> = pubkey_pbe:pbdkdf2("password", "salt", 4096, 20, fun crypto:sha_mac/3, 20),
+
+ %% Input:
+ %% P = "password" (8 octets)
+ %% S = "salt" (4 octets)
+ %% c = 16777216
+ %% dkLen = 20
+
+ %% Output:
+ %% DK = ee fe 3d 61 cd 4d a4 e4
+ %% e9 94 5b 3d 6b a2 15 8c
+ %% 26 34 e9 84 (20 octets)
+
+
+ <<16#ee, 16#fe, 16#3d, 16#61, 16#cd, 16#4d, 16#a4, 16#e4,
+ 16#e9, 16#94, 16#5b, 16#3d, 16#6b, 16#a2, 16#15, 16#8c,
+ 16#26, 16#34, 16#e9, 16#84>> = pubkey_pbe:pbdkdf2("password", "salt", 16777216, 20, fun crypto:sha_mac/3, 20),
+
+ %% Input:
+ %% P = "passwordPASSWORDpassword" (24 octets)
+ %% S = "saltSALTsaltSALTsaltSALTsaltSALTsalt" (36 octets)
+ %% c = 4096
+ %% dkLen = 25
+
+ %% Output:
+ %% DK = 3d 2e ec 4f e4 1c 84 9b
+ %% 80 c8 d8 36 62 c0 e4 4a
+ %% 8b 29 1a 96 4c f2 f0 70
+ %% 38 (25 octets)
+
+ <<16#3d, 16#2e, 16#ec, 16#4f, 16#e4, 16#1c, 16#84, 16#9b,
+ 16#80, 16#c8, 16#d8, 16#36, 16#62, 16#c0, 16#e4, 16#4a,
+ 16#8b, 16#29, 16#1a, 16#96, 16#4c, 16#f2, 16#f0, 16#70,
+ 16#38>>
+ = pubkey_pbe:pbdkdf2("passwordPASSWORDpassword",
+ "saltSALTsaltSALTsaltSALTsaltSALTsalt", 4096, 25, fun crypto:sha_mac/3, 20),
+
+ %% Input:
+ %% P = "pass\0word" (9 octets)
+ %% S = "sa\0lt" (5 octets)
+ %% c = 4096
+ %% dkLen = 16
+
+ %% Output:
+ %% DK = 56 fa 6a a7 55 48 09 9d
+ %% cc 37 d7 f0 34 25 e0 c3 (16 octets)
+
+ <<16#56, 16#fa, 16#6a, 16#a7, 16#55, 16#48, 16#09, 16#9d,
+ 16#cc, 16#37, 16#d7, 16#f0, 16#34, 16#25, 16#e0, 16#c3>>
+ = pubkey_pbe:pbdkdf2("pass\0word",
+ "sa\0lt", 4096, 16, fun crypto:sha_mac/3, 20).
+
+encrypted_private_key_info(doc) ->
+ ["Tests reading a EncryptedPrivateKeyInfo file encrypted with different ciphers"];
+encrypted_private_key_info(Config) when is_list(Config) ->
+ Datadir = ?config(data_dir, Config),
+ {ok, PemDes} = file:read_file(filename:join(Datadir, "des_cbc_enc_key.pem")),
+
+ PemDesEntry = public_key:pem_decode(PemDes),
+ test_server:format("Pem entry: ~p" , [PemDesEntry]),
+ [{'PrivateKeyInfo', _, {"DES-CBC",_}} = PubEntry0] = PemDesEntry,
+ KeyInfo = public_key:pem_entry_decode(PubEntry0, "password"),
+
+ {ok, Pem3Des} = file:read_file(filename:join(Datadir, "des_ede3_cbc_enc_key.pem")),
+
+ Pem3DesEntry = public_key:pem_decode(Pem3Des),
+ test_server:format("Pem entry: ~p" , [Pem3DesEntry]),
+ [{'PrivateKeyInfo', _, {"DES-EDE3-CBC",_}} = PubEntry1] = Pem3DesEntry,
+ KeyInfo = public_key:pem_entry_decode(PubEntry1, "password"),
+
+ {ok, PemRc2} = file:read_file(filename:join(Datadir, "rc2_cbc_enc_key.pem")),
+
+ PemRc2Entry = public_key:pem_decode(PemRc2),
+ test_server:format("Pem entry: ~p" , [PemRc2Entry]),
+ [{'PrivateKeyInfo', _, {"RC2-CBC",_}} = PubEntry2] = PemRc2Entry,
+ KeyInfo = public_key:pem_entry_decode(PubEntry2, "password"),
+
+ check_key_info(KeyInfo).
+
+
+check_key_info(#'PrivateKeyInfo'{privateKeyAlgorithm =
+ #'PrivateKeyInfo_privateKeyAlgorithm'{algorithm = ?rsaEncryption},
+ privateKey = Key}) ->
+ #'RSAPrivateKey'{} = public_key:der_decode('RSAPrivateKey', iolist_to_binary(Key)).
diff --git a/lib/public_key/test/pbe_SUITE_data/des_cbc_enc_key.pem b/lib/public_key/test/pbe_SUITE_data/des_cbc_enc_key.pem
new file mode 100644
index 0000000000..eaa06145aa
--- /dev/null
+++ b/lib/public_key/test/pbe_SUITE_data/des_cbc_enc_key.pem
@@ -0,0 +1,11 @@
+-----BEGIN ENCRYPTED PRIVATE KEY-----
+MIIBozA9BgkqhkiG9w0BBQ0wMDAbBgkqhkiG9w0BBQwwDgQIfWBDXwLp4K4CAggA
+MBEGBSsOAwIHBAiaCF/AvOgQ6QSCAWDWX4BdAzCRNSQSANSuNsT5X8mWYO27mr3Y
+9c9LoBVXGNmYWKA77MI4967f7SmjNcgXj3xNE/jmnVz6hhsjS8E5VPT3kfyVkpdZ
+0lr5e9Yk2m3JWpPU7++v5zBkZmC4V/MwV/XuIs6U+vykgzMgpxQg0oZKS9zgmiZo
+f/4dOCL0UtCDnyOSvqT7mCVIcMDIEKu8QbVlgZYBop08l60EuEU3gARUo8WsYQmO
+Dz/ldx0Z+znIT0SXVuOwc+RVItC5T/Qx+aijmmpt+9l14nmaGBrEkmuhmtdvU/4v
+aptewGRgmjOfD6cqK+zs0O5NrrJ3P/6ZSxXj91CQgrThGfOv72bUncXEMNtc8pks
+2jpHFjGMdKufnadAD7XuMgzkkaklEXZ4f5tU6heIIwr51g0GBEGF96gYPFnjnSQM
+75JE02Clo+DfcfXpcybPTwwFg2jd6JTTOfkdf6OdSlA/1XNK43FA
+-----END ENCRYPTED PRIVATE KEY-----
diff --git a/lib/public_key/test/pbe_SUITE_data/des_ede3_cbc_enc_key.pem b/lib/public_key/test/pbe_SUITE_data/des_ede3_cbc_enc_key.pem
new file mode 100644
index 0000000000..22ea46d56f
--- /dev/null
+++ b/lib/public_key/test/pbe_SUITE_data/des_ede3_cbc_enc_key.pem
@@ -0,0 +1,11 @@
+-----BEGIN ENCRYPTED PRIVATE KEY-----
+MIIBpjBABgkqhkiG9w0BBQ0wMzAbBgkqhkiG9w0BBQwwDgQIeFeOWl1jywYCAggA
+MBQGCCqGSIb3DQMHBAjUJ5eGBhQGtQSCAWBrHrRgqO8UUMLcWzZEtpk1l3mjxiF/
+koCMkHsFwowgyWhEbgIkTgbSViK54LVK8PskekcGNLph+rB6bGZ7pPbL5pbXASJ8
++MkQcG3FZdlS4Ek9tTJDApj3O1UubZGFG4uvTlJJFbF1BOJ3MkY3XQ9Gl1qwv7j5
+6e103Da7Cq9+oIDKmznza78XXQYrUsPo8mJGjUxPskEYlzwvHjKubRnYm/K6RKhi
+5f4zX4BQ/Dt3H812ZjRXrsjAJP0KrD/jyD/jCT7zNBVPH1izBds+RwizyQAHwfNJ
+BFR78TH4cgzB619X47FDVOnT0LqQNVd0O3cSwnPrXE9XR3tPayE+iOB15llFSmi8
+z0ByOXldEpkezCn92Umk++suzIVj1qfsK+bv2phZWJPbLEIWPDRHUbYf76q5ArAr
+u4xtxT/hoK3krEs/IN3d70qjlUJ36SEw1UaZ82PWhakQbdtu39ZraMJB
+-----END ENCRYPTED PRIVATE KEY-----
diff --git a/lib/public_key/test/pbe_SUITE_data/rc2_cbc_enc_key.pem b/lib/public_key/test/pbe_SUITE_data/rc2_cbc_enc_key.pem
new file mode 100644
index 0000000000..618cddcfd7
--- /dev/null
+++ b/lib/public_key/test/pbe_SUITE_data/rc2_cbc_enc_key.pem
@@ -0,0 +1,12 @@
+-----BEGIN ENCRYPTED PRIVATE KEY-----
+MIIBrjBIBgkqhkiG9w0BBQ0wOzAeBgkqhkiG9w0BBQwwEQQIrHyQPBZqWLUCAggA
+AgEQMBkGCCqGSIb3DQMCMA0CAToECEhbh7YZKiPSBIIBYCT1zp6o5jpFlIkgwPop
+7bW1+8ACr4exqzkeb3WflQ8cWJ4cURxzVdvxUnXeW1VJdaQZtjS/QHs5GhPTG/0f
+wtvnaPfwrIJ3FeGaZfcg2CrYhalOFmEb4xrE4KyoEQmUN8tb/Cg94uzd16BOPw21
+RDnE8bnPdIGY7TyL95kbkqH23mK53pi7h+xWIgduW+atIqDyyt55f7WMZcvDvlj6
+VpN/V0h+qxBHL274WA4dj6GYgeyUFpi60HdGCK7By2TBy8h1ZvKGjmB9h8jZvkx1
+MkbRumXxyFsowTZawyYvO8Um6lbfEDP9zIEUq0IV8RqH2MRyblsPNSikyYhxX/cz
+tdDxRKhilySbSBg5Kr8OfcwKp9bpinN96nmG4xr3Tch1bnVvqJzOQ5+Vva2WwVvH
+2JkWvYm5WaANg4Q6bRxu9vz7DuhbJjQdZbxFezIAgrJdSe92B00jO/0Kny1WjiVO
+6DA=
+-----END ENCRYPTED PRIVATE KEY-----
diff --git a/lib/public_key/test/public_key_SUITE.erl b/lib/public_key/test/public_key_SUITE.erl
index b11e4d092a..a91dcfa029 100644
--- a/lib/public_key/test/public_key_SUITE.erl
+++ b/lib/public_key/test/public_key_SUITE.erl
@@ -23,8 +23,8 @@
%% Note: This directive should only be used in test suites.
-compile(export_all).
--include_lib("common_test/include/ct.hrl").
--include_lib("test_server/include/test_server_line.hrl").
+%%-include_lib("common_test/include/ct.hrl").
+-include_lib("test_server/include/test_server.hrl").
-include_lib("public_key/include/public_key.hrl").
@@ -107,7 +107,7 @@ all() ->
{group, ssh_public_key_decode_encode},
encrypt_decrypt,
{group, sign_verify},
- pkix, pkix_path_validation, deprecated].
+ pkix, pkix_path_validation].
groups() ->
[{pem_decode_encode, [], [dsa_pem, rsa_pem, encrypted_pem,
@@ -699,27 +699,6 @@ pkix_path_validation(Config) when is_list(Config) ->
VerifyFunAndState1}]),
ok.
-%%--------------------------------------------------------------------
-deprecated(doc) ->
- ["Check deprecated functions."];
-deprecated(suite) ->
- [];
-deprecated(Config) when is_list(Config) ->
- Datadir = ?config(data_dir, Config),
- {ok, [DsaKey = {'DSAPrivateKey', _DsaKey, _}]} =
- public_key:pem_to_der(filename:join(Datadir, "dsa.pem")),
- {ok, [RsaKey = {'RSAPrivateKey', _RsaKey,_}]} =
- public_key:pem_to_der(filename:join(Datadir, "client_key.pem")),
- {ok, [ProtectedRsaKey = {'RSAPrivateKey', _ProtectedRsaKey,_}]} =
- public_key:pem_to_der(filename:join(Datadir, "rsa.pem")),
-
- {ok, #'DSAPrivateKey'{}} = public_key:decode_private_key(DsaKey),
- {ok, #'RSAPrivateKey'{}} = public_key:decode_private_key(RsaKey),
- {ok, #'RSAPrivateKey'{}} = public_key:decode_private_key(ProtectedRsaKey, "abcd1234"),
- ok.
-
-%%--------------------------------------------------------------------
-
check_entry_type(#'DSAPrivateKey'{}, 'DSAPrivateKey') ->
true;
check_entry_type(#'RSAPrivateKey'{}, 'RSAPrivateKey') ->
diff --git a/lib/public_key/vsn.mk b/lib/public_key/vsn.mk
index 66ac78a65d..d8f811bf25 100644
--- a/lib/public_key/vsn.mk
+++ b/lib/public_key/vsn.mk
@@ -1 +1 @@
-PUBLIC_KEY_VSN = 0.13
+PUBLIC_KEY_VSN = 0.14
diff --git a/lib/reltool/doc/src/make.dep b/lib/reltool/doc/src/make.dep
deleted file mode 100644
index 59e77e8162..0000000000
--- a/lib/reltool/doc/src/make.dep
+++ /dev/null
@@ -1,20 +0,0 @@
-# ----------------------------------------------------
-# >>>> Do not edit this file <<<<
-# This file was automaticly generated by
-# /home/otp/bin/docdepend
-# ----------------------------------------------------
-
-
-# ----------------------------------------------------
-# TeX files that the DVI file depend on
-# ----------------------------------------------------
-
-book.dvi: book.tex part.tex ref_man.tex reltool.tex \
- reltool_examples.tex reltool_intro.tex reltool_usage.tex
-
-# ----------------------------------------------------
-# Source inlined when transforming from source to LaTeX
-# ----------------------------------------------------
-
-book.tex: ref_man.xml
-
diff --git a/lib/runtime_tools/c_src/Makefile.in b/lib/runtime_tools/c_src/Makefile.in
index 840de39f07..73ab6cdc11 100644
--- a/lib/runtime_tools/c_src/Makefile.in
+++ b/lib/runtime_tools/c_src/Makefile.in
@@ -89,42 +89,31 @@ endif
# Targets
# ----------------------------------------------------
-debug opt: $(OBJDIR) $(BINDIR) $(SOLIBS)
+_create_dirs := $(shell mkdir -p $(OBJDIR) $(LIBDIR))
-$(OBJDIR):
- -@mkdir -p $(OBJDIR)
-
-$(BINDIR):
- -@mkdir -p $(BINDIR)
+debug opt: $(SOLIBS)
$(OBJDIR)/%.o: %.c
- $(INSTALL_DIR) $(OBJDIR)
$(CC) -c -o $@ $(ALL_CFLAGS) $<
$(LIBDIR)/trace_ip_drv.so: $(TRACE_IP_DRV_OBJS)
- $(INSTALL_DIR) $(LIBDIR)
$(LD) $(LDFLAGS) -o $@ $^ -lc $(LIBS)
$(LIBDIR)/trace_file_drv.so: $(TRACE_FILE_DRV_OBJS)
- $(INSTALL_DIR) $(LIBDIR)
$(LD) $(LDFLAGS) -o $@ $^ -lc $(LIBS)
$(LIBDIR)/trace_ip_drv.dll: $(TRACE_IP_DRV_OBJS)
- $(INSTALL_DIR) $(LIBDIR)
$(LD) $(LDFLAGS) -o $@ $^ $(LIBS)
$(LIBDIR)/trace_file_drv.dll: $(TRACE_FILE_DRV_OBJS)
- $(INSTALL_DIR) $(LIBDIR)
$(LD) $(LDFLAGS) -o $@ $^ $(LIBS)
#
# VxWorks is simply to different from Unix in this sense.
# Here are the inference rules for VxWorks
#
$(LIBDIR)/trace_ip_drv.eld: $(TRACE_IP_DRV_OBJS)
- $(INSTALL_DIR) $(LIBDIR)
$(LD) $(LDFLAGS) -o $@ $^
$(LIBDIR)/trace_file_drv.eld: $(TRACE_FILE_DRV_OBJS)
- $(INSTALL_DIR) $(LIBDIR)
$(LD) $(LDFLAGS) -o $@ $^
clean:
diff --git a/lib/runtime_tools/doc/src/dbg.xml b/lib/runtime_tools/doc/src/dbg.xml
index f26789fa21..c7c5cd4ff0 100644
--- a/lib/runtime_tools/doc/src/dbg.xml
+++ b/lib/runtime_tools/doc/src/dbg.xml
@@ -316,7 +316,8 @@ Error: fun containing local erlang function calls ('is_atomm' called in guard) c
<v>Module = atom() | '_'</v>
<v>Function = atom() | '_'</v>
<v>Arity = integer() |'_'</v>
- <v>MatchSpec = integer() | atom() | [] | match_spec()</v>
+ <v>MatchSpec = integer() | Built-inAlias | [] | match_spec()</v>
+ <v>Built-inAlias = x | c | cx</v>
<v>MatchDesc = [MatchInfo]</v>
<v>MatchInfo = {saved, integer()} | MatchNum</v>
<v>MatchNum = {matched, node(), integer()} | {matched, node(), 0, RPCError}</v>
@@ -349,8 +350,9 @@ Error: fun containing local erlang function calls ('is_atomm' called in guard) c
if the MatchSpec is other
than []. The integer <c>N</c> may then be used in
subsequent calls to this function and will stand as an
- "alias" for the given expression. There are also built-in
- aliases named with atoms (see also <c>ltp/0</c> below).</p>
+ "alias" for the given expression. There are also a couple of
+ built-in aliases for common expressions, see <c>ltp/0</c> below
+ for details.</p>
<p>If an error is returned, it can be due to errors in
compilation of the match specification. Such errors are
presented as a list of tuples <c>{error, string()}</c> where
@@ -528,6 +530,21 @@ Error: fun containing local erlang function calls ('is_atomm' called in guard) c
<p>Match specifications used can be saved in a file (if a
read-write file system is present) for use in later
debugging sessions, see <c>wtp/1</c> and <c>rtp/1</c></p>
+ <p>There are three built-in trace patterns:
+ <c>exception_trace</c>, <c>caller_trace</c>
+ and <c>caller_exception_trace</c> (or <c>x</c>, <c>c</c> and
+ <c>cx</c> respectively).
+ Exception trace sets a trace which will show function names,
+ parameters, return values and exceptions thrown from functions.
+ Caller traces display function names, parameters and information
+ about which function called it. An example using a built-in alias:</p>
+ <pre>
+(x@y)4> <input>dbg:tp(lists,sort,cx).</input>
+{ok,[{matched,nonode@nohost,2},{saved,cx}]}
+(x@y)4> <input>lists:sort([2,1]).</input>
+(&lt;0.32.0&gt;) call lists:sort([2,1]) ({erl_eval,do_apply,5})
+(&lt;0.32.0&gt;) returned from lists:sort/1 -> [1,2]
+[1,2]</pre>
</desc>
</func>
<func>
diff --git a/lib/runtime_tools/doc/src/make.dep b/lib/runtime_tools/doc/src/make.dep
deleted file mode 100644
index 85eae88adf..0000000000
--- a/lib/runtime_tools/doc/src/make.dep
+++ /dev/null
@@ -1,20 +0,0 @@
-# ----------------------------------------------------
-# >>>> Do not edit this file <<<<
-# This file was automaticly generated by
-# /home/otp/bin/docdepend
-# ----------------------------------------------------
-
-
-# ----------------------------------------------------
-# TeX files that the DVI file depend on
-# ----------------------------------------------------
-
-book.dvi: book.tex dbg.tex erts_alloc_config.tex refman.tex \
- runtime_tools_app.tex
-
-# ----------------------------------------------------
-# Source inlined when transforming from source to LaTeX
-# ----------------------------------------------------
-
-book.tex: refman.xml
-
diff --git a/lib/runtime_tools/src/Makefile b/lib/runtime_tools/src/Makefile
index 4f831f3dd8..46b570210a 100644
--- a/lib/runtime_tools/src/Makefile
+++ b/lib/runtime_tools/src/Makefile
@@ -46,7 +46,8 @@ MODULES= \
runtime_tools_sup \
dbg \
percept_profile \
- observer_backend
+ observer_backend \
+ ttb_autostart
HRL_FILES= ../include/observer_backend.hrl
ERL_FILES= $(MODULES:%=%.erl)
diff --git a/lib/runtime_tools/src/dbg.erl b/lib/runtime_tools/src/dbg.erl
index 56283f4d3d..385047ee73 100644
--- a/lib/runtime_tools/src/dbg.erl
+++ b/lib/runtime_tools/src/dbg.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2010. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2011. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -32,7 +32,7 @@
-export([fun2ms/1]).
%% Local exports
--export([erlang_trace/3,get_info/0]).
+-export([erlang_trace/3,get_info/0,deliver_and_flush/1]).
%% Debug exports
-export([wrap_presort/2, wrap_sort/2, wrap_postsort/1, wrap_sortfix/2,
@@ -348,17 +348,16 @@ trace_port_control(Operation) ->
trace_port_control(node(), Operation).
trace_port_control(Node, flush) ->
- Ref = erlang:trace_delivered(all),
- receive
- {trace_delivered,all,Ref} -> ok
- end,
- case trace_port_control(Node, $f, "") of
- {ok, [0]} ->
- ok;
- {ok, _} ->
- {error, not_supported_by_trace_driver};
- Other ->
- Other
+ case get_tracer(Node) of
+ {ok, Port} when is_port(Port) ->
+ case catch rpc:call(Node,?MODULE,deliver_and_flush,[Port]) of
+ [0] ->
+ ok;
+ _ ->
+ {error, not_supported_by_trace_driver}
+ end;
+ _ ->
+ {error, no_trace_driver}
end;
trace_port_control(Node,get_listen_port) ->
case trace_port_control(Node,$p, "") of
@@ -378,7 +377,14 @@ trace_port_control(Node, Command, Arg) ->
{error, no_trace_driver}
end.
-
+%% A bit more than just flush - it also makes sure all trace messages
+%% are delivered first, before flushing the driver.
+deliver_and_flush(Port) ->
+ Ref = erlang:trace_delivered(all),
+ receive
+ {trace_delivered,all,Ref} -> ok
+ end,
+ erlang:port_control(Port, $f, "").
trace_port(file, {Filename, wrap, Tail}) ->
@@ -684,18 +690,12 @@ loop({C,T}=SurviveLinks, Table) ->
%% tracing on the node it removes from the list of active trace nodes,
%% we will call erlang:trace_delivered/1 on ALL nodes that we have
%% connections to.
- Delivered = fun() ->
- Ref = erlang:trace_delivered(all),
- receive
- {trace_delivered,all,Ref} -> ok
- end
- end,
- catch rpc:multicall(nodes(), erlang, apply, [Delivered,[]]),
- Ref = erlang:trace_delivered(all),
- receive
- {trace_delivered,all,Ref} ->
- exit(done)
- end;
+ %% If it is a file trace driver, we will also flush the port.
+ lists:foreach(fun({Node,{_Relay,Port}}) ->
+ rpc:call(Node,?MODULE,deliver_and_flush,[Port])
+ end,
+ get()),
+ exit(done);
{From, {link_to, Pid}} ->
case (catch link(Pid)) of
{'EXIT', Reason} ->
@@ -1449,6 +1449,19 @@ new_pattern_table() ->
ets:insert(PT,
{exception_trace,
term_to_binary(x)}),
+ ets:insert(PT,
+ {c,
+ term_to_binary([{'_',[],[{message,{caller}}]}])}),
+ ets:insert(PT,
+ {caller_trace,
+ term_to_binary(c)}),
+ ets:insert(PT,
+ {cx,
+ term_to_binary([{'_',[],[{exception_trace},
+ {message,{caller}}]}])}),
+ ets:insert(PT,
+ {caller_exception_trace,
+ term_to_binary(cx)}),
PT.
diff --git a/lib/runtime_tools/src/inviso_rt.erl b/lib/runtime_tools/src/inviso_rt.erl
index ac7ac2a584..b162f5b045 100644
--- a/lib/runtime_tools/src/inviso_rt.erl
+++ b/lib/runtime_tools/src/inviso_rt.erl
@@ -2359,8 +2359,8 @@ list_wrapset(Prefix,Suffix) ->
list_wrapset_2([File|Rest],RegExp) ->
Length=length(File),
- case regexp:first_match(File,RegExp) of
- {match,1,Length} -> % This is a member of the set.
+ case re:run(File,RegExp) of
+ {match,[{0,Length}]} -> % This is a member of the set.
[File|list_wrapset_2(Rest,RegExp)];
_ ->
list_wrapset_2(Rest,RegExp)
diff --git a/lib/runtime_tools/src/inviso_rt_lib.erl b/lib/runtime_tools/src/inviso_rt_lib.erl
index 2c6964e53e..ee6a72ae0c 100644
--- a/lib/runtime_tools/src/inviso_rt_lib.erl
+++ b/lib/runtime_tools/src/inviso_rt_lib.erl
@@ -197,15 +197,15 @@ match_modules(RegExpDir,RegExpMod,Actions) ->
handle_expand_regexp_2([{Mod,Path}|Rest],RegExpDir,RegExpMod,Result) ->
ModStr=atom_to_list(Mod),
ModLen=length(ModStr),
- case regexp:first_match(ModStr,RegExpMod) of
- {match,1,ModLen} -> % Ok, The regexp matches the module.
+ case re:run(ModStr,RegExpMod) of
+ {match,[{0,ModLen}]} -> % Ok, The regexp matches the module.
if
is_list(RegExpDir),is_atom(Path) -> % Preloaded or covercompiled...
handle_expand_regexp_2(Rest,RegExpDir,RegExpMod,Result);
is_list(RegExpDir),is_list(Path) -> % Dir reg-exp is used!
PathOnly=filename:dirname(Path), % Must remove beam-file name.
- case regexp:first_match(PathOnly,RegExpDir) of
- {match,_,_} -> % Did find a match, that is enough!
+ case re:run(PathOnly,RegExpDir,[{capture,none}]) of
+ match -> % Did find a match, that is enough!
handle_expand_regexp_2(Rest,RegExpDir,RegExpMod,[Mod|Result]);
_ -> % Either error or nomatch.
handle_expand_regexp_2(Rest,RegExpDir,RegExpMod,Result)
@@ -233,8 +233,8 @@ handle_expand_regexp_3([Path|Rest],RegExpDir,RegExpMod,AllLoaded,Result) ->
volumerelative -> % Only on Windows!?
filename:absname(Path)
end,
- case regexp:first_match(AbsPath,RegExpDir) of
- {match,_,_} -> % Ok, the directory is allowed.
+ case re:run(AbsPath,RegExpDir,[{capture,none}]) of
+ match -> % Ok, the directory is allowed.
NewResult=handle_expand_regexp_3_1(Path,RegExpMod,AllLoaded,Result),
handle_expand_regexp_3(Rest,RegExpDir,RegExpMod,AllLoaded,NewResult);
_ -> % This directory does not qualify.
@@ -262,8 +262,8 @@ handle_expand_regexp_3_2([File|Rest],RegExpMod,AllLoaded,Result) ->
case {lists:keysearch(Mod,1,AllLoaded),lists:member(Mod,Result)} of
{false,false} -> % This module is not tried before.
ModLen=length(ModStr),
- case regexp:first_match(ModStr,RegExpMod) of
- {match,1,ModLen} -> % This module satisfies the regexp.
+ case re:run(ModStr,RegExpMod) of
+ {match,[{0,ModLen}]} -> % This module satisfies the regexp.
handle_expand_regexp_3_2(Rest,RegExpMod,AllLoaded,[Mod|Result]);
_ -> % Error or not perfect match.
handle_expand_regexp_3_2(Rest,RegExpMod,AllLoaded,Result)
diff --git a/lib/runtime_tools/src/observer_backend.erl b/lib/runtime_tools/src/observer_backend.erl
index 0f428de07a..9c1f9da5b1 100644
--- a/lib/runtime_tools/src/observer_backend.erl
+++ b/lib/runtime_tools/src/observer_backend.erl
@@ -31,6 +31,7 @@
ttb_write_binary/2,
ttb_stop/1,
ttb_fetch/2,
+ ttb_resume_trace/0,
ttb_get_filenames/1]).
-define(CHUNKSIZE,8191). % 8 kbytes - 1 byte
@@ -92,16 +93,22 @@ etop_collect([], Acc) -> Acc.
%%
%% ttb backend
%%
-ttb_init_node(MetaFile,PI,Traci) ->
+ttb_init_node(MetaFile_0,PI,Traci) ->
if
- is_list(MetaFile);
- is_atom(MetaFile) ->
+ is_list(MetaFile_0);
+ is_atom(MetaFile_0) ->
+ {ok, Cwd} = file:get_cwd(),
+ MetaFile = filename:join(Cwd, MetaFile_0),
file:delete(MetaFile);
true -> % {local,_,_}
- ok
+ MetaFile = MetaFile_0
+ end,
+ case proplists:get_value(resume, Traci) of
+ {true, _} -> (autostart_module()):write_config(Traci);
+ _ -> ok
end,
Self = self(),
- MetaPid = spawn(fun() -> ttb_meta_tracer(MetaFile,PI,Self) end),
+ MetaPid = spawn(fun() -> ttb_meta_tracer(MetaFile,PI,Self,Traci) end),
receive {MetaPid,started} -> ok end,
MetaPid ! {metadata,Traci},
case PI of
@@ -111,13 +118,14 @@ ttb_init_node(MetaFile,PI,Traci) ->
false ->
ok
end,
- {ok,MetaPid}.
+ {ok,MetaFile,MetaPid}.
ttb_write_trace_info(MetaPid,Key,What) ->
MetaPid ! {metadata,Key,What},
ok.
-ttb_meta_tracer(MetaFile,PI,Parent) ->
+ttb_meta_tracer(MetaFile,PI,Parent,SessionData) ->
+ erlang:monitor(process, proplists:get_value(ttb_control, SessionData)),
case PI of
true ->
ReturnMS = [{'_',[],[{return_trace}]}],
@@ -130,22 +138,29 @@ ttb_meta_tracer(MetaFile,PI,Parent) ->
ok
end,
Parent ! {self(),started},
- ttb_meta_tracer_loop(MetaFile,PI,dict:new()).
+ case proplists:get_value(overload_check, SessionData) of
+ {Ms, M, F} ->
+ catch M:F(init),
+ erlang:send_after(Ms, self(), overload_check);
+ _ ->
+ ok
+ end,
+ ttb_meta_tracer_loop(MetaFile,PI,dict:new(),SessionData).
-ttb_meta_tracer_loop(MetaFile,PI,Acc) ->
+ttb_meta_tracer_loop(MetaFile,PI,Acc,State) ->
receive
{trace_ts,_,call,{erlang,register,[Name,Pid]},_} ->
ttb_store_meta({pid,{Pid,Name}},MetaFile),
- ttb_meta_tracer_loop(MetaFile,PI,Acc);
+ ttb_meta_tracer_loop(MetaFile,PI,Acc,State);
{trace_ts,_,call,{global,register_name,[Name,Pid]},_} ->
ttb_store_meta({pid,{Pid,{global,Name}}},MetaFile),
- ttb_meta_tracer_loop(MetaFile,PI,Acc);
+ ttb_meta_tracer_loop(MetaFile,PI,Acc,State);
{trace_ts,CallingPid,call,{erlang,spawn_opt,[{M,F,Args,_}]},_} ->
MFA = {M,F,length(Args)},
NewAcc = dict:update(CallingPid,
fun(Old) -> [MFA|Old] end, [MFA],
Acc),
- ttb_meta_tracer_loop(MetaFile,PI,NewAcc);
+ ttb_meta_tracer_loop(MetaFile,PI,NewAcc,State);
{trace_ts,CallingPid,return_from,{erlang,spawn_opt,_Arity},Ret,_} ->
case Ret of
{NewPid,_Mref} when is_pid(NewPid) -> ok;
@@ -158,14 +173,14 @@ ttb_meta_tracer_loop(MetaFile,PI,Acc) ->
T
end,
Acc),
- ttb_meta_tracer_loop(MetaFile,PI,NewAcc);
+ ttb_meta_tracer_loop(MetaFile,PI,NewAcc,State);
{trace_ts,CallingPid,call,{erlang,Spawn,[M,F,Args]},_}
when Spawn==spawn;Spawn==spawn_link ->
MFA = {M,F,length(Args)},
NewAcc = dict:update(CallingPid,
fun(Old) -> [MFA|Old] end, [MFA],
Acc),
- ttb_meta_tracer_loop(MetaFile,PI,NewAcc);
+ ttb_meta_tracer_loop(MetaFile,PI,NewAcc,State);
{trace_ts,CallingPid,return_from,{erlang,Spawn,_Arity},NewPid,_}
when Spawn==spawn;Spawn==spawn_link ->
@@ -176,28 +191,53 @@ ttb_meta_tracer_loop(MetaFile,PI,Acc) ->
T
end,
Acc),
- ttb_meta_tracer_loop(MetaFile,PI,NewAcc);
+ ttb_meta_tracer_loop(MetaFile,PI,NewAcc,State);
{metadata,Data} when is_list(Data) ->
ttb_store_meta(Data,MetaFile),
- ttb_meta_tracer_loop(MetaFile,PI,Acc);
+ ttb_meta_tracer_loop(MetaFile,PI,Acc,State);
{metadata,Key,Fun} when is_function(Fun) ->
ttb_store_meta([{Key,Fun()}],MetaFile),
- ttb_meta_tracer_loop(MetaFile,PI,Acc);
+ ttb_meta_tracer_loop(MetaFile,PI,Acc,State);
{metadata,Key,What} ->
ttb_store_meta([{Key,What}],MetaFile),
- ttb_meta_tracer_loop(MetaFile,PI,Acc);
-
- stop when PI=:=true ->
- erlang:trace_pattern({erlang,spawn,3},false,[meta]),
+ ttb_meta_tracer_loop(MetaFile,PI,Acc,State);
+ overload_check ->
+ {Ms, M, F} = proplists:get_value(overload_check, State),
+ case catch M:F(check) of
+ true ->
+ erlang:trace(all, false, [all]),
+ ControlPid = proplists:get_value(ttb_control, State),
+ ControlPid ! {node_overloaded, node()},
+ catch M:F(stop),
+ ttb_meta_tracer_loop(MetaFile,PI,Acc,lists:keydelete(overload_check, 1, State));
+ _ ->
+ erlang:send_after(Ms, self(), overload_check),
+ ttb_meta_tracer_loop(MetaFile,PI,Acc, State)
+ end;
+ {'DOWN', _, _, _, _} ->
+ stop_seq_trace(),
+ self() ! stop,
+ ttb_meta_tracer_loop(MetaFile,PI,Acc, State);
+ stop when PI=:=true ->
+ try_stop_resume(State),
+ try_stop_overload_check(State),
+ erlang:trace_pattern({erlang,spawn,3},false,[meta]),
erlang:trace_pattern({erlang,spawn_link,3},false,[meta]),
erlang:trace_pattern({erlang,spawn_opt,1},false,[meta]),
erlang:trace_pattern({erlang,register,2},false,[meta]),
erlang:trace_pattern({global,register_name,2},false,[meta]);
stop ->
- ok
+ try_stop_resume(State),
+ try_stop_overload_check(State)
+ end.
+
+try_stop_overload_check(State) ->
+ case proplists:get_value(overload, State) of
+ undefined -> ok;
+ {_, M, F} -> catch M:F(stop)
end.
pnames() ->
@@ -222,6 +262,40 @@ pinfo(P,Globals) ->
undefined -> [] % the process has terminated
end.
+autostart_module() ->
+ element(2, application:get_env(runtime_tools, ttb_autostart_module)).
+
+try_stop_resume(State) ->
+ case proplists:get_value(resume, State) of
+ true -> (autostart_module()):delete_config();
+ _ -> ok
+ end.
+
+ttb_resume_trace() ->
+ case (autostart_module()):read_config() of
+ {error, _} ->
+ ok;
+ {ok, Data} ->
+ Pid = proplists:get_value(ttb_control, Data),
+ {_, Timeout} = proplists:get_value(resume, Data),
+ case rpc:call(node(Pid), erlang, whereis, [ttb]) of
+ Pid ->
+ Pid ! {noderesumed, node(), self()},
+ wait_for_fetch_ready(Timeout);
+ _ ->
+ ok
+ end,
+ (autostart_module()):delete_config(),
+ ok
+ end.
+
+wait_for_fetch_ready(Timeout) ->
+ receive
+ trace_resumed ->
+ ok
+ after Timeout ->
+ ok
+ end.
ttb_store_meta(Data,{local,MetaFile,Port}) when is_list(Data) ->
ttb_send_to_port(Port,MetaFile,Data);
@@ -273,6 +347,9 @@ ttb_stop(MetaPid) ->
%% returns, and then the Port (in {local,MetaFile,Port})
%% cannot be accessed any more.
receive {'DOWN', Ref, process, MetaPid, _Info} -> ok end,
+ stop_seq_trace().
+
+stop_seq_trace() ->
seq_trace:reset_trace(),
seq_trace:set_system_tracer(false).
@@ -287,7 +364,7 @@ ttb_fetch(MetaFile,{Port,Host}) ->
send_files({Sock,Host},[File|Files]) ->
{ok,Fd} = file:open(File,[raw,read,binary]),
- gen_tcp:send(Sock,<<1,(list_to_binary(File))/binary>>),
+ gen_tcp:send(Sock,<<1,(list_to_binary(filename:basename(File)))/binary>>),
send_chunks(Sock,Fd),
file:delete(File),
send_files({Sock,Host},Files);
diff --git a/lib/runtime_tools/src/runtime_tools.app.src b/lib/runtime_tools/src/runtime_tools.app.src
index e6dc7a21d4..095567b165 100644
--- a/lib/runtime_tools/src/runtime_tools.app.src
+++ b/lib/runtime_tools/src/runtime_tools.app.src
@@ -22,7 +22,8 @@
{modules, [dbg,observer_backend,percept_profile,
inviso_rt,inviso_rt_lib,inviso_rt_meta,
inviso_as_lib,inviso_autostart,inviso_autostart_server,
- runtime_tools,runtime_tools_sup,erts_alloc_config]},
+ runtime_tools,runtime_tools_sup,erts_alloc_config,
+ ttb_autostart]},
{registered, [runtime_tools_sup,inviso_rt,inviso_rt_meta]},
{applications, [kernel, stdlib]},
% {env, [{inviso_autostart_mod,your_own_autostart_module}]},
diff --git a/lib/runtime_tools/src/runtime_tools_sup.erl b/lib/runtime_tools/src/runtime_tools_sup.erl
index 1a872c355d..4fcb2292d0 100644
--- a/lib/runtime_tools/src/runtime_tools_sup.erl
+++ b/lib/runtime_tools/src/runtime_tools_sup.erl
@@ -38,6 +38,8 @@
init(AutoModArgs) ->
Flags = {one_for_one, 0, 3600},
Children = [{inviso_rt, {inviso_rt, start_link_auto, [AutoModArgs]},
- temporary, 3000, worker, [inviso_rt]}],
+ temporary, 3000, worker, [inviso_rt]},
+ {ttb_autostart, {ttb_autostart, start_link, []},
+ temporary, 3000, worker, [ttb_autostart]}],
{ok, {Flags, Children}}.
%% -----------------------------------------------------------------------------
diff --git a/lib/runtime_tools/src/ttb_autostart.erl b/lib/runtime_tools/src/ttb_autostart.erl
new file mode 100644
index 0000000000..4c6971c119
--- /dev/null
+++ b/lib/runtime_tools/src/ttb_autostart.erl
@@ -0,0 +1,55 @@
+%%%-------------------------------------------------------------------
+%%% File : ttb_autostart.erl
+%%% Author : BartÅ‚omiej PuzoÅ„ <[email protected]>
+%%% Description : This supervisor is used to resume ttb tracing
+%%% Users are able to provide custom restart modules for *_config, as
+%%% file:write/read/delete may not be possible on diskless nodes.
+%%%
+%%% Created : 31 Jul 2010 by <[email protected]>
+%%%-------------------------------------------------------------------
+-module(ttb_autostart).
+
+-behaviour(gen_server).
+
+%% API
+-export([start_link/0,
+ read_config/0,
+ write_config/1,
+ delete_config/0]).
+
+%% gen_server callbacks
+-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
+ terminate/2, code_change/3]).
+
+-define(DEF_AUTOSTART_MODULE, ?MODULE).
+-define(AUTOSTART_FILENAME, "ttb_autostart.bin").
+
+start_link() ->
+ gen_server:start_link(?MODULE, no_args, []).
+
+delete_config() ->
+ file:delete(?AUTOSTART_FILENAME).
+
+read_config() ->
+ case file:read_file(?AUTOSTART_FILENAME) of
+ {ok, Data} -> {ok, binary_to_term(Data)};
+ Error -> Error
+ end.
+
+write_config(Data) ->
+ file:write_file(?AUTOSTART_FILENAME, term_to_binary(Data)).
+
+init(no_args) ->
+ case application:get_env(runtime_tools, ttb_autostart_module) of
+ {ok, _} -> ok;
+ undefined -> application:set_env(runtime_tools, ttb_autostart_module, ?DEF_AUTOSTART_MODULE)
+ end,
+ observer_backend:ttb_resume_trace(),
+ %%As the process is not needed any more, it will shut itself down
+ {ok, no_args, 10000}.
+
+handle_call(_,_,_) -> {noreply, no_args}.
+handle_cast(_,_) -> {noreply, no_args}.
+handle_info(timeout,_) -> {stop, normal, no_args}.
+terminate(_,_) -> ok.
+code_change(_,_,_) -> {ok, no_args}.
diff --git a/lib/runtime_tools/test/inviso_SUITE.erl b/lib/runtime_tools/test/inviso_SUITE.erl
index 3ae8d34dd6..758867cf45 100644
--- a/lib/runtime_tools/test/inviso_SUITE.erl
+++ b/lib/runtime_tools/test/inviso_SUITE.erl
@@ -1380,9 +1380,10 @@ fetch_log_dist_trace_2(Config) ->
io:format("~p~n",[NodeResults]),
CheckFun=fun({N,{complete,[{trace_log,FileResults1},{ti_log,[{ok,TiFile}]}]}}) ->
Fun2=fun({ok,File}) ->
- {match,1,_}=
- regexp:first_match(File,
- "^"++"p1"++Name++atom_to_list(N)),
+ match=
+ re:run(File,
+ "^"++"p1"++Name++atom_to_list(N),
+ [{capture,none}]),
true;
(_) ->
false
@@ -1425,8 +1426,8 @@ fetch_log_dist_trace_3(Config) ->
CheckFun=fun({N,{ok,[{trace_log,PrivDir2,[F1,F2]},{ti_log,PrivDir2,[F3]}]}})->
PrivDir2=PrivDir,
RegExp="^"++Name++atom_to_list(N)++"[0-9]+"++"\.log",
- {match,1,_}=regexp:first_match(F1,RegExp),
- {match,1,_}=regexp:first_match(F2,RegExp),
+ match=re:run(F1,RegExp,[{capture,none}]),
+ match=re:run(F2,RegExp,[{capture,none}]),
F3=Name++"_ti_"++atom_to_list(N)++".ti",
true;
(_) ->
@@ -1439,9 +1440,10 @@ fetch_log_dist_trace_3(Config) ->
io:format("~p~n",[NodeResults2]),
CheckFun2=fun({N,{complete,[{trace_log,FileResults1},{ti_log,[{ok,TiFile}]}]}}) ->
Fun2=fun({ok,File}) ->
- {match,1,_}=
- regexp:first_match(File,
- "^"++"p1"++Name++atom_to_list(N)),
+ match=
+ re:run(File,
+ "^"++"p1"++Name++atom_to_list(N),
+ [{capture,none}]),
true;
(_) ->
false
@@ -2649,8 +2651,8 @@ check_on_nodes([],_,_,_,_) ->
how_many_files_regexp([],_,N) ->
{ok,N};
how_many_files_regexp([FName|Rest],RegExp,N) ->
- case regexp:first_match(FName,RegExp) of
- {match,1,_} ->
+ case re:run(FName,RegExp,[{capture,none}]) of
+ match ->
how_many_files_regexp(Rest,RegExp,N+1);
nomatch ->
how_many_files_regexp(Rest,RegExp,N);
diff --git a/lib/sasl/doc/src/appup.xml b/lib/sasl/doc/src/appup.xml
index 89bcf23b5e..195f9fe1d3 100644
--- a/lib/sasl/doc/src/appup.xml
+++ b/lib/sasl/doc/src/appup.xml
@@ -319,12 +319,37 @@ point_of_no_return
<pre>
restart_new_emulator
</pre>
- <p>Shuts down the current emulator and starts a ne one. All
- processes are terminated gracefully. The new release must still
- be made permanent when the new emulator is up and running.
- Otherwise, the old emulator is started in case of a emulator
- restart. This instruction should be used when a new emulator is
- introduced, or if a complete reboot of the system should be done.</p>
+ <p>This instruction is used when erts, kernel, stdlib or sasl is
+ upgraded. It shuts down the current emulator and starts a new
+ one. All processes are terminated gracefully, and the new
+ version of erts, kernel, stdlib and sasl are used when the
+ emulator restarts. Only one <c>restart_new_emulator</c>
+ instruction is allowed in the relup, and it shall be placed
+ first. <seealso marker="systools#make_relup/3">systools:make_relup3,4</seealso>
+ will ensure this when the relup is generated. The rest of the
+ relup script is executed after the restart as a part of the boot
+ script.</p>
+ <p>An info report will be written when the upgrade is
+ completed. To programatically find out if the upgrade is
+ complete,
+ call <seealso marker="release_handler#which_release/0">
+ release_handler:which_releases</seealso> and check if the
+ expected release has status <c>current</c>.</p>
+ <p>The new release must still be made permanent after the upgrade
+ is completed. Otherwise, the old emulator is started in case of
+ an emulator restart.</p>
+ <pre>
+restart_emulator
+ </pre>
+ <p>This instruction is similar to <c>restart_new_emulator</c>,
+ except it shall be placed at the end of the relup script. It is
+ not related to an upgrade of the emulator or the core
+ applications, but can be used by any application when a complete
+ reboot of the system is reqiured. When generating the
+ relup, <seealso marker="systools#make_relup/3">systools:make_relup/3,4</seealso>
+ ensures that there is only one <c>restart_emulator</c>
+ instruction and that it is the last instruction of the
+ relup.</p>
</section>
<section>
diff --git a/lib/sasl/doc/src/make.dep b/lib/sasl/doc/src/make.dep
deleted file mode 100644
index 4843b7934a..0000000000
--- a/lib/sasl/doc/src/make.dep
+++ /dev/null
@@ -1,22 +0,0 @@
-# ----------------------------------------------------
-# >>>> Do not edit this file <<<<
-# This file was automaticly generated by
-# /home/otp/bin/docdepend
-# ----------------------------------------------------
-
-
-# ----------------------------------------------------
-# TeX files that the DVI file depend on
-# ----------------------------------------------------
-
-book.dvi: alarm_handler.tex appup.tex book.tex error_logging.tex \
- overload.tex part.tex rb.tex ref_man.tex rel.tex \
- release_handler.tex relup.tex sasl_app.tex \
- sasl_intro.tex script.tex systools.tex
-
-# ----------------------------------------------------
-# Source inlined when transforming from source to LaTeX
-# ----------------------------------------------------
-
-book.tex: ref_man.xml
-
diff --git a/lib/sasl/doc/src/release_handler.xml b/lib/sasl/doc/src/release_handler.xml
index 5ac0dc1acc..bd4a513750 100644
--- a/lib/sasl/doc/src/release_handler.xml
+++ b/lib/sasl/doc/src/release_handler.xml
@@ -238,7 +238,7 @@ old reboot_old permanent
</func>
<func>
<name>install_release(Vsn) -> {ok, OtherVsn, Descr} | {error, Reason}</name>
- <name>install_release(Vsn, [Opt]) -> {ok, OtherVsn, Descr} | {error, Reason}</name>
+ <name>install_release(Vsn, [Opt]) -> {ok, OtherVsn, Descr} | {continue_after_restart, OtherVsn, Descr} | {error, Reason}</name>
<fsummary>Install a release in the system.</fsummary>
<type>
<v>Vsn = OtherVsn = string()</v>
@@ -248,7 +248,8 @@ old reboot_old permanent
<v>&nbsp;Timeout = default | infinity | int()>0</v>
<v>&nbsp;Bool = boolean()</v>
<v>Descr = term()</v>
- <v>Reason = {illegal_option, Opt} | {already_installed, Vsn} | {change_appl_data, term()} | term()</v>
+ <v>Reason = {illegal_option, Opt} | {already_installed, Vsn} | {change_appl_data, term()} | {missing_base_app, OtherVsn, App} | {could_not_create_hybrid_boot, term()} | term()</v>
+ <v>App = atom()</v>
</type>
<desc>
<p>Installs the specified version <c>Vsn</c> of the release.
@@ -268,6 +269,15 @@ old reboot_old permanent
<c>OtherVsn</c> and <c>Descr</c> are the version
(<c>UpFromVsn</c> or <c>Vsn</c>) and description
(<c>Descr1</c> or <c>Descr2</c>) as specified in the script.</p>
+ <p>If <c>{continue_after_restart,OtherVsn,Descr}</c> is
+ returned, it means that the emulator will be restarted
+ before the upgrade instructions are executed. This will
+ happen if the emulator or any of the applications kernel,
+ stdlib or sasl are updated. The new version of the emulator
+ and these core applications will execute after the restart,
+ but for all other applications the old versions will be
+ started and the upgrade will be performed as normal by
+ executing the upgrade instructions.</p>
<p>If a recoverable error occurs, the function returns
<c>{error,Reason}</c> and the original application
specifications are restored. If a non-recoverable error
@@ -325,6 +335,18 @@ release_handler:set_unpacked(RelFile, [{myapp,"1.0","/home/user"},...]).
upgrade, but it will allow checks and purge to be executed
in the background before the real upgrade is started.</p>
</note>
+ <note>
+ <p>When upgrading the emulator from a version older than OTP
+ R15, there will be an attempt to load new application beam
+ code into the old emulator. In some cases, the new beam
+ format can not be read by the old emulator, and so the code
+ loading will fail and terminate the complete upgrade. To
+ overcome this problem, the new application code should be
+ compiled with the old emulator. See <seealso
+ marker="doc/design_principles:appup_cookbook">Design
+ Principles</seealso> for more information about emulator
+ upgrade from pre OTP R15 versions.</p>
+ </note>
</desc>
</func>
<func>
@@ -431,6 +453,18 @@ release_handler:set_unpacked(RelFile, [{myapp,"1.0","/home/user"},...]).
<p>Returns all releases known to the release handler.</p>
</desc>
</func>
+ <func>
+ <name>which_releases(Status) -> [{Name, Vsn, Apps, Status}]</name>
+ <fsummary>Return all known releases of a specific status</fsummary>
+ <type>
+ <v>Name = Vsn = string()</v>
+ <v>Apps = ["App-Vsn"]</v>
+ <v>Status = unpacked | current | permanent | old</v>
+ </type>
+ <desc>
+ <p>Returns all releases known to the release handler of a specific status.</p>
+ </desc>
+ </func>
</funcs>
<section>
@@ -442,7 +476,7 @@ release_handler:set_unpacked(RelFile, [{myapp,"1.0","/home/user"},...]).
and evaluated exactly in the same way as <c>release_handler</c>
does.</p>
<warning>
- <p>These function is primarily intended for simplified testing of
+ <p>These functions are primarily intended for simplified testing
of <c>.appup</c> files. They are not run within the context of
the <c>release_handler</c> process. They must therefore
<em>not</em> be used together with calls to
@@ -458,7 +492,7 @@ release_handler:set_unpacked(RelFile, [{myapp,"1.0","/home/user"},...]).
</section>
<funcs>
<func>
- <name>upgrade_app(App, Dir) -> {ok, Unpurged} | restart_new_emulator | {error, Reason}</name>
+ <name>upgrade_app(App, Dir) -> {ok, Unpurged} | restart_emulator | {error, Reason}</name>
<fsummary>Upgrade to a new application version</fsummary>
<type>
<v>App = atom()</v>
@@ -487,14 +521,21 @@ release_handler:set_unpacked(RelFile, [{myapp,"1.0","/home/user"},...]).
does.</p>
<p>Returns <c>{ok, Unpurged}</c> if evaluating the script is
successful, where <c>Unpurged</c> is a list of unpurged
- modules, or <c>restart_new_emulator</c> if this instruction is
+ modules, or <c>restart_emulator</c> if this instruction is
encountered in the script, or <c>{error, Reason}</c> if
an error occurred when finding or evaluating the script.</p>
+ <p>If the <c>restart_new_emulator</c> instruction is found in
+ the script, <c>upgrade_app/2</c> will return
+ <c>{error,restart_new_emulator}</c>. The reason for this is
+ that this instruction requires that a new version of the
+ emulator is started before the rest of the upgrade
+ instructions can be executed, and this can only be done by
+ <c>install_release/1,2</c>.</p>
</desc>
</func>
<func>
<name>downgrade_app(App, Dir) -></name>
- <name>downgrade_app(App, OldVsn, Dir) -> {ok, Unpurged} | restart_new_emulator | {error, Reason}</name>
+ <name>downgrade_app(App, OldVsn, Dir) -> {ok, Unpurged} | restart_emulator | {error, Reason}</name>
<fsummary>Downgrade to a previous application version</fsummary>
<type>
<v>App = atom()</v>
@@ -528,7 +569,7 @@ release_handler:set_unpacked(RelFile, [{myapp,"1.0","/home/user"},...]).
does.</p>
<p>Returns <c>{ok, Unpurged}</c> if evaluating the script is
successful, where <c>Unpurged</c> is a list of unpurged
- modules, or <c>restart_new_emulator</c> if this instruction is
+ modules, or <c>restart_emulator</c> if this instruction is
encountered in the script, or <c>{error, Reason}</c> if
an error occurred when finding or evaluating the script.</p>
</desc>
@@ -604,7 +645,7 @@ release_handler:set_unpacked(RelFile, [{myapp,"1.0","/home/user"},...]).
</desc>
</func>
<func>
- <name>eval_appup_script(App, ToVsn, ToDir, Script) -> {ok, Unpurged} | restart_new_emulator | {error, Reason}</name>
+ <name>eval_appup_script(App, ToVsn, ToDir, Script) -> {ok, Unpurged} | restart_emulator | {error, Reason}</name>
<fsummary>Evaluate an application upgrade or downgrade script</fsummary>
<type>
<v>App = atom()</v>
@@ -617,8 +658,8 @@ release_handler:set_unpacked(RelFile, [{myapp,"1.0","/home/user"},...]).
<desc>
<p>Evaluates an application upgrade or downgrade script
<c>Script</c>, the result from calling
- <seealso marker="#upgrade_app/2">upgrade_app/2</seealso> or
- <seealso marker="#downgrade_app/3">downgrade_app/2,3</seealso>,
+ <seealso marker="#upgrade_app/2">upgrade_script/2</seealso> or
+ <seealso marker="#downgrade_app/3">downgrade_script/3</seealso>,
exactly in the same way as
<seealso marker="#install_release/1">install_release/1,2</seealso>
does.</p>
@@ -629,9 +670,16 @@ release_handler:set_unpacked(RelFile, [{myapp,"1.0","/home/user"},...]).
<c>.appup</c> files should be located under <c>Dir/ebin</c>.</p>
<p>Returns <c>{ok, Unpurged}</c> if evaluating the script is
successful, where <c>Unpurged</c> is a list of unpurged
- modules, or <c>restart_new_emulator</c> if this instruction is
+ modules, or <c>restart_emulator</c> if this instruction is
encountered in the script, or <c>{error, Reason}</c> if
an error occurred when evaluating the script.</p>
+ <p>If the <c>restart_new_emulator</c> instruction is found in
+ the script, <c>eval_appup_script/4</c> will return
+ <c>{error,restart_new_emulator}</c>. The reason for this is
+ that this instruction requires that a new version of the
+ emulator is started before the rest of the upgrade
+ instructions can be executed, and this can only be done by
+ <c>install_release/1,2</c>.</p>
</desc>
</func>
</funcs>
diff --git a/lib/sasl/doc/src/systools.xml b/lib/sasl/doc/src/systools.xml
index 8c1c327d74..1b90f0d4ee 100644
--- a/lib/sasl/doc/src/systools.xml
+++ b/lib/sasl/doc/src/systools.xml
@@ -111,6 +111,11 @@
low-level instruction to restart the emulator is appended to
the relup scripts. This ensures that a complete reboot of
the system is done when the system is upgraded or downgraded.</p>
+ <p>If an upgrade includes a change from an emulator earlier
+ than OTP R15 to OTP R15 or later, the warning
+ <c>pre_R15_emulator_upgrade</c> is issued. See <seealso
+ marker="doc/design_principles:appup_cookbook">Design
+ Principles</seealso> for more information about this.</p>
<p>By default, errors and warnings are printed to tty and
the function returns <c>ok</c> or <c>error</c>. If the option
<c>silent</c> is provided, the function instead returns
@@ -133,8 +138,9 @@
<fsummary>Generate a boot script <c>.script/.boot</c>.</fsummary>
<type>
<v>Name = string()</v>
- <v>Opt = src_tests | {path,[Dir]} | local | {variables,[Var]} | exref | {exref,[App]}]
- | silent | {outdir,Dir} | warnings_as_errors</v>
+ <v>Opt = src_tests | {path,[Dir]} | local | {variables,[Var]} | exref |
+ {exref,[App]}] | silent | {outdir,Dir} | no_warn_sasl |
+ warnings_as_errors</v>
<v>&nbsp;Dir = string()</v>
<v>&nbsp;Var = {VarName,Prefix}</v>
<v>&nbsp;&nbsp;VarName = Prefix = string()</v>
@@ -190,6 +196,10 @@
<p>The applications are sorted according to the dependencies
between the applications. Where there are no dependencies,
the order in the <c>.rel</c> file is kept.</p>
+ <p>If <c>sasl</c> is not included as an application in
+ the <c>.rel</c> file, a warning is emitted because such a
+ release can not be used in an upgrade. To turn of this
+ warning, add the option <c>no_warn_sasl</c>.</p>
<p>All files are searched for in the current path. It is
assumed that the <c>.app</c> and <c>.beam</c> files for an
application is located in the same directory. The <c>.erl</c>
@@ -220,7 +230,7 @@
<p>Example: If the option <c>{variables,[{"TEST","lib"}]}</c> is
supplied, and <c>myapp.app</c> is found in
<c>lib/myapp/ebin</c>, then the path to this application in
- the boot script will be <c>$TEST/myapp-1/ebin"</c>. If
+ the boot script will be <c>"$TEST/myapp-1/ebin"</c>. If
<c>myapp.app</c> is found in <c>lib/test</c>, then the path
will be <c>$TEST/test/myapp-1/ebin</c>.</p>
<p>The checks performed before the boot script is generated can
diff --git a/lib/sasl/examples/src/target_system.erl b/lib/sasl/examples/src/target_system.erl
index 0e1e0b2324..ffc0fcf443 100644
--- a/lib/sasl/examples/src/target_system.erl
+++ b/lib/sasl/examples/src/target_system.erl
@@ -16,6 +16,7 @@
%%
%% %CopyrightEnd%
%%
+%module
-module(target_system).
-export([create/1, create/2, install/2]).
@@ -130,14 +131,14 @@ install(RelFileName, RootDir) ->
[ErlVsn, _RelVsn| _] = string:tokens(StartErlData, " \n"),
ErtsBinDir = filename:join([RootDir, "erts-" ++ ErlVsn, "bin"]),
BinDir = filename:join([RootDir, "bin"]),
- io:fwrite("Substituting in erl.src, start.src and start_erl.src to\n"
+ io:fwrite("Substituting in erl.src, start.src and start_erl.src to "
"form erl, start and start_erl ...\n"),
subst_src_scripts(["erl", "start", "start_erl"], ErtsBinDir, BinDir,
[{"FINAL_ROOTDIR", RootDir}, {"EMU", "beam"}],
[preserve]),
io:fwrite("Creating the RELEASES file ...\n"),
- create_RELEASES(RootDir,
- filename:join([RootDir, "releases", RelFileName])).
+ create_RELEASES(RootDir, filename:join([RootDir, "releases",
+ filename:basename(RelFileName)])).
%% LOCALS
@@ -257,3 +258,4 @@ remove_all_files(Dir, Files) ->
file:delete(FilePath)
end
end, Files).
+%module
diff --git a/lib/sasl/src/release_handler.erl b/lib/sasl/src/release_handler.erl
index bc08f94dff..522c7b496b 100644
--- a/lib/sasl/src/release_handler.erl
+++ b/lib/sasl/src/release_handler.erl
@@ -26,8 +26,9 @@
create_RELEASES/1, create_RELEASES/2, create_RELEASES/4,
unpack_release/1,
check_install_release/1, check_install_release/2,
- install_release/1, install_release/2, remove_release/1,
- which_releases/0, make_permanent/1, reboot_old_release/1,
+ install_release/1, install_release/2, new_emulator_upgrade/2,
+ remove_release/1, which_releases/0, which_releases/1,
+ make_permanent/1, reboot_old_release/1,
set_unpacked/2, set_removed/1, install_file/2]).
-export([upgrade_app/2, downgrade_app/2, downgrade_app/3,
upgrade_script/2, downgrade_script/3,
@@ -40,7 +41,7 @@
%% Internal exports, a client release_handler may call this functions.
-export([do_write_release/3, do_copy_file/2, do_copy_files/2,
do_copy_files/1, do_rename_files/1, do_remove_files/1,
- do_write_file/2, do_ensure_RELEASES/1]).
+ remove_file/1, do_write_file/2, do_ensure_RELEASES/1]).
-record(state, {unpurged = [],
root,
@@ -61,10 +62,11 @@
%% remove -
%% current make_permanent permanent
%% install other old
+%% restart node unpacked
%% remove -
%% permanent make other permanent old
%% install permanent
-%% old reboot permanen
+%% old reboot_old permanent
%% install current
%% remove -
%%-----------------------------------------------------------------
@@ -74,6 +76,14 @@
-define(timeout, 10000).
%%-----------------------------------------------------------------
+%% The version set on the temporary release that will be used when the
+%% emulator is upgraded.
+-define(tmp_vsn(__BaseVsn__), "__new_emulator__"++__BaseVsn__).
+
+
+
+
+%%-----------------------------------------------------------------
%% Assumes the following file structure:
%% root --- lib --- Appl-Vsn1 --- <src>
%% | | |- ebin
@@ -183,11 +193,15 @@ check_check_install_options([],Purge) ->
%%-----------------------------------------------------------------
%% Purpose: Executes the relup script for the specified version.
%% The release must be unpacked.
-%% Returns: {ok, FromVsn, Descr} | {error, Reason}
+%% Returns: {ok, FromVsn, Descr} |
+%% {continue_after_restart, FromVsn, Descr} |
+%% {error, Reason}
%% Reason = {already_installed, Vsn} |
%% {bad_relup_file, RelFile} |
%% {no_such_release, Vsn} |
%% {no_such_from_vsn, Vsn} |
+%% {could_not_create_hybrid_boot,Why} |
+%% {missing_base_app,Vsn,App} |
%% {illegal_option, Opt}} |
%% exit_reason()
%%-----------------------------------------------------------------
@@ -230,6 +244,21 @@ check_timeout(Int) when is_integer(Int), Int > 0 -> true;
check_timeout(_Else) -> false.
%%-----------------------------------------------------------------
+%% Purpose: Called by boot script after emulator is restarted due to
+%% new erts version.
+%% Returns: Same as install_release/2
+%% If this crashes, the emulator restart will fail
+%% (since the function is called from the boot script)
+%% and there will be a rollback.
+%%-----------------------------------------------------------------
+new_emulator_upgrade(Vsn, Opts) ->
+ Result = call({install_release, Vsn, reboot, Opts}),
+ error_logger:info_msg(
+ "~p:install_release(~p,~p) completed after node restart "
+ "with new emulator version~nResult: ~p~n",[?MODULE,Vsn,Opts,Result]),
+ Result.
+
+%%-----------------------------------------------------------------
%% Purpose: Makes the specified release version be the one that is
%% used when the system starts (or restarts).
%% The release must be installed (not unpacked).
@@ -305,6 +334,14 @@ which_releases() ->
call(which_releases).
%%-----------------------------------------------------------------
+%% Returns: [{Name, Vsn, [LibName], Status}]
+%% Status = unpacked | current | permanent | old
+%%-----------------------------------------------------------------
+which_releases(Status) ->
+ Releases = which_releases(),
+ get_releases_with_status(Releases, Status, []).
+
+%%-----------------------------------------------------------------
%% check_script(Script, LibDirs) -> ok | {error, Reason}
%%-----------------------------------------------------------------
check_script(Script, LibDirs) ->
@@ -313,7 +350,7 @@ check_script(Script, LibDirs) ->
%%-----------------------------------------------------------------
%% eval_script(Script, Apps, LibDirs, NewLibs, Opts) ->
%% {ok, UnPurged} |
-%% restart_new_emulator |
+%% restart_emulator |
%% {error, Error}
%% {'EXIT', Reason}
%% If sync_nodes is present, the calling process must have called
@@ -350,7 +387,7 @@ create_RELEASES(Root, RelDir, RelFile, LibDirs) ->
%%-----------------------------------------------------------------
%% Func: upgrade_app(App, Dir) -> {ok, Unpurged}
-%% | restart_new_emulator
+%% | restart_emulator
%% | {error, Error}
%% Types:
%% App = atom()
@@ -370,7 +407,7 @@ upgrade_app(App, NewDir) ->
%%-----------------------------------------------------------------
%% Func: downgrade_app(App, Dir)
%% downgrade_app(App, Vsn, Dir) -> {ok, Unpurged}
-%% | restart_new_emulator
+%% | restart_emulator
%% | {error, Error}
%% Types:
%% App = atom()
@@ -578,7 +615,7 @@ handle_call({check_install_release, Vsn, Purge}, _From, S) ->
handle_call({install_release, Vsn, ErrorAction, Opts}, From, S) ->
NS = resend_sync_nodes(S),
case catch do_install_release(S, Vsn, Opts) of
- {ok, NewReleases, CurrentVsn, Descr} ->
+ {ok, NewReleases, [], CurrentVsn, Descr} ->
{reply, {ok, CurrentVsn, Descr}, NS#state{releases=NewReleases}};
{ok, NewReleases, Unpurged, CurrentVsn, Descr} ->
Timer =
@@ -593,10 +630,14 @@ handle_call({install_release, Vsn, ErrorAction, Opts}, From, S) ->
{reply, {ok, CurrentVsn, Descr}, NewS};
{error, Reason} ->
{reply, {error, Reason}, NS};
- {restart_new_emulator, CurrentVsn, Descr} ->
+ {restart_emulator, CurrentVsn, Descr} ->
gen_server:reply(From, {ok, CurrentVsn, Descr}),
init:reboot(),
{noreply, NS};
+ {restart_new_emulator, CurrentVsn, Descr} ->
+ gen_server:reply(From, {continue_after_restart, CurrentVsn, Descr}),
+ init:reboot(),
+ {noreply, NS};
{'EXIT', Reason} ->
io:format("release_handler:"
"install_release(Vsn=~p Opts=~p) failed, "
@@ -801,8 +842,13 @@ do_unpack_release(Root, RelDir, ReleaseName, Releases) ->
extract_tar(Root, Tar),
NewReleases = [Release#release{status = unpacked} | Releases],
write_releases(RelDir, NewReleases, false),
+
+ %% Keeping this for backwards compatibility reasons with older
+ %% systools:make_tar, where there is no copy of the .rel file in
+ %% the releases/<vsn> dir. See OTP-9746.
Dir = filename:join([RelDir, Vsn]),
copy_file(RelFile, Dir, false),
+
{ok, NewReleases, Vsn}.
%% Note that this function is not executed by a client
@@ -941,7 +987,38 @@ do_install_release(#state{start_prg = StartPrg,
{value, Release} ->
LatestRelease = get_latest_release(Releases),
case get_rh_script(LatestRelease, Release, RelDir, Masters) of
+ {ok, {_CurrentVsn, _Descr, [restart_new_emulator|_Script]}}
+ when Static == true ->
+ throw(static_emulator);
+ {ok, {CurrentVsn, Descr, [restart_new_emulator|_Script]}} ->
+ %% This will only happen if the upgrade includes
+ %% an emulator upgrade (and it is not a downgrade)
+ %% - then the new emulator must be started before
+ %% new code can be loaded.
+ %% Create a temporary release which includes new
+ %% emulator, kernel, stdlib and sasl - and old
+ %% versions of other applications.
+ {TmpVsn,TmpRelease} =
+ new_emulator_make_tmp_release(LatestRelease,Release,
+ RelDir,Opts,Masters),
+ NReleases = [TmpRelease|Releases],
+
+ %% Then uppgrade to the temporary release.
+ %% The rest of the upgrade will continue after the restart
+ prepare_restart_new_emulator(StartPrg, RootDir,
+ RelDir, TmpVsn, TmpRelease,
+ NReleases, Masters),
+ {restart_new_emulator, CurrentVsn, Descr};
{ok, {CurrentVsn, Descr, Script}} ->
+ %% In case there has been an emulator upgrade,
+ %% remove the temporary release
+ NReleases =
+ new_emulator_rm_tmp_release(
+ LatestRelease#release.vsn,
+ LatestRelease#release.erts_vsn,
+ Vsn,RelDir,Releases,Masters),
+
+ %% Then execute the relup script
mon_nodes(true),
EnvBefore = application_controller:prep_config_change(),
Apps = change_appl_data(RelDir, Release, Masters),
@@ -949,31 +1026,19 @@ do_install_release(#state{start_prg = StartPrg,
NewLibs = get_new_libs(LatestRelease#release.libs,
Release#release.libs),
case eval_script(Script, Apps, LibDirs, NewLibs, Opts) of
- {ok, []} ->
- application_controller:config_change(EnvBefore),
- mon_nodes(false),
- NewReleases = set_status(Vsn, current, Releases),
- {ok, NewReleases, CurrentVsn, Descr};
{ok, Unpurged} ->
application_controller:config_change(EnvBefore),
mon_nodes(false),
- NewReleases = set_status(Vsn, current, Releases),
- {ok, NewReleases, Unpurged, CurrentVsn, Descr};
- restart_new_emulator when Static == true ->
+ NReleases1 = set_status(Vsn, current, NReleases),
+ {ok, NReleases1, Unpurged, CurrentVsn, Descr};
+ restart_emulator when Static == true ->
throw(static_emulator);
- restart_new_emulator ->
+ restart_emulator ->
mon_nodes(false),
- {value, PermanentRelease} =
- lists:keysearch(permanent, #release.status,
- Releases),
- NReleases = set_status(Vsn, current, Releases),
- NReleases2 = set_status(Vsn,tmp_current,NReleases),
- write_releases(RelDir, NReleases2, Masters),
prepare_restart_new_emulator(StartPrg, RootDir,
- RelDir, Release,
- PermanentRelease,
- Masters),
- {restart_new_emulator, CurrentVsn, Descr};
+ RelDir, Vsn, Release,
+ NReleases, Masters),
+ {restart_emulator, CurrentVsn, Descr};
Else ->
application_controller:config_change(EnvBefore),
mon_nodes(false),
@@ -986,6 +1051,158 @@ do_install_release(#state{start_prg = StartPrg,
{error, {no_such_release, Vsn}}
end.
+new_emulator_make_tmp_release(CurrentRelease,ToRelease,RelDir,Opts,Masters) ->
+ CurrentVsn = CurrentRelease#release.vsn,
+ ToVsn = ToRelease#release.vsn,
+ TmpVsn = ?tmp_vsn(CurrentVsn),
+ case get_base_libs(ToRelease#release.libs) of
+ {ok,{Kernel,Stdlib,Sasl}=BaseLibs,_} ->
+ case get_base_libs(ToRelease#release.libs) of
+ {ok,_,RestLibs} ->
+ TmpErtsVsn = ToRelease#release.erts_vsn,
+ TmpLibs = [Kernel,Stdlib,Sasl|RestLibs],
+ TmpRelease = CurrentRelease#release{vsn=TmpVsn,
+ erts_vsn=TmpErtsVsn,
+ libs = TmpLibs,
+ status = unpacked},
+ new_emulator_make_hybrid_boot(CurrentVsn,ToVsn,TmpVsn,
+ BaseLibs,RelDir,Opts,Masters),
+ new_emulator_make_hybrid_config(CurrentVsn,ToVsn,TmpVsn,
+ RelDir,Masters),
+ {TmpVsn,TmpRelease};
+ {error,{missing,Missing}} ->
+ throw({error,{missing_base_app,CurrentVsn,Missing}})
+ end;
+ {error,{missing,Missing}} ->
+ throw({error,{missing_base_app,ToVsn,Missing}})
+ end.
+
+%% Get kernel, stdlib and sasl libs,
+%% and also return the rest of the libs as a list.
+%% Return error if any of kernel, stdlib or sasl does not exist.
+get_base_libs(Libs) ->
+ get_base_libs(Libs,undefined,undefined,undefined,[]).
+get_base_libs([{kernel,_,_}=Kernel|Libs],undefined,Stdlib,Sasl,Rest) ->
+ get_base_libs(Libs,Kernel,Stdlib,Sasl,Rest);
+get_base_libs([{stdlib,_,_}=Stdlib|Libs],Kernel,undefined,Sasl,Rest) ->
+ get_base_libs(Libs,Kernel,Stdlib,Sasl,Rest);
+get_base_libs([{sasl,_,_}=Sasl|Libs],Kernel,Stdlib,undefined,Rest) ->
+ get_base_libs(Libs,Kernel,Stdlib,Sasl,Rest);
+get_base_libs([Lib|Libs],Kernel,Stdlib,Sasl,Rest) ->
+ get_base_libs(Libs,Kernel,Stdlib,Sasl,[Lib|Rest]);
+get_base_libs([],undefined,_Stdlib,_Sasl,_Rest) ->
+ {error,{missing,kernel}};
+get_base_libs([],_Kernel,undefined,_Sasl,_Rest) ->
+ {error,{missing,stdlib}};
+get_base_libs([],_Kernel,_Stdlib,undefined,_Rest) ->
+ {error,{missing,sasl}};
+get_base_libs([],Kernel,Stdlib,Sasl,Rest) ->
+ {ok,{Kernel,Stdlib,Sasl},lists:reverse(Rest)}.
+
+new_emulator_make_hybrid_boot(CurrentVsn,ToVsn,TmpVsn,BaseLibs,RelDir,Opts,Masters) ->
+ FromBootFile = filename:join([RelDir,CurrentVsn,"start.boot"]),
+ ToBootFile = filename:join([RelDir,ToVsn,"start.boot"]),
+ TmpBootFile = filename:join([RelDir,TmpVsn,"start.boot"]),
+ ensure_dir(TmpBootFile,Masters),
+ Args = [ToVsn,Opts],
+ {ok,FromBoot} = read_file(FromBootFile,Masters),
+ {ok,ToBoot} = read_file(ToBootFile,Masters),
+ {{_,_,KernelPath},{_,_,SaslPath},{_,_,StdlibPath}} = BaseLibs,
+ Paths = {filename:join(KernelPath,"ebin"),
+ filename:join(StdlibPath,"ebin"),
+ filename:join(SaslPath,"ebin")},
+ case systools_make:make_hybrid_boot(TmpVsn,FromBoot,ToBoot,Paths,Args) of
+ {ok,TmpBoot} ->
+ write_file(TmpBootFile,TmpBoot,Masters);
+ {error,Reason} ->
+ throw({error,{could_not_create_hybrid_boot,Reason}})
+ end.
+
+new_emulator_make_hybrid_config(CurrentVsn,ToVsn,TmpVsn,RelDir,Masters) ->
+ FromFile = filename:join([RelDir,CurrentVsn,"sys.config"]),
+ ToFile = filename:join([RelDir,ToVsn,"sys.config"]),
+ TmpFile = filename:join([RelDir,TmpVsn,"sys.config"]),
+
+ FromConfig =
+ case consult(FromFile,Masters) of
+ {ok,[FC]} ->
+ FC;
+ {error,Error1} ->
+ io:format("Warning: ~p can not read ~p: ~p~n",
+ [?MODULE,FromFile,Error1]),
+ []
+ end,
+
+ [Kernel,Stdlib,Sasl] =
+ case consult(ToFile,Masters) of
+ {ok,[ToConfig]} ->
+ [lists:keyfind(App,1,ToConfig) || App <- [kernel,stdlib,sasl]];
+ {error,Error2} ->
+ io:format("Warning: ~p can not read ~p: ~p~n",
+ [?MODULE,ToFile,Error2]),
+ [false,false,false]
+ end,
+
+ Config1 = replace_config(kernel,FromConfig,Kernel),
+ Config2 = replace_config(stdlib,Config1,Stdlib),
+ Config3 = replace_config(sasl,Config2,Sasl),
+
+ ConfigStr = io_lib:format("~p.~n",[Config3]),
+ write_file(TmpFile,ConfigStr,Masters).
+
+%% Take the configuration for application App from the new config and
+%% insert in the old config.
+%% If no entry exists in the new config, then delete the entry (if it exists)
+%% from the old config.
+%% If entry exists in the new config, but not in the old config, then
+%% add the entry.
+replace_config(App,Config,false) ->
+ lists:keydelete(App,1,Config);
+replace_config(App,Config,AppConfig) ->
+ lists:keystore(App,1,Config,AppConfig).
+
+%% Remove all files related to the temporary release
+new_emulator_rm_tmp_release(?tmp_vsn(_)=TmpVsn,EVsn,NewVsn,
+ RelDir,Releases,Masters) ->
+ case os:type() of
+ {win32, nt} ->
+ rename_tmp_service(EVsn,TmpVsn,NewVsn);
+ _ ->
+ ok
+ end,
+ remove_dir(filename:join(RelDir,TmpVsn),Masters),
+ lists:keydelete(TmpVsn,#release.vsn,Releases);
+new_emulator_rm_tmp_release(_,_,_,_,Releases,_) ->
+ Releases.
+
+%% Rename the tempoarary service (for erts ugprade) to the real ToVsn
+rename_tmp_service(EVsn,TmpVsn,NewVsn) ->
+ FromName = hd(string:tokens(atom_to_list(node()),"@")) ++ "_" ++ TmpVsn,
+ ToName = hd(string:tokens(atom_to_list(node()),"@")) ++ "_" ++ NewVsn,
+ case erlsrv:get_service(EVsn,ToName) of
+ {error, _Error} ->
+ ok;
+ _Data ->
+ erlsrv:remove_service(ToName)
+ end,
+ rename_service(EVsn,FromName,ToName).
+
+
+%% Rename a service and check that it succeeded
+rename_service(EVsn,FromName,ToName) ->
+ case erlsrv:rename_service(EVsn,FromName,ToName) of
+ {ok,_} ->
+ case erlsrv:get_service(EVsn,ToName) of
+ {error,Error1} ->
+ throw({error,Error1});
+ _Data2 ->
+ ok
+ end;
+ Error2 ->
+ throw({error,{service_rename_failed, Error2}})
+ end.
+
+
%%% This code chunk updates the services in one of two ways,
%%% Either the emulator is restarted, in which case the old service
%%% is to be removed and the new enabled, or the emulator is NOT restarted
@@ -1002,26 +1219,16 @@ do_make_services_permanent(PermanentVsn,Vsn, PermanentEVsn, EVsn) ->
%% rename.
case os:getenv("ERLSRV_SERVICE_NAME") == PermName of
true ->
- case erlsrv:rename_service(EVsn,PermName,Name) of
- {ok,_} ->
- case erlsrv:get_service(EVsn,Name) of
- {error,Error2} ->
- throw({error,Error2});
- _Data2 ->
- %% The interfaces for doing this are
- %% NOT published and may be subject to
- %% change. Do NOT do this anywhere else!
-
- os:putenv("ERLSRV_SERVICE_NAME", Name),
-
- %% Restart heart port program, this
- %% function is only to be used here.
- heart:cycle(),
- ok
- end;
- Error3 ->
- throw({error,{service_rename_failed, Error3}})
- end;
+ rename_service(EVsn,PermName,Name),
+ %% The interfaces for doing this are
+ %% NOT published and may be subject to
+ %% change. Do NOT do this anywhere else!
+
+ os:putenv("ERLSRV_SERVICE_NAME", Name),
+
+ %% Restart heart port program, this
+ %% function is only to be used here.
+ heart:cycle();
false ->
throw({error,service_name_missmatch})
end;
@@ -1260,21 +1467,31 @@ do_set_removed(RelDir, Vsn, Releases, Masters) ->
%% corresponding relup instructions, we check if it's possible to
%% downgrade from CurrentVsn to ToVsn.
%%-----------------------------------------------------------------
+get_rh_script(#release{vsn = ?tmp_vsn(CurrentVsn)},
+ #release{vsn = ToVsn},
+ RelDir,
+ Masters) ->
+ {ok,{Vsn,Descr,[restart_new_emulator|Script]}} =
+ do_get_rh_script(CurrentVsn,ToVsn,RelDir,Masters),
+ {ok,{Vsn,Descr,Script}};
get_rh_script(#release{vsn = CurrentVsn},
- #release{vsn = Vsn},
+ #release{vsn = ToVsn},
RelDir,
Masters) ->
- Relup = filename:join([RelDir, Vsn, "relup"]),
- case try_upgrade(Vsn, CurrentVsn, Relup, Masters) of
+ do_get_rh_script(CurrentVsn,ToVsn,RelDir,Masters).
+
+do_get_rh_script(CurrentVsn, ToVsn, RelDir, Masters) ->
+ Relup = filename:join([RelDir, ToVsn, "relup"]),
+ case try_upgrade(ToVsn, CurrentVsn, Relup, Masters) of
{ok, RhScript} ->
{ok, RhScript};
_ ->
Relup2 = filename:join([RelDir, CurrentVsn,"relup"]),
- case try_downgrade(Vsn, CurrentVsn, Relup2, Masters) of
+ case try_downgrade(ToVsn, CurrentVsn, Relup2, Masters) of
{ok, RhScript} ->
{ok, RhScript};
_ ->
- throw({error, {no_matching_relup, Vsn, CurrentVsn}})
+ throw({error, {no_matching_relup, ToVsn, CurrentVsn}})
end
end.
@@ -1487,6 +1704,15 @@ prepare_restart_nt(#release{erts_vsn = EVsn, vsn = Vsn},
%% restart is performed by calling init:reboot() higher up.
%%-----------------------------------------------------------------
prepare_restart_new_emulator(StartPrg, RootDir, RelDir,
+ Vsn, Release, Releases, Masters) ->
+ {value, PRelease} = lists:keysearch(permanent, #release.status,Releases),
+ NReleases1 = set_status(Vsn, current, Releases),
+ NReleases2 = set_status(Vsn,tmp_current,NReleases1),
+ write_releases(RelDir, NReleases2, Masters),
+ prepare_restart_new_emulator(StartPrg, RootDir, RelDir,
+ Release, PRelease, Masters).
+
+prepare_restart_new_emulator(StartPrg, RootDir, RelDir,
Release, PRelease, Masters) ->
#release{erts_vsn = EVsn, vsn = Vsn} = Release,
Data = EVsn ++ " " ++ Vsn,
@@ -1512,19 +1738,10 @@ check_start_prg({do_check, StartPrg}, Masters) ->
check_start_prg({_, StartPrg}, _) ->
StartPrg.
-write_new_start_erl(Data, RelDir, false) ->
- DataFile = filename:join([RelDir, "new_start_erl.data"]),
- case do_write_file(DataFile, Data) of
- ok -> DataFile;
- Error -> throw(Error)
- end;
write_new_start_erl(Data, RelDir, Masters) ->
DataFile = filename:join([RelDir, "new_start_erl.data"]),
- case at_all_masters(Masters, ?MODULE, do_write_file,
- [DataFile, Data]) of
- ok -> DataFile;
- Error -> throw(Error)
- end.
+ write_file(DataFile, Data, Masters),
+ DataFile.
%%-----------------------------------------------------------------
%% When a new emulator shall be restarted, the current release
@@ -1538,27 +1755,41 @@ write_new_start_erl(Data, RelDir, Masters) ->
%% If the release is made permanent, this is written to disk.
%%-----------------------------------------------------------------
transform_release(ReleaseDir, Releases, Masters) ->
- F = fun(Release) when Release#release.status == tmp_current ->
- Release#release{status = unpacked};
- (Release) -> Release
- end,
- case lists:map(F, Releases) of
- Releases ->
- Releases;
- DReleases ->
+ case init:script_id() of
+ {Name, ?tmp_vsn(_)=TmpVsn} ->
+ %% This is was a reboot due to a new emulator version. The
+ %% current release is a temporary internal release, which
+ %% must be removed. It is the "real new release" that is
+ %% set to unpacked on disk and current in memory.
+ DReleases = lists:keydelete(TmpVsn,#release.vsn,Releases),
write_releases(ReleaseDir, DReleases, Masters),
- F1 = fun(Release) when Release#release.status == tmp_current ->
- case init:script_id() of
- {_Name, Vsn} when Release#release.vsn == Vsn ->
- Release#release{status = current};
- _ ->
- Release#release{status = unpacked}
- end;
- (Release) -> Release
- end,
- lists:map(F1, Releases)
+ set_current({Name,TmpVsn},Releases);
+ ScriptId ->
+ F = fun(Release) when Release#release.status == tmp_current ->
+ Release#release{status = unpacked};
+ (Release) -> Release
+ end,
+ case lists:map(F, Releases) of
+ Releases ->
+ Releases;
+ DReleases ->
+ write_releases(ReleaseDir, DReleases, Masters),
+ set_current(ScriptId, Releases)
+ end
end.
+set_current(ScriptId, Releases) ->
+ F1 = fun(Release) when Release#release.status == tmp_current ->
+ case ScriptId of
+ {_Name,Vsn} when Release#release.vsn == Vsn ->
+ Release#release{status = current};
+ _ ->
+ Release#release{status = unpacked}
+ end;
+ (Release) -> Release
+ end,
+ lists:map(F1, Releases).
+
%%-----------------------------------------------------------------
%% Functions handling files, RELEASES, start_erl.data etc.
%% This functions consider if the release_handler is a client and
@@ -1617,12 +1848,25 @@ extract_tar(Root, Tar) ->
throw({error, {cannot_extract_file, Name, Reason}})
end.
-write_releases(Dir, NewReleases, false) ->
+write_releases(Dir, Releases, Masters) ->
+ %% We must never write 'current' to disk, since this will confuse
+ %% us after a node restart - since we would then have a permanent
+ %% release running, but state set to current for a non-running
+ %% release.
+ NewReleases = lists:zf(fun(Release) when Release#release.status == current ->
+ {true, Release#release{status = unpacked}};
+ (_) ->
+ true
+ end, Releases),
+ write_releases_1(Dir, NewReleases, Masters).
+
+
+write_releases_1(Dir, NewReleases, false) ->
case do_write_release(Dir, "RELEASES", NewReleases) of
ok -> ok;
Error -> throw(Error)
end;
-write_releases(Dir, NewReleases, Masters) ->
+write_releases_1(Dir, NewReleases, Masters) ->
all_masters(Masters),
write_releases_m(Dir, NewReleases, Masters).
@@ -1844,6 +2088,37 @@ read_file(File, false) ->
read_file(File, Masters) ->
read_master(Masters, File).
+write_file(File, Data, false) ->
+ case file:write_file(File, Data) of
+ ok -> ok;
+ Error -> throw(Error)
+ end;
+write_file(File, Data, Masters) ->
+ case at_all_masters(Masters, file, write_file, [File, Data]) of
+ ok -> ok;
+ Error -> throw(Error)
+ end.
+
+ensure_dir(File, false) ->
+ case filelib:ensure_dir(File) of
+ ok -> ok;
+ Error -> throw(Error)
+ end;
+ensure_dir(File, Masters) ->
+ case at_all_masters(Masters,filelib,ensure_dir,[File]) of
+ ok -> ok;
+ Error -> throw(Error)
+ end.
+
+remove_dir(Dir, false) ->
+ remove_file(Dir);
+remove_dir(Dir, Masters) ->
+ case at_all_masters(Masters,?MODULE,remove_file,[Dir]) of
+ ok -> ok;
+ Error -> throw(Error)
+ end.
+
+
%% Ignore status of each delete !
remove_files(Master, Files, Masters) ->
takewhile(Master, Masters, ?MODULE, do_remove_files, [Files]).
@@ -2010,3 +2285,14 @@ get_new_libs([{App,Vsn,_LibDir}|CurrentLibs], NewLibs) ->
end;
get_new_libs([],_) ->
[].
+
+%%-----------------------------------------------------------------
+%% Return a list of releases witch a specific status
+%%-----------------------------------------------------------------
+get_releases_with_status([], _, Acc) ->
+ Acc;
+get_releases_with_status([ {_, _, _, ReleaseStatus } = Head | Tail],
+ Status, Acc) when ReleaseStatus == Status ->
+ get_releases_with_status(Tail, Status, [Head | Acc]);
+get_releases_with_status([_ | Tail], Status, Acc) ->
+ get_releases_with_status(Tail, Status, Acc).
diff --git a/lib/sasl/src/release_handler_1.erl b/lib/sasl/src/release_handler_1.erl
index 8d0baf3ab1..93d12cf609 100644
--- a/lib/sasl/src/release_handler_1.erl
+++ b/lib/sasl/src/release_handler_1.erl
@@ -47,26 +47,38 @@
%%%-----------------------------------------------------------------
%%% This is a low-level release handler.
%%%-----------------------------------------------------------------
+check_script([restart_new_emulator|Script], LibDirs) ->
+ %% There is no need to check for old processes, since the node
+ %% will be restarted before anything else happens.
+ do_check_script(Script, LibDirs, []);
check_script(Script, LibDirs) ->
case catch check_old_processes(Script,soft_purge) of
{ok, PurgeMods} ->
- {Before, _After} = split_instructions(Script),
- case catch lists:foldl(fun(Instruction, EvalState1) ->
- eval(Instruction, EvalState1)
- end,
- #eval_state{libdirs = LibDirs},
- Before) of
- EvalState2 when is_record(EvalState2, eval_state) ->
- {ok,PurgeMods};
- {error, Error} ->
- {error, Error};
- Other ->
- {error, Other}
- end;
+ do_check_script(Script, LibDirs, PurgeMods);
{error, Mod} ->
{error, {old_processes, Mod}}
end.
+do_check_script(Script, LibDirs, PurgeMods) ->
+ {Before, After} = split_instructions(Script),
+ case catch lists:foldl(fun(Instruction, EvalState1) ->
+ eval(Instruction, EvalState1)
+ end,
+ #eval_state{libdirs = LibDirs},
+ Before) of
+ EvalState2 when is_record(EvalState2, eval_state) ->
+ case catch syntax_check_script(After) of
+ ok ->
+ {ok,PurgeMods};
+ Other ->
+ {error,Other}
+ end;
+ {error, Error} ->
+ {error, Error};
+ Other ->
+ {error, Other}
+ end.
+
%% eval_script/1 - For testing only - no apps added, just testing instructions
eval_script(Script) ->
eval_script(Script, [], [], [], []).
@@ -83,22 +95,30 @@ eval_script(Script, Apps, LibDirs, NewLibs, Opts) ->
newlibs = NewLibs,
opts = Opts},
Before) of
- EvalState2 when is_record(EvalState2, eval_state) ->
- case catch lists:foldl(fun(Instruction, EvalState3) ->
- eval(Instruction, EvalState3)
- end,
- EvalState2,
- After) of
- EvalState4 when is_record(EvalState4, eval_state) ->
- {ok, EvalState4#eval_state.unpurged};
- restart_new_emulator ->
- restart_new_emulator;
- Error ->
- {'EXIT', Error}
- end;
- {error, Error} -> {error, Error};
- Other -> {error, Other}
- end;
+ EvalState2 when is_record(EvalState2, eval_state) ->
+ case catch syntax_check_script(After) of
+ ok ->
+ case catch lists:foldl(
+ fun(Instruction, EvalState3) ->
+ eval(Instruction,
+ EvalState3)
+ end,
+ EvalState2,
+ After) of
+ EvalState4
+ when is_record(EvalState4, eval_state) ->
+ {ok, EvalState4#eval_state.unpurged};
+ restart_emulator ->
+ restart_emulator;
+ Error ->
+ {'EXIT', Error}
+ end;
+ Other ->
+ {error,Other}
+ end;
+ {error, Error} -> {error, Error};
+ Other -> {error, Other}
+ end;
{error, Mod} ->
{error, {old_processes, Mod}}
end.
@@ -174,6 +194,42 @@ do_check_old_code(Mod,Procs) ->
[Mod].
+%% Check the last part of the script, i.e. the part after point_of_no_return.
+%% More or less a syntax check in case the script was handwritten.
+syntax_check_script([point_of_no_return | Script]) ->
+ syntax_check_script(Script);
+syntax_check_script([{load, {_,_,_}} | Script]) ->
+ syntax_check_script(Script);
+syntax_check_script([{remove, {_,_,_}} | Script]) ->
+ syntax_check_script(Script);
+syntax_check_script([{purge, _} | Script]) ->
+ syntax_check_script(Script);
+syntax_check_script([{suspend, _} | Script]) ->
+ syntax_check_script(Script);
+syntax_check_script([{resume, _} | Script]) ->
+ syntax_check_script(Script);
+syntax_check_script([{code_change, _} | Script]) ->
+ syntax_check_script(Script);
+syntax_check_script([{code_change, _, _} | Script]) ->
+ syntax_check_script(Script);
+syntax_check_script([{stop, _} | Script]) ->
+ syntax_check_script(Script);
+syntax_check_script([{start, _} | Script]) ->
+ syntax_check_script(Script);
+syntax_check_script([{sync_nodes, _, {_,_,_}} | Script]) ->
+ syntax_check_script(Script);
+syntax_check_script([{sync_nodes, _, _} | Script]) ->
+ syntax_check_script(Script);
+syntax_check_script([{apply, {_,_,_}} | Script]) ->
+ syntax_check_script(Script);
+syntax_check_script([restart_emulator | Script]) ->
+ syntax_check_script(Script);
+syntax_check_script([Illegal | _Script]) ->
+ throw({illegal_instruction_after_point_of_no_return,Illegal});
+syntax_check_script([]) ->
+ ok.
+
+
%%-----------------------------------------------------------------
%% An unpurged module is a module for which there exist an old
%% version of the code. This should only be the case if there are
@@ -243,7 +299,7 @@ do_check_old_code(Mod,Procs) ->
%% must also exectue the same line. Waits for all these nodes to get
%% to this line.
%% point_of_no_return
-%% restart_new_emulator
+%% restart_emulator
%% {stop_application, Appl} - Impl with apply
%% {unload_application, Appl} - Impl with {remove..}
%% {load_application, Appl} - Impl with {load..}
@@ -402,6 +458,8 @@ eval({sync_nodes, Id, Nodes}, EvalState) ->
eval({apply, {M, F, A}}, EvalState) ->
apply(M, F, A),
EvalState;
+eval(restart_emulator, _EvalState) ->
+ throw(restart_emulator);
eval(restart_new_emulator, _EvalState) ->
throw(restart_new_emulator).
@@ -447,15 +505,20 @@ resume(Pids) ->
change_code(Pids, Mod, Vsn, Extra, Timeout) ->
Fun = fun(Pid) ->
- case Timeout of
- default ->
- ok = sys:change_code(Pid, Mod, Vsn, Extra);
- _Else ->
- ok = sys:change_code(Pid, Mod, Vsn, Extra, Timeout)
+ case sys_change_code(Pid, Mod, Vsn, Extra, Timeout) of
+ ok ->
+ ok;
+ {error,Reason} ->
+ throw({code_change_failed,Pid,Mod,Vsn,Reason})
end
end,
lists:foreach(Fun, Pids).
+sys_change_code(Pid, Mod, Vsn, Extra, default) ->
+ sys:change_code(Pid, Mod, Vsn, Extra);
+sys_change_code(Pid, Mod, Vsn, Extra, Timeout) ->
+ sys:change_code(Pid, Mod, Vsn, Extra, Timeout).
+
stop(Mod, Procs) ->
lists:zf(fun({undefined, _Name, _Pid, _Mods}) ->
false;
diff --git a/lib/sasl/src/sasl.appup.src b/lib/sasl/src/sasl.appup.src
index 64c653a4e5..ce4aa1f8f8 100644
--- a/lib/sasl/src/sasl.appup.src
+++ b/lib/sasl/src/sasl.appup.src
@@ -1,25 +1,27 @@
-%%
+%% -*- erlang -*-
%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1999-2009. All Rights Reserved.
-%%
+%%
+%% Copyright Ericsson AB 1999-2011. All Rights Reserved.
+%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
%% compliance with the License. You should have received a copy of the
%% Erlang Public License along with this software. If not, it can be
%% retrieved online at http://www.erlang.org/.
-%%
+%%
%% Software distributed under the License is distributed on an "AS IS"
%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
%% the License for the specific language governing rights and limitations
%% under the License.
-%%
-%% %CopyrightEnd%
%%
-
+%% %CopyrightEnd%
{"%VSN%",
- [{"2.1.4", [{load_module, release_handler},
- {load_module, systools_relup}]}],
- [{"2.1.4", [{load_module, release_handler},
- {load_module, systools_relup}]}]
+ %% Up from - max two major revisions back
+ [{<<"2\\.2(\\.[0-9]+)*">>,[restart_new_emulator]}, %% R15
+ {<<"2\\.1\\.10(\\.[0-9]+)*">>,[restart_new_emulator]}, %% R14B04 (and later?)
+ {<<"2\\.1\\.[6-9](\\.[0-9]+)*">>,[restart_new_emulator]}],%% R13B-R14B03
+ %% Down to - max two major revisions back
+ [{<<"2\\.2(\\.[0-9]+)*">>,[restart_new_emulator]}, %% R15
+ {<<"2\\.1\\.10(\\.[0-9]+)*">>,[restart_new_emulator]}, %% R14B04 (and later?)
+ {<<"2\\.1\\.[6-9](\\.[0-9]+)*">>,[restart_new_emulator]}] %% R13B-R14B03
}.
diff --git a/lib/sasl/src/systools_make.erl b/lib/sasl/src/systools_make.erl
index 7f400f5cce..8fd90c50f9 100644
--- a/lib/sasl/src/systools_make.erl
+++ b/lib/sasl/src/systools_make.erl
@@ -31,6 +31,8 @@
-export([read_application/4]).
+-export([make_hybrid_boot/5]).
+
-import(lists, [filter/2, keysort/2, keysearch/3, map/2, reverse/1,
append/1, foldl/3, member/2, foreach/2]).
@@ -56,6 +58,7 @@
%% {variables,[{Name,AbsString}]}
%% {machine, jam | beam | vee}
%% exref | {exref, [AppName]}
+%% no_warn_sasl
%%-----------------------------------------------------------------
make_script(RelName) when is_list(RelName) ->
@@ -86,7 +89,8 @@ make_script(RelName, Output, Flags) when is_list(RelName),
Path = make_set(Path1 ++ code:get_path()),
ModTestP = {member(src_tests, Flags),xref_p(Flags)},
case get_release(RelName, Path, ModTestP, machine(Flags)) of
- {ok, Release, Appls, Warnings} ->
+ {ok, Release, Appls, Warnings0} ->
+ Warnings = wsasl(Flags, Warnings0),
case systools_lib:werror(Flags, Warnings) of
true ->
return(ok,Warnings,Flags);
@@ -110,7 +114,13 @@ make_script(RelName, _Output, Flags) when is_list(Flags) ->
make_script(RelName, _Output, Flags) ->
badarg(Flags,[RelName, Flags]).
-%% Inlined.
+
+wsasl(Options, Warnings) ->
+ case lists:member(no_warn_sasl,Options) of
+ true -> lists:delete({warning,missing_sasl},Warnings);
+ false -> Warnings
+ end.
+
badarg(BadArg, Args) ->
erlang:error({badarg,BadArg}, Args).
@@ -162,6 +172,118 @@ return({error,Mod,Error},_,Flags) ->
error
end.
+
+%%-----------------------------------------------------------------
+%% Make hybrid boot file for upgrading emulator. The resulting boot
+%% file is a combination of the two input files, where kernel, stdlib
+%% and sasl versions are taken from the second file (the boot file of
+%% the new release), and all other application versions from the first
+%% file (the boot file of the old release).
+%%
+%% The most important thing that can fail here is that the input boot
+%% files do not contain all three base applications - kernel, stdlib
+%% and sasl.
+%%
+%% TmpVsn = string(),
+%% Paths = {KernelPath,StdlibPath,SaslPath}
+%% Returns {ok,Boot} | {error,Reason}
+%% Boot1 = Boot2 = Boot = binary()
+%% Reason = {app_not_found,App} | {app_not_replaced,App}
+%% App = kernel | stdlib | sasl
+make_hybrid_boot(TmpVsn, Boot1, Boot2, Paths, Args) ->
+ catch do_make_hybrid_boot(TmpVsn, Boot1, Boot2, Paths, Args).
+do_make_hybrid_boot(TmpVsn, Boot1, Boot2, Paths, Args) ->
+ {script,{_RelName1,_RelVsn1},Script1} = binary_to_term(Boot1),
+ {script,{RelName2,_RelVsn2},Script2} = binary_to_term(Boot2),
+ MatchPaths = get_regexp_path(Paths),
+ NewScript1 = replace_paths(Script1,MatchPaths),
+ {Kernel,Stdlib,Sasl} = get_apps(Script2,undefined,undefined,undefined),
+ NewScript2 = replace_apps(NewScript1,Kernel,Stdlib,Sasl),
+ NewScript3 = add_apply_upgrade(NewScript2,Args),
+ Boot = term_to_binary({script,{RelName2,TmpVsn},NewScript3}),
+ {ok,Boot}.
+
+%% For each app, compile a regexp that can be used for finding its path
+get_regexp_path({KernelPath,StdlibPath,SaslPath}) ->
+ {ok,KernelMP} = re:compile("kernel-[0-9\.]+",[unicode]),
+ {ok,StdlibMP} = re:compile("stdlib-[0-9\.]+",[unicode]),
+ {ok,SaslMP} = re:compile("sasl-[0-9\.]+",[unicode]),
+ [{KernelMP,KernelPath},{StdlibMP,StdlibPath},{SaslMP,SaslPath}].
+
+%% For each path in the script, check if it matches any of the MPs
+%% found above, and if so replace it with the correct new path.
+replace_paths([{path,Path}|Script],MatchPaths) ->
+ [{path,replace_path(Path,MatchPaths)}|replace_paths(Script,MatchPaths)];
+replace_paths([Stuff|Script],MatchPaths) ->
+ [Stuff|replace_paths(Script,MatchPaths)];
+replace_paths([],_) ->
+ [].
+
+replace_path([Path|Paths],MatchPaths) ->
+ [do_replace_path(Path,MatchPaths)|replace_path(Paths,MatchPaths)];
+replace_path([],_) ->
+ [].
+
+do_replace_path(Path,[{MP,ReplacePath}|MatchPaths]) ->
+ case re:run(Path,MP,[{capture,none}]) of
+ nomatch -> do_replace_path(Path,MatchPaths);
+ match -> ReplacePath
+ end;
+do_replace_path(Path,[]) ->
+ Path.
+
+%% Return the entries for loading the three base applications
+get_apps([{kernelProcess,application_controller,
+ {application_controller,start,[{application,kernel,_}]}}=Kernel|
+ Script],_,Stdlib,Sasl) ->
+ get_apps(Script,Kernel,Stdlib,Sasl);
+get_apps([{apply,{application,load,[{application,stdlib,_}]}}=Stdlib|Script],
+ Kernel,_,Sasl) ->
+ get_apps(Script,Kernel,Stdlib,Sasl);
+get_apps([{apply,{application,load,[{application,sasl,_}]}}=Sasl|_Script],
+ Kernel,Stdlib,_) ->
+ {Kernel,Stdlib,Sasl};
+get_apps([_|Script],Kernel,Stdlib,Sasl) ->
+ get_apps(Script,Kernel,Stdlib,Sasl);
+get_apps([],undefined,_,_) ->
+ throw({error,{app_not_found,kernel}});
+get_apps([],_,undefined,_) ->
+ throw({error,{app_not_found,stdlib}});
+get_apps([],_,_,undefined) ->
+ throw({error,{app_not_found,sasl}}).
+
+
+%% Replace the entries for loading the base applications
+replace_apps([{kernelProcess,application_controller,
+ {application_controller,start,[{application,kernel,_}]}}|
+ Script],Kernel,Stdlib,Sasl) ->
+ [Kernel|replace_apps(Script,undefined,Stdlib,Sasl)];
+replace_apps([{apply,{application,load,[{application,stdlib,_}]}}|Script],
+ Kernel,Stdlib,Sasl) ->
+ [Stdlib|replace_apps(Script,Kernel,undefined,Sasl)];
+replace_apps([{apply,{application,load,[{application,sasl,_}]}}|Script],
+ _Kernel,_Stdlib,Sasl) ->
+ [Sasl|Script];
+replace_apps([Stuff|Script],Kernel,Stdlib,Sasl) ->
+ [Stuff|replace_apps(Script,Kernel,Stdlib,Sasl)];
+replace_apps([],undefined,undefined,_) ->
+ throw({error,{app_not_replaced,sasl}});
+replace_apps([],undefined,_,_) ->
+ throw({error,{app_not_replaced,stdlib}});
+replace_apps([],_,_,_) ->
+ throw({error,{app_not_replaced,kernel}}).
+
+
+%% Finally add an apply of release_handler:new_emulator_upgrade - which will
+%% complete the execution of the upgrade script (relup).
+add_apply_upgrade(Script,Args) ->
+ [{progress, started} | RevScript] = lists:reverse(Script),
+ lists:reverse([{progress,started},
+ {apply,{release_handler,new_emulator_upgrade,Args}} |
+ RevScript]).
+
+
+
%%-----------------------------------------------------------------
%% Create a release package from a release file.
%% Options is a list of {path, Path} | silent |
@@ -250,13 +372,13 @@ get_release(File, Path, ModTestP, Machine) ->
end.
get_release1(File, Path, ModTestP, Machine) ->
- {ok, Release} = read_release(File, Path),
+ {ok, Release, Warnings1} = read_release(File, Path),
{ok, Appls0} = collect_applications(Release, Path),
{ok, Appls1} = check_applications(Appls0),
{ok, Appls2} = sort_included_applications(Appls1, Release), % OTP-4121
- {ok, Warnings} = check_modules(Appls2, Path, ModTestP, Machine),
+ {ok, Warnings2} = check_modules(Appls2, Path, ModTestP, Machine),
{ok, Appls} = sort_appls(Appls2),
- {ok, Release, Appls, Warnings}.
+ {ok, Release, Appls, Warnings1 ++ Warnings2}.
%%______________________________________________________________________
%% read_release(File, Path) -> {ok, #release} | throw({error, What})
@@ -271,11 +393,12 @@ read_release(File, Path) ->
check_rel(Release) ->
case catch check_rel1(Release) of
- {ok, {Name,Vsn,Evsn,Appl,Incl}} ->
+ {ok, {Name,Vsn,Evsn,Appl,Incl}, Ws} ->
{ok, #release{name=Name, vsn=Vsn,
erts_vsn=Evsn,
applications=Appl,
- incl_apps=Incl}};
+ incl_apps=Incl},
+ Ws};
{error, Error} ->
throw({error,?MODULE,Error});
Error ->
@@ -286,8 +409,8 @@ check_rel1({release,{Name,Vsn},{erts,EVsn},Appl}) when is_list(Appl) ->
check_name(Name),
check_vsn(Vsn),
check_evsn(EVsn),
- {Appls,Incls} = check_appl(Appl),
- {ok, {Name,Vsn,EVsn,Appls,Incls}};
+ {{Appls,Incls},Ws} = check_appl(Appl),
+ {ok, {Name,Vsn,EVsn,Appls,Incls},Ws};
check_rel1(_) ->
{error, badly_formatted_release}.
@@ -340,8 +463,8 @@ check_appl(Appl) ->
end,
Appl) of
[] ->
- mandatory_applications(Appl),
- split_app_incl(Appl);
+ {ok,Ws} = mandatory_applications(Appl),
+ {split_app_incl(Appl),Ws};
Illegal ->
throw({error, {illegal_applications,Illegal}})
end.
@@ -352,7 +475,12 @@ mandatory_applications(Appl) ->
Mand = mandatory_applications(),
case filter(fun(X) -> member(X, AppNames) end, Mand) of
Mand ->
- ok;
+ case member(sasl,AppNames) of
+ true ->
+ {ok,[]};
+ _ ->
+ {ok, [{warning,missing_sasl}]}
+ end;
_ ->
throw({error, {missing_mandatory_app, Mand}})
end.
@@ -1510,8 +1638,19 @@ add_system_files(Tar, RelName, Release, Path1) ->
SVsn = Release#release.vsn,
RelName0 = filename:basename(RelName),
+ RelVsnDir = filename:join("releases", SVsn),
+
+ %% OTP-9746: store rel file in releases/<vsn>
+ %% Adding rel file to
+ %% 1) releases directory - so it can be easily extracted
+ %% separately (see release_handler:unpack_release)
+ %% 2) releases/<vsn> - so the file must not be explicitly moved
+ %% after unpack.
add_to_tar(Tar, RelName ++ ".rel",
filename:join("releases", RelName0 ++ ".rel")),
+ add_to_tar(Tar, RelName ++ ".rel",
+ filename:join(RelVsnDir, RelName0 ++ ".rel")),
+
%% OTP-6226 Look for the system files not only in cwd
%% --
@@ -1527,26 +1666,25 @@ add_system_files(Tar, RelName, Release, Path1) ->
[RelDir, "."|Path1]
end,
- ToDir = filename:join("releases", SVsn),
case lookup_file(RelName0 ++ ".boot", Path) of
false ->
throw({error, {tar_error,{add, RelName0++".boot",enoent}}});
Boot ->
- add_to_tar(Tar, Boot, filename:join(ToDir, "start.boot"))
+ add_to_tar(Tar, Boot, filename:join(RelVsnDir, "start.boot"))
end,
case lookup_file("relup", Path) of
false ->
ignore;
Relup ->
- add_to_tar(Tar, Relup, filename:join(ToDir, "relup"))
+ add_to_tar(Tar, Relup, filename:join(RelVsnDir, "relup"))
end,
case lookup_file("sys.config", Path) of
false ->
ignore;
Sys ->
- add_to_tar(Tar, Sys, filename:join(ToDir, "sys.config"))
+ add_to_tar(Tar, Sys, filename:join(RelVsnDir, "sys.config"))
end,
ok.
@@ -1850,90 +1988,67 @@ get_flag(_,_) -> false.
%% Check Options for make_script
check_args_script(Args) ->
- cas(Args,
- {undef, undef, undef, undef, undef, undef, undef, undef,
- undef, []}).
+ cas(Args, []).
-cas([], {_Path,_Sil,_Loc,_Test,_Var,_Mach,_Xref,_XrefApps,_Werror, X}) ->
+cas([], X) ->
X;
%%% path ---------------------------------------------------------------
-cas([{path, P} | Args], {Path, Sil, Loc, Test, Var, Mach, Xref,
- XrefApps, Werror, X}) when is_list(P) ->
+cas([{path, P} | Args], X) when is_list(P) ->
case check_path(P) of
ok ->
- cas(Args, {P, Sil, Loc, Test, Var, Mach, Xref, XrefApps,
- Werror, X});
+ cas(Args, X);
error ->
- cas(Args, {Path, Sil, Loc, Test, Var, Mach, Xref, XrefApps,
- Werror, X++[{path,P}]})
+ cas(Args, X++[{path,P}])
end;
%%% silent -------------------------------------------------------------
-cas([silent | Args], {Path, _Sil, Loc, Test, Var, Mach, Xref,
- XrefApps, Werror, X}) ->
- cas(Args, {Path, silent, Loc, Test, Var, Mach, Xref, XrefApps,
- Werror, X});
+cas([silent | Args], X) ->
+ cas(Args, X);
%%% local --------------------------------------------------------------
-cas([local | Args], {Path, Sil, _Loc, Test, Var, Mach, Xref,
- XrefApps, Werror, X}) ->
- cas(Args, {Path, Sil, local, Test, Var, Mach, Xref, XrefApps,
- Werror, X});
+cas([local | Args], X) ->
+ cas(Args, X);
%%% src_tests -------------------------------------------------------
-cas([src_tests | Args], {Path, Sil, Loc, _Test, Var, Mach, Xref,
- XrefApps, Werror, X}) ->
- cas(Args,
- {Path, Sil, Loc, src_tests, Var, Mach, Xref, Werror, XrefApps,X});
+cas([src_tests | Args], X) ->
+ cas(Args, X);
%%% variables ----------------------------------------------------------
-cas([{variables, V} | Args], {Path, Sil, Loc, Test, Var, Mach, Xref,
- XrefApps, Werror, X}) when is_list(V) ->
+cas([{variables, V} | Args], X) when is_list(V) ->
case check_vars(V) of
ok ->
- cas(Args,
- {Path, Sil, Loc, Test, V, Mach, Xref, XrefApps, Werror, X});
+ cas(Args, X);
error ->
- cas(Args, {Path, Sil, Loc, Test, Var, Mach, Xref, XrefApps,
- Werror, X++[{variables, V}]})
+ cas(Args, X++[{variables, V}])
end;
%%% machine ------------------------------------------------------------
-cas([{machine, M} | Args], {Path, Sil, Loc, Test, Var, Mach, Xref,
- XrefApps, Werror, X}) when is_atom(M) ->
- cas(Args, {Path, Sil, Loc, Test, Var, Mach, Xref, XrefApps, Werror, X});
+cas([{machine, M} | Args], X) when is_atom(M) ->
+ cas(Args, X);
%%% exref --------------------------------------------------------------
-cas([exref | Args], {Path, Sil, Loc, Test, Var, Mach, _Xref,
- XrefApps, Werror, X}) ->
- cas(Args, {Path, Sil, Loc, Test, Var, Mach, exref, XrefApps, Werror, X});
+cas([exref | Args], X) ->
+ cas(Args, X);
%%% exref Apps ---------------------------------------------------------
-cas([{exref, Apps} | Args], {Path, Sil, Loc, Test, Var, Mach, Xref,
- XrefApps, Werror, X}) when is_list(Apps) ->
+cas([{exref, Apps} | Args], X) when is_list(Apps) ->
case check_apps(Apps) of
ok ->
- cas(Args, {Path, Sil, Loc, Test, Var, Mach,
- Xref, Apps, Werror, X});
+ cas(Args, X);
error ->
- cas(Args, {Path, Sil, Loc, Test, Var, Mach,
- Xref, XrefApps, Werror, X++[{exref, Apps}]})
+ cas(Args, X++[{exref, Apps}])
end;
%%% outdir Dir ---------------------------------------------------------
-cas([{outdir, Dir} | Args], {Path, Sil, Loc, Test, Var, Mach, Xref,
- XrefApps, Werror, X}) when is_list(Dir) ->
- cas(Args, {Path, Sil, Loc, Test, Var, Mach, Xref, XrefApps, Werror, X});
+cas([{outdir, Dir} | Args], X) when is_list(Dir) ->
+ cas(Args, X);
%%% otp_build (secret, not documented) ---------------------------------
-cas([otp_build | Args], {Path, Sil, Loc, Test, Var, Mach, Xref,
- XrefApps, Werror, X}) ->
- cas(Args, {Path, Sil, Loc, Test, Var, Mach, Xref, XrefApps, Werror, X});
+cas([otp_build | Args], X) ->
+ cas(Args, X);
+%%% warnings_as_errors -------------------------------------------------
+cas([warnings_as_errors | Args], X) ->
+ cas(Args, X);
+%%% no_warn_sasl -------------------------------------------------------
+cas([no_warn_sasl | Args], X) ->
+ cas(Args, X);
%%% no_module_tests (kept for backwards compatibility, but ignored) ----
-cas([no_module_tests | Args], {Path, Sil, Loc, Test, Var, Mach, Xref,
- XrefApps, Werror, X}) ->
- cas(Args, {Path, Sil, Loc, Test, Var, Mach, Xref, XrefApps, Werror, X});
-%%% warnings_as_errors (kept for backwards compatibility, but ignored) ----
-cas([warnings_as_errors | Args], {Path, Sil, Loc, Test, Var, Mach, Xref,
- XrefApps, _Werror, X}) ->
- cas(Args, {Path, Sil, Loc, Test, Var, Mach, Xref, XrefApps,
- warnings_as_errors, X});
+cas([no_module_tests | Args], X) ->
+ cas(Args, X);
%%% ERROR --------------------------------------------------------------
-cas([Y | Args], {Path, Sil, Loc, Test, Var, Mach, Xref, XrefApps,
- Werror, X}) ->
- cas(Args, {Path, Sil, Loc, Test, Var, Mach, Xref, XrefApps, Werror,
- X++[Y]}).
+cas([Y | Args], X) ->
+ cas(Args, X++[Y]).
@@ -2198,5 +2313,9 @@ form_warn(Prefix, {exref_undef, Undef}) ->
[Prefix,M,F,A])
end,
map(F, Undef);
+form_warn(Prefix, missing_sasl) ->
+ io_lib:format("~s: Missing application sasl. "
+ "Can not upgrade with this release~n",
+ [Prefix]);
form_warn(Prefix, What) ->
io_lib:format("~s ~p~n", [Prefix,What]).
diff --git a/lib/sasl/src/systools_rc.erl b/lib/sasl/src/systools_rc.erl
index daadb79967..c16f6aa845 100644
--- a/lib/sasl/src/systools_rc.erl
+++ b/lib/sasl/src/systools_rc.erl
@@ -54,6 +54,7 @@
%% {sync_nodes, Id, Nodes}
%% {apply, {M, F, A}}
%% restart_new_emulator
+%% restart_emulator
%%-----------------------------------------------------------------
%% High-level instructions that contain dependencies
@@ -144,7 +145,10 @@ translate_merged_script(Mode, Script, Appls, PreAppls) ->
{Before2, After2} = translate_dependent_instrs(Mode, Before1, After1,
Appls),
Before3 = merge_load_object_code(Before2),
- NewScript = Before3 ++ [point_of_no_return | After2],
+
+ {Before4,After4} = sort_emulator_restart(Mode,Before3,After2),
+ NewScript = Before4 ++ [point_of_no_return | After4],
+
check_syntax(NewScript),
{ok, NewScript}.
@@ -699,6 +703,39 @@ mlo([{load_object_code, {Lib, LibVsn, Mods}} | T]) ->
mlo([]) -> [].
%%-----------------------------------------------------------------
+%% RESTART EMULATOR
+%% -----------------------------------------------------------------
+%% -----------------------------------------------------------------
+%% Check if there are any 'restart_new_emulator' instructions (i.e. if
+%% the emulator or core application version is changed). If so, this
+%% must be done first for upgrade and last for downgrade.
+%% Check if there are any 'restart_emulator' instructions, if so
+%% remove all and place one the end.
+%% -----------------------------------------------------------------
+sort_emulator_restart(Mode,Before,After) ->
+ {Before1,After1} =
+ case filter_out(restart_new_emulator, After) of
+ After ->
+ {Before,After};
+ A1 when Mode==up ->
+ {[restart_new_emulator|Before],A1};
+ A1 when Mode==dn ->
+ {Before,A1++[restart_emulator]}
+ end,
+ After2 =
+ case filter_out(restart_emulator, After1) of
+ After1 ->
+ After1;
+ A2 ->
+ A2++[restart_emulator]
+ end,
+ {Before1,After2}.
+
+
+filter_out(What,List) ->
+ lists:filter(fun(X) when X=:=What -> false; (_) -> true end, List).
+
+%%-----------------------------------------------------------------
%% SYNTAX CHECK
%%-----------------------------------------------------------------
%%-----------------------------------------------------------------
@@ -817,6 +854,7 @@ check_op({apply, {M, F, A}}) ->
check_func(F),
check_args(A);
check_op(restart_new_emulator) -> ok;
+check_op(restart_emulator) -> ok;
check_op(X) -> throw({error, {bad_instruction, X}}).
check_mod(Mod) when is_atom(Mod) -> ok;
diff --git a/lib/sasl/src/systools_relup.erl b/lib/sasl/src/systools_relup.erl
index 6d9e922900..7fb623bb85 100644
--- a/lib/sasl/src/systools_relup.erl
+++ b/lib/sasl/src/systools_relup.erl
@@ -112,6 +112,11 @@
-export([mk_relup/3, mk_relup/4, format_error/1, format_warning/1]).
-include("systools.hrl").
+-define(R15_SASL_VSN,"2.2").
+
+%% For test purposes only - used by kernel, stdlib and sasl tests
+-export([appup_search_for_version/2]).
+
%%-----------------------------------------------------------------
%% mk_relup(TopRelFile, BaseUpRelDcs, BaseDnRelDcs)
%% mk_relup(TopRelFile, BaseUpRelDcs, BaseDnRelDcs, Opts) -> Ret
@@ -200,7 +205,13 @@ do_mk_relup(TopRelFile, BaseUpRelDcs, BaseDnRelDcs, Path, Opts) ->
%% TopRel = #release
%% NameVsnApps = [{{Name, Vsn}, #application}]
{ok, TopRel, NameVsnApps, Ws0} ->
- %%
+ case lists:member({warning,missing_sasl},Ws0) of
+ true ->
+ throw({error,?MODULE,{missing_sasl,TopRel}});
+ false ->
+ ok
+ end,
+
%% TopApps = [#application]
TopApps = lists:map(fun({_, App}) -> App end, NameVsnApps),
@@ -247,7 +258,21 @@ foreach_baserel_up(TopRel, TopApps, [BaseRelDc|BaseRelDcs], Path, Opts,
Ws, Acc) ->
BaseRelFile = extract_filename(BaseRelDc),
- {ok, BaseRel} = systools_make:read_release(BaseRelFile, Path),
+ {BaseRel, {BaseNameVsns, BaseApps}, Ws0} =
+ case systools_make:get_release(BaseRelFile, Path) of
+ {ok, BR, NameVsnApps, Warns} ->
+ case lists:member({warning,missing_sasl},Warns) of
+ true ->
+ throw({error,?MODULE,{missing_sasl,BR}});
+ false ->
+ %% NameVsnApps = [{{Name,Vsn},#application}]
+ %% Gives two lists - [{Name,Vsn}] and [#application]
+ {BR,lists:unzip(NameVsnApps),Warns}
+ end;
+ Other1 ->
+ throw(Other1)
+ end,
+
%%
%% BaseRel = #release
@@ -257,29 +282,23 @@ foreach_baserel_up(TopRel, TopApps, [BaseRelDc|BaseRelDcs], Path, Opts,
%% application, one for each added applications, and one for
%% each removed applications.
%%
- {RUs1, Ws1} = collect_appup_scripts(up, TopApps, BaseRel, Ws, []),
+ {RUs1, Ws1} = collect_appup_scripts(up, TopApps, BaseRel, Ws0++Ws, []),
{RUs2, Ws2} = create_add_app_scripts(BaseRel, TopRel, RUs1, Ws1),
{RUs3, Ws3} = create_remove_app_scripts(BaseRel, TopRel, RUs2, Ws2),
- {RUs4, Ws4} =
- check_for_emulator_restart(TopRel, BaseRel, RUs3, Ws3, Opts),
-
- BaseApps =
- case systools_make:get_release(BaseRelFile, Path) of
- {ok, _, NameVsnApps, _Warns} ->
- lists:map(fun({_,App}) -> App end, NameVsnApps);
- Other1 ->
- throw(Other1)
- end,
+ {RUs4, Ws4} = check_for_emulator_restart(TopRel, BaseRel, RUs3, Ws3, Opts),
case systools_rc:translate_scripts(up, RUs4, TopApps, BaseApps) of
- {ok, RUs} ->
+ {ok, RUs5} ->
+
+ {RUs, Ws5} = fix_r15_sasl_upgrade(RUs5,Ws4,BaseNameVsns),
+
VDR = {BaseRel#release.vsn,
extract_description(BaseRelDc), RUs},
foreach_baserel_up(TopRel, TopApps, BaseRelDcs, Path,
- Opts, Ws4, [VDR| Acc]);
+ Opts, Ws5, [VDR| Acc]);
XXX ->
throw(XXX)
end;
@@ -294,42 +313,41 @@ foreach_baserel_dn(TopRel, TopApps, [BaseRelDc|BaseRelDcs], Path, Opts,
Ws, Acc) ->
BaseRelFile = extract_filename(BaseRelDc),
- {ok, BaseRel} = systools_make:read_release(BaseRelFile, Path),
-
- %% BaseRel = #release
-
- %% RUs = (release upgrade scripts)
- %%
- {RUs1, Ws1} = collect_appup_scripts(dn, TopApps, BaseRel, Ws, []),
-
- {BaseApps, Ws2} =
+ {BaseRel, BaseApps, Ws0} =
case systools_make:get_release(BaseRelFile, Path) of
%%
%% NameVsnApps = [{{Name, Vsn}, #application}]
- {ok, _, NameVsnApps, Warns} ->
- %%
- %% NApps = [#application]
- NApps = lists:map(fun({_,App}) -> App end, NameVsnApps),
- {NApps, Warns ++ Ws1};
+ {ok, BR, NameVsnApps, Warns} ->
+ case lists:member({warning,missing_sasl},Warns) of
+ true ->
+ throw({error,?MODULE,{missing_sasl,BR}});
+ false ->
+ %% NApps = [#application]
+ NApps = lists:map(fun({_,App}) -> App end, NameVsnApps),
+ {BR, NApps, Warns}
+ end;
Other ->
throw(Other)
end,
- RUs2 = RUs1,
+ %% BaseRel = #release
+
+ %% RUs = (release upgrade scripts)
+ %%
+ {RUs1, Ws1} = collect_appup_scripts(dn, TopApps, BaseRel, Ws0++Ws, []),
- {RUs3, Ws3} = create_add_app_scripts(TopRel, BaseRel, RUs2, Ws2),
+ {RUs2, Ws2} = create_add_app_scripts(TopRel, BaseRel, RUs1, Ws1),
- {RUs4, Ws4} = create_remove_app_scripts(TopRel, BaseRel, RUs3, Ws3),
+ {RUs3, Ws3} = create_remove_app_scripts(TopRel, BaseRel, RUs2, Ws2),
- {RUs5, Ws5} = check_for_emulator_restart(TopRel, BaseRel,
- RUs4, Ws4, Opts),
+ {RUs4, Ws4} = check_for_emulator_restart(TopRel, BaseRel, RUs3, Ws3, Opts),
- case systools_rc:translate_scripts(dn, RUs5, BaseApps, TopApps) of
+ case systools_rc:translate_scripts(dn, RUs4, BaseApps, TopApps) of
{ok, RUs} ->
VDR = {BaseRel#release.vsn,
extract_description(BaseRelDc), RUs},
foreach_baserel_dn(TopRel, TopApps, BaseRelDcs, Path,
- Opts, Ws5, [VDR| Acc]);
+ Opts, Ws4, [VDR| Acc]);
XXX ->
throw(XXX)
end;
@@ -343,14 +361,42 @@ foreach_baserel_dn( _, _, [], _, _, Ws, Acc) ->
%%
check_for_emulator_restart(#release{erts_vsn = Vsn1, name = N1},
#release{erts_vsn = Vsn2, name = N2}, RUs, Ws,
- _Opts) when Vsn1 /= Vsn2 ->
- {RUs++[[restart_new_emulator]], [{erts_vsn_changed, {N1, N2}} | Ws]};
+ Opts) when Vsn1 /= Vsn2 ->
+ %% Automatically insert a restart_new_emulator instruction when
+ %% erts version is changed. Also allow extra restart at the end of
+ %% the upgrade if restart_emulator option is given.
+ NewRUs = [[restart_new_emulator]|RUs],
+ NewWs = [{erts_vsn_changed, {{N1,Vsn1}, {N2,Vsn2}}} | Ws],
+ check_for_restart_emulator_opt(NewRUs, NewWs, Opts);
check_for_emulator_restart(_, _, RUs, Ws, Opts) ->
+ check_for_restart_emulator_opt(RUs, Ws, Opts).
+
+check_for_restart_emulator_opt(RUs, Ws, Opts) ->
case get_opt(restart_emulator, Opts) of
- true -> {RUs++[[restart_new_emulator]], Ws};
+ true -> {RUs++[[restart_emulator]], Ws};
_ -> {RUs, Ws}
end.
+
+%% Special handling of the upgrade from pre R15 to post R15. In R15,
+%% upgrade of the emulator was improved by moving the restart of the
+%% emulator before the rest of the upgrade instructions. However, it
+%% can only work if the release_handler is already upgraded to a post
+%% R15 version. If not, the upgrade instructions must be backwards
+%% compatible - i.e. restart_new_emulator will be the last
+%% instruction, executed after all code loading, code_change etc.
+fix_r15_sasl_upgrade([restart_new_emulator | RestRUs]=RUs, Ws, BaseApps) ->
+ case lists:keyfind(sasl,1,BaseApps) of
+ {sasl,Vsn} when Vsn < ?R15_SASL_VSN ->
+ {lists:delete(restart_emulator,RestRUs) ++ [restart_new_emulator],
+ [pre_R15_emulator_upgrade|Ws]};
+ _ ->
+ {RUs,Ws}
+ end;
+fix_r15_sasl_upgrade(RUs, Ws, _BaseApps) ->
+ {RUs,Ws}.
+
+
%% collect_appup_scripts(Mode, TopApps, BaseRel, Ws, RUs) -> {NRUs, NWs}
%% Mode = up | dn
%% TopApps = [#application]
@@ -440,13 +486,32 @@ get_script_from_appup(Mode, TopApp, BaseVsn, Ws, RUs) ->
%% XXX Why is this a warning only?
[{bad_vsn, {TopVsn, TopApp#application.vsn}}| Ws]
end,
- case lists:keysearch(BaseVsn, 1, VsnRUs) of
- {value, {_, RU}} ->
+ case appup_search_for_version(BaseVsn, VsnRUs) of
+ {ok, RU} ->
{RUs ++ [RU], Ws1};
- _ ->
+ error ->
throw({error, ?MODULE, {no_relup, FName, TopApp, BaseVsn}})
end.
+appup_search_for_version(BaseVsn, VsnRUs) ->
+ appup_search_for_version(BaseVsn, length(BaseVsn), VsnRUs).
+
+appup_search_for_version(BaseVsn,_,[{BaseVsn,RU}|_]) ->
+ {ok,RU};
+appup_search_for_version(BaseVsn,Size,[{Vsn,RU}|VsnRUs]) when is_binary(Vsn) ->
+ case re:run(BaseVsn,Vsn,[unicode,{capture,first,index}]) of
+ {match,[{0,Size}]} ->
+ {ok, RU};
+ _ ->
+ appup_search_for_version(BaseVsn,Size,VsnRUs)
+ end;
+appup_search_for_version(BaseVsn,Size,[_|VsnRUs]) ->
+ appup_search_for_version(BaseVsn,Size,VsnRUs);
+appup_search_for_version(_,_,[]) ->
+ error.
+
+
+
%% Primitives for the "lists of release names" that we upgrade from
%% and to.
@@ -543,7 +608,9 @@ format_error({no_relup, File, App, Vsn}) ->
"in file ~p~n",
[App#application.name, App#application.vsn,
App#application.name, Vsn, File]);
-
+format_error({missing_sasl,Release}) ->
+ io_lib:format("No sasl application in release ~p, ~p. Can not be upgraded.",
+ [Release#release.name, Release#release.vsn]);
format_error(Error) ->
io:format("~p~n", [Error]).
diff --git a/lib/sasl/test/Makefile b/lib/sasl/test/Makefile
index 65be134462..91a8c42484 100644
--- a/lib/sasl/test/Makefile
+++ b/lib/sasl/test/Makefile
@@ -36,6 +36,8 @@ MODULES= \
ERL_FILES= $(MODULES:%=%.erl)
+HRL_FILES= test_lib.hrl
+
TARGET_FILES= $(MODULES:%=$(EBIN)/%.$(EMULATOR))
INSTALL_PROGS= $(TARGET_FILES)
@@ -84,7 +86,7 @@ release_spec: opt
release_tests_spec: make_emakefile
$(INSTALL_DIR) $(RELSYSDIR)
- $(INSTALL_DATA) $(ERL_FILES) $(RELSYSDIR)
+ $(INSTALL_DATA) $(ERL_FILES) $(HRL_FILES) $(RELSYSDIR)
$(INSTALL_DATA) sasl.spec sasl.cover $(EMAKEFILE) $(RELSYSDIR)
chmod -R u+w $(RELSYSDIR)
@tar cfh - *_SUITE_data | (cd $(RELSYSDIR); tar xf -)
diff --git a/lib/sasl/test/installer.erl b/lib/sasl/test/installer.erl
index f5ceab0dc4..6942ec21ea 100644
--- a/lib/sasl/test/installer.erl
+++ b/lib/sasl/test/installer.erl
@@ -19,20 +19,33 @@
-module(installer).
+-include("test_lib.hrl").
+
%%-compile(export_all).
-export([install_1/2]).
-export([install_2/1]).
-export([install_3/2]).
--export([install_3a/1]).
+-export([install_6a/1]).
-export([install_4/1]).
-export([install_5/1]).
-export([install_5a/1]).
-export([install_6/1]).
-export([install_7/1]).
+-export([install_7a/1]).
-export([install_8/1]).
+-export([install_8a/1]).
-export([install_9/1]).
-export([install_10/1]).
-export([install_11/1]).
+-export([install_12/1]).
+-export([install_13/1]).
+-export([install_14/1]).
+-export([upgrade_restart_1/2]).
+-export([upgrade_restart_1a/1]).
+-export([upgrade_restart_2/1]).
+-export([upgrade_restart_2a/1]).
+-export([upgrade_restart_2b/1]).
+-export([upgrade_restart_3/1]).
-export([client1_1/4]).
-export([client2/3]).
-export([stop/1]).
@@ -46,28 +59,35 @@
-define(fail(Term), exit({?MODULE, ?LINE, Term})).
-define(fail_line(Line,Term), exit({?MODULE, Line, Term})).
--define(check_release(Vsn,Status,Apps),
- check_release(TestNode,node(),Vsn,Status,Apps,?LINE)).
--define(check_release_client(Node,Vsn,Status,Apps),
- check_release(TestNode,Node,Vsn,Status,Apps,?LINE)).
+-define(check_release_states(States),
+ check_release_states(TestNode,node(),States,?LINE)).
+-define(check_release_states_client(Node,States),
+ check_release_states(TestNode,Node,States,?LINE)).
+
+-define(check_release_lib(Vsn,Apps),
+ check_release_lib(TestNode,node(),Vsn,Apps,?LINE)).
+-define(check_release_lib_client(Node,Vsn,Apps),
+ check_release_lib(TestNode,Node,Vsn,Apps,?LINE)).
-define(check_running_app(App,Vsn),
check_running_app(TestNode,node(),App,Vsn,?LINE)).
-define(check_running_app_client(Node,App,Vsn),
check_running_app(TestNode,Node,App,Vsn,?LINE)).
+-define(check_disallowed_calls,check_disallowed_calls(TestNode,?LINE)).
+
install_1(TestNode,PrivDir) ->
?print([TestNode]),
?print(["install_1 start"]),
+ ?check_release_states([permanent]),
% Unpack and install P1H
{ok, "P1H"} = unpack_release(PrivDir,"rel1"),
- ?print(["unpack_release P1H ok"]),
- ?check_release("P1H",unpacked,["a-1.0"]),
+ ?check_release_states([permanent,unpacked]),
+ ?check_release_lib("P1H",["a-1.0"]),
{ok,"P1G",[new_appl]} = release_handler:install_release("P1H"),
- ?print(["install_release P1H ok"]),
- ?check_release("P1H",current,["a-1.0"]),
+ ?check_release_states([permanent,current]),
?check_running_app(a,"1.0"),
X = a:a(),
?print(["X", X]),
@@ -81,173 +101,351 @@ install_2(TestNode) ->
?print(["install_2 start"]),
% Check that P1H is still unpacked, install it and make_permanent
- ?check_release("P1H",unpacked,["a-1.0"]),
- ?print(["install_2 P1H unpacked"]),
+ ?check_release_states([permanent,unpacked]),
{ok,"P1G",[new_appl]} = release_handler:install_release("P1H"),
?print(["install_2 install_release ok"]),
- ?check_release("P1H",current,["a-1.0"]),
+ ?check_release_states([permanent,current]),
+ ?check_running_app(a,"1.0"),
+ ok = release_handler:make_permanent("P1H"),
+ ?print(["install_2 make permanent P1H ok"]),
+ ?check_release_states([old,permanent]),
?check_running_app(a,"1.0"),
- ok = release_handler:make_permanent("P1H").
+ ok.
% release_handler_SUITE will reboot this node now!
install_3(TestNode,PrivDir) ->
?print(["install_3 start"]),
% Check that P1H is permanent
- ?check_release("P1H",permanent,["a-1.0"]),
+ ?check_release_states([old,permanent]),
+ ?check_running_app(a,"1.0"),
X = a:a(),
{key2, val2} = lists:keyfind(key2, 1, X),
{key1, val1} = lists:keyfind(key1, 1, X),
% Unpack and install P1I
{ok, "P1I"} = unpack_release(PrivDir,"rel2"),
- ?print(["install_3 unpack_release P1I ok"]),
- ?check_release("P1I",unpacked,["a-1.1"]),
+ ?check_release_states([old,permanent,unpacked]),
+ ?check_release_lib("P1I",["a-1.1"]),
{ok,"P1H",[{extra, gott}]} = release_handler:check_install_release("P1I"),
+ ?print(["install_3 check_install_release P1I ok"]),
{error,_} = release_handler:check_install_release("P1J"),
+ ?print(["install_3 check_install_release P1J fails - ok"]),
{ok,"P1H",[{extra, gott}]} = release_handler:install_release("P1I"),
- ?print(["install_3 install_release P1I ok"]),
- ?check_release("P1I",current,["a-1.1"]),
+ ?check_release_states([old,permanent,current]),
?check_running_app(a,"1.1"),
X2 = a:a(),
{key2, newval2} = lists:keyfind(key2, 1, X2),
{key1, val1} = lists:keyfind(key1, 1, X2),
{ok, bval} = a:b(),
+ ?print(["install_3 env ok"]),
- % Unpack and install P2A
+ % Unpack P2A
{ok, "P2A"} = unpack_release(PrivDir,"rel3"),
- ?print(["install_3 unpack_release P2A ok"]),
- ?check_release("P2A",unpacked,["a-1.1"]),
+ ?check_release_states([old,permanent,current,unpacked]),
+ ?check_release_lib("P2A",["a-1.1"]),
{ok, "P1I", [new_emu]} = release_handler:check_install_release("P2A"),
?print(["install_3 check_install_release P2A ok"]),
- ok = release_handler:make_permanent("P1I"),
- ?print(["install_3 make_permanent P1I ok"]),
- ?check_release("P1I",permanent,["a-1.1"]),
ok.
+ % release_handler_SUITE will reboot this node now!
+
+install_4(TestNode) ->
+ ?print(["install_4 start"]),
-install_3a(TestNode) ->
- {ok, "P1I", [new_emu]} = release_handler:install_release("P2A"),
+ %% Check that P1H is the one that is used
+ ?check_release_states([old,permanent,unpacked,unpacked]),
+ ?check_running_app(a,"1.0"),
+
+ %% Install P2A
+ {continue_after_restart, "P1H", [new_emu,new_appl]} =
+ release_handler:install_release("P2A"),
%% Node is rebooted by the release_handler:install_release
%% (init:reboot) because P2A includes a new erts vsn and the relup
%% file contains a 'restart_new_emulator' instruction.
- ?print(["install_3 P2A installed"]),
+ ?print(["install_4 P2A installed"]),
ok.
+install_5(TestNode) ->
+ ?print(["install_5 start"]),
-install_4(TestNode) ->
- ?print(["install_4 start"]),
+ %% Check that the upgrade was done via a temporary release due to
+ %% new emulator version.
+ {"SASL-test","__new_emulator__P1H"} = init:script_id(),
+
+ %% Check that P2A is in use.
+ ?check_release_states([old,permanent,unpacked,current]),
+ ?check_running_app(a,"1.1"),
+ X = a:a(),
+ {key2, newval2} = lists:keyfind(key2, 1, X),
+ {key1, val1} = lists:keyfind(key1, 1, X),
+ {ok, bval} = a:b(),
+ ?print(["install_5 check env ok"]),
+ ok.
+
+install_5a(TestNode) ->
+ ?print(["install_5a start"]),
+
+ %% Install P1I (this will be a downgrade)
+ {ok, "P1I", [old_emu]} = release_handler:install_release("P1I"),
+ %% Node is rebooted by the release_handler:install_release
+ %% (init:reboot) because P2A includes a new erts vsn and the relup
+ %% file contains a 'restart_new_emulator' instruction.
+ ?print(["install_5a P1I installed"]),
+ ok.
+
+install_6(TestNode) ->
+ ?print(["install_6 start"]),
+
+ %% Check that P1I is used
+ ?check_release_states([old,permanent,current,old]),
+ ?check_running_app(a,"1.1"),
+
+ %% Make P1I permanent
+ ok = release_handler:make_permanent("P1I"),
+ ?check_release_states([old,old,permanent,old]),
+ ?check_running_app(a,"1.1"),
+ ok.
+
+install_6a(TestNode) ->
+ %% Install P2A
+ {continue_after_restart, "P1I", [new_emu]} =
+ release_handler:install_release("P2A"),
+ %% Node is rebooted by the release_handler:install_release
+ %% (init:reboot) because P2A includes a new erts vsn and the relup
+ %% file contains a 'restart_new_emulator' instruction.
+ ?print(["install_6a P2A installed"]),
+ ok.
+
+install_7(TestNode) ->
+ ?print(["install_7 start"]),
+
+ %% Check that the upgrade was done via a temporary release due to
+ %% new emulator version.
+ {"SASL-test","__new_emulator__P1I"} = init:script_id(),
% Check that P2A is in use.
- ?check_release("P2A",current,["a-1.1"]),
+ ?check_release_states([old,old,permanent,current]),
?check_running_app(a,"1.1"),
X = a:a(),
{key2, newval2} = lists:keyfind(key2, 1, X),
{key1, val1} = lists:keyfind(key1, 1, X),
{ok, bval} = a:b(),
+ ?print(["install_7 check env ok"]),
ok.
- % release_handler_SUITE will reboot this node now!
-install_5(TestNode) ->
- ?print(["install_5 start"]),
+install_7a(TestNode) ->
+ %% Install P1H (this will be a downgrade)
+ {ok, "P1H", [old_emu,old_appl]} = release_handler:install_release("P1H"),
+ %% Node is rebooted by the release_handler:install_release
+ %% (init:reboot) because P2A includes a new erts vsn and the relup
+ %% file contains a 'restart_new_emulator' instruction.
+ ?print(["install_7a P1H installed"]),
+ ok.
- % Check that P1I is used
- {ok, "P1I", [new_emu]} = release_handler:check_install_release("P2A"),
+install_8(TestNode) ->
+ ?print(["install_8 start"]),
+
+ %% Check that P1H is used
+ ?check_release_states([old,current,permanent,old]),
+ ?check_running_app(a,"1.0"),
+ {ok,"P1H",[new_emu,new_appl]} = release_handler:check_install_release("P2A"),
+ ?print(["install_8 check_install_release P2A ok"]),
+
+ %% Install P1I and check that it is permanent
+ {ok,"P1H",[{extra, gott}]} = release_handler:install_release("P1I"),
+ ?check_release_states([old,old,permanent,old]),
+ ?check_running_app(a,"1.1"),
ok.
-install_5a(TestNode) ->
+install_8a(TestNode) ->
% Install P2A again
- {ok, "P1I", [new_emu]} = release_handler:install_release("P2A"),
+ {continue_after_restart, "P1I", [new_emu]} =
+ release_handler:install_release("P2A"),
%% Node is rebooted by the release_handler:install_release
%% (init:reboot) because P2A includes a new erts vsn and the relup
%% file contains a 'restart_new_emulator' instruction.
- ?print(["install_5 P2A installed"]),
+ ?print(["install_8a P2A installed"]),
ok.
-install_6(TestNode) ->
- ?print(["install_6 start"]),
+install_9(TestNode) ->
+ ?print(["install_9 start"]),
+
+ %% Check that the upgrade was done via a temporary release due to
+ %% new emulator version.
+ {"SASL-test","__new_emulator__P1I"} = init:script_id(),
% Check that P2A is used
- ?check_release("P2A",current,["a-1.1"]),
+ ?check_release_states([old,old,permanent,current]),
?check_running_app(a,"1.1"),
X = a:a(),
{key2, newval2} = lists:keyfind(key2, 1, X),
{key1, val1} = lists:keyfind(key1, 1, X),
{ok, bval} = a:b(),
- ok = release_handler:make_permanent("P2A").
+ ?print(["install_9 check env ok"]),
+ ok = release_handler:make_permanent("P2A"),
+ ?check_release_states([old,old,old,permanent]),
+ ?check_running_app(a,"1.1"),
+ ok.
% release_handler_SUITE will reboot this node now!
-install_7(TestNode) ->
- ?print(["install_7 start"]),
+install_10(TestNode) ->
+ ?print(["install_10 start"]),
% Check that P2A is used
- ?check_release("P2A",permanent,["a-1.1"]),
+ ?check_release_states([old,old,old,permanent]),
+ ?check_running_app(a,"1.1"),
% Install old P1H
ok = release_handler:reboot_old_release("P1H"),
+ ?print(["install_10 reboot_old ok"]),
ok.
-install_8(TestNode) ->
- ?print(["install_8 start"]),
+
+install_11(TestNode) ->
+ ?print(["install_11 start"]),
% Check that P1H is permanent
- ?check_release("P1H",permanent,["a-1.0"]),
+ ?check_release_states([old,permanent,old,old]),
+ ?check_running_app(a,"1.0"),
X = a:a(),
{key2, val2} = lists:keyfind(key2, 1, X),
{key1, val1} = lists:keyfind(key1, 1, X),
+ ?print(["install_11 check env ok"]),
%% Remove P1I and P2A and check that a-1.1 and erts-<latest> are removed
ok = release_handler:remove_release("P2A"),
+ ?check_release_states([old,permanent,old]),
ok = release_handler:remove_release("P1I"),
+ ?check_release_states([old,permanent]),
{ok, Libs} = file:list_dir(code:lib_dir()),
{_,_,StdlibVsn} = lists:keyfind(stdlib,1,application:which_applications()),
true = lists:member("stdlib-"++StdlibVsn, Libs),
true = lists:member("a-1.0", Libs),
false = lists:member("a-1.1", Libs),
{ok, Dirs} = file:list_dir(code:root_dir()),
- ["erts-4.4"] = lists:filter(fun(Dir) -> lists:prefix("erts-",Dir) end, Dirs),
+ ErtsDir = "erts-"++?ertsvsn,
+ [ErtsDir] = lists:filter(fun(Dir) -> lists:prefix("erts-",Dir) end, Dirs),
+ ?print(["install_11 file checks ok"]),
ok.
% release_handler_SUITE will reboot this node now!
-install_9(TestNode) ->
- ?print(["install_9 start"]),
+install_12(TestNode) ->
+ ?print(["install_12 start"]),
% Check that P1H is permanent
- ?check_release("P1H",permanent,["a-1.0"]),
+ ?check_release_states([old,permanent]),
+ ?check_running_app(a,"1.0"),
X = a:a(),
{key2, val2} = lists:keyfind(key2, 1, X),
{key1, val1} = lists:keyfind(key1, 1, X),
+ ?print(["install_12 check env ok"]),
% Install old P1G
ok = release_handler:reboot_old_release("P1G"),
+ ?print(["install_12 reboot_old ok"]),
ok.
-install_10(TestNode) ->
- ?print(["install_10 start"]),
+install_13(TestNode) ->
+ ?print(["install_13 start"]),
% Check that P1G is permanent
- ?check_release("P1G",permanent,[]),
- ?check_release("P1H",old,["a-1.0"]),
+ ?check_release_states([permanent,old]),
+ false = lists:keysearch(a,1,application:loaded_applications()),
+ ?print(["install_13 no a application found - ok"]),
%% Remove P1H and check that both versions of application a is removed
ok = release_handler:remove_release("P1H"),
+ ?check_release_states([permanent]),
{ok, Libs} = file:list_dir(code:lib_dir()),
{_,_,StdlibVsn} = lists:keyfind(stdlib,1,application:which_applications()),
true = lists:member("stdlib-"++StdlibVsn, Libs),
false = lists:member("a-1.0", Libs),
false = lists:member("a-1.1", Libs),
+ ?print(["install_13 file checks ok"]),
ok.
% release_handler_SUITE will reboot this node now!
-install_11(TestNode) ->
- ?print(["install_11 start"]),
+install_14(TestNode) ->
+ ?print(["install_14 start"]),
% Check that P1G is permanent
- ?check_release("P1G",permanent,[]),
+ ?check_release_states([permanent]),
+ false = lists:keysearch(a,1,application:loaded_applications()),
+ ?print(["install_13 no a application found - ok"]),
ok.
+%%%-----------------------------------------------------------------
+%%% Ths test checks that an upgrade which both upgrades to a new
+%%% emulator version, and had a restart_emulator option to
+%%% systools:make_relup will be restarted twice on upgrade.
+%%% (On downgrade it will happen only once.)
+upgrade_restart_1(TestNode,PrivDir) ->
+ ?print([TestNode]),
+ ?print(["upgrade_restart_1 start"]),
+ ?check_release_states([permanent]),
+
+ {ok, "P2B"} = unpack_release(PrivDir,"rel4"),
+ ?check_release_states([permanent,unpacked]),
+ ?check_release_lib("P2B",["a-1.1"]),
+ ok.
+
+upgrade_restart_1a(TestNode) ->
+ ?print(["upgrade_restart_1a start"]),
+
+ {continue_after_restart,"P1G",[new_emu,add_appl]} =
+ release_handler:install_release("P2B"),
+ ?print(["upgrade_restart_1a P2B installed"]),
+ ok.
+
+upgrade_restart_2(TestNode) ->
+ ?print(["upgrade_restart_2 start"]),
+
+ %% Check that the node has been restarted once more after the tmp release
+ case init:script_id() of
+ {"SASL-test","P2B"} ->
+ upgrade_restart_2a(TestNode);
+ {"SASL-test","__new_emulator__P1G"} ->
+ %% catched the node too early - give it another try
+ {wait,whereis(init)}
+ end.
+
+upgrade_restart_2a(TestNode) ->
+ ?print(["upgrade_restart_2a start"]),
+
+ %% This time we must be there, else something is definitely wrong
+ {"SASL-test","P2B"} = init:script_id(),
+
+ ?check_release_states([permanent,current]),
+ ?check_running_app(a,"1.1"),
+
+ ok = release_handler:make_permanent("P2B"),
+ ?check_release_states([old,permanent]),
+
+ ok.
+
+upgrade_restart_2b(TestNode) ->
+ ?print(["upgrade_restart_2b start"]),
+
+ {ok,"P1G",[old_emu,rm_appl]} = release_handler:install_release("P1G"),
+ ?print(["upgrade_restart_2b P1G installed"]),
+ ok.
+
+upgrade_restart_3(TestNode) ->
+ ?print(["upgrade_restart_3 start"]),
+
+ %% Ideally we should test that the node has only been restarted
+ %% once... but that's not so easy. Let's just check that P1G is running.
+ ?check_release_states([current,permanent]),
+ false = lists:keysearch(a,1,application:loaded_applications()),
+ ?print(["upgrade_restart_3 no a application found - ok"]),
+
+ ok.
+
+
+
%%-----------------------------------------------------------------
%% This test starts a client node which uses this node as master
@@ -272,6 +470,8 @@ client1_1(TestNode,PrivDir,MasterDir,ClientSname) ->
Node = start_client(TestNode,client1,ClientSname),
trace_disallowed_calls(Node),
+ ?check_release_states_client(Node,[permanent]),
+
%% Check env var for SASL on client node
SaslEnv = rpc:call(Node, application, get_all_env, [sasl]),
?print([{client1_1,sasl_env},SaslEnv]),
@@ -300,13 +500,14 @@ client1_1(TestNode,PrivDir,MasterDir,ClientSname) ->
%% as default. But it is given here in order to force hitting the
%% release_handler:check_path function so it can be checked that
%% it does not use file:read_file_info on the client node, see
- %% trace_disallowed_calls/1 and check_disallowed_calls/0 below.
+ %% trace_disallowed_calls/1 and check_disallowed_calls/2 below.
%% (OTP-9142)
{ok, "P1H"} = rpc:call(Node, release_handler, set_unpacked,
[filename:join(P1HDir, "rel1.rel"),
[{a,"1.0",filename:join(MasterDir,lib)}]]),
- ?check_release_client(Node,"P1H",unpacked,["a-1.0"]),
+ ?check_release_states_client(Node,[permanent,unpacked]),
+ ?check_release_lib_client(Node,"P1H",["a-1.0"]),
ok = rpc:call(Node, release_handler, install_file,
["P1H", filename:join(P1HDir, "start.boot")]),
@@ -323,13 +524,16 @@ client1_1(TestNode,PrivDir,MasterDir,ClientSname) ->
{ok,"P1G",[new_appl]} =
rpc:call(Node, release_handler, install_release, ["P1H"]),
+ ?check_release_states_client(Node,[permanent,current]),
+ ?check_running_app_client(Node,a,"1.0"),
+
Apps = rpc:call(Node, application, which_applications, []),
{a,"A CXC 138 11","1.0"} = lists:keyfind(a, 1, Apps),
X = rpc:call(Node, a, a, []),
{key2, val2} = lists:keyfind(key2, 1, X),
{key1, val1} = lists:keyfind(key1, 1, X),
- check_disallowed_calls(),
+ ?check_disallowed_calls,
reboot(TestNode,Node),
trace_disallowed_calls(Node),
@@ -339,17 +543,17 @@ client1_2(TestNode,PrivDir,Node) ->
?print(["client1_2 start"]),
%% Check that P1H is still unpacked, install it and make_permanent
- ?check_release_client(Node,"P1H",unpacked,["a-1.0"]),
+ ?check_release_states_client(Node,[permanent,unpacked]),
{ok,"P1G",[new_appl]} =
rpc:call(Node, release_handler, install_release, ["P1H"]),
- ?check_release_client(Node,"P1H",current,["a-1.0"]),
+ ?check_release_states_client(Node,[permanent,current]),
?check_running_app_client(Node,a,"1.0"),
ok = rpc:call(Node, release_handler, make_permanent, ["P1H"]),
- ?check_release_client(Node,"P1H",permanent,["a-1.0"]),
+ ?check_release_states_client(Node,[old,permanent]),
- check_disallowed_calls(),
+ ?check_disallowed_calls,
reboot(TestNode,Node),
trace_disallowed_calls(Node),
@@ -359,10 +563,8 @@ client1_3(TestNode,PrivDir,Node) ->
?print(["client1_3 start"]),
%% Check that P1H is permanent
- ?check_release_client(Node,"P1H",permanent,["a-1.0"]),
- X = rpc:call(Node, a, a, []),
- {key2, val2} = lists:keyfind(key2, 1, X),
- {key1, val1} = lists:keyfind(key1, 1, X),
+ ?check_release_states_client(Node,[old,permanent]),
+ ?check_running_app_client(Node,a,"1.0"),
%% Unpack P1I on master
{ok, "P1I"} = unpack_release(PrivDir,"rel2"),
@@ -374,7 +576,8 @@ client1_3(TestNode,PrivDir,Node) ->
{ok, "P1I"} = rpc:call(Node, release_handler, set_unpacked,
[filename:join(P1IDir, "rel2.rel"),[]]),
- ?check_release_client(Node,"P1I",unpacked,["a-1.1"]),
+ ?check_release_states_client(Node,[old,permanent,unpacked]),
+ ?check_release_lib_client(Node,"P1I",["a-1.1"]),
ok = rpc:call(Node, release_handler, install_file,
["P1I", filename:join(P1IDir, "start.boot")]),
@@ -389,6 +592,7 @@ client1_3(TestNode,PrivDir,Node) ->
{ok,"P1H",[{extra, gott}]} =
rpc:call(Node, release_handler, install_release, ["P1I"]),
+ ?check_release_states_client(Node,[old,permanent,current]),
?check_running_app_client(Node,a,"1.1"),
X2 = rpc:call(Node, a, a, []),
{key2, newval2} = lists:keyfind(key2, 1, X2),
@@ -404,6 +608,9 @@ client1_3(TestNode,PrivDir,Node) ->
rpc:call(Node, release_handler, set_unpacked,
[filename:join(P2ADir, "rel3.rel"),[]]),
+ ?check_release_states_client(Node,[old,permanent,current,unpacked]),
+ ?check_release_lib_client(Node,"P2A",["a-1.1"]),
+
ok = rpc:call(Node, release_handler, install_file,
["P2A", filename:join(P2ADir, "start.boot")]),
ok = rpc:call(Node, release_handler, install_file,
@@ -413,66 +620,136 @@ client1_3(TestNode,PrivDir,Node) ->
{ok, "P1I", [new_emu]} =
rpc:call(Node, release_handler, check_install_release, ["P2A"]),
+
+ %% Reboot from P1H
+ ?check_disallowed_calls,
+ reboot(TestNode,Node),
+ trace_disallowed_calls(Node),
+
+ client1_4(TestNode,Node).
+
+client1_4(TestNode,Node) ->
+ ?print(["client1_4 start"]),
+
+ %% check that P1H is used
+ ?check_release_states_client(Node,[old,permanent,unpacked,unpacked]),
+
+ %% since the install_release below reboot the node...
+ ?check_disallowed_calls,
+ cover_client(TestNode,Node,stop_cover),
+
+ {continue_after_restart, "P1H", [new_emu,new_appl]} =
+ rpc:call(Node, release_handler, install_release, ["P2A"]),
+ %% Reboots the client !
+
+ check_reboot(TestNode,Node),
+ trace_disallowed_calls(Node),
+
+ client1_5(TestNode,Node).
+
+client1_5(TestNode,Node) ->
+ ?print(["client1_5 start"]),
+
+ %% Check that P2A is in use.
+ ?check_release_states_client(Node,[old,permanent,unpacked,current]),
+ ?check_running_app_client(Node,a,"1.1"),
+ X = rpc:call(Node, a, a, []),
+ {key2, newval2} = lists:keyfind(key2, 1, X),
+ {key1, val1} = lists:keyfind(key1, 1, X),
+ {ok, bval} = rpc:call(Node, a, b, []),
+
+ %% since the install_release below reboot the node...
+ ?check_disallowed_calls,
+ cover_client(TestNode,Node,stop_cover),
+
+ {ok,"P1I",[old_emu]} =
+ rpc:call(Node, release_handler, install_release, ["P1I"]),
+
+ check_reboot(TestNode,Node),
+ trace_disallowed_calls(Node),
+
+ client1_6(TestNode,Node).
+
+client1_6(TestNode,Node) ->
+ ?print(["client1_6 start"]),
+
+ ?check_release_states_client(Node,[old,permanent,current,old]),
+ ?check_running_app_client(Node,a,"1.1"),
+
ok = rpc:call(Node, release_handler, make_permanent, ["P1I"]),
- ?check_release_client(Node,"P1I",permanent,["a-1.1"]),
+ ?check_release_states_client(Node,[old,old,permanent,old]),
%% since the install_release below reboot the node...
- check_disallowed_calls(),
+ ?check_disallowed_calls,
cover_client(TestNode,Node,stop_cover),
- {ok, "P1I", [new_emu]} =
+ {continue_after_restart, "P1I", [new_emu]} =
rpc:call(Node, release_handler, install_release, ["P2A"]),
%% Reboots the client !
check_reboot(TestNode,Node),
trace_disallowed_calls(Node),
- client1_4(TestNode,Node).
+ client1_7(TestNode,Node).
-client1_4(TestNode,Node) ->
- ?print(["client1_4 start"]),
+client1_7(TestNode,Node) ->
+ ?print(["client1_7 start"]),
%% Check that P2A is in use.
- ?check_release_client(Node,"P2A",current,["a-1.1"]),
+ ?check_release_states_client(Node,[old,old,permanent,current]),
?check_running_app_client(Node,a,"1.1"),
X = rpc:call(Node, a, a, []),
{key2, newval2} = lists:keyfind(key2, 1, X),
{key1, val1} = lists:keyfind(key1, 1, X),
{ok, bval} = rpc:call(Node, a, b, []),
- %% Reboot from P1I
- check_disallowed_calls(),
- reboot(TestNode,Node),
+ %% since the install_release below reboot the node...
+ ?check_disallowed_calls,
+ cover_client(TestNode,Node,stop_cover),
+
+ {ok,"P1H",[old_emu,old_appl]} =
+ rpc:call(Node, release_handler, install_release, ["P1H"]),
+
+ check_reboot(TestNode,Node),
trace_disallowed_calls(Node),
- client1_5(TestNode,Node).
+ client1_8(TestNode,Node).
-client1_5(TestNode,Node) ->
- ?print(["client1_5 start"]),
+client1_8(TestNode,Node) ->
+ ?print(["client1_8 start"]),
- %% Check that P1I is used
- {ok, "P1I", [new_emu]} =
+ %% Check that P1H is used
+ ?check_release_states_client(Node,[old,current,permanent,old]),
+ ?check_running_app_client(Node,a,"1.0"),
+ {ok, "P1H", [new_emu,new_appl]} =
rpc:call(Node, release_handler, check_install_release, ["P2A"]),
+
+ {ok,"P1H",[{extra, gott}]} =
+ rpc:call(Node, release_handler, install_release, ["P1I"]),
+ ?check_release_states_client(Node,[old,old,permanent,old]),
+ ?check_running_app_client(Node,a,"1.1"),
+
+
%% since the install_release below will reboot the node...
- check_disallowed_calls(),
+ ?check_disallowed_calls,
cover_client(TestNode,Node,stop_cover),
%% Install P2A again
- {ok, "P1I", [new_emu]} =
+ {continue_after_restart, "P1I", [new_emu]} =
rpc:call(Node, release_handler, install_release, ["P2A"]),
%% We are rebooted again.
check_reboot(TestNode,Node),
trace_disallowed_calls(Node),
- client1_6(TestNode,Node).
+ client1_9(TestNode,Node).
-client1_6(TestNode,Node) ->
- ?print(["client1_6 start"]),
+client1_9(TestNode,Node) ->
+ ?print(["client1_9 start"]),
%% Check that P2A is used
- ?check_release_client(Node,"P2A",current,["a-1.1"]),
+ ?check_release_states_client(Node,[old,old,permanent,current]),
?check_running_app_client(Node,a,"1.1"),
X = rpc:call(Node, a, a, []),
{key2, newval2} = lists:keyfind(key2, 1, X),
@@ -481,22 +758,23 @@ client1_6(TestNode,Node) ->
%% Make P2A permanent
ok = rpc:call(Node, release_handler, make_permanent, ["P2A"]),
+ ?check_release_states_client(Node,[old,old,old,permanent]),
%% Reboot from P2A
- check_disallowed_calls(),
+ ?check_disallowed_calls,
reboot(TestNode,Node),
trace_disallowed_calls(Node),
- client1_7(TestNode,Node).
+ client1_10(TestNode,Node).
-client1_7(TestNode,Node) ->
- ?print(["client1_7 start"]),
+client1_10(TestNode,Node) ->
+ ?print(["client1_10 start"]),
%% Check that P2A is used
- ?check_release_client(Node,"P2A",permanent,["a-1.1"]),
+ ?check_release_states_client(Node,[old,old,old,permanent]),
%% since the reboot_old_release below will reboot the node
- check_disallowed_calls(),
+ ?check_disallowed_calls,
cover_client(TestNode,Node,stop_cover),
%% Install old P1H
@@ -505,41 +783,45 @@ client1_7(TestNode,Node) ->
check_reboot(TestNode,Node),
trace_disallowed_calls(Node),
- client1_8(TestNode,Node).
+ client1_11(TestNode,Node).
-client1_8(TestNode,Node) ->
- ?print(["client1_8 start"]),
+client1_11(TestNode,Node) ->
+ ?print(["client1_11 start"]),
%% Check that P1H is permanent
- ?check_release_client(Node,"P1H",permanent,["a-1.0"]),
+ ?check_release_states_client(Node,[old,permanent,old,old]),
+ ?check_running_app_client(Node,a,"1.0"),
X = rpc:call(Node, a, a, []),
{key2, val2} = lists:keyfind(key2, 1, X),
{key1, val1} = lists:keyfind(key1, 1, X),
- %% Remove P1I and P2I from client
+ %% Remove P1I and P2A from client
ok = rpc:call(Node, release_handler, set_removed, ["P2A"]),
+ ?check_release_states_client(Node,[old,permanent,old]),
ok = rpc:call(Node, release_handler, set_removed, ["P1I"]),
+ ?check_release_states_client(Node,[old,permanent]),
- check_disallowed_calls(),
- reboot(TestNode,Node),
- trace_disallowed_calls(Node),
-
- client1_9(TestNode,Node).
-
-client1_9(TestNode,Node) ->
- ?print(["client1_9 start"]),
-
- %% Check that P2A and P1I does not exists and that PiH is permanent.
+ %% Check that P2A and P1I does not exists
Rels = rpc:call(Node, release_handler, which_releases, []),
false = lists:keysearch("P2A", 2, Rels),
false = lists:keysearch("P1I", 2, Rels),
- ?check_release_client(Node,"P1H",permanent,["a-1.0"]),
X = rpc:call(Node, a, a, []),
{key2, val2} = lists:keyfind(key2, 1, X),
{key1, val1} = lists:keyfind(key1, 1, X),
+ ?check_disallowed_calls,
+ reboot(TestNode,Node),
+ trace_disallowed_calls(Node),
+
+ client1_12(TestNode,Node).
+
+client1_12(TestNode,Node) ->
+ ?print(["client1_12 start"]),
+
+ ?check_release_states_client(Node,[old,permanent]),
+
%% since the reboot_old_release below will reboot the node
- check_disallowed_calls(),
+ ?check_disallowed_calls,
cover_client(TestNode,Node,stop_cover),
%% Install old P1G
@@ -548,33 +830,34 @@ client1_9(TestNode,Node) ->
check_reboot(TestNode,Node),
trace_disallowed_calls(Node),
- client1_10(TestNode,Node).
+ client1_13(TestNode,Node).
-client1_10(TestNode,Node) ->
- ?print(["client1_10 start"]),
+client1_13(TestNode,Node) ->
+ ?print(["client1_13 start"]),
%% Check that P1G is permanent
- ?check_release_client(Node,"P1G",permanent,[]),
- ?check_release_client(Node,"P1H",old,["a-1.0"]),
+ ?check_release_states_client(Node,[permanent,old]),
{error,client_node} = rpc:call(Node,release_handler,remove_release,["P1H"]),
ok = rpc:call(Node, release_handler, set_removed, ["P1H"]),
+ ?check_release_states_client(Node,[permanent]),
- check_disallowed_calls(),
+ ?check_disallowed_calls,
reboot(TestNode,Node),
trace_disallowed_calls(Node),
- client1_11(TestNode,Node).
+ client1_14(TestNode,Node).
-client1_11(TestNode,Node) ->
- ?print(["client1_11 start"]),
+client1_14(TestNode,Node) ->
+ ?print(["client1_14 start"]),
%% Check that P1G is permanent
- ?check_release_client(Node,"P1G",permanent,[]),
+ ?check_release_states_client(Node,[permanent]),
- check_disallowed_calls(),
+ ?check_disallowed_calls,
stop_client(TestNode,Node), %% TEST IS OK !!
net_kernel:monitor_nodes(false),
+ %% Remove releases from master
ok = release_handler:remove_release("P2A"),
ok = release_handler:remove_release("P1I"),
ok = release_handler:remove_release("P1H"),
@@ -595,9 +878,10 @@ trace_disallowed_calls(Node) ->
rpc:call(Node,dbg,p,[all,call]),
rpc:call(Node,dbg,tp,[file,[{'_',[],[{message,{caller}}]}]]).
-check_disallowed_calls() ->
+check_disallowed_calls(TestNode,Line) ->
receive
Trace when element(1,Trace)==trace ->
+ ?print_line(Line,["Disallowed function called",Trace]),
exit({disallowed_function_call,Trace})
after 0 ->
ok
@@ -628,7 +912,7 @@ start_client_unix(TestNode,Sname,Node) ->
start_client_win32(TestNode,Client,ClientSname) ->
Name = atom_to_list(ClientSname) ++ "_P1G",
RootDir = code:root_dir(),
- ErtsBinDir = filename:join(RootDir,"erts-4.4/bin"),
+ ErtsBinDir = filename:join([RootDir,"erts-"++?ertsvsn,"bin"]),
{ClientArgs,RelClientDir} = rh_test_lib:get_client_args(Client,ClientSname,
RootDir),
@@ -729,8 +1013,10 @@ client2(TestNode,PrivDir,ClientSname) ->
ok
end,
+ %% Unpack P1H on master
{ok, "P1H"} = unpack_release(PrivDir,"rel1"),
+ %% Try to set P1H unpacked on client
Root = code:root_dir(),
{error,{bad_masters,[Master2]}} =
rpc:call(Node, release_handler, set_unpacked,
@@ -755,15 +1041,17 @@ stop(Now) ->
unpack_p1h(TestNode,PrivDir) ->
{ok, "P1H"} = unpack_release(PrivDir,"rel1"),
- ?check_release("P1H",unpacked,["a-1.0"]),
+ ?check_release_states([permanent,unpacked]),
+ ?check_release_lib("P1H",["a-1.0"]),
ok.
permanent_p1h(TestNode) ->
- ?check_release("P1H",unpacked,["a-1.0"]),
+ ?check_release_states([permanent,unpacked]),
+ ?check_release_lib("P1H",["a-1.0"]),
{ok,"P1G",[new_appl]} = release_handler:install_release("P1H"),
- ?check_release("P1H",current,["a-1.0"]),
+ ?check_release_states([permanent,current]),
ok = release_handler:make_permanent("P1H"),
- ?check_release("P1H",permanent,["a-1.0"]),
+ ?check_release_states([old,permanent]),
ok.
@@ -779,24 +1067,38 @@ registered_loop(_Name) ->
exit(killed)
end.
-check_release(TestNode,Node,Vsn,Status,Apps,Line) ->
+%% Checks that the list of states for all releases (sorted on vsn)
+%% equals the input States
+check_release_states(TestNode,Node,States,Line) ->
+ case rpc:call(Node,release_handler,which_releases,[]) of
+ {badrpc,_}=Error ->
+ ?fail_line(Line,{check_release_states,Node,States,Error});
+ Rels ->
+ ?print_line(Line,["check_release_states:", Rels]),
+ States = [Status || {_,_,_,Status} <- lists:keysort(2,Rels)],
+ ok
+ end.
+
+%% Check that the given release (Vsn) sees the correct vsn of App.
+check_release_lib(TestNode,Node,Vsn,Apps,Line) ->
case rpc:call(Node,release_handler,which_releases,[]) of
{badrpc,_}=Error ->
- ?fail_line(Line,{check_release,Node,Vsn,Status,Error});
+ ?fail_line(Line,{check_release_lib,Node,Vsn,Apps,Error});
Rels ->
- ?print_line(Line,["check_release:", Rels]),
- {"SASL-test", Vsn, Libs, Status} = lists:keyfind(Vsn, 2, Rels),
+ ?print_line(Line,["check_release_lib:", Rels]),
+ {"SASL-test", Vsn, Libs, _Status} = lists:keyfind(Vsn, 2, Rels),
true = lists:all(fun(App) -> lists:member(App,Libs) end,Apps),
ok
end.
+%% Check that the given Vsn of App is executed
check_running_app(TestNode,Node,App,Vsn,Line) ->
case rpc:call(Node,application,which_applications,[]) of
{badrpc,_}=Error ->
?fail_line(Line,{check_running_app,Node,App,Vsn,Error});
Apps ->
?print_line(Line,["check_running_app:", Apps]),
- {App, _, Vsn} = lists:keyfind(a, 1, Apps),
+ {App, _, Vsn} = lists:keyfind(App, 1, Apps),
ok
end.
diff --git a/lib/sasl/test/release_handler_SUITE.erl b/lib/sasl/test/release_handler_SUITE.erl
index af2183bfff..ac616dab72 100644
--- a/lib/sasl/test/release_handler_SUITE.erl
+++ b/lib/sasl/test/release_handler_SUITE.erl
@@ -19,6 +19,7 @@
-module(release_handler_SUITE).
-include_lib("common_test/include/ct.hrl").
+-include("test_lib.hrl").
-compile(export_all).
@@ -30,6 +31,7 @@ suite() ->
[{ct_hooks, [ts_install_cth]}].
init_per_suite(Config) ->
+ init_priv_dir(Config),
application:start(sasl),
Config.
@@ -58,7 +60,10 @@ cases() ->
[otp_2740, otp_2760, otp_5761, otp_9402, otp_9417,
otp_9395_check_old_code, otp_9395_check_and_purge,
otp_9395_update_many_mods, otp_9395_rm_many_mods,
- instructions, eval_appup, supervisor_which_children_timeout].
+ instructions, eval_appup, eval_appup_with_restart,
+ supervisor_which_children_timeout,
+ release_handler_which_releases, install_release_syntax_check,
+ upgrade_supervisor, upgrade_supervisor_fail].
groups() ->
[{release,[],
@@ -69,6 +74,7 @@ groups() ->
{release_single,[],
[
upgrade,
+ upgrade_restart,
client1,
client2
]},
@@ -82,7 +88,7 @@ groups() ->
init_per_group(release, Config) ->
Dog = ?t:timetrap(?default_timeout),
P1gInstall = filename:join(priv_dir(Config),p1g_install),
- ok = do_create_p1g(Config,P1gInstall),
+ ok = create_p1g(Config,P1gInstall),
ok = create_p1h(Config),
?t:timetrap_cancel(Dog);
@@ -95,6 +101,7 @@ init_per_group(release_single, Config) ->
%% Create some more releases to upgrade to
ok = create_p1i(Config),
ok = create_p2a(Config),
+ ok = create_p2b(Config),
?t:timetrap_cancel(Dog);
@@ -155,7 +162,7 @@ end_per_group(release, Config) ->
{win32,_} -> delete_all_services();
_ -> ok
end,
- delete_release(Config),
+ clean_priv_dir(Config,true),
?t:timetrap_cancel(Dog),
Config;
end_per_group(_GroupName, Config) ->
@@ -191,7 +198,10 @@ end_per_testcase(Case, Config) ->
FailDir = filename:join(SaveDir,lists:concat(["failed-",Case])),
ok = filelib:ensure_dir(filename:join(FailDir,"*")),
- LogDirs = filelib:wildcard(filename:join([PrivDir,"*",log])),
+ LogDirs =
+ filelib:wildcard(filename:join([PrivDir,"*",log])) ++
+ filelib:wildcard(filename:join([PrivDir,"*",clients,
+ type1,"*",log])),
lists:foreach(
fun(LogDir) ->
@@ -236,7 +246,7 @@ break(Config) ->
?t:break(priv_dir(Config)),
ok.
-%% Test upgrade and downgrade of erts
+%% Test upgrade and downgrade of erts and other apps on embedded node
upgrade(Conf) when is_list(Conf) ->
reg_print_proc(), %% starts a printer process on test_server node
?t:format("upgrade ~p~n",[reg_print_proc]),
@@ -259,54 +269,75 @@ upgrade(Conf) when is_list(Conf) ->
stop_cover(TestNode),
reboot_and_wait(TestNode,"install_2",[a]),
- %% check that P1H is permanent, unpack and install P1I, unpack and install P2A
- TestNodeInit1 = rpc:call(TestNode,erlang,whereis,[init]),
+ %% check that P1H is permanent, unpack and install P1I, unpack P2A
ok = rpc_inst(TestNode, install_3, [PrivDir]),
stop_cover(TestNode),
- ok = rpc_inst(TestNode, install_3a, []),
- wait_nodes_up([{TestNode,TestNodeInit1}],"install_3",[a]),
+ reboot_and_wait(TestNode,"install_3",[a]),
- %% check that P2A is used, reboot from P1I
- ok = rpc_inst(TestNode, install_4, []),
+ %% check that P1H is used, install P2A
+ TestNodeInit1 = rpc:call(TestNode,erlang,whereis,[init]),
stop_cover(TestNode),
- reboot_and_wait(TestNode,"install_4",[a]),
+ ok = rpc_inst(TestNode, install_4, []),
+ wait_nodes_up([{TestNode,TestNodeInit1}],"install_4",[a]),
- %% check that P1I, reinstall P2A
+ %% check that P2A is used, then downgrade to P1I
TestNodeInit2 = rpc:call(TestNode,erlang,whereis,[init]),
ok = rpc_inst(TestNode, install_5, []),
stop_cover(TestNode),
ok = rpc_inst(TestNode, install_5a, []),
wait_nodes_up([{TestNode,TestNodeInit2}],"install_5",[a]),
- %% check that P2A is used, make P2A permanent
+ %% Check that P1I is used, then make P1I permanent and install P2A
+ TestNodeInit3 = rpc:call(TestNode,erlang,whereis,[init]),
ok = rpc_inst(TestNode, install_6, []),
stop_cover(TestNode),
- reboot_and_wait(TestNode,"install_6",[a]),
+ ok = rpc_inst(TestNode, install_6a, []),
+ wait_nodes_up([{TestNode,TestNodeInit3}],"install_6",[a]),
- %% check that P2A is permanent, install old P1H
- TestNodeInit3 = rpc:call(TestNode,erlang,whereis,[init]),
- stop_cover(TestNode),
+ %% check that P2A is used, then downgrade to P1H
+ TestNodeInit4 = rpc:call(TestNode,erlang,whereis,[init]),
ok = rpc_inst(TestNode, install_7, []),
- wait_nodes_up([{TestNode,TestNodeInit3}],"install_7",[a]),
+ stop_cover(TestNode),
+ ok = rpc_inst(TestNode, install_7a, []),
+ wait_nodes_up([{TestNode,TestNodeInit4}],"install_7",[a]),
- %% check that P1H is permanent, remove P1I and P2A
+ %% check that P1H is used, then install P1I and check that it is permanent
+ %% then reinstall P2A
+ TestNodeInit5 = rpc:call(TestNode,erlang,whereis,[init]),
ok = rpc_inst(TestNode, install_8, []),
stop_cover(TestNode),
- reboot_and_wait(TestNode,"install_8",[a]),
+ ok = rpc_inst(TestNode, install_8a, []),
+ wait_nodes_up([{TestNode,TestNodeInit5}],"install_8",[a]),
+
+ %% check that P2A is used, make P2A permanent
+ ok = rpc_inst(TestNode, install_9, []),
+ stop_cover(TestNode),
+ reboot_and_wait(TestNode,"install_9",[a]),
+
+ %% check that P2A is permanent, reboot to old P1H
+ TestNodeInit6 = rpc:call(TestNode,erlang,whereis,[init]),
+ stop_cover(TestNode),
+ ok = rpc_inst(TestNode, install_10, []),
+ wait_nodes_up([{TestNode,TestNodeInit6}],"install_10",[a]),
+
+ %% check that P1H is permanent, remove P1I and P2A
+ ok = rpc_inst(TestNode, install_11, []),
+ stop_cover(TestNode),
+ reboot_and_wait(TestNode,"install_11",[a]),
%% check that P1H is permanent, reboot old P1G
- TestNodeInit4 = rpc:call(TestNode,erlang,whereis,[init]),
+ TestNodeInit7 = rpc:call(TestNode,erlang,whereis,[init]),
stop_cover(TestNode),
- ok = rpc_inst(TestNode, install_9, []),
- wait_nodes_up([{TestNode,TestNodeInit4}],"install_9"),
+ ok = rpc_inst(TestNode, install_12, []),
+ wait_nodes_up([{TestNode,TestNodeInit7}],"install_12"),
%% check that P1G is permanent, remove P1H
- ok = rpc_inst(TestNode, install_10, []),
+ ok = rpc_inst(TestNode, install_13, []),
stop_cover(TestNode),
- reboot_and_wait(TestNode,"install_10"),
+ reboot_and_wait(TestNode,"install_13"),
%% check that P1G is permanent
- ok = rpc_inst(TestNode, install_11, []),
+ ok = rpc_inst(TestNode, install_14, []),
ok.
@@ -323,6 +354,54 @@ reboot_and_wait(Node,Tag,Apps) ->
wait_nodes_up([{Node,InitPid}],Tag,Apps).
+%% Test upgrade and downgrade of erts in combination with the
+%% restart_emulator option to systools:make_relup. For upgrade, this
+%% should cause one restart before the upgrade code, and one
+%% after. For downgrade, there will be one restart only - at the end.
+upgrade_restart(Conf) when is_list(Conf) ->
+ reg_print_proc(), %% starts a printer process on test_server node
+ ?t:format("upgrade_restart ~p~n",[reg_print_proc]),
+ PrivDir = priv_dir(Conf),
+ Sname = tc_sname(Conf), % nodename for use in this testcase
+
+ %% Copy the P1G release to a directory for use in this testcase
+ ok = copy_installed(Conf,p1g_install,[Sname]),
+
+ %% start the test node
+ [TestNode] = start_nodes(Conf,[Sname],"upgrade_restart start"),
+
+ %% unpack and install P2B
+ TestNodeInit1 = rpc:call(TestNode,erlang,whereis,[init]),
+ ok = rpc_inst(TestNode, upgrade_restart_1, [PrivDir]),
+ stop_cover(TestNode),
+ ok = rpc_inst(TestNode, upgrade_restart_1a, []),
+ wait_nodes_up([{TestNode,TestNodeInit1}],"upgrade_restart_1",[a]),
+
+ %% install P1G
+ case rpc_inst(TestNode, upgrade_restart_2, []) of
+ ok ->
+ ok;
+ {wait,TestNodeInit2a} ->
+ %% We catched the node too early - it was supposed to
+ %% restart twice, so let's wait for one more restart.
+ wait_nodes_up([{TestNode,TestNodeInit2a}],"upgrade_restart_2a",[]),
+ ok = rpc_inst(TestNode, upgrade_restart_2a, [])
+ end,
+ TestNodeInit2 = rpc:call(TestNode,erlang,whereis,[init]),
+ stop_cover(TestNode),
+ ok = rpc_inst(TestNode, upgrade_restart_2b, []),
+ wait_nodes_up([{TestNode,TestNodeInit2}],"upgrade_restart_2b",[]),
+
+ %% Check that P1G is going again
+ ok = rpc_inst(TestNode, upgrade_restart_3, []),
+
+ ok.
+
+upgrade_restart(cleanup,Config) ->
+ TestNode = tc_full_node_name(Config),
+ ok = stop_nodes([TestNode]).
+
+
%% Test upgrade and downgrade of erts, diskless
client1(Conf) when is_list(Conf) ->
reg_print_proc(), %% starts a printer process on test_server node
@@ -542,9 +621,51 @@ supervisor_which_children_timeout(Conf) ->
ok.
-supervisor_which_children_timeout(cleanup, Conf) ->
+supervisor_which_children_timeout(cleanup, _Conf) ->
stop_node(node_name(supervisor_which_children_timeout)).
+
+%% Test that check_install_release will fail for illegal relup
+%% instructions, even after point of no return.
+install_release_syntax_check(Conf) when is_list(Conf) ->
+
+ S1 = [point_of_no_return, illegal_instruction],
+ {error,{illegal_instruction_after_point_of_no_return,illegal_instruction}} =
+ release_handler_1:check_script(S1,[]),
+
+ S2 = [point_of_no_return,restart_new_emulator],
+ {error,{illegal_instruction_after_point_of_no_return,restart_new_emulator}} =
+ release_handler_1:check_script(S2,[]),
+
+ ok.
+
+
+%%-----------------------------------------------------------------
+%% release_handler:which_releases/0 and 1 test
+%%-----------------------------------------------------------------
+release_handler_which_releases(Conf) ->
+ PrivDir = priv_dir(Conf),
+ Dir = filename:join(PrivDir,"release_handler_which_releases"),
+ DataDir = ?config(data_dir,Conf),
+ LibDir = filename:join([DataDir,release_handler_timeouts]),
+
+ Rel1 = create_and_install_fake_first_release(Dir,[{dummy,"0.1",LibDir}]),
+
+ {ok, Node} = t_start_node(release_handler_which_releases, Rel1, []),
+ Releases0 = rpc:call(Node, release_handler, which_releases, []),
+ Releases1 = rpc:call(Node, release_handler, which_releases, [permanent]),
+ Releases2 = rpc:call(Node, release_handler, which_releases, [old]),
+
+ 1 = length(Releases0),
+ 1 = length(Releases1),
+ 0 = length(Releases2),
+
+ ?t:format("release_handler:which_releases/0: ~p~n", [Releases0]),
+ ?t:format("release_handler:which_releases/1: ~p~n", [Releases1]),
+ ?t:format("release_handler:which_releases/1: ~p~n", [Releases2]),
+
+ ok.
+
%%-----------------------------------------------------------------
%% Ticket: OTP-2740
%% Slogan: vsn not numeric doesn't work so good in release_handling
@@ -1085,6 +1206,109 @@ otp_9395_rm_many_mods(cleanup,_Conf) ->
stop_node(node_name(otp_9395_rm_many_mods)).
+upgrade_supervisor(Conf) when is_list(Conf) ->
+ %% Set some paths
+ PrivDir = priv_dir(Conf),
+ Dir = filename:join(PrivDir,"upgrade_supervisor"),
+ LibDir = filename:join(?config(data_dir, Conf), "lib"),
+
+ %% Create the releases
+ Lib1 = [{a,"1.0",LibDir}],
+ Lib2 = [{a,"9.0",LibDir}],
+ Rel1 = create_and_install_fake_first_release(Dir,Lib1),
+ Rel2 = create_fake_upgrade_release(Dir,"2",Lib2,{[Rel1],[Rel1],[LibDir]}),
+ Rel1Dir = filename:dirname(Rel1),
+ Rel2Dir = filename:dirname(Rel2),
+
+ %% Start a slave node
+ {ok, Node} = t_start_node(upgrade_supervisor, Rel1,
+ filename:join(Rel1Dir,"sys.config")),
+
+ %% Check path
+ Dir1 = filename:join([LibDir, "a-1.0"]),
+ Dir1 = rpc:call(Node, code, lib_dir, [a]),
+ ASupBeam1 = filename:join([Dir1,ebin,"a_sup.beam"]),
+ ASupBeam1 = rpc:call(Node, code, which, [a_sup]),
+
+ %% Install second release, with no changed modules
+ {ok, RelVsn2} = rpc:call(Node, release_handler, set_unpacked,
+ [Rel2++".rel", Lib2]),
+ ok = rpc:call(Node, release_handler, install_file,
+ [RelVsn2, filename:join(Rel2Dir, "relup")]),
+ ok = rpc:call(Node, release_handler, install_file,
+ [RelVsn2, filename:join(Rel2Dir, "start.boot")]),
+ ok = rpc:call(Node, release_handler, install_file,
+ [RelVsn2, filename:join(Rel2Dir, "sys.config")]),
+
+ {ok, _RelVsn1, []} =
+ rpc:call(Node, release_handler, install_release, [RelVsn2]),
+
+ %% Check that libdir is changed
+ Dir2 = filename:join([LibDir, "a-9.0"]),
+ Dir2 = rpc:call(Node, code, lib_dir, [a]),
+ ASupBeam2 = filename:join([Dir2,ebin,"a_sup.beam"]),
+ ASupBeam2 = rpc:call(Node, code, which, [a_sup]),
+
+ %% Check that the restart strategy and child spec is updated
+ {status, _, {module, _}, [_, _, _, _, [_,_,{data,[{"State",State}]}]]} =
+ rpc:call(Node,sys,get_status,[a_sup]),
+ {state,_,RestartStrategy,[Child],_,_,_,_,_,_} = State,
+ one_for_all = RestartStrategy, % changed from one_for_one
+ {child,_,_,_,_,brutal_kill,_,_} = Child, % changed from timeout 2000
+
+ ok.
+
+%% Check that if the supervisor fails, then the upgrade is rolled back
+%% and an ok error message is returned
+upgrade_supervisor_fail(Conf) when is_list(Conf) ->
+ %% Set some paths
+ PrivDir = priv_dir(Conf),
+ Dir = filename:join(PrivDir,"upgrade_supervisor_fail"),
+ LibDir = filename:join(?config(data_dir, Conf), "lib"),
+
+ %% Create the releases
+ Lib1 = [{a,"1.0",LibDir}],
+ Lib2 = [{a,"9.1",LibDir}],
+ Rel1 = create_and_install_fake_first_release(Dir,Lib1),
+ Rel2 = create_fake_upgrade_release(Dir,"2",Lib2,{[Rel1],[Rel1],[LibDir]}),
+ Rel1Dir = filename:dirname(Rel1),
+ Rel2Dir = filename:dirname(Rel2),
+
+ %% Start a slave node
+ {ok, Node} = t_start_node(upgrade_supervisor_fail, Rel1,
+ filename:join(Rel1Dir,"sys.config")),
+
+ %% Check path
+ Dir1 = filename:join([LibDir, "a-1.0"]),
+ Dir1 = rpc:call(Node, code, lib_dir, [a]),
+ ASupBeam1 = filename:join([Dir1,ebin,"a_sup.beam"]),
+ ASupBeam1 = rpc:call(Node, code, which, [a_sup]),
+
+ %% Install second release, with no changed modules
+ {ok, RelVsn2} = rpc:call(Node, release_handler, set_unpacked,
+ [Rel2++".rel", Lib2]),
+ ok = rpc:call(Node, release_handler, install_file,
+ [RelVsn2, filename:join(Rel2Dir, "relup")]),
+ ok = rpc:call(Node, release_handler, install_file,
+ [RelVsn2, filename:join(Rel2Dir, "start.boot")]),
+ ok = rpc:call(Node, release_handler, install_file,
+ [RelVsn2, filename:join(Rel2Dir, "sys.config")]),
+ ok = net_kernel:monitor_nodes(true),
+
+ {error,{code_change_failed,_Pid,a_sup,_Vsn,
+ {error,{invalid_shutdown,brutal_kil}}}} =
+ rpc:call(Node, release_handler, install_release, [RelVsn2]),
+
+ %% Check that the upgrade is terminated - normally this would mean
+ %% rollback, but since this testcase is very simplified the node
+ %% is not started with heart supervision and will therefore not be
+ %% restarted. So we just check that the node goes down.
+ receive {nodedown,Node} -> ok
+ after 10000 -> ct:fail(failed_upgrade_never_restarted_node)
+ end,
+
+ ok.
+
%% Test upgrade and downgrade of applications
eval_appup(Conf) when is_list(Conf) ->
@@ -1107,6 +1331,12 @@ eval_appup(Conf) when is_list(Conf) ->
App11Dir = code:lib_dir(app1),
ok = gen_server:call(harry, error),
+ %% Read appup script
+ {ok,"2.0",UpScript} = release_handler:upgrade_script(app1,App12Dir),
+ [{load_object_code,_},
+ point_of_no_return,
+ {load,_}] = UpScript,
+
%% Upgrade to app1-2.0
{ok, []} = release_handler:upgrade_app(app1, App12Dir),
App12Dir = code:lib_dir(app1),
@@ -1117,6 +1347,12 @@ eval_appup(Conf) when is_list(Conf) ->
%% (see myrel/lib2/app1-2.0/ebin/app1.app)
[{var,val2}] = ets:lookup(otp_6162, var),
+ %% Read appup script
+ {ok,DnScript} = release_handler:downgrade_script(app1,"1.0",App11Dir),
+ [{load_object_code,_},
+ point_of_no_return,
+ {load,_}] = DnScript,
+
%% Downgrade to app1-1.0
{ok, []} = release_handler:downgrade_app(app1,"1.0",App11Dir),
App11Dir = code:lib_dir(app1),
@@ -1134,6 +1370,85 @@ eval_appup(Conf) when is_list(Conf) ->
ok.
+%% Test upgrade and downgrade of applications when appup contains
+%% restart_emulator and restart_new_emulator instructions
+eval_appup_with_restart(Conf) when is_list(Conf) ->
+
+ %% Set some paths
+ RelDir = filename:join(?config(data_dir, Conf), "app1_app2"),
+ App11Dir = filename:join([RelDir, "lib1", "app1-1.0"]),
+ App13Dir = filename:join([RelDir, "lib3", "app1-3.0"]), %restart_emulator
+ App14Dir = filename:join([RelDir, "lib4", "app1-4.0"]), %restart_new_emulator
+ EbinDir1 = filename:join(App11Dir, "ebin"),
+ EbinDir3 = filename:join(App13Dir, "ebin"),
+ EbinDir4 = filename:join(App14Dir, "ebin"),
+
+ %% Start app1-1.0
+ code:add_patha(EbinDir1),
+ ok = application:start(app1),
+ App11Dir = code:lib_dir(app1),
+
+ %% Read appup script
+ {ok,"3.0",UpScript3} = release_handler:upgrade_script(app1,App13Dir),
+ [{load_object_code,_},
+ point_of_no_return,
+ {load,_},
+ restart_emulator] = UpScript3,
+
+ %% Upgrade to app1-3.0 - restart_emulator
+ restart_emulator = release_handler:upgrade_app(app1, App13Dir),
+ App13Dir = code:lib_dir(app1),
+
+ %% Fake full upgrade to 3.0
+ {ok,AppSpec} = file:consult(filename:join([App13Dir,"ebin","app1.app"])),
+ application_controller:change_application_data(AppSpec,[]),
+
+ %% Read appup script
+ {ok,"4.0",UpScript4} = release_handler:upgrade_script(app1,App14Dir),
+ [restart_new_emulator,point_of_no_return] = UpScript4,
+
+ %% Try pgrade to app1-4.0 - restart_new_emulator
+ {error,restart_new_emulator} = release_handler:upgrade_app(app1, App14Dir),
+ App13Dir = code:lib_dir(app1),
+
+ %% Read appup script
+ {ok,DnScript1} = release_handler:downgrade_script(app1,"1.0",App11Dir),
+ [{load_object_code,_},
+ point_of_no_return,
+ {load,_},
+ restart_emulator] = DnScript1,
+
+ %% Still running 3.0 - downgrade to app1-1.0 - restart_emulator
+ restart_emulator = release_handler:downgrade_app(app1,"1.0",App11Dir),
+ App11Dir = code:lib_dir(app1),
+
+ ok = application:stop(app1),
+ ok = application:unload(app1),
+ true = code:del_path(EbinDir1),
+
+ %% Start again as version 4.0
+ code:add_patha(EbinDir4),
+ ok = application:start(app1),
+ App14Dir = code:lib_dir(app1),
+
+ %% Read appup script
+ {ok,DnScript3} = release_handler:downgrade_script(app1,"3.0",App13Dir),
+ [point_of_no_return,restart_emulator] = DnScript3,
+
+ %% Downgrade to app1-3.0 - restart_new_emulator
+ restart_emulator = release_handler:downgrade_app(app1,"3.0",App13Dir),
+ App13Dir = code:lib_dir(app1),
+
+ ok = application:stop(app1),
+ ok = application:unload(app1),
+
+ true = code:del_path(EbinDir3),
+ false = code:del_path(EbinDir1),
+ false = code:del_path(EbinDir4),
+
+ ok.
+
+
%% Test the example/target_system.erl module
target_system(Conf) when is_list(Conf) ->
PrivDir = priv_dir(Conf),
@@ -1147,11 +1462,10 @@ target_system(Conf) when is_list(Conf) ->
%% Create the .rel file
- ErtsVsn = erlang:system_info(version),
RelName = filename:join(TargetCreateDir,"ts-1.0"),
RelFile = RelName++".rel",
RelVsn = "R1A",
- create_rel_file(RelFile,RelName,RelVsn,ErtsVsn,[{a, "1.0"}]),
+ create_rel_file(RelFile,RelName,RelVsn,current,[{a, "1.0"}]),
%% Build the target_system module
ExamplesEbin = filename:join([code:lib_dir(sasl),examples,ebin]),
@@ -1179,11 +1493,13 @@ target_system(Conf) when is_list(Conf) ->
code:del_path(TSPath),
%% Check that all files exist in installation
- true = filelib:is_dir(filename:join(TargetInstallDir,"erts-"++ErtsVsn)),
+ ErtsDir = app_dir(erts,current),
+ true = filelib:is_dir(filename:join(TargetInstallDir,ErtsDir)),
LibDir = filename:join(TargetInstallDir,lib),
- {ok,KernelVsn} = application:get_key(kernel,vsn),
- {ok,StdlibVsn} = application:get_key(stdlib,vsn),
- {ok,SaslVsn} = application:get_key(sasl,vsn),
+ KernelVsn = vsn(kernel,current),
+ StdlibVsn = vsn(stdlib,current),
+ SaslVsn = vsn(sasl,current),
+ RelFileBasename = filename:basename(RelFile),
true = filelib:is_dir(filename:join(LibDir,"kernel-"++KernelVsn)),
true = filelib:is_dir(filename:join(LibDir,"stdlib-"++StdlibVsn)),
true = filelib:is_dir(filename:join(LibDir,"sasl-"++SaslVsn)),
@@ -1191,10 +1507,10 @@ target_system(Conf) when is_list(Conf) ->
RelDir = filename:join(TargetInstallDir,releases),
true = filelib:is_regular(filename:join(RelDir,"RELEASES")),
true = filelib:is_regular(filename:join(RelDir,"start_erl.data")),
- true = filelib:is_regular(filename:join(RelDir,
- filename:basename(RelFile))),
+ true = filelib:is_regular(filename:join(RelDir,RelFileBasename)),
true = filelib:is_dir(filename:join(RelDir,RelVsn)),
true = filelib:is_regular(filename:join([RelDir,RelVsn,"start.boot"])),
+ true = filelib:is_regular(filename:join([RelDir,RelVsn,RelFileBasename])),
BinDir = filename:join(TargetInstallDir,bin),
true = filelib:is_regular(filename:join(BinDir,"start.boot")),
true = filelib:is_regular(filename:join(BinDir,erl)),
@@ -1205,6 +1521,7 @@ target_system(Conf) when is_list(Conf) ->
true = filelib:is_regular(filename:join(BinDir,to_erl)),
%% Check content of files
+ ErtsVsn = vsn(erts,current),
{ok,SED} = file:read_file(filename:join(RelDir,"start_erl.data")),
[ErtsVsn,RelVsn] = string:tokens(binary_to_list(SED),"\s\n"),
ok.
@@ -1456,7 +1773,7 @@ copy_client(Conf,Master,Sname,Client) ->
ok.
-delete_release(Conf) ->
+clean_priv_dir(Conf,Save) ->
PrivDir = priv_dir(Conf),
{ok, OrigWd} = file:get_cwd(),
@@ -1466,7 +1783,7 @@ delete_release(Conf) ->
{ok, Dirs} = file:list_dir(PrivDir),
?t:format("======== deleting ~p~n",[Dirs]),
- ok = delete_release_os(Dirs--["save"]),
+ ok = clean_dirs_os(Dirs,Save),
{ok,Remaining} = file:list_dir(PrivDir),
?t:format("======== remaining ~p~n",[Remaining]),
@@ -1474,7 +1791,7 @@ delete_release(Conf) ->
[] ->
ok;
_ ->
- delete_release_os(Remaining),
+ clean_dirs_os(Remaining,Save),
Remaining2 = file:list_dir(PrivDir),
?t:format("======== remaining after second try ~p~n",[Remaining2])
end,
@@ -1483,22 +1800,22 @@ delete_release(Conf) ->
ok.
-delete_release_os(Dirs) ->
+clean_dirs_os(Dirs,Save) ->
case os:type() of
{unix, _} ->
- delete_release_unix(Dirs);
+ clean_dirs_unix(Dirs,Save);
{win32, _} ->
- delete_release_win32(Dirs);
+ clean_dirs_win32(Dirs,Save);
Os ->
test_server:fail({error, {not_yet_implemented_os, Os}})
end.
-delete_release_unix([]) ->
+clean_dirs_unix([],_) ->
ok;
-delete_release_unix(["save"|Dirs]) ->
- delete_release_unix(Dirs);
-delete_release_unix([Dir|Dirs]) ->
+clean_dirs_unix(["save"|Dirs],Save) when Save ->
+ clean_dirs_unix(Dirs,Save);
+clean_dirs_unix([Dir|Dirs],Save) ->
Rm = string:concat("rm -rf ", Dir),
?t:format("============== COMMAND ~p~n",[Rm]),
case file:list_dir(Dir) of
@@ -1515,13 +1832,13 @@ delete_release_unix([Dir|Dirs]) ->
?t:format("------- ls -al ~p~n",[os:cmd("ls -al " ++ Dir)])
end,
- delete_release_unix(Dirs).
+ clean_dirs_unix(Dirs,Save).
-delete_release_win32([]) ->
+clean_dirs_win32([],_) ->
ok;
-delete_release_win32(["save"|Dirs]) ->
- delete_release_win32(Dirs);
-delete_release_win32([Dir|Dirs]) ->
+clean_dirs_win32(["save"|Dirs],Save) when Save ->
+ clean_dirs_win32(Dirs,Save);
+clean_dirs_win32([Dir|Dirs],Save) ->
Rm =
case filelib:is_dir(Dir) of
true ->
@@ -1531,7 +1848,7 @@ delete_release_win32([Dir|Dirs]) ->
end,
?t:format("============== COMMAND ~p~n",[Rm]),
[] = os:cmd(Rm),
- delete_release_win32(Dirs).
+ clean_dirs_win32(Dirs,Save).
node_name(Sname) when is_atom(Sname) ->
@@ -1657,9 +1974,17 @@ priv_dir(Conf) ->
%% filename:absname(?config(priv_dir, Conf)). % Get rid of trailing slash
%% Due to problem with long paths on windows => creating a new
%% priv_dir under data_dir
+ filename:absname(filename:join(?config(data_dir, Conf),priv_dir)).
+
+init_priv_dir(Conf) ->
Dir = filename:absname(filename:join(?config(data_dir, Conf),priv_dir)),
- filelib:ensure_dir(filename:join(Dir,"*")),
- Dir.
+ case filelib:is_dir(Dir) of
+ true ->
+ clean_priv_dir(Conf,false);
+ false ->
+ ok
+ end,
+ filelib:ensure_dir(filename:join(Dir,"*")).
latest_version(Dir) ->
List = filelib:wildcard(Dir ++ "*"),
@@ -1694,14 +2019,22 @@ stop_print_proc() ->
%% Create the first target release, vsn P1G. This release is used for
%% all test cases in {group,release}
-create_p1g(Conf,Sname) ->
- do_create_p1g(Conf,filename:join(priv_dir(Conf),Sname)).
-
-do_create_p1g(Conf,TargetDir) ->
- PrivDir = priv_dir(Conf),
+create_p1g(Conf,TargetDir) ->
DataDir = ?config(data_dir,Conf),
- ErtsVsn = "4.4",
- ErtsDir = "erts-"++ErtsVsn,
+ PrivDir = priv_dir(Conf),
+ ErtsDir = app_dir(erts,old),
+ KernelDir = app_dir(kernel,old),
+ StdlibDir = app_dir(stdlib,old),
+
+ %% Fake earlier version of kernel and stdlib
+ SystemLib = system_lib(PrivDir),
+ ok = filelib:ensure_dir(filename:join(SystemLib,"*")),
+ KernelLib = code:lib_dir(kernel),
+ StdlibLib = code:lib_dir(stdlib),
+ ok = copy_tree(Conf,KernelLib,KernelDir,SystemLib),
+ ok = copy_tree(Conf,StdlibLib,StdlibDir,SystemLib),
+ fix_version(SystemLib,kernel),
+ fix_version(SystemLib,stdlib),
%% Create dirs
BinDir = filename:join(TargetDir,bin),
@@ -1745,17 +2078,15 @@ do_create_p1g(Conf,TargetDir) ->
RelFileName = filename:join(RelDir,RelName),
RelFile = RelFileName ++ ".rel",
ok = filelib:ensure_dir(RelFile),
- LibPath = filename:join([DataDir,lib,"*",ebin]),
- TarFile = create_basic_release(Conf, RelFile, RelVsn, {ErtsVsn,false},
- LibPath, [], [], [], []),
+ TarFile = create_basic_release(Conf,RelFile,RelVsn,{old,false}),
%% Extract tar file in target directory (i.e. same directory as erts etc.)
ok = erl_tar:extract(TarFile, [{cwd, TargetDir}, compressed]),
%% Create start_erl.data
StartErlDataFile = filename:join([ReleasesDir, "start_erl.data"]),
- StartErlData = io_lib:fwrite("~s ~s~n", [ErtsVsn, RelVsn]),
+ StartErlData = io_lib:fwrite("~s ~s~n", [vsn(erts,old), RelVsn]),
ok = file:write_file(StartErlDataFile, StartErlData),
%% Create RELEASES
@@ -1763,60 +2094,98 @@ do_create_p1g(Conf,TargetDir) ->
ok.
+fix_version(SystemLib,App) ->
+ FromVsn = vsn(App,current),
+ ToVsn = vsn(App,old),
+ Rootname = filename:join([SystemLib,app_dir(App,old),ebin,atom_to_list(App)]),
+
+ AppFile = Rootname ++ ".app",
+ {ok,OrigApp} = file:read_file(AppFile),
+ ok = file:write_file(AppFile,re:replace(OrigApp,FromVsn,ToVsn,
+ [{return,binary}])),
+ AppupFile = Rootname ++ ".appup",
+ {ok,OrigAppup} = file:read_file(AppupFile),
+ ok = file:write_file(AppupFile,re:replace(OrigAppup,FromVsn,ToVsn,
+ [{return,binary}])).
+
+
%% Create version P1H - which is P1G + a-1.0
%% Must have run create_p1g first!!
create_p1h(Conf) ->
- create_upgrade_release(Conf,"rel1","P1H",{"4.4",false},[{a,"1.0"}],
- [{a,[{key2,val2}]}],{"rel0",[new_appl]}).
+ create_upgrade_release(Conf,"rel1","P1H",{old,false},[{a,"1.0"}],
+ [{a,[{key2,val2}]}],[{"rel0",[new_appl]}]).
%% Create version P1I - which is P1H, but with application a upgraded to a-1.1
%% Must have run create_p1h first!!
create_p1i(Conf) ->
- create_upgrade_release(Conf,"rel2","P1I",{"4.4",false},[{a,"1.1"}],
+ create_upgrade_release(Conf,"rel2","P1I",{old,false},[{a,"1.1"}],
[{a,[{key2,newval2}]}],
- {"rel1",[{extra,gott}]}).
+ [{"rel1",[{extra,gott}]}]).
%% Create version P2A - which is P1I, but with erts-<latest>
%% Must have run create_p1i first!!
create_p2a(Conf) ->
- ErtsVsn = erlang:system_info(version),
- create_upgrade_release(Conf,"rel3","P2A",{ErtsVsn,code:root_dir()},
+ create_upgrade_release(Conf,"rel3","P2A",{current,code:root_dir()},
[{a,"1.1"}],[{a,[{key2,newval2}]}],
- {"rel2",[new_emu]}).
+ [{"rel1",[new_emu,new_appl]},{"rel2",[new_emu]}],
+ [{"rel1",[old_emu,old_appl]},{"rel2",[old_emu]}]).
+
+%% Create version P2B - which is P2A, but with relup containing an
+%% extra reboot.
+%% Can be upgraded to from P1G - so must have run create_p1g first!!
+create_p2b(Conf) ->
+ create_upgrade_release(Conf,"rel4","P2B",{current,code:root_dir()},
+ [{a,"1.1"}],[{a,[{key2,newval2}]}],
+ [{"rel0",[new_emu,add_appl]}],
+ [{"rel0",[old_emu,rm_appl]}],
+ [restart_emulator]).
%% Create a release tar package which can be installed on top of P1G
-create_upgrade_release(Conf,RelName,RelVsn,Erts,Apps,Config,{UpFromName,Descr}) ->
+create_upgrade_release(Conf,RelName,RelVsn,Erts,Apps,Config,UpFrom) ->
+ create_upgrade_release(Conf,RelName,RelVsn,Erts,Apps,Config,UpFrom,[]).
+create_upgrade_release(Conf,RelName,RelVsn,Erts,Apps,Config,UpFrom,DownTo) ->
+ create_upgrade_release(Conf,RelName,RelVsn,Erts,Apps,Config,UpFrom,DownTo,[]).
+create_upgrade_release(Conf,RelName,RelVsn,Erts,Apps,Config,UpFrom0,DownTo0,RelupOpts) ->
PrivDir = priv_dir(Conf),
- DataDir = ?config(data_dir,Conf),
-
RelDir = filename:join(PrivDir,RelName),
RelFileName = filename:join(RelDir,RelName),
RelFile = RelFileName ++ ".rel",
ok = filelib:ensure_dir(RelFile),
- LibPath = filename:join([DataDir,lib,"*",ebin]),
- UpFrom = [{filename:join([PrivDir,UpFromName,UpFromName]),Descr}],
+ UpFrom = [{filename:join([PrivDir,UpFromName,UpFromName]),Descr} ||
+ {UpFromName,Descr} <- UpFrom0],
+ DownTo = [{filename:join([PrivDir,DownToName,DownToName]),Descr} ||
+ {DownToName,Descr} <- DownTo0],
- create_basic_release(Conf, RelFile, RelVsn, Erts, LibPath,
- Apps, Config, UpFrom, []),
+ create_basic_release(Conf,RelFile,RelVsn,Erts,Apps,Config,
+ UpFrom,DownTo,RelupOpts),
ok.
%% Create .rel, .script, .boot, sys.config and tar
-create_basic_release(Conf, RelFile,RelVsn,{ErtsVsn,ErtsDir},LibPath,ExtraApps,Config,UpFrom,DownTo) ->
+create_basic_release(Conf,RelFile,RelVsn,{Erts,ErtsDir}) ->
+ create_basic_release(Conf, RelFile,RelVsn,{Erts,ErtsDir},[],[],[],[],[]).
+create_basic_release(Conf,RelFile,RelVsn,{Erts,ErtsDir},ExtraApps,Config,UpFrom,DownTo,RelupOpts) ->
+ DataDir = ?config(data_dir,Conf),
+ PrivDir = priv_dir(Conf),
+ SystemLib = system_lib(PrivDir),
+ LibPath = [filename:join([SystemLib,"*",ebin]),
+ filename:join([DataDir,lib,"*",ebin])],
+
RelDir = filename:dirname(RelFile),
RelFileName = filename:rootname(RelFile),
%% Create .rel file
- create_installer_rel_file(RelFile,RelVsn,ErtsVsn,ExtraApps),
+ create_installer_rel_file(RelFile,RelVsn,Erts,ExtraApps),
%% Generate .script and .boot
ok = systools:make_script(RelFileName,
- [{path,[LibPath]},
+ [{path,LibPath},
{outdir,RelDir}]),
%% Generate relup
- ok = systools:make_relup(RelFileName,UpFrom,DownTo,[{path,[LibPath]},
- {outdir,RelDir}]),
+ ok = systools:make_relup(RelFileName,UpFrom,DownTo,[{path,LibPath},
+ {outdir,RelDir} |
+ RelupOpts]),
%% Create sys.config
ok = write_term_file(filename:join(RelDir,"sys.config"),Config),
@@ -1824,7 +2193,7 @@ create_basic_release(Conf, RelFile,RelVsn,{ErtsVsn,ErtsDir},LibPath,ExtraApps,Co
%% Create tar file (i.e. collect all lib/app-*/* and system files)
ok = systools:make_tar(RelFileName,
- [{path,[LibPath]},
+ [{path,LibPath},
{outdir,RelDir} |
case ErtsDir of
false -> [];
@@ -1841,18 +2210,19 @@ create_basic_release(Conf, RelFile,RelVsn,{ErtsVsn,ErtsDir},LibPath,ExtraApps,Co
TarFileName.
%% Create a .rel file
-create_installer_rel_file(RelFile,RelVsn,ErtsVsn,ExtraApps) ->
- create_rel_file(RelFile,"SASL-test",RelVsn,ErtsVsn,
+create_installer_rel_file(RelFile,RelVsn,Erts,ExtraApps) ->
+ create_rel_file(RelFile,"SASL-test",RelVsn,Erts,
[{installer,"1.0"}|ExtraApps]).
-create_rel_file(RelFile,RelName,RelVsn,ErtsVsn,ExtraApps) ->
- {ok,KernelVsn} = application:get_key(kernel,vsn),
- {ok,StdlibVsn} = application:get_key(stdlib,vsn),
- {ok,SaslVsn} = application:get_key(sasl,vsn),
+create_rel_file(RelFile,RelName,RelVsn,Erts,ExtraApps) ->
+ ErtsVsn = vsn(erts,Erts),
+ KernelVsn = vsn(kernel,Erts),
+ StdlibVsn = vsn(stdlib,Erts),
+ SaslVsn = vsn(sasl,current),
application:load(tools),
- {ok,ToolsVsn} = application:get_key(tools,vsn),
+ ToolsVsn = vsn(tools,current),
application:load(runtime_tools),
- {ok,RuntimeToolsVsn} = application:get_key(runtime_tools,vsn),
+ RuntimeToolsVsn = vsn(runtime_tools,current),
RelFileContent = {release,
{RelName, RelVsn},
@@ -2033,7 +2403,7 @@ start_node_unix(Sname,NodeDir) ->
start_node_win32(Sname,NodeDir) ->
Name = atom_to_list(Sname) ++ "_P1G",
- ErtsBinDir = filename:join(NodeDir,"erts-4.4/bin"),
+ ErtsBinDir = filename:join([NodeDir,app_dir(erts,old),"bin"]),
StartErlArgs = rh_test_lib:get_start_erl_args(NodeDir),
ServiceArgs = rh_test_lib:get_service_args(NodeDir, Sname, StartErlArgs),
@@ -2158,7 +2528,6 @@ create_fake_release(Dir,RelName,RelVsn,AppDirs) ->
RelDir = filename:join(Dir,"rel_" ++ RelVsn),
Rel = filename:join([RelDir,"rel_" ++ RelVsn]),
ok = filelib:ensure_dir(Rel),
- ErtsVsn = erlang:system_info(version),
{Apps,Paths} =
lists:foldl(fun({App,Vsn,Lib},{As,Ps}) ->
@@ -2168,7 +2537,7 @@ create_fake_release(Dir,RelName,RelVsn,AppDirs) ->
{[],[]},
AppDirs),
- create_rel_file(Rel++".rel",RelName,RelVsn,ErtsVsn,Apps),
+ create_rel_file(Rel++".rel",RelName,RelVsn,current,Apps),
%% Generate boot scripts
ok = systools:make_script(Rel,[local,
@@ -2217,3 +2586,16 @@ modify_tar_win32(Conf, TarFileName) ->
[ok = erl_tar:add(T,filename:join(TmpDir,F),F,[]) || F <- Fs],
ok = erl_tar:close(T),
ok.
+
+app_dir(App,Vsn) ->
+ atom_to_list(App) ++ "-" ++ vsn(App,Vsn).
+vsn(erts,old) -> ?ertsvsn;
+vsn(kernel,old) -> ?kernelvsn;
+vsn(stdlib,old) -> ?stdlibvsn;
+vsn(erts,current) -> erlang:system_info(version);
+vsn(App,current) ->
+ {ok,Vsn} = application:get_key(App,vsn),
+ Vsn.
+
+system_lib(PrivDir) ->
+ filename:join(PrivDir,"system_lib").
diff --git a/lib/sasl/test/release_handler_SUITE_data/Makefile.src b/lib/sasl/test/release_handler_SUITE_data/Makefile.src
index edb446413d..55d20aa8b6 100644
--- a/lib/sasl/test/release_handler_SUITE_data/Makefile.src
+++ b/lib/sasl/test/release_handler_SUITE_data/Makefile.src
@@ -5,6 +5,10 @@ P2B= \
P2B/a-2.0/ebin/a_sup.@EMULATOR@
LIB= \
+ lib/a-9.1/ebin/a.@EMULATOR@ \
+ lib/a-9.1/ebin/a_sup.@EMULATOR@ \
+ lib/a-9.0/ebin/a.@EMULATOR@ \
+ lib/a-9.0/ebin/a_sup.@EMULATOR@ \
lib/a-1.2/ebin/a.@EMULATOR@ \
lib/a-1.2/ebin/a_sup.@EMULATOR@ \
lib/a-1.1/ebin/a.@EMULATOR@ \
@@ -50,7 +54,13 @@ APP= \
app1_app2/lib2/app1-2.0/ebin/app1.@EMULATOR@ \
app1_app2/lib2/app2-1.0/ebin/app2_sup.@EMULATOR@ \
app1_app2/lib2/app2-1.0/ebin/app2_server.@EMULATOR@ \
- app1_app2/lib2/app2-1.0/ebin/app2.@EMULATOR@
+ app1_app2/lib2/app2-1.0/ebin/app2.@EMULATOR@ \
+ app1_app2/lib3/app1-3.0/ebin/app1_sup.@EMULATOR@ \
+ app1_app2/lib3/app1-3.0/ebin/app1_server.@EMULATOR@ \
+ app1_app2/lib3/app1-3.0/ebin/app1.@EMULATOR@ \
+ app1_app2/lib4/app1-4.0/ebin/app1_sup.@EMULATOR@ \
+ app1_app2/lib4/app1-4.0/ebin/app1_server.@EMULATOR@ \
+ app1_app2/lib4/app1-4.0/ebin/app1.@EMULATOR@
OTP2740= \
otp_2740/vsn_atom.@EMULATOR@ \
@@ -95,6 +105,17 @@ lib/a-1.2/ebin/a.@EMULATOR@: lib/a-1.2/src/a.erl
lib/a-1.2/ebin/a_sup.@EMULATOR@: lib/a-1.2/src/a_sup.erl
erlc $(EFLAGS) -olib/a-1.2/ebin lib/a-1.2/src/a_sup.erl
+lib/a-9.0/ebin/a.@EMULATOR@: lib/a-9.0/src/a.erl
+ erlc $(EFLAGS) -olib/a-9.0/ebin lib/a-9.0/src/a.erl
+lib/a-9.0/ebin/a_sup.@EMULATOR@: lib/a-9.0/src/a_sup.erl
+ erlc $(EFLAGS) -olib/a-9.0/ebin lib/a-9.0/src/a_sup.erl
+
+lib/a-9.1/ebin/a.@EMULATOR@: lib/a-9.1/src/a.erl
+ erlc $(EFLAGS) -olib/a-9.1/ebin lib/a-9.1/src/a.erl
+lib/a-9.1/ebin/a_sup.@EMULATOR@: lib/a-9.1/src/a_sup.erl
+ erlc $(EFLAGS) -olib/a-9.1/ebin lib/a-9.1/src/a_sup.erl
+
+
lib/b-1.0/ebin/b_server.@EMULATOR@: lib/b-1.0/src/b_server.erl
erlc $(EFLAGS) -olib/b-1.0/ebin lib/b-1.0/src/b_server.erl
lib/b-1.0/ebin/b_lib.@EMULATOR@: lib/b-1.0/src/b_lib.erl
@@ -183,6 +204,22 @@ app1_app2/lib2/app2-1.0/ebin/app2.@EMULATOR@: app1_app2/lib2/app2-1.0/src/app2.e
erlc $(EFLAGS) -oapp1_app2/lib2/app2-1.0/ebin app1_app2/lib2/app2-1.0/src/app2.erl
+app1_app2/lib3/app1-3.0/ebin/app1_sup.@EMULATOR@: app1_app2/lib3/app1-3.0/src/app1_sup.erl
+ erlc $(EFLAGS) -oapp1_app2/lib3/app1-3.0/ebin app1_app2/lib3/app1-3.0/src/app1_sup.erl
+app1_app2/lib3/app1-3.0/ebin/app1_server.@EMULATOR@: app1_app2/lib3/app1-3.0/src/app1_server.erl
+ erlc $(EFLAGS) -oapp1_app2/lib3/app1-3.0/ebin app1_app2/lib3/app1-3.0/src/app1_server.erl
+app1_app2/lib3/app1-3.0/ebin/app1.@EMULATOR@: app1_app2/lib3/app1-3.0/src/app1.erl
+ erlc $(EFLAGS) -oapp1_app2/lib3/app1-3.0/ebin app1_app2/lib3/app1-3.0/src/app1.erl
+
+
+app1_app2/lib4/app1-4.0/ebin/app1_sup.@EMULATOR@: app1_app2/lib4/app1-4.0/src/app1_sup.erl
+ erlc $(EFLAGS) -oapp1_app2/lib4/app1-4.0/ebin app1_app2/lib4/app1-4.0/src/app1_sup.erl
+app1_app2/lib4/app1-4.0/ebin/app1_server.@EMULATOR@: app1_app2/lib4/app1-4.0/src/app1_server.erl
+ erlc $(EFLAGS) -oapp1_app2/lib4/app1-4.0/ebin app1_app2/lib4/app1-4.0/src/app1_server.erl
+app1_app2/lib4/app1-4.0/ebin/app1.@EMULATOR@: app1_app2/lib4/app1-4.0/src/app1.erl
+ erlc $(EFLAGS) -oapp1_app2/lib4/app1-4.0/ebin app1_app2/lib4/app1-4.0/src/app1.erl
+
+
otp_2740/vsn_atom.@EMULATOR@: otp_2740/vsn_atom.erl
erlc $(EFLAGS) -ootp_2740 otp_2740/vsn_atom.erl
otp_2740/vsn_list.@EMULATOR@: otp_2740/vsn_list.erl
diff --git a/lib/sasl/test/release_handler_SUITE_data/app1_app2/lib3/app1-3.0/ebin/app1.app b/lib/sasl/test/release_handler_SUITE_data/app1_app2/lib3/app1-3.0/ebin/app1.app
new file mode 100644
index 0000000000..4adc0540c4
--- /dev/null
+++ b/lib/sasl/test/release_handler_SUITE_data/app1_app2/lib3/app1-3.0/ebin/app1.app
@@ -0,0 +1,9 @@
+{application, app1,
+ [{description, "very simple example application"},
+ {id, "app1"},
+ {vsn, "3.0"},
+ {modules, [app1, app1_sup, app1_server]},
+ {registered, [harry]},
+ {applications, [kernel, stdlib, sasl]},
+ {env, [{var,val2}]},
+ {mod, {app1, []}}]}.
diff --git a/lib/sasl/test/release_handler_SUITE_data/app1_app2/lib3/app1-3.0/ebin/app1.appup b/lib/sasl/test/release_handler_SUITE_data/app1_app2/lib3/app1-3.0/ebin/app1.appup
new file mode 100644
index 0000000000..a5cdfe9fcc
--- /dev/null
+++ b/lib/sasl/test/release_handler_SUITE_data/app1_app2/lib3/app1-3.0/ebin/app1.appup
@@ -0,0 +1,4 @@
+{"3.0",
+ [{"1.0", [{load_module, app1_server},restart_emulator]}],
+ [{"1.0", [{load_module, app1_server},restart_emulator]}]
+}.
diff --git a/lib/sasl/test/release_handler_SUITE_data/app1_app2/lib3/app1-3.0/src/app1.erl b/lib/sasl/test/release_handler_SUITE_data/app1_app2/lib3/app1-3.0/src/app1.erl
new file mode 100644
index 0000000000..f123c8f470
--- /dev/null
+++ b/lib/sasl/test/release_handler_SUITE_data/app1_app2/lib3/app1-3.0/src/app1.erl
@@ -0,0 +1,22 @@
+-module(app1).
+
+-behaviour(application).
+
+%% Application callbacks
+-export([start/2, stop/1]).
+-export([config_change/3]).
+
+start(_Type, _StartArgs) ->
+ case app1_sup:start_link() of
+ {ok, Pid} ->
+ {ok, Pid};
+ Error ->
+ Error
+ end.
+
+stop(_State) ->
+ ok.
+
+config_change(Changed, _New, _Removed) ->
+ catch ets:insert(otp_6162, hd(Changed)),
+ ok.
diff --git a/lib/sasl/test/release_handler_SUITE_data/app1_app2/lib3/app1-3.0/src/app1_server.erl b/lib/sasl/test/release_handler_SUITE_data/app1_app2/lib3/app1-3.0/src/app1_server.erl
new file mode 100644
index 0000000000..660d095ebf
--- /dev/null
+++ b/lib/sasl/test/release_handler_SUITE_data/app1_app2/lib3/app1-3.0/src/app1_server.erl
@@ -0,0 +1,35 @@
+-module(app1_server).
+
+-behaviour(gen_server).
+
+%% API
+-export([start_link/0]).
+
+%% gen_server callbacks
+-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
+ terminate/2, code_change/3]).
+
+start_link() ->
+ gen_server:start_link({local, harry}, ?MODULE, [], []).
+
+init([]) ->
+ {ok, []}.
+
+handle_call(error, _From, State) ->
+ Reply = error,
+ {reply, Reply, State};
+handle_call(_Request, _From, State) ->
+ Reply = ok,
+ {reply, Reply, State}.
+
+handle_cast(_Msg, State) ->
+ {noreply, State}.
+
+handle_info(_Info, State) ->
+ {noreply, State}.
+
+terminate(_Reason, _State) ->
+ ok.
+
+code_change(_OldVsn, State, _Extra) ->
+ {ok, State}.
diff --git a/lib/sasl/test/release_handler_SUITE_data/app1_app2/lib3/app1-3.0/src/app1_sup.erl b/lib/sasl/test/release_handler_SUITE_data/app1_app2/lib3/app1-3.0/src/app1_sup.erl
new file mode 100644
index 0000000000..e6ad9b6967
--- /dev/null
+++ b/lib/sasl/test/release_handler_SUITE_data/app1_app2/lib3/app1-3.0/src/app1_sup.erl
@@ -0,0 +1,17 @@
+-module(app1_sup).
+
+-behaviour(supervisor).
+
+%% API
+-export([start_link/0]).
+
+%% Supervisor callbacks
+-export([init/1]).
+
+start_link() ->
+ supervisor:start_link(?MODULE, []).
+
+init([]) ->
+ AChild = {harry,{app1_server,start_link,[]},
+ permanent,2000,worker,[app1_server]},
+ {ok,{{one_for_all,0,1}, [AChild]}}.
diff --git a/lib/sasl/test/release_handler_SUITE_data/app1_app2/lib4/app1-4.0/ebin/app1.app b/lib/sasl/test/release_handler_SUITE_data/app1_app2/lib4/app1-4.0/ebin/app1.app
new file mode 100644
index 0000000000..243bc21f02
--- /dev/null
+++ b/lib/sasl/test/release_handler_SUITE_data/app1_app2/lib4/app1-4.0/ebin/app1.app
@@ -0,0 +1,9 @@
+{application, app1,
+ [{description, "very simple example application"},
+ {id, "app1"},
+ {vsn, "4.0"},
+ {modules, [app1, app1_sup, app1_server]},
+ {registered, [harry]},
+ {applications, [kernel, stdlib, sasl]},
+ {env, [{var,val2}]},
+ {mod, {app1, []}}]}.
diff --git a/lib/sasl/test/release_handler_SUITE_data/app1_app2/lib4/app1-4.0/ebin/app1.appup b/lib/sasl/test/release_handler_SUITE_data/app1_app2/lib4/app1-4.0/ebin/app1.appup
new file mode 100644
index 0000000000..72535c8b34
--- /dev/null
+++ b/lib/sasl/test/release_handler_SUITE_data/app1_app2/lib4/app1-4.0/ebin/app1.appup
@@ -0,0 +1,4 @@
+{"4.0",
+ [{"3.0", [restart_new_emulator]}],
+ [{"3.0", [restart_new_emulator]}]
+}.
diff --git a/lib/sasl/test/release_handler_SUITE_data/app1_app2/lib4/app1-4.0/src/app1.erl b/lib/sasl/test/release_handler_SUITE_data/app1_app2/lib4/app1-4.0/src/app1.erl
new file mode 100644
index 0000000000..f123c8f470
--- /dev/null
+++ b/lib/sasl/test/release_handler_SUITE_data/app1_app2/lib4/app1-4.0/src/app1.erl
@@ -0,0 +1,22 @@
+-module(app1).
+
+-behaviour(application).
+
+%% Application callbacks
+-export([start/2, stop/1]).
+-export([config_change/3]).
+
+start(_Type, _StartArgs) ->
+ case app1_sup:start_link() of
+ {ok, Pid} ->
+ {ok, Pid};
+ Error ->
+ Error
+ end.
+
+stop(_State) ->
+ ok.
+
+config_change(Changed, _New, _Removed) ->
+ catch ets:insert(otp_6162, hd(Changed)),
+ ok.
diff --git a/lib/sasl/test/release_handler_SUITE_data/app1_app2/lib4/app1-4.0/src/app1_server.erl b/lib/sasl/test/release_handler_SUITE_data/app1_app2/lib4/app1-4.0/src/app1_server.erl
new file mode 100644
index 0000000000..660d095ebf
--- /dev/null
+++ b/lib/sasl/test/release_handler_SUITE_data/app1_app2/lib4/app1-4.0/src/app1_server.erl
@@ -0,0 +1,35 @@
+-module(app1_server).
+
+-behaviour(gen_server).
+
+%% API
+-export([start_link/0]).
+
+%% gen_server callbacks
+-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
+ terminate/2, code_change/3]).
+
+start_link() ->
+ gen_server:start_link({local, harry}, ?MODULE, [], []).
+
+init([]) ->
+ {ok, []}.
+
+handle_call(error, _From, State) ->
+ Reply = error,
+ {reply, Reply, State};
+handle_call(_Request, _From, State) ->
+ Reply = ok,
+ {reply, Reply, State}.
+
+handle_cast(_Msg, State) ->
+ {noreply, State}.
+
+handle_info(_Info, State) ->
+ {noreply, State}.
+
+terminate(_Reason, _State) ->
+ ok.
+
+code_change(_OldVsn, State, _Extra) ->
+ {ok, State}.
diff --git a/lib/sasl/test/release_handler_SUITE_data/app1_app2/lib4/app1-4.0/src/app1_sup.erl b/lib/sasl/test/release_handler_SUITE_data/app1_app2/lib4/app1-4.0/src/app1_sup.erl
new file mode 100644
index 0000000000..e6ad9b6967
--- /dev/null
+++ b/lib/sasl/test/release_handler_SUITE_data/app1_app2/lib4/app1-4.0/src/app1_sup.erl
@@ -0,0 +1,17 @@
+-module(app1_sup).
+
+-behaviour(supervisor).
+
+%% API
+-export([start_link/0]).
+
+%% Supervisor callbacks
+-export([init/1]).
+
+start_link() ->
+ supervisor:start_link(?MODULE, []).
+
+init([]) ->
+ AChild = {harry,{app1_server,start_link,[]},
+ permanent,2000,worker,[app1_server]},
+ {ok,{{one_for_all,0,1}, [AChild]}}.
diff --git a/lib/sasl/test/release_handler_SUITE_data/heart_restart.bat b/lib/sasl/test/release_handler_SUITE_data/heart_restart.bat
index ede1ad4ff3..ede1ad4ff3 100755..100644
--- a/lib/sasl/test/release_handler_SUITE_data/heart_restart.bat
+++ b/lib/sasl/test/release_handler_SUITE_data/heart_restart.bat
diff --git a/lib/sasl/test/release_handler_SUITE_data/lib/README b/lib/sasl/test/release_handler_SUITE_data/lib/README
index 639a4ca0fb..ffb8c5120b 100644
--- a/lib/sasl/test/release_handler_SUITE_data/lib/README
+++ b/lib/sasl/test/release_handler_SUITE_data/lib/README
@@ -8,6 +8,14 @@ a-1.2:
can be upgraded to from a-1.1.
No module have changed, but priv dir is added including one 'file'
+a-9.0:
+can be upgrade to from a-1.0
+Changes a_sup correctly - to test successful upgrade of supervisor
+
+a-9.1:
+can be upgrade to from a-1.0
+Changes a_sup faulty - to test failing upgrade of supervisor
+
b-1.0:
start version, includes b_lib and b_server
diff --git a/lib/sasl/test/release_handler_SUITE_data/lib/a-1.1/ebin/a.appup b/lib/sasl/test/release_handler_SUITE_data/lib/a-1.1/ebin/a.appup
index 05db4cb541..6ef67b869e 100644
--- a/lib/sasl/test/release_handler_SUITE_data/lib/a-1.1/ebin/a.appup
+++ b/lib/sasl/test/release_handler_SUITE_data/lib/a-1.1/ebin/a.appup
@@ -1,3 +1,3 @@
{"1.1",
[{"1.0",[{update,a,{advanced,extra_par}}]}],
- []}.
+ [{"1.0",[{update,a,{advanced,extra_par}}]}]}.
diff --git a/lib/sasl/test/release_handler_SUITE_data/lib/a-1.1/src/a.erl b/lib/sasl/test/release_handler_SUITE_data/lib/a-1.1/src/a.erl
index c082ad5339..1050e53f35 100644
--- a/lib/sasl/test/release_handler_SUITE_data/lib/a-1.1/src/a.erl
+++ b/lib/sasl/test/release_handler_SUITE_data/lib/a-1.1/src/a.erl
@@ -51,4 +51,6 @@ terminate(_Reason, _State) ->
ok.
code_change(1, Extra, State) ->
- {ok, {state, bval}}.
+ {ok, {state, bval}};
+code_change({down,1},Extra,State) ->
+ {ok, state}.
diff --git a/lib/sasl/test/release_handler_SUITE_data/lib/a-9.0/ebin/a.app b/lib/sasl/test/release_handler_SUITE_data/lib/a-9.0/ebin/a.app
new file mode 100644
index 0000000000..aa436d3e8c
--- /dev/null
+++ b/lib/sasl/test/release_handler_SUITE_data/lib/a-9.0/ebin/a.app
@@ -0,0 +1,8 @@
+{application, a,
+ [{description, "A CXC 138 11"},
+ {vsn, "9.0"},
+ {modules, [a, a_sup]},
+ {registered, [a_sup]},
+ {applications, [kernel, stdlib]},
+ {env, [{key1, val1}]},
+ {mod, {a_sup, []}}]}.
diff --git a/lib/sasl/test/release_handler_SUITE_data/lib/a-9.0/ebin/a.appup b/lib/sasl/test/release_handler_SUITE_data/lib/a-9.0/ebin/a.appup
new file mode 100644
index 0000000000..c4071d57a3
--- /dev/null
+++ b/lib/sasl/test/release_handler_SUITE_data/lib/a-9.0/ebin/a.appup
@@ -0,0 +1,3 @@
+{"9.0",
+ [{"1.0",[{update,a_sup,{advanced,update_supervisor}}]}],
+ [{"1.0",[{update,a_sup,{advanced,update_supervisor}}]}]}.
diff --git a/lib/sasl/test/release_handler_SUITE_data/lib/a-9.0/src/a.erl b/lib/sasl/test/release_handler_SUITE_data/lib/a-9.0/src/a.erl
new file mode 100644
index 0000000000..1050e53f35
--- /dev/null
+++ b/lib/sasl/test/release_handler_SUITE_data/lib/a-9.0/src/a.erl
@@ -0,0 +1,56 @@
+%% ``The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved via the world wide web at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% The Initial Developer of the Original Code is Ericsson Utvecklings AB.
+%% Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings
+%% AB. All Rights Reserved.''
+%%
+%% $Id$
+%%
+-module(a).
+
+
+-behaviour(gen_server).
+
+%% External exports
+-export([start_link/0, a/0, b/0]).
+%% Internal exports
+-export([init/1, handle_call/3, handle_info/2, terminate/2, code_change/3]).
+
+start_link() -> gen_server:start_link({local, aa}, a, [], []).
+
+a() -> gen_server:call(aa, a).
+b() -> gen_server:call(aa, b).
+
+%%-----------------------------------------------------------------
+%% Callback functions from gen_server
+%%-----------------------------------------------------------------
+init([]) ->
+ process_flag(trap_exit, true),
+ {ok, {state, bval}}.
+
+handle_call(a, _From, State) ->
+ X = application:get_all_env(a),
+ {reply, X, State};
+
+handle_call(b, _From, State) ->
+ {reply, {ok, element(2, State)}, State}.
+
+handle_info(_, State) ->
+ {noreply, State}.
+
+terminate(_Reason, _State) ->
+ ok.
+
+code_change(1, Extra, State) ->
+ {ok, {state, bval}};
+code_change({down,1},Extra,State) ->
+ {ok, state}.
diff --git a/lib/asn1/src/asn1_sup.erl b/lib/sasl/test/release_handler_SUITE_data/lib/a-9.0/src/a_sup.erl
index a241dec6f4..ae1d080f58 100644
--- a/lib/asn1/src/asn1_sup.erl
+++ b/lib/sasl/test/release_handler_SUITE_data/lib/a-9.0/src/a_sup.erl
@@ -3,35 +3,35 @@
%% compliance with the License. You should have received a copy of the
%% Erlang Public License along with this software. If not, it can be
%% retrieved via the world wide web at http://www.erlang.org/.
-%%
+%%
%% Software distributed under the License is distributed on an "AS IS"
%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
%% the License for the specific language governing rights and limitations
%% under the License.
-%%
+%%
%% The Initial Developer of the Original Code is Ericsson Utvecklings AB.
%% Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings
%% AB. All Rights Reserved.''
-%%
+%%
%% $Id$
%%
+-module(a_sup).
-%% Purpose: Main supervisor in asn1 application.
-
--module(asn1_sup).
-behaviour(supervisor).
--export([start_link/0, init/1]).
+%% External exports
+-export([start/2]).
-start_link() ->
- supervisor:start_link({local, asn1_sup}, asn1_sup, []).
+%% Internal exports
+-export([init/1]).
+start(_, _) ->
+ supervisor:start_link({local, a_sup}, a_sup, []).
-%% init([])
-%% Returns: {ok, {SupFlags, [ChildSpec]}}
-%%
init([]) ->
- Child = {asn1_server, {asn1_server, start_link, []},
- permanent, 2000, worker, [asn1_server]},
- {ok, {{one_for_all, 10, 3600}, [Child]}}.
+ SupFlags = {one_for_all, 4, 3600},
+ Config = {a,
+ {a, start_link, []},
+ permanent, brutal_kill, worker, [a]},
+ {ok, {SupFlags, [Config]}}.
diff --git a/lib/sasl/test/release_handler_SUITE_data/lib/a-9.1/ebin/a.app b/lib/sasl/test/release_handler_SUITE_data/lib/a-9.1/ebin/a.app
new file mode 100644
index 0000000000..5b467ec4e8
--- /dev/null
+++ b/lib/sasl/test/release_handler_SUITE_data/lib/a-9.1/ebin/a.app
@@ -0,0 +1,8 @@
+{application, a,
+ [{description, "A CXC 138 11"},
+ {vsn, "9.1"},
+ {modules, [a, a_sup]},
+ {registered, [a_sup]},
+ {applications, [kernel, stdlib]},
+ {env, [{key1, val1}]},
+ {mod, {a_sup, []}}]}.
diff --git a/lib/sasl/test/release_handler_SUITE_data/lib/a-9.1/ebin/a.appup b/lib/sasl/test/release_handler_SUITE_data/lib/a-9.1/ebin/a.appup
new file mode 100644
index 0000000000..efeb7f1fe3
--- /dev/null
+++ b/lib/sasl/test/release_handler_SUITE_data/lib/a-9.1/ebin/a.appup
@@ -0,0 +1,3 @@
+{"9.1",
+ [{"1.0",[{update,a_sup,{advanced,update_supervisor}}]}],
+ [{"1.0",[{update,a_sup,{advanced,update_supervisor}}]}]}.
diff --git a/lib/sasl/test/release_handler_SUITE_data/lib/a-9.1/src/a.erl b/lib/sasl/test/release_handler_SUITE_data/lib/a-9.1/src/a.erl
new file mode 100644
index 0000000000..1050e53f35
--- /dev/null
+++ b/lib/sasl/test/release_handler_SUITE_data/lib/a-9.1/src/a.erl
@@ -0,0 +1,56 @@
+%% ``The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved via the world wide web at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% The Initial Developer of the Original Code is Ericsson Utvecklings AB.
+%% Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings
+%% AB. All Rights Reserved.''
+%%
+%% $Id$
+%%
+-module(a).
+
+
+-behaviour(gen_server).
+
+%% External exports
+-export([start_link/0, a/0, b/0]).
+%% Internal exports
+-export([init/1, handle_call/3, handle_info/2, terminate/2, code_change/3]).
+
+start_link() -> gen_server:start_link({local, aa}, a, [], []).
+
+a() -> gen_server:call(aa, a).
+b() -> gen_server:call(aa, b).
+
+%%-----------------------------------------------------------------
+%% Callback functions from gen_server
+%%-----------------------------------------------------------------
+init([]) ->
+ process_flag(trap_exit, true),
+ {ok, {state, bval}}.
+
+handle_call(a, _From, State) ->
+ X = application:get_all_env(a),
+ {reply, X, State};
+
+handle_call(b, _From, State) ->
+ {reply, {ok, element(2, State)}, State}.
+
+handle_info(_, State) ->
+ {noreply, State}.
+
+terminate(_Reason, _State) ->
+ ok.
+
+code_change(1, Extra, State) ->
+ {ok, {state, bval}};
+code_change({down,1},Extra,State) ->
+ {ok, state}.
diff --git a/lib/docbuilder/test/docb_SUITE.erl b/lib/sasl/test/release_handler_SUITE_data/lib/a-9.1/src/a_sup.erl
index d286824539..b0597dc5c3 100644
--- a/lib/docbuilder/test/docb_SUITE.erl
+++ b/lib/sasl/test/release_handler_SUITE_data/lib/a-9.1/src/a_sup.erl
@@ -3,48 +3,35 @@
%% compliance with the License. You should have received a copy of the
%% Erlang Public License along with this software. If not, it can be
%% retrieved via the world wide web at http://www.erlang.org/.
-%%
+%%
%% Software distributed under the License is distributed on an "AS IS"
%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
%% the License for the specific language governing rights and limitations
%% under the License.
-%%
+%%
%% The Initial Developer of the Original Code is Ericsson Utvecklings AB.
%% Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings
%% AB. All Rights Reserved.''
-%%
+%%
%% $Id$
%%
--module(docb_SUITE).
-
--export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1, init_per_group/2,end_per_group/2,html/1]).
-
--include_lib("common_test/include/ct.hrl").
-
--include_lib("kernel/include/file.hrl").
-
-suite() -> [{ct_hooks,[ts_install_cth]}].
-
-all() ->
-[html].
-
-groups() ->
- [].
-
-init_per_suite(Config) ->
- Config.
+-module(a_sup).
-end_per_suite(_Config) ->
- ok.
-init_per_group(_GroupName, Config) ->
- Config.
+-behaviour(supervisor).
-end_per_group(_GroupName, Config) ->
- Config.
+%% External exports
+-export([start/2]).
+%% Internal exports
+-export([init/1]).
-html(suite) -> [];
-html(Config) when is_list(Config) ->
- ok.
+start(_, _) ->
+ supervisor:start_link({local, a_sup}, a_sup, []).
+init([]) ->
+ SupFlags = {one_for_all, 4, 3600},
+ Config = {a,
+ {a, start_link, []},
+ permanent, brutal_kil, worker, [a]},
+ {ok, {SupFlags, [Config]}}.
diff --git a/lib/sasl/test/sasl_SUITE.erl b/lib/sasl/test/sasl_SUITE.erl
index 454095db6a..195324daa0 100644
--- a/lib/sasl/test/sasl_SUITE.erl
+++ b/lib/sasl/test/sasl_SUITE.erl
@@ -30,10 +30,11 @@
% Test cases must be exported.
-export([app_test/1,
+ appup_test/1,
log_mf_h_env/1]).
all() ->
- [app_test, log_mf_h_env].
+ [app_test, appup_test, log_mf_h_env].
groups() ->
[].
@@ -57,6 +58,102 @@ app_test(Config) when is_list(Config) ->
?line ?t:app_test(sasl, allow),
ok.
+%% Test that appup allows upgrade from/downgrade to a maximum of two
+%% major releases back.
+appup_test(_Config) ->
+ application:load(sasl),
+ {sasl,_,SaslVsn} = lists:keyfind(sasl,1,application:loaded_applications()),
+ Ebin = filename:join(code:lib_dir(sasl),ebin),
+ {ok,[{SaslVsn,UpFrom,DownTo}=Appup]} =
+ file:consult(filename:join(Ebin,"sasl.appup")),
+ ct:log("~p~n",[Appup]),
+ ?line {OkVsns,NokVsns} = create_test_vsns(SaslVsn),
+ ?line check_appup(OkVsns,UpFrom,{ok,[restart_new_emulator]}),
+ ?line check_appup(OkVsns,DownTo,{ok,[restart_new_emulator]}),
+ ?line check_appup(NokVsns,UpFrom,error),
+ ?line check_appup(NokVsns,DownTo,error),
+ ok.
+
+
+%% For sasl, the versions up to R14B03 were not according to the rule
+%% used for other core applications - i.e. to change the second number
+%% at major releases, the third at maintenance releases and the fourth
+%% for patches - therefore test versions up to and including R16 are
+%% hardcoded.
+%% (All versions below are not necessarily existing.)
+-define(r12_vsns,["2.1.5"]).
+-define(r13_vsns,["2.1.6","2.1.7.1","2.1.9","2.1.9.1.2"]).
+-define(r14_vsns,["2.1.9.2","2.1.9.2.20","2.1.9.4","2.1.10"]).
+-define(r15_major,"2.2").
+-define(r16_major,"2.3").
+-define(r17_major,"2.4").
+create_test_vsns(?r15_major ++ Rest) ->
+ R15Vsns =
+ case string:tokens(Rest,".") of
+ [] -> [];
+ ["1"] -> [?r15_major];
+ _ -> [?r15_major,?r15_major++".1"]
+ end,
+ OkVsns = ?r13_vsns ++ ?r14_vsns ++ R15Vsns,
+ NokVsns = ?r12_vsns ++ [?r15_major++",1", ?r16_major],
+ {OkVsns,NokVsns};
+create_test_vsns(?r16_major ++ Rest) ->
+ R16Vsns =
+ case string:tokens(Rest,".") of
+ [] -> [];
+ ["1"] -> [?r16_major];
+ _ -> [?r16_major,?r16_major++".1"]
+ end,
+ OkVsns = ?r14_vsns ++ [?r15_major, ?r15_major ++ ".1.4"] ++ R16Vsns,
+ NokVsns = ?r13_vsns ++ [?r16_major++",1", ?r17_major],
+ {OkVsns,NokVsns};
+%% Normal erts case - i.e. for versions that comply to the erts standard
+create_test_vsns(Current) ->
+ [XStr,YStr|Rest] = string:tokens(Current,"."),
+ X = list_to_integer(XStr),
+ Y = list_to_integer(YStr),
+ SecondMajor = vsn(X,Y-2),
+ SecondMinor = SecondMajor ++ ".1.3",
+ FirstMajor = vsn(X,Y-1),
+ FirstMinor = FirstMajor ++ ".57",
+ ThisMajor = vsn(X,Y),
+ This =
+ case Rest of
+ [] ->
+ [];
+ ["1"] ->
+ [ThisMajor];
+ _ ->
+ ThisMinor = ThisMajor ++ ".1",
+ [ThisMajor,ThisMinor]
+ end,
+ OkVsns = This ++ [FirstMajor, FirstMinor, SecondMajor, SecondMinor],
+
+ ThirdMajor = vsn(X,Y-3),
+ ThirdMinor = ThirdMajor ++ ".10.12",
+ Illegal = ThisMajor ++ ",1",
+ Newer1Major = vsn(X,Y+1),
+ Newer1Minor = Newer1Major ++ ".1",
+ Newer2Major = ThisMajor ++ "1",
+ NokVsns = [ThirdMajor,ThirdMinor,
+ Illegal,
+ Newer1Major,Newer1Minor,
+ Newer2Major],
+ {OkVsns,NokVsns}.
+
+vsn(X,Y) ->
+ integer_to_list(X) ++ "." ++ integer_to_list(Y).
+
+check_appup([Vsn|Vsns],Instrs,Expected) ->
+ case systools_relup:appup_search_for_version(Vsn, Instrs) of
+ Expected -> check_appup(Vsns,Instrs,Expected);
+ Other -> ct:fail({unexpected_result_for_vsn,Vsn,Other})
+ end;
+check_appup([],_,_) ->
+ ok.
+
+
+
%% OTP-9185 - fail sasl start if some but not all log_mf_h env vars
%% are given.
log_mf_h_env(Config) ->
diff --git a/lib/sasl/test/systools_SUITE.erl b/lib/sasl/test/systools_SUITE.erl
index e352247d44..beb1e48ca7 100644
--- a/lib/sasl/test/systools_SUITE.erl
+++ b/lib/sasl/test/systools_SUITE.erl
@@ -41,7 +41,7 @@
-export([all/0,suite/0,groups/0,init_per_group/2,end_per_group/2]).
-export([ script_options/1, normal_script/1, no_mod_vsn_script/1,
- wildcard_script/1, variable_script/1,
+ wildcard_script/1, variable_script/1, no_sasl_script/1,
abnormal_script/1, src_tests_script/1, crazy_script/1,
warn_shadow_script/1,
included_script/1, included_override_script/1,
@@ -49,10 +49,11 @@
-export([ tar_options/1, normal_tar/1, no_mod_vsn_tar/1, variable_tar/1,
src_tests_tar/1, shadow_tar/1, var_tar/1,
exref_tar/1, link_tar/1, otp_9507/1]).
--export([ normal_relup/1, abnormal_relup/1, no_appup_relup/1,
- bad_appup_relup/1, app_start_type_relup/1, otp_3065/1]).
--export([
- otp_6226/1]).
+-export([ normal_relup/1, restart_relup/1, abnormal_relup/1, no_sasl_relup/1,
+ no_appup_relup/1, bad_appup_relup/1, app_start_type_relup/1,
+ regexp_relup/1, otp_3065/1]).
+-export([otp_6226/1]).
+-export([normal_hybrid/1,hybrid_no_old_sasl/1,hybrid_no_new_sasl/1]).
-export([init_per_suite/1, end_per_suite/1,
init_per_testcase/2, end_per_testcase/2]).
@@ -67,15 +68,15 @@ suite() ->
[{ct_hooks, [ts_install_cth]}].
all() ->
- [{group, script}, {group, tar}, {group, relup},
+ [{group, script}, {group, tar}, {group, relup}, {group, hybrid},
{group, tickets}].
groups() ->
[{script, [],
[script_options, normal_script, no_mod_vsn_script,
wildcard_script, variable_script, abnormal_script,
- src_tests_script, crazy_script, warn_shadow_script,
- included_script, included_override_script,
+ no_sasl_script, src_tests_script, crazy_script,
+ warn_shadow_script, included_script, included_override_script,
included_fail_script, included_bug_script, exref_script,
otp_3065]},
{tar, [],
@@ -83,8 +84,10 @@ groups() ->
src_tests_tar, shadow_tar, var_tar,
exref_tar, link_tar, otp_9507]},
{relup, [],
- [normal_relup, abnormal_relup, no_appup_relup,
- bad_appup_relup, app_start_type_relup]},
+ [normal_relup, restart_relup, abnormal_relup, no_sasl_relup,
+ no_appup_relup, bad_appup_relup, app_start_type_relup, regexp_relup
+ ]},
+ {hybrid, [], [normal_hybrid,hybrid_no_old_sasl,hybrid_no_new_sasl]},
{tickets, [], [otp_6226]}].
init_per_group(_GroupName, Config) ->
@@ -388,6 +391,35 @@ abnormal_script(Config) when is_list(Config) ->
%% make_script
%%
+no_sasl_script(suite) -> [];
+no_sasl_script(doc) ->
+ ["Create script without sasl appl. Check warning."];
+no_sasl_script(Config) when is_list(Config) ->
+ ?line {ok, OldDir} = file:get_cwd(),
+
+ ?line {LatestDir, LatestName} = create_script(latest1_no_sasl,Config),
+
+ ?line DataDir = filename:absname(?copydir),
+ ?line LibDir = [fname([DataDir, d_normal, lib])],
+ ?line P = [fname([LibDir, '*', ebin]),
+ fname([DataDir, lib, kernel, ebin]),
+ fname([DataDir, lib, stdlib, ebin]),
+ fname([DataDir, lib, sasl, ebin])],
+
+ ?line ok = file:set_cwd(LatestDir),
+
+ ?line {ok, _ , [{warning,missing_sasl}]} =
+ systools:make_script(LatestName,[{path, P},silent]),
+
+ ?line {ok, _ , []} =
+ systools:make_script(LatestName,[{path, P},silent, no_warn_sasl]),
+
+ ?line ok = file:set_cwd(OldDir),
+ ok.
+
+
+%% make_script
+%%
src_tests_script(suite) -> [];
src_tests_script(doc) ->
["Do not check date of object file or that source code can be found."];
@@ -1106,15 +1138,17 @@ otp_9507(Config) when is_list(Config) ->
RelName = fname([LatestDir,LatestName]),
?line P1 = ["./ebin",
- fname([DataDir, lib, kernel, ebin]),
- fname([DataDir, lib, stdlib, ebin])],
+ fname([DataDir, lib, kernel, ebin]),
+ fname([DataDir, lib, stdlib, ebin]),
+ fname([DataDir, lib, sasl, ebin])],
?line {ok, _, _} = systools:make_script(RelName, [silent, {path, P1}]),
?line ok = systools:make_tar(RelName, [{path, P1}]),
?line Content1 = tar_contents(RelName),
?line P2 = ["ebin",
- fname([DataDir, lib, kernel, ebin]),
- fname([DataDir, lib, stdlib, ebin])],
+ fname([DataDir, lib, kernel, ebin]),
+ fname([DataDir, lib, stdlib, ebin]),
+ fname([DataDir, lib, sasl, ebin])],
%% Tickets solves the following line - it used to fail with
%% {function_clause,[{filename,join,[[]]},...}
@@ -1148,18 +1182,11 @@ normal_relup(Config) when is_list(Config) ->
?line LibDir = [fname([DataDir, d_normal, lib])],
?line P = [fname([LibDir, '*', ebin]),
fname([DataDir, lib, kernel, ebin]),
- fname([DataDir, lib, stdlib, ebin])],
+ fname([DataDir, lib, stdlib, ebin]),
+ fname([DataDir, lib, sasl, ebin])],
?line ok = file:set_cwd(LatestDir),
- %% OTP-2561: Check that the option 'restart_emulator' generates a
- %% "restart_new_emulator" instruction.
- ?line {ok, _ , _, []} =
- systools:make_relup(LatestName, [LatestName1], [LatestName1],
- [{path, P},restart_emulator,silent]),
- ?line ok = check_relup([{db, "2.1"}], [{db, "1.0"}]),
- ?line ok = check_restart_emulator(),
-
%% This is the ultra normal case
?line ok = systools:make_relup(LatestName, [LatestName1], [LatestName1],
[{path, P}]),
@@ -1188,7 +1215,7 @@ normal_relup(Config) when is_list(Config) ->
?line ok = systools:make_relup(LatestName, [LatestName2], [LatestName1],
[{path, P}]),
?line ok = check_relup([{fe, "3.1"}, {db, "2.1"}], [{db, "1.0"}]),
- ?line {ok, _, _, [{erts_vsn_changed, _}]} =
+ ?line {ok, _, _, [pre_R15_emulator_upgrade,{erts_vsn_changed, _}]} =
systools:make_relup(LatestName, [LatestName2], [LatestName1],
[{path, P}, silent]),
?line ok = check_relup([{fe, "3.1"}, {db, "2.1"}], [{db, "1.0"}]),
@@ -1200,6 +1227,91 @@ normal_relup(Config) when is_list(Config) ->
ok.
+restart_relup(suite) -> [];
+restart_relup(doc) ->
+ ["Test relup which includes emulator restart"];
+restart_relup(Config) when is_list(Config) ->
+ ?line {ok, OldDir} = file:get_cwd(),
+
+ ?line {LatestDir,LatestName} = create_script(latest0,Config),
+ ?line {_LatestDir1,LatestName1} = create_script(latest1,Config),
+ ?line {_LatestDir0CurrErts,LatestName0CurrErts} =
+ create_script(latest0_current_erts,Config),
+ ?line {_CurrentAllDir,CurrentAllName} = create_script(current_all,Config),
+ ?line {_CurrentAllFutErtsDir,CurrentAllFutErtsName} =
+ create_script(current_all_future_erts,Config),
+ ?line {_CurrentAllFutSaslDir,CurrentAllFutSaslName} =
+ create_script(current_all_future_sasl,Config),
+
+ ?line DataDir = filename:absname(?copydir),
+ ?line LibDir = [fname([DataDir, d_normal, lib])],
+ ?line P = [fname([LibDir, '*', ebin]),
+ fname([DataDir, lib, kernel, ebin]),
+ fname([DataDir, lib, stdlib, ebin]),
+ fname([DataDir, lib, sasl, ebin]),
+ fname([DataDir, lib, 'sasl-9.9', ebin])],
+
+ ?line ok = file:set_cwd(LatestDir),
+
+ %% OTP-2561: Check that the option 'restart_emulator' generates a
+ %% "restart_emulator" instruction.
+ ?line {ok, _ , _, []} =
+ systools:make_relup(LatestName, [LatestName1], [LatestName1],
+ [{path, P},restart_emulator,silent]),
+ ?line ok = check_relup([{db, "2.1"}], [{db, "1.0"}]),
+ ?line ok = check_restart_emulator(),
+
+
+ %% Pre-R15 to Post-R15 upgrade
+ ?line {ok, _ , _, Ws} =
+ systools:make_relup(LatestName0CurrErts,
+ [LatestName1],
+ [LatestName1],
+ [{path, P},silent]),
+ ?line ok = check_relup([{db,"2.1"}], [{db, "1.0"}]),
+ ?line ok = check_pre_to_post_r15_restart_emulator(),
+ ?line ok = check_pre_to_post_r15_warnings(Ws),
+
+
+ %% Check that new sasl version generates a restart_new_emulator
+ %% instruction
+ ?line {ok, _ , _, []} =
+ systools:make_relup(CurrentAllFutSaslName,
+ [CurrentAllName],
+ [CurrentAllName],
+ [{path, P},silent]),
+ ?line ok = check_relup([{fe, "3.1"}], []),
+ ?line ok = check_restart_emulator_diff_coreapp(),
+
+
+ %% Check that new erts version generates a restart_new_emulator
+ %% instruction, if FromSaslVsn >= R15SaslVsn
+ %% (One erts_vsn_changed warning for upgrade and one for downgrade)
+ ?line {ok, _ , _, [{erts_vsn_changed,_},{erts_vsn_changed,_}]} =
+ systools:make_relup(CurrentAllFutErtsName,
+ [CurrentAllName],
+ [CurrentAllName],
+ [{path, P},silent]),
+ ?line ok = check_relup([{fe, "3.1"}], []),
+ ?line ok = check_restart_emulator_diff_coreapp(),
+
+
+ %% Check that new erts version generates a restart_new_emulator
+ %% instruction, and can be combined with restart_emulator opt.
+ %% (One erts_vsn_changed warning for upgrade and one for downgrade)
+ ?line {ok, _ , _, [{erts_vsn_changed,_},{erts_vsn_changed,_}]} =
+ systools:make_relup(CurrentAllFutErtsName,
+ [CurrentAllName],
+ [CurrentAllName],
+ [{path, P},restart_emulator,silent]),
+ ?line ok = check_relup([{fe, "3.1"}], []),
+ ?line ok = check_restart_emulator(),
+ ?line ok = check_restart_emulator_diff_coreapp(),
+
+ ?line ok = file:set_cwd(OldDir),
+ ok.
+
+
%% This test fails if wrong version numbers are seen in the relup file
%% or if any application is missing. This was triggered by OTP-1360.
check_relup(UpVsnL, DnVsnL) ->
@@ -1216,10 +1328,40 @@ check_relup(UpVsnL, DnVsnL) ->
[{App, Vsn} || {load_object_code,{App,Vsn,_}} <- Dn]),
ok.
+check_relup_up_only(UpVsnL) ->
+ {ok, [{_V1, [{_, _, Up}], []}]} = file:consult(relup),
+ [] = foldl(fun(X, Acc) ->
+ true = lists:member(X, Acc),
+ lists:delete(X, Acc) end,
+ UpVsnL,
+ [{App, Vsn} || {load_object_code,{App,Vsn,_}} <- Up]),
+ ok.
+
check_restart_emulator() ->
{ok, [{_V1, [{_, _, Up}], [{_, _, Dn}]}]} = file:consult(relup),
+ restart_emulator = lists:last(Up),
+ restart_emulator = lists:last(Dn),
+ ok.
+
+check_restart_emulator_up_only() ->
+ {ok, [{_V1, [{_, _, Up}], []}]} = file:consult(relup),
+ restart_emulator = lists:last(Up),
+ ok.
+
+check_restart_emulator_diff_coreapp() ->
+ {ok, [{_V1, [{_, _, Up}], [{_, _, Dn}]}]} = file:consult(relup),
+ [restart_new_emulator|_] = Up,
+ restart_emulator = lists:last(Dn),
+ ok.
+
+check_pre_to_post_r15_restart_emulator() ->
+ {ok, [{_V1, [{_, _, Up}], [{_, _, Dn}]}]} = file:consult(relup),
restart_new_emulator = lists:last(Up),
- restart_new_emulator = lists:last(Dn),
+ restart_emulator = lists:last(Dn),
+ ok.
+
+check_pre_to_post_r15_warnings(Ws) ->
+ true = lists:member(pre_R15_emulator_upgrade,Ws),
ok.
%% make_relup
@@ -1235,13 +1377,14 @@ no_appup_relup(Config) when is_list(Config) ->
?line {_LatestDir1,LatestName1} = create_script(latest_small1,Config),
?line DataDir = filename:absname(?copydir),
- ?line P1 = [fname([DataDir, d_no_appup, lib, 'fe-3.1', ebin]),
- fname([DataDir, lib, kernel, ebin]),
- fname([DataDir, lib, stdlib, ebin])],
?line ok = file:set_cwd(LatestDir),
%% Check that appup might be missing
+ ?line P1 = [fname([DataDir, d_no_appup, lib, 'fe-3.1', ebin]),
+ fname([DataDir, lib, kernel, ebin]),
+ fname([DataDir, lib, stdlib, ebin]),
+ fname([DataDir, lib, sasl, ebin])],
?line ok =
systools:make_relup(LatestName, [LatestName], [], [{path, P1}]),
?line {ok,_, _, []} =
@@ -1249,22 +1392,29 @@ no_appup_relup(Config) when is_list(Config) ->
[silent, {path, P1}]),
%% Check that appup might NOT be missing when we need it
+ ?line P2 = [fname([DataDir, d_no_appup, lib, 'fe-3.1', ebin]),
+ fname([DataDir, d_no_appup, lib, 'fe-2.1', ebin]),
+ fname([DataDir, lib, kernel, ebin]),
+ fname([DataDir, lib, stdlib, ebin]),
+ fname([DataDir, lib, sasl, ebin])],
?line error =
- systools:make_relup(LatestName, [LatestName0], [], [{path, P1}]),
+ systools:make_relup(LatestName, [LatestName0], [], [{path, P2}]),
?line {error,_,{file_problem, {_,{error,{open,_,_}}}}} =
systools:make_relup(LatestName, [], [LatestName0],
- [silent, {path, P1}]),
+ [silent, {path, P2}]),
%% Check that appups missing vsn traps
- ?line P2 = [fname([DataDir, d_no_appup, lib, 'fe-2.1', ebin]),
+ ?line P3 = [fname([DataDir, d_no_appup, lib, 'fe-2.1', ebin]),
+ fname([DataDir, d_no_appup, lib, 'fe-500.18.7', ebin]),
fname([DataDir, lib, kernel, ebin]),
- fname([DataDir, lib, stdlib, ebin])],
+ fname([DataDir, lib, stdlib, ebin]),
+ fname([DataDir, lib, sasl, ebin])],
?line error =
- systools:make_relup(LatestName0, [LatestName1], [], [{path, P2}]),
+ systools:make_relup(LatestName0, [LatestName1], [], [{path, P3}]),
?line {error,_,{no_relup, _, _, _}} =
systools:make_relup(LatestName0, [], [LatestName1],
- [silent, {path, P2}]),
+ [silent, {path, P3}]),
?line ok = file:set_cwd(OldDir),
ok.
@@ -1282,8 +1432,10 @@ bad_appup_relup(Config) when is_list(Config) ->
?line DataDir = filename:absname(?copydir),
?line N2 = [fname([DataDir, d_bad_appup, lib, 'fe-3.1', ebin]),
+ fname([DataDir, d_bad_appup, lib, 'fe-2.1', ebin]),
fname([DataDir, lib, kernel, ebin]),
- fname([DataDir, lib, stdlib, ebin])],
+ fname([DataDir, lib, stdlib, ebin]),
+ fname([DataDir, lib, sasl, ebin])],
?line ok = file:set_cwd(LatestDir),
@@ -1313,7 +1465,8 @@ abnormal_relup(Config) when is_list(Config) ->
?line P = [fname([DataDir, d_bad_app_vsn, lib, 'db-2.1', ebin]),
fname([DataDir, d_bad_app_vsn, lib, 'fe-3.1', ebin]),
fname([DataDir, lib, kernel, ebin]),
- fname([DataDir, lib, stdlib, ebin])],
+ fname([DataDir, lib, stdlib, ebin]),
+ fname([DataDir, lib, sasl, ebin])],
?line ok = file:set_cwd(LatestDir),
@@ -1329,6 +1482,37 @@ abnormal_relup(Config) when is_list(Config) ->
ok.
+%% make_relup
+%%
+no_sasl_relup(suite) -> [];
+no_sasl_relup(doc) ->
+ ["Check relup can not be created is sasl is not in rel file"];
+no_sasl_relup(Config) when is_list(Config) ->
+ ?line {ok, OldDir} = file:get_cwd(),
+ ?line {Dir1,Name1} = create_script(latest1_no_sasl,Config),
+ ?line {_Dir2,Name2} = create_script(latest1,Config),
+
+ ?line DataDir = filename:absname(?copydir),
+ ?line LibDir = [fname([DataDir, d_normal, lib])],
+ ?line P = [fname([LibDir, '*', ebin]),
+ fname([DataDir, lib, kernel, ebin]),
+ fname([DataDir, lib, stdlib, ebin]),
+ fname([DataDir, lib, sasl, ebin])],
+
+ ?line ok = file:set_cwd(Dir1),
+
+ ?line error = systools:make_relup(Name2, [Name1], [Name1], [{path, P}]),
+ ?line R1 = systools:make_relup(Name2, [Name1], [Name1],[silent, {path, P}]),
+ ?line {error,systools_relup,{missing_sasl,_}} = R1,
+
+ ?line error = systools:make_relup(Name1, [Name2], [Name2], [{path, P}]),
+ ?line R2 = systools:make_relup(Name1, [Name2], [Name2],[silent, {path, P}]),
+ ?line {error,systools_relup,{missing_sasl,_}} = R2,
+
+ ?line ok = file:set_cwd(OldDir),
+ ok.
+
+
%% Check that application start type is used in relup
app_start_type_relup(suite) ->
[];
@@ -1342,35 +1526,243 @@ app_start_type_relup(Config) when is_list(Config) ->
?line Release2 = filename:join(Dir2,Name2),
?line {ok, Release2Relup, systools_relup, []} = systools:make_relup(Release2, [Release1], [Release1], [{outdir, PrivDir}, silent]),
- ?line {"2", [{"1",[], UpInstructions}], [{"1",[], DownInstructions}]} = Release2Relup,
+ ?line {"LATEST_APP_START_TYPE2",
+ [{"LATEST_APP_START_TYPE1",[], UpInstructions}],
+ [{"LATEST_APP_START_TYPE1",[], DownInstructions}]} = Release2Relup,
%% ?t:format("Up: ~p",[UpInstructions]),
%% ?t:format("Dn: ~p",[DownInstructions]),
?line [{load_object_code, {mnesia, _, _}},
- {load_object_code, {sasl, _, _}},
+ {load_object_code, {runtime_tools, _, _}},
{load_object_code, {webtool, _, _}},
{load_object_code, {snmp, _, _}},
{load_object_code, {xmerl, _, _}},
point_of_no_return
| UpInstructionsT] = UpInstructions,
?line true = lists:member({apply,{application,start,[mnesia,permanent]}}, UpInstructionsT),
- ?line true = lists:member({apply,{application,start,[sasl,transient]}}, UpInstructionsT),
+ ?line true = lists:member({apply,{application,start,[runtime_tools,transient]}}, UpInstructionsT),
?line true = lists:member({apply,{application,start,[webtool,temporary]}}, UpInstructionsT),
?line true = lists:member({apply,{application,load,[snmp]}}, UpInstructionsT),
?line false = lists:any(fun({apply,{application,_,[xmerl|_]}}) -> true; (_) -> false end, UpInstructionsT),
?line [point_of_no_return | DownInstructionsT] = DownInstructions,
?line true = lists:member({apply,{application,stop,[mnesia]}}, DownInstructionsT),
- ?line true = lists:member({apply,{application,stop,[sasl]}}, DownInstructionsT),
+ ?line true = lists:member({apply,{application,stop,[runtime_tools]}}, DownInstructionsT),
?line true = lists:member({apply,{application,stop,[webtool]}}, DownInstructionsT),
?line true = lists:member({apply,{application,stop,[snmp]}}, DownInstructionsT),
?line true = lists:member({apply,{application,stop,[xmerl]}}, DownInstructionsT),
?line true = lists:member({apply,{application,unload,[mnesia]}}, DownInstructionsT),
- ?line true = lists:member({apply,{application,unload,[sasl]}}, DownInstructionsT),
+ ?line true = lists:member({apply,{application,unload,[runtime_tools]}}, DownInstructionsT),
?line true = lists:member({apply,{application,unload,[webtool]}}, DownInstructionsT),
?line true = lists:member({apply,{application,unload,[snmp]}}, DownInstructionsT),
?line true = lists:member({apply,{application,unload,[xmerl]}}, DownInstructionsT),
ok.
+%% regexp_relup
+regexp_relup(Config) ->
+ ?line {ok, OldDir} = file:get_cwd(),
+
+ ?line {LatestDir,LatestName} = create_script(latest_small,Config),
+ ?line {_LatestDir0,LatestName0} = create_script(latest_small0,Config),
+ ?line {_LatestDir1,LatestName1} = create_script(latest_small2,Config),
+
+ ?line DataDir = filename:absname(?copydir),
+ ?line P = [fname([DataDir, d_regexp_appup, lib, '*', ebin]),
+ fname([DataDir, lib, kernel, ebin]),
+ fname([DataDir, lib, stdlib, ebin]),
+ fname([DataDir, lib, sasl, ebin])],
+
+ ?line ok = file:set_cwd(LatestDir),
+
+ %% Upgrade fe 2.1 -> 3.1, and downgrade 2.1 -> 3.1
+ %% Shall match the first entry if fe-3.1 appup.
+ ?line {ok, _, _, []} =
+ systools:make_relup(LatestName, [LatestName0], [LatestName0],
+ [{path, P}, silent]),
+ ?line ok = check_relup([{fe, "3.1"}], [{fe, "2.1"}]),
+
+ %% Upgrade fe 2.1.1 -> 3.1
+ %% Shall match the second entry in fe-3.1 appup. Have added a
+ %% restart_emulator instruction there to distinguish it from
+ %% the first entry...
+ ?line {ok, _, _, []} =
+ systools:make_relup(LatestName, [LatestName1], [], [{path, P}, silent]),
+ ?line ok = check_relup_up_only([{fe, "3.1"}]),
+ ?line ok = check_restart_emulator_up_only(),
+
+ %% Attempt downgrade fe 3.1 -> 2.1.1
+ %% Shall not match any entry!!
+ ?line {error,systools_relup,{no_relup,_,_,_}} =
+ systools:make_relup(LatestName, [], [LatestName1], [{path, P}, silent]),
+
+ ?line ok = file:set_cwd(OldDir),
+
+ ok.
+
+
+%% For upgrade of erts - create a boot file which is a hybrid between
+%% old and new release - i.e. starts erts, kernel, stdlib, sasl from
+%% new release, all other apps from old release.
+normal_hybrid(Config) ->
+ ?line {ok, OldDir} = file:get_cwd(),
+ ?line {Dir1,Name1} = create_script(latest1,Config),
+ ?line {_Dir2,Name2} = create_script(current_all,Config),
+
+ ?line DataDir = filename:absname(?copydir),
+ ?line LibDir = [fname([DataDir, d_normal, lib])],
+ ?line P = [fname([LibDir, '*', ebin]),
+ fname([DataDir, lib, kernel, ebin]),
+ fname([DataDir, lib, stdlib, ebin]),
+ fname([DataDir, lib, sasl, ebin])],
+
+ ?line ok = file:set_cwd(Dir1),
+
+ ?line {ok, _ , []} = systools:make_script(Name1,[{path, P},silent]),
+ ?line {ok, _ , []} = systools:make_script(Name2,[{path, P},silent]),
+ ?line {ok,Boot1} = file:read_file(Name1 ++ ".boot"),
+ ?line {ok,Boot2} = file:read_file(Name2 ++ ".boot"),
+
+ ?line ok = file:set_cwd(OldDir),
+
+ ?line BasePaths = {"testkernelpath","teststdlibpath","testsaslpath"},
+ ?line {ok,Hybrid} = systools_make:make_hybrid_boot("tmp_vsn",Boot1,Boot2,
+ BasePaths, [dummy,args]),
+
+ ?line {script,{"Test release","tmp_vsn"},Script} = binary_to_term(Hybrid),
+ ct:log("~p.~n",[Script]),
+
+ %% Check that all paths to base apps are replaced by paths from BaseLib
+ Boot1Str = io_lib:format("~p~n",[binary_to_term(Boot1)]),
+ HybridStr = io_lib:format("~p~n",[binary_to_term(Hybrid)]),
+ ReOpts = [global,{capture,first,list},unicode],
+ ?line {match,OldKernelMatch} = re:run(Boot1Str,"kernel-[0-9\.]+",ReOpts),
+ ?line {match,OldStdlibMatch} = re:run(Boot1Str,"stdlib-[0-9\.]+",ReOpts),
+ ?line {match,OldSaslMatch} = re:run(Boot1Str,"sasl-[0-9\.]+",ReOpts),
+
+ ?line nomatch = re:run(HybridStr,"kernel-[0-9\.]+",ReOpts),
+ ?line nomatch = re:run(HybridStr,"stdlib-[0-9\.]+",ReOpts),
+ ?line nomatch = re:run(HybridStr,"sasl-[0-9\.]+",ReOpts),
+ ?line {match,NewKernelMatch} = re:run(HybridStr,"testkernelpath",ReOpts),
+ ?line {match,NewStdlibMatch} = re:run(HybridStr,"teststdlibpath",ReOpts),
+ ?line {match,NewSaslMatch} = re:run(HybridStr,"testsaslpath",ReOpts),
+
+ NewKernelN = length(NewKernelMatch),
+ ?line NewKernelN = length(OldKernelMatch),
+ NewStdlibN = length(NewStdlibMatch),
+ ?line NewStdlibN = length(OldStdlibMatch),
+ NewSaslN = length(NewSaslMatch),
+ ?line NewSaslN = length(OldSaslMatch),
+
+ %% Check that application load instruction has correct versions
+ Apps = application:loaded_applications(),
+ {_,_,KernelVsn} = lists:keyfind(kernel,1,Apps),
+ {_,_,StdlibVsn} = lists:keyfind(stdlib,1,Apps),
+ {_,_,SaslVsn} = lists:keyfind(sasl,1,Apps),
+
+ ?line [KernelInfo] = [I || {kernelProcess,application_controller,
+ {application_controller,start,
+ [{application,kernel,I}]}} <- Script],
+ ?line [StdlibInfo] = [I || {apply,
+ {application,load,
+ [{application,stdlib,I}]}} <- Script],
+ ?line [SaslInfo] = [I || {apply,
+ {application,load,
+ [{application,sasl,I}]}} <- Script],
+
+ ?line {vsn,KernelVsn} = lists:keyfind(vsn,1,KernelInfo),
+ ?line {vsn,StdlibVsn} = lists:keyfind(vsn,1,StdlibInfo),
+ ?line {vsn,SaslVsn} = lists:keyfind(vsn,1,SaslInfo),
+
+ %% Check that new_emulator_upgrade call is added
+ ?line [_,{apply,{release_handler,new_emulator_upgrade,[dummy,args]}}|_] =
+ lists:reverse(Script),
+
+ %% Check that db-1.0 and fe-3.1 are used (i.e. vsns from old release)
+ %% And that fe is in there (it exists in old rel but not in new)
+ ?line {match,DbMatch} = re:run(HybridStr,"db-[0-9\.]+",ReOpts),
+ ?line {match,[_|_]=FeMatch} = re:run(HybridStr,"fe-[0-9\.]+",ReOpts),
+ ?line true = lists:all(fun(["db-1.0"]) -> true;
+ (_) -> false
+ end,
+ DbMatch),
+ ?line true = lists:all(fun(["fe-3.1"]) -> true;
+ (_) -> false
+ end,
+ FeMatch),
+
+ %% Check that script has same length as old script, plus one (the
+ %% new_emulator_upgrade apply)
+ {_,_,Old} = binary_to_term(Boot1),
+ OldLength = length(Old),
+ NewLength = length(Script),
+ ?line NewLength = OldLength + 1,
+
+ ok.
+
+%% Check that systools_make:make_hybrid_boot fails with a meaningful
+%% error message if the FromBoot does not include the sasl
+%% application.
+hybrid_no_old_sasl(Config) ->
+ ?line {ok, OldDir} = file:get_cwd(),
+ ?line {Dir1,Name1} = create_script(latest1_no_sasl,Config),
+ ?line {_Dir2,Name2} = create_script(current_all,Config),
+
+ ?line DataDir = filename:absname(?copydir),
+ ?line LibDir = [fname([DataDir, d_normal, lib])],
+ ?line P = [fname([LibDir, '*', ebin]),
+ fname([DataDir, lib, kernel, ebin]),
+ fname([DataDir, lib, stdlib, ebin]),
+ fname([DataDir, lib, sasl, ebin])],
+
+ ?line ok = file:set_cwd(Dir1),
+
+ ?line {ok, _ , [{warning,missing_sasl}]} =
+ systools:make_script(Name1,[{path, P},silent]),
+ ?line {ok, _ , []} = systools:make_script(Name2,[{path, P},silent]),
+ ?line {ok,Boot1} = file:read_file(Name1 ++ ".boot"),
+ ?line {ok,Boot2} = file:read_file(Name2 ++ ".boot"),
+
+ ?line BasePaths = {"testkernelpath","teststdlibpath","testsaslpath"},
+ ?line {error,{app_not_replaced,sasl}} =
+ systools_make:make_hybrid_boot("tmp_vsn",Boot1,Boot2,
+ BasePaths,[dummy,args]),
+
+ ?line ok = file:set_cwd(OldDir),
+ ok.
+
+
+%% Check that systools_make:make_hybrid_boot fails with a meaningful
+%% error message if the ToBoot does not include the sasl
+%% application.
+hybrid_no_new_sasl(Config) ->
+ ?line {ok, OldDir} = file:get_cwd(),
+ ?line {Dir1,Name1} = create_script(latest1,Config),
+ ?line {_Dir2,Name2} = create_script(current_all_no_sasl,Config),
+
+ ?line DataDir = filename:absname(?copydir),
+ ?line LibDir = [fname([DataDir, d_normal, lib])],
+ ?line P = [fname([LibDir, '*', ebin]),
+ fname([DataDir, lib, kernel, ebin]),
+ fname([DataDir, lib, stdlib, ebin]),
+ fname([DataDir, lib, sasl, ebin])],
+
+ ?line ok = file:set_cwd(Dir1),
+
+ ?line {ok, _ , []} = systools:make_script(Name1,[{path, P},silent]),
+ ?line {ok, _ , [{warning,missing_sasl}]} =
+ systools:make_script(Name2,[{path, P},silent]),
+ ?line {ok,Boot1} = file:read_file(Name1 ++ ".boot"),
+ ?line {ok,Boot2} = file:read_file(Name2 ++ ".boot"),
+
+ ?line BasePaths = {"testkernelpath","teststdlibpath","testsaslpath"},
+ ?line {error,{app_not_found,sasl}} =
+ systools_make:make_hybrid_boot("tmp_vsn",Boot1,Boot2,
+ BasePaths,[dummy,args]),
+
+ ?line ok = file:set_cwd(OldDir),
+ ok.
+
+
+
otp_6226(suite) ->
[];
otp_6226(doc) ->
@@ -1388,7 +1780,8 @@ otp_6226(Config) when is_list(Config) ->
fname([LibDir, 'db-1.0', ebin]),
fname([LibDir, 'fe-3.1', ebin]),
fname([DataDir, lib, kernel, ebin]),
- fname([DataDir, lib, stdlib, ebin])],
+ fname([DataDir, lib, stdlib, ebin]),
+ fname([DataDir, lib, sasl, ebin])],
?line ok = file:set_cwd(LatestDir),
@@ -1656,165 +2049,95 @@ tar_name(Name) ->
Name ++ ".tar.gz".
create_script(latest,Config) ->
- ?line PrivDir = ?privdir,
- ?line Name = fname(PrivDir, latest),
- ?line Apps = application_controller:which_applications(),
- ?line {value,{_,_,KernelVer}} = lists:keysearch(kernel,1,Apps),
- ?line {value,{_,_,StdlibVer}} = lists:keysearch(stdlib,1,Apps),
- ?line {ok,Fd} = file:open(Name++".rel",write),
- ?line io:format(Fd,
- "{release, {\"Test release 3\", \"LATEST\"}, \n"
- " {erts, \"4.4\"}, \n"
- " [{kernel, \"~s\"}, {stdlib, \"~s\"}, \n"
- " {db, \"2.1\"}, {fe, \"3.1\"}]}.\n",
- [KernelVer,StdlibVer]),
- ?line ok = file:close(Fd),
- {filename:dirname(Name), filename:basename(Name)};
+ Apps = core_apps(current) ++ [{db,"2.1"},{fe,"3.1"}],
+ do_create_script(latest,Config,"4.4",Apps);
create_script(latest_no_mod_vsn,Config) ->
- ?line PrivDir = ?privdir,
- ?line Name = fname(PrivDir, latest),
- ?line Apps = application_controller:which_applications(),
- ?line {value,{_,_,KernelVer}} = lists:keysearch(kernel,1,Apps),
- ?line {value,{_,_,StdlibVer}} = lists:keysearch(stdlib,1,Apps),
- ?line {ok,Fd} = file:open(Name++".rel",write),
- ?line io:format(Fd,
- "{release, {\"Test release 3\", \"LATESTNOMOD\"}, \n"
- " {erts, \"4.4\"}, \n"
- " [{kernel, \"~s\"}, {stdlib, \"~s\"}, \n"
- " {db, \"3.1\"}, {fe, \"3.1\"}]}.\n",
- [KernelVer,StdlibVer]),
- ?line ok = file:close(Fd),
- {filename:dirname(Name), filename:basename(Name)};
+ Apps = core_apps(current) ++ [{db,"3.1"},{fe,"3.1"}],
+ do_create_script(latest_no_mod_vsn,Config,"4.4",Apps);
create_script(latest0,Config) ->
- ?line PrivDir = ?privdir,
- ?line Name = fname(PrivDir, 'latest-1'),
- ?line {ok,Fd} = file:open(Name++".rel",write),
- ?line io:format(Fd,
- "{release, {\"Test release 2\", \"LATEST0\"}, \n"
- " {erts, \"4.4\"}, \n"
- " [{kernel, \"1.0\"}, {stdlib, \"1.0\"}, \n"
- " {db, \"2.1\"}, {fe, \"3.1\"}]}.\n",
- []),
- ?line ok = file:close(Fd),
- {filename:dirname(Name), filename:basename(Name)};
+ Apps = core_apps("1.0") ++ [{db,"2.1"},{fe,"3.1"}],
+ do_create_script(latest0,Config,"4.4",Apps);
+create_script(latest0_current_erts,Config) ->
+ Apps = core_apps("1.0") ++ [{db,"2.1"},{fe,"3.1"}],
+ do_create_script(latest0_current_erts,Config,current,Apps);
create_script(latest1,Config) ->
- ?line PrivDir = ?privdir,
- ?line Name = fname(PrivDir, latest),
- ?line {ok,Fd} = file:open(Name++".rel",write),
- ?line io:format(Fd,
- "{release, {\"Test release 2\", \"LATEST1\"}, \n"
- " {erts, \"4.4\"}, \n"
- " [{kernel, \"1.0\"}, {stdlib, \"1.0\"}, \n"
- " {db, \"1.0\"}, {fe, \"3.1\"}]}.\n",
- []),
- ?line ok = file:close(Fd),
- {filename:dirname(Name), filename:basename(Name)};
+ Apps = core_apps("1.0") ++ [{db,"1.0"},{fe,"3.1"}],
+ do_create_script(latest1,Config,"4.4",Apps);
+create_script(latest1_no_sasl,Config) ->
+ Apps = [{kernel,"1.0"},{stdlib,"1.0"},{db,"1.0"},{fe,"3.1"}],
+ do_create_script(latest1_no_sasl,Config,"4.4",Apps);
create_script(latest2,Config) ->
- ?line PrivDir = ?privdir,
- ?line Name = fname(PrivDir, 'latest-2'),
- ?line {ok,Fd} = file:open(Name++".rel",write),
- ?line io:format(Fd,
- "{release, {\"Test release 1\", \"LATEST2\"}, \n"
- " {erts, \"4.3\"}, \n"
- " [{kernel, \"1.0\"}, {stdlib, \"1.0\"}, \n"
- " {db, \"1.0\"}, {fe, \"2.1\"}]}.\n",
- []),
- ?line ok = file:close(Fd),
- {filename:dirname(Name), filename:basename(Name)};
+ Apps = core_apps("1.0") ++ [{db,"1.0"},{fe,"2.1"}],
+ do_create_script(latest2,Config,"4.3",Apps);
create_script(latest_small,Config) ->
- ?line PrivDir = ?privdir,
- ?line Name = fname(PrivDir, 'latest-small'),
- ?line {ok,Fd} = file:open(Name++".rel",write),
- ?line io:format(Fd,
- "{release, {\"Test release 2\", \"LATEST_SMALL\"}, \n"
- " {erts, \"4.4\"}, \n"
- " [{kernel, \"1.0\"}, {stdlib, \"1.0\"}, \n"
- " {fe, \"3.1\"}]}.\n",
- []),
- ?line ok = file:close(Fd),
- {filename:dirname(Name), filename:basename(Name)};
+ Apps = core_apps("1.0") ++ [{fe,"3.1"}],
+ do_create_script(latest_small,Config,"4.4",Apps);
create_script(latest_small0,Config) -> %Differs in fe vsn
- ?line PrivDir = ?privdir,
- ?line Name = fname(PrivDir, 'latest-small0'),
- ?line {ok,Fd} = file:open(Name++".rel",write),
- ?line io:format(Fd,
- "{release, {\"Test release 2\", \"LATEST_SMALL0\"}, \n"
- " {erts, \"4.4\"}, \n"
- " [{kernel, \"1.0\"}, {stdlib, \"1.0\"}, \n"
- " {fe, \"2.1\"}]}.\n",
- []),
- ?line ok = file:close(Fd),
- {filename:dirname(Name), filename:basename(Name)};
+ Apps = core_apps("1.0") ++ [{fe,"2.1"}],
+ do_create_script(latest_small0,Config,"4.4",Apps);
create_script(latest_small1,Config) ->
- ?line PrivDir = ?privdir,
- ?line Name = fname(PrivDir, 'latest-small1'),
- ?line {ok,Fd} = file:open(Name++".rel",write),
- ?line io:format(Fd,
- "{release, {\"Test release 2\", \"LATEST_SMALL1\"}, \n"
- " {erts, \"4.4\"}, \n"
- " [{kernel, \"1.0\"}, {stdlib, \"1.0\"}, \n"
- " {fe, \"500.18.7\"}]}.\n",
- []),
- ?line ok = file:close(Fd),
- {filename:dirname(Name), filename:basename(Name)};
+ Apps = core_apps("1.0") ++ [{fe,"500.18.7"}],
+ do_create_script(latest_small1,Config,"4.4",Apps);
+create_script(latest_small2,Config) ->
+ Apps = core_apps("1.0") ++ [{fe,"2.1.1"}],
+ do_create_script(latest_small2,Config,"4.4",Apps);
create_script(latest_nokernel,Config) ->
- ?line PrivDir = ?privdir,
- ?line Name = fname(PrivDir, 'latest-nokernel'),
- ?line {ok,Fd} = file:open(Name++".rel",write),
- ?line io:format(Fd,
- "{release, {\"Test release 3\", \"LATEST_NOKERNEL\"}, \n"
- " {erts, \"4.4\"}, \n"
- " [{db, \"2.1\"}, {fe, \"3.1\"}]}.\n",
- []),
- ?line ok = file:close(Fd),
- {filename:dirname(Name), filename:basename(Name)};
+ Apps = [{db,"2.1"},{fe,"3.1"}],
+ do_create_script(latest_nokernel,Config,"4.4",Apps);
create_script(latest_app_start_type1,Config) ->
- ?line PrivDir = ?privdir,
- ?line Name = fname(PrivDir, latest_app_start_type1),
- ?line ErtsVer = erlang:system_info(version),
- ?line Apps = application_controller:which_applications(),
- ?line {value,{_,_,KernelVer}} = lists:keysearch(kernel,1,Apps),
- ?line {value,{_,_,StdlibVer}} = lists:keysearch(stdlib,1,Apps),
- ?line {ok,Fd} = file:open(Name++".rel",write),
- ?line RelfileContent =
- {release,{"Test release", "1"},
- {erts,ErtsVer},
- [{kernel,KernelVer},
- {stdlib,StdlibVer}]},
- ?line io:format(Fd,"~p.~n",[RelfileContent]),
- ?line ok = file:close(Fd),
- {filename:dirname(Name), filename:basename(Name)};
+ Apps = core_apps(current),
+ do_create_script(latest_app_start_type1,Config,current,Apps);
create_script(latest_app_start_type2,Config) ->
+ OtherApps = [{mnesia,current,permanent},
+ {runtime_tools,current,transient},
+ {webtool,current,temporary},
+ {snmp,current,load},
+ {xmerl,current,none}],
+ Apps = core_apps(current) ++ OtherApps,
+ do_create_script(latest_app_start_type2,Config,current,Apps);
+create_script(current_all_no_sasl,Config) ->
+ Apps = [{kernel,current},{stdlib,current},{db,"2.1"},{fe,"3.1"}],
+ do_create_script(current_all_no_sasl,Config,current,Apps);
+create_script(current_all,Config) ->
+ Apps = core_apps(current) ++ [{db,"2.1"}],
+ do_create_script(current_all,Config,current,Apps);
+create_script(current_all_future_erts,Config) ->
+ Apps = core_apps(current) ++ [{db,"2.1"},{fe,"3.1"}],
+ do_create_script(current_all_future_erts,Config,"99.99",Apps);
+create_script(current_all_future_sasl,Config) ->
+ Apps = [{kernel,current},{stdlib,current},{sasl,"9.9"},{db,"2.1"},{fe,"3.1"}],
+ do_create_script(current_all_future_sasl,Config,current,Apps).
+
+
+do_create_script(Id,Config,ErtsVsn,AppVsns) ->
?line PrivDir = ?privdir,
- ?line Name = fname(PrivDir, latest_app_start_type2),
- ?line ErtsVer = erlang:system_info(version),
- ?line Apps = application_controller:which_applications(),
- ?line {value,{_,_,KernelVer}} = lists:keysearch(kernel,1,Apps),
- ?line {value,{_,_,StdlibVer}} = lists:keysearch(stdlib,1,Apps),
- ?line OtherApps = [{mnesia,permanent},
- {sasl,transient},
- {webtool,temporary},
- {snmp,load},
- {xmerl,none}],
- ?line lists:foreach(fun({App,_}) -> application:load(App) end,
- OtherApps),
- ?line Loaded = application:loaded_applications(),
- ?line OtherAppsRel =
- lists:map(fun({App,StartType}) ->
- {_,_,Ver} = lists:keyfind(App,1,Loaded),
- {App,Ver,StartType}
- end,
- OtherApps),
+ ?line Name = fname(PrivDir, Id),
?line {ok,Fd} = file:open(Name++".rel",write),
- ?line RelfileContent =
- {release,{"Test release", "2"},
- {erts,ErtsVer},
- [{kernel,KernelVer},
- {stdlib,StdlibVer} | OtherAppsRel]},
+ ?line RelfileContent =
+ {release,{"Test release", string:to_upper(atom_to_list(Id))},
+ {erts,erts_vsn(ErtsVsn)},
+ app_vsns(AppVsns)},
?line io:format(Fd,"~p.~n",[RelfileContent]),
?line ok = file:close(Fd),
{filename:dirname(Name), filename:basename(Name)}.
+core_apps(Vsn) ->
+ [{App,Vsn} || App <- [kernel,stdlib,sasl]].
+
+app_vsns(AppVsns) ->
+ [{App,app_vsn(App,Vsn)} || {App,Vsn} <- AppVsns] ++
+ [{App,app_vsn(App,Vsn),Type} || {App,Vsn,Type} <- AppVsns].
+app_vsn(App,current) ->
+ application:load(App),
+ {ok,Vsn} = application:get_key(App,vsn),
+ Vsn;
+app_vsn(_App,Vsn) ->
+ Vsn.
+
+erts_vsn(current) -> erlang:system_info(version);
+erts_vsn(Vsn) -> Vsn.
+
+
create_include_files(inc1, Config) ->
?line PrivDir = ?privdir,
?line Name = fname(PrivDir, inc1),
diff --git a/lib/sasl/test/systools_SUITE_data/d_bad_appup/lib/fe-2.1/ebin/fe.app b/lib/sasl/test/systools_SUITE_data/d_bad_appup/lib/fe-2.1/ebin/fe.app
new file mode 100644
index 0000000000..3cb0b0c2cf
--- /dev/null
+++ b/lib/sasl/test/systools_SUITE_data/d_bad_appup/lib/fe-2.1/ebin/fe.app
@@ -0,0 +1,7 @@
+{application, fe,
+ [{description, "ERICSSON NR FOR FE"},
+ {vsn, "2.1"},
+ {modules, [{fe1, "1.0"}, {fe2, "1.0"}, {fe3, "2.0"}]},
+ {registered, []},
+ {applications, []},
+ {mod, {fe1, []}}]}.
diff --git a/lib/sasl/test/systools_SUITE_data/d_no_appup/lib/fe-500.18.7/ebin/fe.app b/lib/sasl/test/systools_SUITE_data/d_no_appup/lib/fe-500.18.7/ebin/fe.app
new file mode 100644
index 0000000000..3a5c0ddd9b
--- /dev/null
+++ b/lib/sasl/test/systools_SUITE_data/d_no_appup/lib/fe-500.18.7/ebin/fe.app
@@ -0,0 +1,7 @@
+{application, fe,
+ [{description, "ERICSSON NR FOR FE"},
+ {vsn, "500.18.7"},
+ {modules, [{fe1, "1.0"}, {fe2, "1.0"}, {fe3, "2.0"}]},
+ {registered, []},
+ {applications, []},
+ {mod, {fe1, []}}]}.
diff --git a/lib/sasl/test/systools_SUITE_data/d_regexp_appup/lib/fe-2.1.1/ebin/fe.app b/lib/sasl/test/systools_SUITE_data/d_regexp_appup/lib/fe-2.1.1/ebin/fe.app
new file mode 100644
index 0000000000..c7ba1dfe91
--- /dev/null
+++ b/lib/sasl/test/systools_SUITE_data/d_regexp_appup/lib/fe-2.1.1/ebin/fe.app
@@ -0,0 +1,8 @@
+{application, fe,
+ [{description, "ERICSSON NR FOR FE"},
+ {vsn, "2.1.1"},
+ {modules, [{fe1, "1.0"}, {fe2, "1.0"}, {fe3, "2.0"}]},
+ {registered, []},
+ {applications, []},
+ {env, []},
+ {start, {fe2, start, []}}]}.
diff --git a/lib/sasl/test/systools_SUITE_data/d_regexp_appup/lib/fe-2.1/ebin/fe.app b/lib/sasl/test/systools_SUITE_data/d_regexp_appup/lib/fe-2.1/ebin/fe.app
new file mode 100644
index 0000000000..47ea248720
--- /dev/null
+++ b/lib/sasl/test/systools_SUITE_data/d_regexp_appup/lib/fe-2.1/ebin/fe.app
@@ -0,0 +1,8 @@
+{application, fe,
+ [{description, "ERICSSON NR FOR FE"},
+ {vsn, "2.1"},
+ {modules, [{fe1, "1.0"}, {fe2, "1.0"}, {fe3, "2.0"}]},
+ {registered, []},
+ {applications, []},
+ {env, []},
+ {start, {fe2, start, []}}]}.
diff --git a/lib/sasl/test/systools_SUITE_data/d_regexp_appup/lib/fe-3.1/ebin/fe.app b/lib/sasl/test/systools_SUITE_data/d_regexp_appup/lib/fe-3.1/ebin/fe.app
new file mode 100644
index 0000000000..0696e2494c
--- /dev/null
+++ b/lib/sasl/test/systools_SUITE_data/d_regexp_appup/lib/fe-3.1/ebin/fe.app
@@ -0,0 +1,7 @@
+{application, fe,
+ [{description, "ERICSSON NR FOR FE"},
+ {vsn, "3.1"},
+ {modules, [{fe1, "1.0"}, {fe2, "1.0"}, {fe3, "2.0"}]},
+ {registered, []},
+ {applications, []},
+ {mod, {fe1, []}}]}.
diff --git a/lib/sasl/test/systools_SUITE_data/d_regexp_appup/lib/fe-3.1/ebin/fe.appup b/lib/sasl/test/systools_SUITE_data/d_regexp_appup/lib/fe-3.1/ebin/fe.appup
new file mode 100644
index 0000000000..6b99c47e53
--- /dev/null
+++ b/lib/sasl/test/systools_SUITE_data/d_regexp_appup/lib/fe-3.1/ebin/fe.appup
@@ -0,0 +1,28 @@
+%% -*- erlang -*-
+%% Release upgrade script for fe (front end)
+%%
+
+{
+ "3.1",
+ %% Upgrade from:
+ [
+ {<<"2\\.[0-9]+">>, % matches 2.X in full length and 2.X.Y... only partly
+ [{update, fe1, soft, soft_purge, soft_purge, []},
+ {update, fe2, soft, soft_purge, soft_purge, [fe1]},
+ {update, fe3, {advanced, extra}, soft_purge, soft_purge, [fe1, fe2]}
+ ]},
+ {<<"2(\\.[0-9]+)+">>, % matches 2.X.Y... in full length
+ [{update, fe1, soft, soft_purge, soft_purge, []},
+ {update, fe2, soft, soft_purge, soft_purge, [fe1]},
+ {update, fe3, {advanced, extra}, soft_purge, soft_purge,[fe1, fe2]},
+ restart_emulator]}
+ ],
+
+ %% Downgrade to:
+ [
+ {<<"2\\.[0-9]+">>, % matches 2.X in full length and 2.X.Y... only partly
+ [{update, fe2, soft, soft_purge, soft_purge, []},
+ {update, fe3, {advanced, extra}, soft_purge, soft_purge, [fe2]}
+ ]}
+ ]
+}.
diff --git a/lib/sasl/test/systools_SUITE_data/lib/sasl-9.9/ebin/sasl.app b/lib/sasl/test/systools_SUITE_data/lib/sasl-9.9/ebin/sasl.app
new file mode 100644
index 0000000000..3bcc1a4619
--- /dev/null
+++ b/lib/sasl/test/systools_SUITE_data/lib/sasl-9.9/ebin/sasl.app
@@ -0,0 +1,6 @@
+{application, sasl,
+ [{description, "FAKE FUTURE SASL"},
+ {vsn, "9.9"},
+ {modules, []},
+ {registered, []},
+ {applications, []}]}.
diff --git a/lib/sasl/test/systools_SUITE_data/lib/sasl-9.9/ebin/sasl.appup b/lib/sasl/test/systools_SUITE_data/lib/sasl-9.9/ebin/sasl.appup
new file mode 100644
index 0000000000..cff0c69b6e
--- /dev/null
+++ b/lib/sasl/test/systools_SUITE_data/lib/sasl-9.9/ebin/sasl.appup
@@ -0,0 +1,12 @@
+%%
+%% Fake release upgrade script for sasl
+%%
+
+{
+ "9.9",
+ [{<<".+">>,[restart_new_emulator]}
+ ],
+
+ [{<<".+">>,[restart_new_emulator]}
+ ]
+}.
diff --git a/lib/sasl/test/systools_SUITE_data/lib/sasl/ebin/sasl.app b/lib/sasl/test/systools_SUITE_data/lib/sasl/ebin/sasl.app
new file mode 100644
index 0000000000..aaeb37fa4d
--- /dev/null
+++ b/lib/sasl/test/systools_SUITE_data/lib/sasl/ebin/sasl.app
@@ -0,0 +1,6 @@
+{application, sasl,
+ [{description, "FAKE SASL"},
+ {vsn, "1.0"},
+ {modules, []},
+ {registered, []},
+ {applications, []}]}.
diff --git a/lib/sasl/test/systools_SUITE_data/lib/sasl/ebin/sasl.appup b/lib/sasl/test/systools_SUITE_data/lib/sasl/ebin/sasl.appup
new file mode 100644
index 0000000000..796a1e7368
--- /dev/null
+++ b/lib/sasl/test/systools_SUITE_data/lib/sasl/ebin/sasl.appup
@@ -0,0 +1,12 @@
+%%
+%% Fake release upgrade script for sasl
+%%
+
+{
+ "1.0",
+ [
+ ],
+
+ [
+ ]
+}.
diff --git a/lib/sasl/test/systools_rc_SUITE.erl b/lib/sasl/test/systools_rc_SUITE.erl
index bb93f38fa7..2ab9e269f9 100644
--- a/lib/sasl/test/systools_rc_SUITE.erl
+++ b/lib/sasl/test/systools_rc_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2010. All Rights Reserved.
+%% Copyright Ericsson AB 2010-2011. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -21,14 +21,15 @@
-include_lib("test_server/include/test_server.hrl").
-include_lib("sasl/src/systools.hrl").
-export([all/0,groups/0,init_per_group/2,end_per_group/2,
- syntax_check/1, translate/1, translate_app/1]).
+ syntax_check/1, translate/1, translate_app/1,
+ translate_emulator_restarts/1]).
%%-----------------------------------------------------------------
%% erl -compile systools_rc_SUITE @i ../src/ @i ../../test_server/include/
%% c(systools_rc_SUITE, [{i, "../src"}, {i, "../../test_server/include"}]).
%%-----------------------------------------------------------------
all() ->
- [syntax_check, translate, translate_app].
+ [syntax_check, translate, translate_app, translate_emulator_restarts].
groups() ->
[].
@@ -87,7 +88,8 @@ syntax_check(Config) when is_list(Config) ->
{sync_nodes, id1, {m, f, [a]}},
{sync_nodes, id2, [cp1, cp2]},
{apply, {m,f,[a]}},
- restart_new_emulator
+ restart_new_emulator,
+ restart_emulator
],
?line {ok, _} = systools_rc:translate_scripts([S2], Apps, []),
S3 = [{apply, {m, f, a}}],
@@ -486,3 +488,85 @@ io:format("X2=~p~n", [X2]),
{purge,[pelle,kalle]},
{apply,{application,unload,[pelle]}}] = X3,
?line ok.
+
+
+translate_emulator_restarts(_Config) ->
+ Apps =
+ [#application{name = test,
+ description = "TEST",
+ vsn = "1.0",
+ modules = [{foo,1},{bar,1},{baz,1}],
+ regs = [],
+ mod = {sasl, []}},
+ #application{name = test,
+ description = "TEST2",
+ vsn = "1.0",
+ modules = [{x,1},{y,1},{z,1}],
+ regs = [],
+ mod = {sasl, []}}],
+ %% restart_new_emulator
+ Up1 = [{update, foo, soft, soft_purge, soft_purge, []},restart_new_emulator],
+ ?line {ok, X1} = systools_rc:translate_scripts([Up1], Apps, []),
+ ?line [restart_new_emulator,
+ {load_object_code, {test,"1.0",[foo]}},
+ point_of_no_return,
+ {suspend,[foo]},
+ {load,{foo,soft_purge,soft_purge}},
+ {resume,[foo]}] = X1,
+
+ %% restart_emulator
+ Up2 = [{update, foo, soft, soft_purge, soft_purge, []},restart_emulator],
+ ?line {ok, X2} = systools_rc:translate_scripts([Up2], Apps, []),
+ ?line [{load_object_code, {test,"1.0",[foo]}},
+ point_of_no_return,
+ {suspend,[foo]},
+ {load,{foo,soft_purge,soft_purge}},
+ {resume,[foo]},
+ restart_emulator] = X2,
+
+ %% restart_emulator + restart_new_emulator
+ Up3 = [{update, foo, soft, soft_purge, soft_purge, []},
+ restart_emulator,
+ restart_new_emulator],
+ ?line {ok, X3} = systools_rc:translate_scripts([Up3], Apps, []),
+ ?line [restart_new_emulator,
+ {load_object_code, {test,"1.0",[foo]}},
+ point_of_no_return,
+ {suspend,[foo]},
+ {load,{foo,soft_purge,soft_purge}},
+ {resume,[foo]},
+ restart_emulator] = X3,
+
+ %% restart_emulator + restart_new_emulator
+ Up4a = [{update, foo, soft, soft_purge, soft_purge, []},
+ restart_emulator,
+ restart_new_emulator],
+ Up4b = [restart_new_emulator,
+ {update, x, soft, soft_purge, soft_purge, []},
+ restart_emulator,
+ restart_emulator],
+ ?line {ok, X4} = systools_rc:translate_scripts([Up4a,Up4b], Apps, []),
+ ?line [restart_new_emulator,
+ {load_object_code, {test,"1.0",[foo,x]}},
+ point_of_no_return,
+ {suspend,[foo]},
+ {load,{foo,soft_purge,soft_purge}},
+ {resume,[foo]},
+ {suspend,[x]},
+ {load,{x,soft_purge,soft_purge}},
+ {resume,[x]},
+ restart_emulator] = X4,
+
+ %% only restart_new_emulator
+ Up5 = [restart_new_emulator],
+ ?line {ok, X5} = systools_rc:translate_scripts([Up5], Apps, []),
+ ?line [restart_new_emulator,
+ point_of_no_return] = X5,
+
+ %% only restart_emulator
+ Up6 = [restart_emulator],
+ ?line {ok, X6} = systools_rc:translate_scripts([Up6], Apps, []),
+ ?line [point_of_no_return,
+ restart_emulator] = X6,
+
+ ok.
diff --git a/lib/sasl/test/test_lib.hrl b/lib/sasl/test/test_lib.hrl
new file mode 100644
index 0000000000..eeef721647
--- /dev/null
+++ b/lib/sasl/test/test_lib.hrl
@@ -0,0 +1,3 @@
+-define(ertsvsn,"4.4").
+-define(kernelvsn,"2.14.3").
+-define(stdlibvsn,"1.17.3").
diff --git a/lib/sasl/vsn.mk b/lib/sasl/vsn.mk
index 2db134af48..23694f1399 100644
--- a/lib/sasl/vsn.mk
+++ b/lib/sasl/vsn.mk
@@ -1 +1 @@
-SASL_VSN = 2.1.10
+SASL_VSN = 2.2
diff --git a/lib/snmp/doc/src/Makefile b/lib/snmp/doc/src/Makefile
index aa9431477c..df597c8ba7 100644
--- a/lib/snmp/doc/src/Makefile
+++ b/lib/snmp/doc/src/Makefile
@@ -28,14 +28,6 @@ VSN = $(SNMP_VSN)
APPLICATION=snmp
# ----------------------------------------------------
-# Include dependency
-# ----------------------------------------------------
-
-ifndef DOCSUPPORT
-include make.dep
-endif
-
-# ----------------------------------------------------
# Release directory specification
# ----------------------------------------------------
RELSYSDIR = $(RELEASE_PATH)/lib/$(APPLICATION)-$(VSN)
@@ -88,40 +80,10 @@ MAN3_FILES = $(XML_REF3_FILES:%.xml=$(MAN3DIR)/%.3)
MAN6_FILES = $(XML_REF6_FILES:%_app.xml=$(MAN6DIR)/%.6)
MAN7_FILES = $(MIB_FILES:$(MIBSDIR)/%.mib=$(MAN7DIR)/%.7)
-ifdef DOCSUPPORT
-
HTML_REF_MAN_FILE = $(HTMLDIR)/index.html
TOP_PDF_FILE = $(PDFDIR)/$(APPLICATION)-$(VSN).pdf
-else
-
-TEX_FILES_BOOK = \
- $(BOOK_FILES:%.xml=%.tex)
-TEX_FILES_REF_MAN = \
- $(XML_REF1_FILES:%.xml=%.tex) \
- $(XML_REF3_FILES:%.xml=%.tex) \
- $(XML_REF6_FILES:%.xml=%.tex) \
- $(XML_APPLICATION_FILES:%.xml=%.tex)
-TEX_PART_FILES = $(XML_PART_FILES:%.xml=%.tex)
-TEX_FILES_USERS_GUIDE = \
- $(XML_CHAPTER_FILES:%.xml=%.tex)
-
-TOP_PDF_FILE = snmp-$(VSN).pdf
-TOP_PS_FILE = snmp-$(VSN).ps
-
-$(TOP_PDF_FILE): book.dvi ../../vsn.mk
- @echo "building $(TOP_PDF_FILE)"
- $(DVI2PS) $(DVIPS_FLAGS) -f $< | $(DISTILL) $(DISTILL_FLAGS) > $@
-
-$(TOP_PS_FILE): book.dvi ../../vsn.mk
- @echo "building $(TOP_PS_FILE)"
- $(DVI2PS) $(DVIPS_FLAGS) -f $< > $@
-
-TOP_HTML_FILES = $(INDEX_TARGET)
-
-endif
-
INDEX_FILE = index.html
INDEX_SRC = $(INDEX_FILE).src
INDEX_TARGET = $(DOCDIR)/$(INDEX_FILE)
@@ -141,8 +103,6 @@ DVIPS_FLAGS +=
$(HTMLDIR)/%.gif: %.gif # Copy them to ../html
$(INSTALL_DATA) $< $@
-ifdef DOCSUPPORT
-
docs: pdf html man
ldocs: local_docs $(INDEX_TARGET)
@@ -157,47 +117,6 @@ html2: html $(INDEX_TARGET)
clean clean_docs: clean_html clean_man clean_pdf
rm -f errs core *~
-else
-
-ifeq ($(DOCTYPE),pdf)
-docs: pdf
-else
-ifeq ($(DOCTYPE),ps)
-docs: ps
-else
-docs: html gifs man
-endif
-endif
-
-pdf: $(TOP_PDF_FILE)
-
-ps: $(TOP_PS_FILE)
-
-html: $(HTML_FILES) $(TOP_HTML_FILES) gifs
-
-html2: gifs $(TOP_HTML_FILES) $(HTML_FILES) $(HTML_REF1_FILES) $(HTML_REF3_FILES) $(HTML_REF6_FILES) $(HTML_CHAP_FILES)
-
-clean: clean_tex clean_html clean_man clean_docs
-
-
-clean_tex:
- @echo "cleaning tex:"
- rm -f $(TEX_FILES_USERS_GUIDE)
- rm -f $(TEX_FILES_REF_MAN)
- rm -f $(TEX_PART_FILES)
- rm -f $(TEX_FILES_BOOK)
-
-clean_docs:
- @echo "cleaning docs:"
- rm -f $(TOP_PDF_FILE)
- rm -f $(TOP_PS_FILE)
- rm -f core $(LATEX_CLEAN)
-
-
-$(HTML_PART_FILES): notes.xml
-
-endif
-
$(INDEX_TARGET): $(INDEX_SRC) ../../vsn.mk # Create top make file
sed -e 's;%VSN%;$(VSN);' $< > $@ # inserting version number
@@ -250,8 +169,6 @@ $(MAN1DIR)/snmpc.1: snmpc_cmd.xml
include $(ERL_TOP)/make/otp_release_targets.mk
-ifdef DOCSUPPORT
-
release_docs_spec: docs
$(INSTALL_DIR) $(RELSYSDIR)/doc/pdf
$(INSTALL_DATA) $(TOP_PDF_FILE) $(RELSYSDIR)/doc/pdf
@@ -268,55 +185,13 @@ release_docs_spec: docs
$(INSTALL_DIR) $(RELEASE_PATH)/man/man7
$(INSTALL_DATA) $(MAN7DIR)/* $(RELEASE_PATH)/man/man7
-else
-
-
-ifeq ($(DOCTYPE),pdf)
-release_docs_spec: pdf
- $(INSTALL_DIR) $(RELEASE_PATH)/pdf
- $(INSTALL_DATA) $(TOP_PDF_FILE) $(RELEASE_PATH)/pdf
-else
-ifeq ($(DOCTYPE),ps)
-release_docs_spec: ps
- $(INSTALL_DIR) $(RELEASE_PATH)/ps
- $(INSTALL_DATA) $(TOP_PS_FILE) $(RELEASE_PATH)/ps
-else
-release_docs_spec: docs
- $(INSTALL_DIR) $(RELSYSDIR)/doc/html
- $(INSTALL_DATA) $(GIF_FILES) $(EXTRA_FILES) $(HTML_FILES) \
- $(RELSYSDIR)/doc/html
- $(INSTALL_DATA) $(INFO_FILE) $(RELSYSDIR)
- $(INSTALL_DIR) $(RELEASE_PATH)/man/man1
- $(INSTALL_DATA) $(MAN1_FILES) $(RELEASE_PATH)/man/man1
- $(INSTALL_DIR) $(RELEASE_PATH)/man/man3
- $(INSTALL_DATA) $(MAN3_FILES) $(RELEASE_PATH)/man/man3
- $(INSTALL_DIR) $(RELEASE_PATH)/man/man6
- $(INSTALL_DATA) $(MAN6_FILES) $(RELEASE_PATH)/man/man6
- $(INSTALL_DIR) $(RELEASE_PATH)/man/man7
- $(INSTALL_DATA) $(MAN7_FILES) $(RELEASE_PATH)/man/man7
- $(INSTALL_DATA) $(TOP_HTML_FILES) \
- $(RELSYSDIR)/doc
-endif
-endif
-
-endif
-
release_spec:
-ifdef DOCSUPPORT
info: info_xml info_man info_html
@echo "MAN1DIR: $(MAN1DIR)"
@echo "MAN3DIR: $(MAN3DIR)"
@echo "MAN6DIR: $(MAN6DIR)"
@echo "MAN7DIR: $(MAN7DIR)"
-else
-info: info_xml info_man info_html info_tex
- @echo "DVI2PS = $(DVI2PS)"
- @echo "DVIPS_FLAGS = $(DVIPS_FLAGS)"
- @echo ""
- @echo "DISTILL = $(DISTILL)"
- @echo "DISTILL_FLAGS = $(DISTILL_FLAGS)"
-endif
info_man:
@echo "man files:"
@@ -362,14 +237,3 @@ info_html:
@echo "HTML_REF3_FILES = $(HTML_REF3_FILES)"
@echo "HTML_REF6_FILES = $(HTML_REF6_FILES)"
@echo "HTML_CHAP_FILES = $(HTML_CHAP_FILES)"
-
-info_tex:
- @echo "tex files:"
- @echo "TEX_FILES_USERS_GUIDE = $(TEX_FILES_USERS_GUIDE)"
- @echo "TEX_FILES_REF_MAN = $(TEX_FILES_REF_MAN)"
- @echo "TEX_PART_FILES = $(TEX_PART_FILES)"
- @echo "TEX_FILES_BOOK = $(TEX_FILES_BOOK)"
-
-ifndef DOCSUPPORT
-include depend.mk
-endif
diff --git a/lib/snmp/doc/src/depend.mk b/lib/snmp/doc/src/depend.mk
deleted file mode 100644
index 20a523dd8c..0000000000
--- a/lib/snmp/doc/src/depend.mk
+++ /dev/null
@@ -1,83 +0,0 @@
-#-*-makefile-*- ; force emacs to enter makefile-mode
-
-# %CopyrightBegin%
-#
-# Copyright Ericsson AB 2004-2011. All Rights Reserved.
-#
-# The contents of this file are subject to the Erlang Public License,
-# Version 1.1, (the "License"); you may not use this file except in
-# compliance with the License. You should have received a copy of the
-# Erlang Public License along with this software. If not, it can be
-# retrieved online at http://www.erlang.org/.
-#
-# Software distributed under the License is distributed on an "AS IS"
-# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
-# the License for the specific language governing rights and limitations
-# under the License.
-#
-# %CopyrightEnd%
-
-$(HTMLDIR)/part_notes.html: \
- part_notes_history.xml \
- part_notes.xml \
- notes_history.xml \
- notes.xml
-
-$(HTMLDIR)/part.html: \
- part.xml \
- snmp_intro.xml \
- snmp_agent_funct_descr.xml \
- snmp_manager_funct_descr.xml \
- snmp_mib_compiler.xml \
- snmp_config.xml \
- snmp_agent_config_files.xml \
- snmp_manager_config_files.xml \
- snmp_impl_example_agent.xml \
- snmp_impl_example_manager.xml \
- snmp_instr_functions.xml \
- snmp_def_instr_functions.xml \
- snmp_agent_netif.xml \
- snmp_manager_netif.xml \
- snmp_audit_trail_log.xml \
- snmp_advanced_agent.xml \
- snmp_app_a.xml \
- snmp_app_b.xml
-
-$(HTMLDIR)/ref_man.html: \
- ref_man.xml \
- snmp_app.xml \
- snmp.xml \
- snmpc.xml \
- snmpc_cmd.xml \
- snmpa.xml \
- snmpa_conf.xml \
- snmpa_discovery_handler.xml \
- snmpa_error_report.xml \
- snmpa_error.xml \
- snmpa_error_io.xml \
- snmpa_error_logger.xml \
- snmpa_local_db.xml \
- snmpa_mpd.xml \
- snmpa_network_interface.xml \
- snmpa_network_interface_filter.xml \
- snmpa_notification_delivery_info_receiver.xml \
- snmpa_notification_filter.xml \
- snmpa_supervisor.xml \
- snmp_community_mib.xml \
- snmp_framework_mib.xml \
- snmp_generic.xml \
- snmp_index.xml \
- snmp_notification_mib.xml \
- snmp_pdus.xml \
- snmp_standard_mib.xml \
- snmp_target_mib.xml \
- snmp_user_based_sm_mib.xml \
- snmp_view_based_acm_mib.xml \
- snmpm.xml \
- snmpm_conf.xml \
- snmpm_mpd.xml \
- snmpm_network_interface.xml \
- snmpm_network_interface_filter.xml \
- snmpm_user.xml
-
-
diff --git a/lib/snmp/doc/src/make.dep b/lib/snmp/doc/src/make.dep
deleted file mode 100644
index 223e197f25..0000000000
--- a/lib/snmp/doc/src/make.dep
+++ /dev/null
@@ -1,77 +0,0 @@
-#-*-makefile-*- ; force emacs to enter makefile-mode
-
-# %CopyrightBegin%
-#
-# Copyright Ericsson AB 1999-2011. All Rights Reserved.
-#
-# The contents of this file are subject to the Erlang Public License,
-# Version 1.1, (the "License"); you may not use this file except in
-# compliance with the License. You should have received a copy of the
-# Erlang Public License along with this software. If not, it can be
-# retrieved online at http://www.erlang.org/.
-#
-# Software distributed under the License is distributed on an "AS IS"
-# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
-# the License for the specific language governing rights and limitations
-# under the License.
-#
-# %CopyrightEnd%
-
-# ----------------------------------------------------
-# >>>> Do not edit this file <<<<
-# This file was automaticly generated by
-# /home/otp/bin/docdepend
-# ----------------------------------------------------
-
-
-# ----------------------------------------------------
-# TeX files that the DVI file depend on
-# ----------------------------------------------------
-
-book.dvi: book.tex part.tex ref_man.tex snmp.tex snmp_advanced_agent.tex \
- snmp_agent_config_files.tex snmp_agent_funct_descr.tex \
- snmp_agent_netif.tex snmp_app.tex snmp_app_a.tex \
- snmp_app_b.tex snmp_audit_trail_log.tex \
- snmp_community_mib.tex \
- snmp_config.tex snmp_def_instr_functions.tex \
- snmp_framework_mib.tex snmp_generic.tex \
- snmp_impl_example_agent.tex \
- snmp_impl_example_manager.tex snmp_index.tex \
- snmp_instr_functions.tex snmp_intro.tex \
- snmp_manager_config_files.tex \
- snmp_manager_funct_descr.tex snmp_manager_netif.tex \
- snmp_mib_compiler.tex snmp_notification_mib.tex \
- snmp_pdus.tex snmp_standard_mib.tex snmp_target_mib.tex \
- snmp_user_based_sm_mib.tex snmp_view_based_acm_mib.tex \
- snmpa.tex snmpa_conf.tex snmpa_error.tex snmpa_error_io.tex \
- snmpa_error_logger.tex snmpa_error_report.tex \
- snmpa_local_db.tex snmpa_mpd.tex \
- snmpa_discovery_handler.tex \
- snmpa_network_interface.tex \
- snmpa_network_interface_filter.tex \
- snmpa_notification_delivery_info_receiver.tex \
- snmpa_notification_filter.tex \
- snmpa_supervisor.tex \
- snmpc.tex snmpc_cmd.tex snmpm.tex snmpm_conf.tex snmpm_mpd.tex \
- snmpm_network_interface.tex snmpm_network_interface_filter.tex \
- snmpm_user.tex
-
-# ----------------------------------------------------
-# Source inlined when transforming from source to LaTeX
-# ----------------------------------------------------
-
-book.tex: ref_man.xml
-
-# ----------------------------------------------------
-# Pictures that the DVI file depend on
-# ----------------------------------------------------
-
-book.dvi: MIB_mechanism.ps snmp-um-1-image-1.ps snmp-um-1-image-2.ps \
- snmp-um-1-image-3.ps
-
-book.dvi: snmp_agent_netif_1.ps
-
-book.dvi: getnext1.ps getnext2.ps getnext3.ps getnext4.ps
-
-book.dvi: snmp_manager_netif_1.ps
-
diff --git a/lib/snmp/doc/src/notes.xml b/lib/snmp/doc/src/notes.xml
index 9e1a060dee..fd5a548b16 100644
--- a/lib/snmp/doc/src/notes.xml
+++ b/lib/snmp/doc/src/notes.xml
@@ -32,6 +32,120 @@
<file>notes.xml</file>
</header>
+
+ <section>
+ <title>SNMP Development Toolkit 4.21.3</title>
+ <p>Version 4.21.3 supports code replacement in runtime from/to
+ version 4.21.2, 4.21.1, 4.21 and 4.20.1. </p>
+
+ <section>
+ <title>Improvements and new features</title>
+<!--
+ <p>-</p>
+-->
+
+ <list type="bulleted">
+ <item>
+ <p>[compiler] Improved version info printout. </p>
+ <p>Own Id: OTP-9618</p>
+ </item>
+
+ </list>
+ </section>
+
+ <section>
+ <title>Fixed Bugs and Malfunctions</title>
+<!--
+ <p>-</p>
+-->
+
+ <list type="bulleted">
+ <item>
+ <p>[compiler] Fix the <c>--warnings/--W</c> option parsing in the
+ <seealso marker="snmpc(command)#option_warnings">snmpc</seealso>
+ wrapper (e)script.
+ The short warning option was incorrectly <c>--w</c>, instead
+ of as documented <c>--W</c>. This has now been corrected. </p>
+ <p>*** POTENTIAL INCOMPATIBILITY ***</p>
+ <p>Tuncer Ayaz</p>
+ <p>Own Id: OTP-9718</p>
+ </item>
+
+ </list>
+
+ </section>
+
+
+ <section>
+ <title>Incompatibilities</title>
+<!--
+ <p>-</p>
+-->
+
+ <list type="bulleted">
+ <item>
+ <p>[compiler] The short warning option has been changed from
+ <c>--w</c> to <c>--W</c> to comply with the documentation. </p>
+ <p>Tuncer Ayaz</p>
+ <p>Own Id: OTP-9718</p>
+ </item>
+
+
+ </list>
+ </section>
+
+ </section> <!-- 4.21.3 -->
+
+
+ <section>
+ <title>SNMP Development Toolkit 4.21.2</title>
+ <p>Version 4.21.2 supports code replacement in runtime from/to
+ version 4.21.1, 4.21, 4.20.1, 4.20 and 4.19. </p>
+
+ <section>
+ <title>Improvements and new features</title>
+ <p>-</p>
+
+<!--
+ <list type="bulleted">
+ <item>
+ <p>Bad note store GC timer deactivation.
+ Wrong field in the state record was set (timeout instead active). </p>
+ <p>Stefan Grundmann</p>
+ <p>Own Id: OTP-9690</p>
+ </item>
+
+ </list>
+-->
+
+ </section>
+
+ <section>
+ <title>Fixed Bugs and Malfunctions</title>
+<!--
+ <p>-</p>
+-->
+
+ <list type="bulleted">
+ <item>
+ <p>Bad note store GC timer deactivation.
+ Wrong field in the state record was set (timeout instead active). </p>
+ <p>Stefan Grundmann</p>
+ <p>Own Id: OTP-9690</p>
+ </item>
+
+ </list>
+ </section>
+
+
+ <section>
+ <title>Incompatibilities</title>
+ <p>-</p>
+ </section>
+
+ </section> <!-- 4.21.2 -->
+
+
<section>
<title>SNMP Development Toolkit 4.21.1</title>
<p>Version 4.21.1 supports code replacement in runtime from/to
@@ -806,927 +920,6 @@ snmp_view_basec_acm_mib:vacmAccessTable(set, RowIndex, Cols).
</section> <!-- 4.15 -->
- <section>
- <title>SNMP Development Toolkit 4.14</title>
-
- <p>Version 4.14 supports code replacement in runtime from/to
- version 4.13.5, 4.13.4, 4.13.3, 4.13.2, 4.13.1 and 4.13.</p>
-
- <section>
- <title>Improvements and new features</title>
- <!--
- <p>-</p>
- -->
-
- <list type="bulleted">
- <item>
- <p>[compiler] Include object- and notification groups in the
- compiled mib.
- This will make it possible to import groups from other mibs. </p>
- <p>Also the SNMPv2-MIB-file has been updated to a more
- up-to-date version. </p>
- <p>Own Id: OTP-8223</p>
- <!-- <p>Aux Id: Seq 11383</p> -->
- </item>
-
- <item>
- <p>[manager] Added support for message filtering in the
- network interface module provided with the application.
- The component that actually make the filter decisions
- is the network interface filter module. This module
- must implement the
- <seealso marker="snmpm_network_interface_filter">network interface filter behaviour</seealso>
- for message filtering.
- See also the Configuring chapter of
- the User's Guide to see how to configure this feature. </p>
- <p>See the
- <seealso marker="snmp_app#configuration_params">configuration</seealso>
- chapter for more info about the filter options.</p>
- <p>Own Id: OTP-8228</p>
- <p>Aux Id: Seq 11411</p>
- </item>
-
- <item>
- <p>The MIBs delivered as part of the application is now
- also available as man pages, section 7. </p>
- <p>Own Id: OTP-8237</p>
- <!-- <p>Aux Id: Seq 11383</p> -->
- </item>
-
- </list>
-
- </section>
-
- <section>
- <title>Reported Fixed Bugs and Malfunctions</title>
- <p>-</p>
-
- <!--
- <list type="bulleted">
- <item>
- <p>[agent] The main agent type header file contained some miss-information
- regarding the type of the entrytype field of the me-record, causing
- unneccessary confusion.</p>
- <p>Own Id: OTP-8116</p>
- <p>Aux Id: Seq 11312</p>
- </item>
-
- </list>
- -->
-
- </section>
-
- <section>
- <title>Incompatibilities</title>
- <p>-</p>
- </section>
- </section> <!-- 4.14 -->
-
-
- <section>
- <title>SNMP Development Toolkit 4.13.5</title>
-
- <p>Version 4.13.5 supports code replacement in runtime from/to
- version 4.13.4, 4.13.3, 4.13.2, 4.13.1 and 4.13.</p>
-
- <section>
- <title>Improvements and new features</title>
- <!--
- <p>-</p>
- -->
-
- <list type="bulleted">
- <item>
- <p>[agent] Improved the cache handling of the mib server. </p>
- <p>A number of new functions and config options for the mib server
- cache has been added. </p>
- <p>See
- <seealso marker="snmpa#invalidate_mibs_cache">invalidate_mibs_cache/0,1</seealso>,
- <seealso marker="snmpa#enable_mibs_cache">enable_mibs_cache/0,1</seealso>,
- <seealso marker="snmpa#disable_mibs_cache">disable_mibs_cache/0,1</seealso>,
- <seealso marker="snmpa#gc_mibs_cache">gc_mibs_cache/0,1,2,3</seealso>,
- <seealso marker="snmpa#enable_mibs_cache_autogc">enable_mibs_cache_autogc/0,1</seealso>,
- <seealso marker="snmpa#disable_mibs_cache_autogc">disable_mibs_cache_autogc/0,1</seealso>,
- <seealso marker="snmpa#update_mibs_cache_age">update_mibs_cache_age/1,2</seealso> and
- <seealso marker="snmpa#update_mibs_cache_gclimit">update_mibs_cache_gclimit/1,2</seealso> for more info. </p>
- <p>See also the
- <seealso marker="snmp_app#configuration_params">configuration</seealso>
- chapter for more info about the mib server cache options.</p>
- <p>Own Id: OTP-8182</p>
- <p>Aux Id: Seq 11383</p>
- </item>
-
- <item>
- <p>[agent] A manager could no longer use the SNMPv3 user "initial"
- as this was interpretated as the first step of the discovery. </p>
- <p>Introduced a new terminating option, <c>trigger_username</c> to
- make it possible to configure the username the agent reacts to.
- Default is <c>""</c>. </p>
- <p>See the
- <seealso marker="snmp_app#configuration_params">configuration</seealso>
- chapter for more info about the discovery options.</p>
- <p>Own Id: OTP-8120</p>
- <p>Aux Id: Seq 11361</p>
- </item>
-
- </list>
-
- </section>
-
- <section>
- <title>Reported Fixed Bugs and Malfunctions</title>
- <!--
- <p>-</p>
- -->
- <list type="bulleted">
- <item>
- <p>[agent] The main agent type header file contained some miss-information
- regarding the type of the entrytype field of the me-record, causing
- unneccessary confusion.</p>
- <p>Own Id: OTP-8116</p>
- <p>Aux Id: Seq 11312</p>
- </item>
-
- </list>
-
- </section>
-
- <section>
- <title>Incompatibilities</title>
- <p>-</p>
- </section>
- </section> <!-- 4.13.5 -->
-
-
- <section>
- <title>SNMP Development Toolkit 4.13.4</title>
-
- <p>Version 4.13.4 supports code replacement in runtime from/to
- version 4.13.3, 4.13.2, 4.13.1 and 4.13.</p>
-
- <section>
- <title>Improvements and new features</title>
- <p>-</p>
-
- <!--
- <list type="bulleted">
- <item>
- <p>[agent] Support for the discovery process. </p>
- <p>The agent can both initiate discovery itself (see the
- <seealso marker="snmp_agent_funct_descr#discovery">discovery</seealso> chapter
- for more info) and respond to discovery initiated by a manager.</p>
- <p>Own Id: OTP-7571</p>
- <p>Aux Id: Seq 11053</p>
- </item>
-
- </list>
- -->
-
- </section>
-
- <section>
- <title>Reported Fixed Bugs and Malfunctions</title>
- <!--
- <p>-</p>
- -->
- <list type="bulleted">
- <item>
- <p>[agent] Originating discovery problems. </p>
- <p>Invalid state variable update during second stage of
- discovery causes master agent crash. </p>
- <p>Also the net_if process failed to activate socket
- ({active, once}) after first discovery response was sent. </p>
- <p>Own Id: OTP-8044</p>
- <p>Aux Id: Seq 11295</p>
- </item>
-
- <item>
- <p>[agent] Terminating discovery problem. </p>
- <p>The reply to the second stage request should include a
- varbind with <c>usmStatsNotInTimeWindows</c>.</p>
- <p>Own Id: OTP-8062</p>
- <p>Aux Id: Seq 11318</p>
- </item>
-
- <item>
- <p>[agent] Originating discovery improvement. </p>
- <p>Added the ExtraInfo argument to the
- <seealso marker="snmpa#discovery">discovery</seealso> function.
- This argument will be passed on to the stage1_finish callback
- function. Also, the
- <seealso marker="snmpa#discovery">discovery</seealso> function
- will now always return <c>{ok, ManagerEngineID}</c> on successful
- discovery. </p>
- <p>The <seealso marker="snmpa_discovery_handler">discovery handler</seealso>
- behaviour updated accordingly. </p>
- <p>Own Id: OTP-8098</p>
- <p>Aux Id: Seq 11346</p>
- </item>
-
- </list>
-
- </section>
-
- <section>
- <title>Incompatibilities</title>
- <p>-</p>
- </section>
- </section> <!-- 4.13.4 -->
-
-
- <section>
- <title>SNMP Development Toolkit 4.13.3</title>
-
- <p>Version 4.13.3 supports code replacement in runtime from/to
- version 4.13.2, 4.13.1 and 4.13.</p>
-
- <section>
- <title>Improvements and new features</title>
- <p>-</p>
-
- <!--
- <list type="bulleted">
- <item>
- <p>[agent] Support for the discovery process. </p>
- <p>The agent can both initiate discovery itself (see the
- <seealso marker="snmp_agent_funct_descr#discovery">discovery</seealso> chapter
- for more info) and respond to discovery initiated by a manager.</p>
- <p>Own Id: OTP-7571</p>
- <p>Aux Id: Seq 11053</p>
- </item>
-
- </list>
- -->
-
- </section>
-
- <section>
- <title>Reported Fixed Bugs and Malfunctions</title>
- <!--
- <p>-</p>
- -->
- <list type="bulleted">
- <item>
- <p>[manager] A request for an oid of type BITS was actually
- returned as OCTET STRING. </p>
- <p>Values of type BITS are encoded as OCTET STRING,
- which makes it impossible for the decoder to know that
- they should really be of type BITS.
- Instead, this has to be done higher up in the stack, where
- there is knowledge of the MIB (assuming that the mib has
- been loaded, there is info about the type of the mibentry). </p>
- <p>This problem has now been fixed, but requires that the MIB
- defining this mib-entry is loaded! </p>
- <p>The utility function
- <seealso marker="snmpm#oid_to_type">oid_to_type</seealso>
- has been added, for debug purpose. </p>
- <p>The utility function(s)
- <seealso marker="snmp#octet_string_to_bits">octet_string_to_bits</seealso>
- and
- <seealso marker="snmp#bits_to_octet_string">bits_to_octet_string</seealso>
- has also been added. These can be used if the user prefers to
- handle the conversion on their own. </p>
- <p>Own Id: OTP-8015</p>
- <p>Aux Id: Seq 11285</p>
- </item>
-
- <item>
- <p>[agent] Fixed some issues with the discovery handling. </p>
- <p>Changed the API of the
- <seealso marker="snmpa#discovery">discovery</seealso>
- function to solve some
- of these problems. </p>
- <p>Introduced various options for controlling the discovery
- process. See the
- <seealso marker="snmp_app#configuration_params">configuration</seealso>
- chapter for more info about the discovery options.</p>
- <p>Own Id: OTP-8020</p>
- <p>Aux Id: Seq 11295</p>
- </item>
-
- </list>
-
- </section>
-
- <section>
- <title>Incompatibilities</title>
- <p>-</p>
- </section>
- </section> <!-- 4.13.3 -->
-
-
- <section>
- <title>SNMP Development Toolkit 4.13.2</title>
-
- <p>Version 4.13.2 supports code replacement in runtime from/to
- version 4.13.1 and 4.13.</p>
-
- <section>
- <title>Improvements and new features</title>
- <p>-</p>
-
- <!--
- <list type="bulleted">
- <item>
- <p>[agent] Support for the discovery process. </p>
- <p>The agent can both initiate discovery itself (see the
- <seealso marker="snmp_agent_funct_descr#discovery">discovery</seealso> chapter
- for more info) and respond to discovery initiated by a manager.</p>
- <p>Own Id: OTP-7571</p>
- <p>Aux Id: Seq 11053</p>
- </item>
-
- </list>
- -->
-
- </section>
-
- <section>
- <title>Reported Fixed Bugs and Malfunctions</title>
- <!--
- <p>-</p>
- -->
- <list type="bulleted">
- <item>
- <p>[manager] Failure during downed user cleanup.
- As part of the cleanup after a crashed user,
- the manager attempts to unregister the agents
- registered by this user. This however failed,
- causing a server crash. </p>
- <p>Own Id: OTP-7961</p>
- <p>Aux Id: Seq 11275</p>
- </item>
-
- <item>
- <p>[manager] Incorrectly documented value type for
- IpAddress (ip). The value type for IpAddress is
- documented as ip but is actually ia. The value type
- ip has been added. The old (not documented) value
- type ia still works. </p>
- <p>Own Id: OTP-7977</p>
- <p>Aux Id: Seq 11279</p>
- </item>
-
- <item>
- <p>[manager] EngineId lookup fails when using version-3. </p>
- <p>Own Id: OTP-7983</p>
- <p>Aux Id: Seq 11275</p>
- </item>
-
- <item>
- <p>[agent] As of version 4.13 the possible return values
- of the function
- <seealso marker="snmpa_mpd#process_packet">snmpa_mpd:process_packet/4</seealso>
- changed, but this was not documented. </p>
- <p>Own Id: OTP-7989</p>
- <p>Aux Id: Seq 11275</p>
- </item>
-
- </list>
-
- </section>
-
- <section>
- <title>Incompatibilities</title>
- <p>-</p>
- </section>
- </section> <!-- 4.13.2 -->
-
- <section>
- <title>SNMP Development Toolkit 4.13.1</title>
-
- <p>Version 4.13.1 supports code replacement in runtime from/to
- version 4.13.</p>
-
- <section>
- <title>Improvements and new features</title>
- <p>-</p>
-
- <!--
- <list type="bulleted">
- <item>
- <p>[agent] Support for the discovery process. </p>
- <p>The agent can both initiate discovery itself (see the
- <seealso marker="snmp_agent_funct_descr#discovery">discovery</seealso> chapter
- for more info) and respond to discovery initiated by a manager.</p>
- <p>Own Id: OTP-7571</p>
- <p>Aux Id: Seq 11053</p>
- </item>
-
- </list>
- -->
-
- </section>
-
- <section>
- <title>Reported Fixed Bugs and Malfunctions</title>
- <!--
- <p>-</p>
- -->
- <list type="bulleted">
- <item>
- <p>[manager] Registration of users had some issues. </p>
- <p>Not all of the registration functions where actually exported
- (<seealso marker="snmpm#register_user">register_user/4</seealso>
- and
- <seealso marker="snmpm#register_user_monitor">register_user_monitor/4</seealso>).
- This has now been fixed. </p>
- <p>Also, the registration did not succeed unless
- user implemented the *new* behaviour. This has now
- also been fixed (registration succeeds if the user
- implements either the new (i.e. updated
- <seealso marker="snmpm_user">snmpm_user</seealso>)
- or the old user behaviour (<c>snmpm_user_old</c>)). </p>
- <p>Own Id: OTP-7902</p>
- <p>Aux Id: Seq 11240</p>
- </item>
-
- </list>
-
- </section>
-
- <section>
- <title>Incompatibilities</title>
- <p>-</p>
- </section>
- </section> <!-- 4.13.1 -->
-
- <section>
- <title>SNMP Development Toolkit 4.13</title>
-<!--
- <p>Version 4.13 supports code replacement in runtime from/to
- version 4.12.1.</p>
--->
-
- <section>
- <title>Improvements and new features</title>
- <!--
- <p>-</p>
- -->
- <list type="bulleted">
- <item>
- <p>[agent] Support for the discovery process. </p>
- <p>The agent can both initiate discovery itself (see the
- <seealso marker="snmp_agent_funct_descr#discovery">discovery</seealso> chapter
- for more info) and respond to discovery initiated by a manager.</p>
- <p>Own Id: OTP-7571</p>
- <p>Aux Id: Seq 11053</p>
- </item>
-
- </list>
-
- </section>
-
- <section>
- <title>Reported Fixed Bugs and Malfunctions</title>
- <!--
- <p>-</p>
- -->
- <list type="bulleted">
- <item>
- <p>[agent] Unnecessary use of math:pow/2 could cause problems
- on systems without floating point support. </p>
- <p>Per Hedeland</p>
- <p>Own Id: OTP-7735</p>
- <!-- <p>Aux Id: Seq 10966</p> -->
- </item>
-
- <item>
- <p>[manager] A major flaw was discovered with the agent handling. </p>
- <p>First, <c>TargetName</c> was never used as intended, as a unique
- identifier for the target (agent in this case). </p>
- <p>Second, <c>TargetName</c> had a <em>default value</em>, which meant
- that several agents could have the same <c>TargetName</c>, causing
- unpredictable behaviour in the manager. </p>
- <p>Third, <c>EngineID</c> was not a mandatory config option and had
- furthermore also a <em>default value</em>. </p>
-
- <p>These problems has been solved in the following way: </p>
- <p>First, a new set of api functions has been introduced (and documented):
- <seealso marker="snmpm#register_user">register_user/4</seealso>,
- <seealso marker="snmpm#register_user_monitor">register_user_monitor/4</seealso>,
- <seealso marker="snmpm#register_agent">register_agent/3</seealso>,
- <seealso marker="snmpm#unregister_agent">unregister_agent/2</seealso>,
- <seealso marker="snmpm#agent_info">agent_info/2</seealso>,
- <seealso marker="snmpm#update_agent_info">update_agent_info/4</seealso>,
- <seealso marker="snmpm#sync_get">sync_get/3,4,5,6</seealso>,
- <seealso marker="snmpm#async_get">async_get/3,4,5,6</seealso>,
- <seealso marker="snmpm#sync_get_next">sync_get_next/3,4,5,6</seealso>,
- <seealso marker="snmpm#async_get_next">async_get_next/3,4,5,6</seealso>,
- <seealso marker="snmpm#sync_set">sync_set/3,4,5,6</seealso>,
- <seealso marker="snmpm#async_set">async_set/3,4,5,6</seealso>,
- <seealso marker="snmpm#sync_get_bulk">sync_get_bulk/5,6,7,8</seealso> and
- <seealso marker="snmpm#async_get_bulk">async_get_bulk/5,6,7,8</seealso>
- that all use <c>TargetName</c> (and not, as previously, <c>Addr</c>
- and <c>Port</c>) to identify the agent (also the return value of
- <seealso marker="snmpm#which_agents">which_agents</seealso> has
- been changed). </p>
- <p>Second, for backward compatibility, the old functions still
- exist, but are no longer documented and are now wrappers for the
- new functions, including erroneous default value for EngineID and
- all. The TargetName is however generated from the provided
- <c>Addr</c>, <c>Port</c> and <c>Version</c> config options. </p>
- <p>Third, the behaviour of the
- <seealso marker="snmpm_user">SNMP manager user</seealso> has
- been changed to reflect this, i.e.
- <seealso marker="snmpm_user#handle_pdu">handle_pdu/4</seealso>,
- <seealso marker="snmpm_user#handle_trap">handle_trap/3</seealso>,
- <seealso marker="snmpm_user#handle_inform">handle_inform/3</seealso>,
- <seealso marker="snmpm_user#handle_report">handle_report/3</seealso>
- and the return-value of
- <seealso marker="snmpm_user#handle_agent">handle_agent/4</seealso>.
- The old (non-documented) callback-functions (using Addr and Port)
- will still be called if the agent was registered using the old
- registration functions. </p>
-
- <p>Own Id: OTP-7836</p>
- <!-- <p>Aux Id: Seq 10966</p> -->
- </item>
-
- </list>
-
- </section>
-
- <section>
- <title>Incompatibilities</title>
- <p>-</p>
- </section>
- </section> <!-- 4.13 -->
-
- <section>
- <title>SNMP Development Toolkit 4.12.2</title>
- <p>Version 4.12.2 supports code replacement in runtime from/to
- version 4.12.1, 4.12, 4.11.2, 4.11.1 and 4.11.</p>
-
- <section>
- <title>Improvements and new features</title>
- <p>-</p>
- <!--
- <list type="bulleted">
- <item>
- <item>
- <p>[agent] Improvement of the inform reporting.
- It was previously not certain how many acks an
- application received, 0, 1 or 2. This has now been
- fixed, so that only 1 (one) ack is issued. </p>
- <p>Per Hedeland</p>
- <p>Own Id: OTP-7525</p>
- </item>
-
- </list>
- -->
-
- </section>
-
- <section>
- <title>Reported Fixed Bugs and Malfunctions</title>
- <!--
- <p>-</p>
- -->
- <list type="bulleted">
- <item>
- <p>[agent] Bad session cache (usm+camv-info) invalidation
- could cause user crash, through call(s) to (a number of)
- MIB API function(s) (undefined function). </p>
- <p>Own Id: OTP-7868</p>
- <!-- <p>Aux Id: Seq 11124</p> -->
- </item>
-
- </list>
-
- </section>
-
- <section>
- <title>Incompatibilities</title>
- <p>-</p>
- </section>
- </section> <!-- 4.12.2 -->
-
- <section>
- <title>SNMP Development Toolkit 4.12.1</title>
- <p>Version 4.12.1 supports code replacement in runtime from/to
- version 4.12, 4.11.2, 4.11.1 and 4.11.</p>
-
- <section>
- <title>Improvements and new features</title>
- <p>-</p>
- <!--
- <list type="bulleted">
- <item>
- <item>
- <p>[agent] Improvement of the inform reporting.
- It was previously not certain how many acks an
- application received, 0, 1 or 2. This has now been
- fixed, so that only 1 (one) ack is issued. </p>
- <p>Per Hedeland</p>
- <p>Own Id: OTP-7525</p>
- </item>
-
- </list>
- -->
-
- </section>
-
- <section>
- <title>Reported Fixed Bugs and Malfunctions</title>
- <!--
- <p>-</p>
- -->
- <list type="bulleted">
- <item>
- <p>Logging of messages with the GetBulk-request PDU
- incorrectly produced an erroneous entry in the
- log: "An error occurred". </p>
- <p>The reason for this was that the PDU-fields
- error_status and error_index is re-used for
- Non-repeaters and Max-repetitions for
- GetBulk-request PDUs, but this was not handled
- by the logging code. </p>
- <p>Own Id: OTP-7695</p>
- <p>Aux Id: Seq 11124</p>
- </item>
-
- <item>
- <p>[agent] An attempt to set the row status to active for an
- notReady table row, could result in an "inconsistentValue"
- error. </p>
- <p>The same problem existed when attempting to set row status
- to notInService for a row in notReady. </p>
- <p>Serge Aleynikov</p>
- <p>Own Id: OTP-7698</p>
- <!-- <p>Aux Id: Seq 10966</p> -->
- </item>
-
- </list>
-
- </section>
-
- <section>
- <title>Incompatibilities</title>
- <p>-</p>
- </section>
- </section> <!-- 4.12.1 -->
-
- <section>
- <title>SNMP Development Toolkit 4.12</title>
- <p>Version 4.12 supports code replacement in runtime from/to
- version 4.11.2, 4.11.1 and 4.11.</p>
-
- <section>
- <title>Improvements and new features</title>
- <!--
- <p>-</p>
- -->
- <list type="bulleted">
- <item>
- <p>[agent] A simple lookup cache has been added to improve
- the mib server lookup performance. </p>
- <p>This can be disabled with the mib_server
- <seealso marker="snmp_app">cache</seealso> option. </p>
- <p>Own Id: OTP-7346</p>
- </item>
-
- <item>
- <p>[agent] Improvement of the inform reporting.
- It was previously not certain how many acks an
- application received, 0, 1 or 2. This has now been
- fixed, so that only 1 (one) ack is issued. </p>
- <p>Per Hedeland</p>
- <p>Own Id: OTP-7525</p>
- </item>
-
- </list>
-
- </section>
-
- <section>
- <title>Reported Fixed Bugs and Malfunctions</title>
- <p>-</p>
- <!--
- <list type="bulleted">
- <item>
- <p>[manager] Encryption error when attempting to send
- version 3 inform-requests. </p>
- <p>Own Id: OTP-7432</p>
- <p>Aux Id: Seq 10966</p>
- </item>
-
- </list>
- -->
-
- </section>
-
- <section>
- <title>Incompatibilities</title>
- <p>-</p>
- </section>
- </section> <!-- 4.12 -->
-
- <section>
- <title>SNMP Development Toolkit 4.11.2</title>
- <p>Version 4.11.2 supports code replacement in runtime from/to
- version 4.11.1 and 4.11. </p>
-
- <section>
- <title>Improvements and new features</title>
- <p>-</p>
- <!--
- <list type="bulleted">
- <item>
- <p>Added utility functions for transforming DateAndTime
- as [int()] to strings;
- <seealso marker="snmp#dat2s">date_and_time_to_string/2</seealso>
- and
- <seealso marker="snmp#dat2s2">date_and_time_to_string2/1</seealso>. </p>
- <p>Also added new validation function
- <seealso marker="snmp#vdat">validate_date_and_time/2</seealso>. </p>
- <p>Own Id: OTP-7412</p>
- <p>Aux Id: Seq 10987</p>
- </item>
- </list>
- -->
- </section>
-
- <section>
- <title>Reported Fixed Bugs and Malfunctions</title>
- <!--
- <p>-</p>
- -->
- <list type="bulleted">
- <item>
- <p>[manager] Erroneous engine-id check when receiving version 3
- informs. </p>
- <p>Own Id: OTP-7570</p>
- <p>Aux Id: Seq 11060</p>
- </item>
-
- <item>
- <p>Receiving an snmp message with a very large version
- number could cause the erlang node to run out of
- memory and consequently crash. </p>
- <p>The standard specifies the snmp version as an
- (unlimited) INTEGER, but today only
- 0 (version 1), 1 (version 2) and 3 (version 3) is
- actually used. So, when decoding a message, a limit
- has been put on the snmp version integer in order
- to not allow this kind of a problem. </p>
- <p>Own Id: OTP-7575</p>
- <p>Aux Id: Seq 11064</p>
- </item>
-
- </list>
- </section>
-
- <section>
- <title>Incompatibilities</title>
- <p>-</p>
- </section>
- </section> <!-- 4.11.2 -->
-
-
- <section>
- <title>SNMP Development Toolkit 4.11.1</title>
- <p>Version 4.11.1 supports code replacement in runtime from/to
- version 4.11.</p>
-
- <section>
- <title>Improvements and new features</title>
- <!--
- <p>-</p>
- -->
- <list type="bulleted">
- <item>
- <p>[compiler] The MIB compiler did not retrieve the REFERENCE part
- of a SNMP MIB definition. </p>
- <p>This problem has been partly solved. For SNMP tables,
- the assocList field of the tables mib-entry record now contains
- this info (as <c>{reference, string()}</c>), <em>if</em> the
- MIB was compiled with the compiler option <em>+reference</em>. </p>
- <p>This solution is temporary, until such time as a permanent
- solution (and probably not backward compatible) is devised, which
- retrieves and stores all REFERENCE part(s) of a MIB. </p>
- <p>See the
- <seealso marker="snmpc#compiler_opts">compiler options</seealso>
- for more info. </p>
-
- <p>Serge Aleynikov</p>
- <p>Own Id: OTP-7426</p>
- </item>
-
- <item>
- <p>Added utility functions for transforming DateAndTime
- as [int()] to strings;
- <seealso marker="snmp#dat2s">date_and_time_to_string/2</seealso>
- and
- <seealso marker="snmp#dat2s2">date_and_time_to_string2/1</seealso>. </p>
- <p>Also added new validation function
- <seealso marker="snmp#vdat">validate_date_and_time/2</seealso>. </p>
- <p>Own Id: OTP-7412</p>
- <p>Aux Id: Seq 10987</p>
- </item>
-
- </list>
-
- </section>
-
- <section>
- <title>Reported Fixed Bugs and Malfunctions</title>
- <!--
- <p>-</p>
- -->
- <list type="bulleted">
- <item>
- <p>[manager] Encryption error when attempting to send
- version 3 inform-requests. </p>
- <p>Own Id: OTP-7432</p>
- <p>Aux Id: Seq 10966</p>
- </item>
-
- </list>
- </section>
-
- <section>
- <title>Incompatibilities</title>
- <p>-</p>
- </section>
- </section> <!-- 4.11.1 -->
-
- <section>
- <title>SNMP Development Toolkit 4.11</title>
- <p>Version 4.11 supports code replacement in runtime from/to
- version 4.10.3, 4.10.2, 4.10.1 and 4.10.</p>
-
- <section>
- <title>Improvements and new features</title>
- <!--
- <p>-</p>
- -->
- <list type="bulleted">
- <item>
- <p>[agent] Performance improvements in the case when an SNMP
- manager performs an snmpwalk. </p>
- <p>Martin Bj&ouml;rklund</p>
- <p>Own Id: OTP-7201</p>
- </item>
-
- <item>
- <p>The API for sending inform(s) has been improved. Also
- the documentation has been corrected and updated. See
- <seealso marker="snmpa#send_notification">snmpa:send_notification</seealso> and
- <seealso marker="snmpa_notification_delivery_info_receiver">snmpa_notification_delivery_info_receiver</seealso>
- for more info.</p>
- <p>Own Id: OTP-7287</p>
- <p>Aux Id: Seq 10926</p>
- </item>
-
- <item>
- <p>[agent] Performance of the internal database (local-db)
- has been improved.</p>
- <p>Own Id: OTP-7319</p>
- <p>Aux Id: Seq 10942</p>
- </item>
-
- <item>
- <p>[agent] Added utility functions,
- <seealso marker="snmpa#restart_worker">snmpa:restart_worker/0,1</seealso> and
- <seealso marker="snmpa#restart_set_worker">snmpa:restart_set_worker/0,1</seealso>,
- for restarting the agent worker processes (in case the agent is
- multi-threaded).</p>
- <p>Own Id: OTP-7369</p>
- </item>
-
- <item>
- <p>Add utility function to
- <seealso marker="snmp#read_mib">read</seealso>
- a compiled mib. </p>
- <p>Own Id: OTP-7371</p>
- </item>
-
- </list>
- </section>
-
- <section>
- <title>Reported Fixed Bugs and Malfunctions</title>
- <!--
- <p>-</p>
- -->
- <list type="bulleted">
- <item>
- <p>[manager] Encryption error when attempting to send
- version 3 inform-requests. </p>
- <p>Own Id: OTP-7377</p>
- <p>Aux Id: Seq 10966</p>
- </item>
-
- </list>
- </section>
-
- <section>
- <title>Incompatibilities</title>
- <p>-</p>
- </section>
- </section> <!-- 4.11 -->
-
<!-- section>
<title>Release notes history</title>
<p>For information about older versions see
diff --git a/lib/snmp/doc/src/notes_history.xml b/lib/snmp/doc/src/notes_history.xml
index 934df87866..722d02afbd 100644
--- a/lib/snmp/doc/src/notes_history.xml
+++ b/lib/snmp/doc/src/notes_history.xml
@@ -1,4 +1,4 @@
-<?xml version="1.0" encoding="latin1" ?>
+<?xml version="1.0" encoding="iso-8859-1" ?>
<!DOCTYPE chapter SYSTEM "chapter.dtd">
<chapter>
@@ -33,6 +33,928 @@
</header>
<section>
+ <title>SNMP Development Toolkit 4.14</title>
+
+ <p>Version 4.14 supports code replacement in runtime from/to
+ version 4.13.5, 4.13.4, 4.13.3, 4.13.2, 4.13.1 and 4.13.</p>
+
+ <section>
+ <title>Improvements and new features</title>
+ <!--
+ <p>-</p>
+ -->
+
+ <list type="bulleted">
+ <item>
+ <p>[compiler] Include object- and notification groups in the
+ compiled mib.
+ This will make it possible to import groups from other mibs. </p>
+ <p>Also the SNMPv2-MIB-file has been updated to a more
+ up-to-date version. </p>
+ <p>Own Id: OTP-8223</p>
+ <!-- <p>Aux Id: Seq 11383</p> -->
+ </item>
+
+ <item>
+ <p>[manager] Added support for message filtering in the
+ network interface module provided with the application.
+ The component that actually make the filter decisions
+ is the network interface filter module. This module
+ must implement the
+ <seealso marker="snmpm_network_interface_filter">network interface filter behaviour</seealso>
+ for message filtering.
+ See also the Configuring chapter of
+ the User's Guide to see how to configure this feature. </p>
+ <p>See the
+ <seealso marker="snmp_app#configuration_params">configuration</seealso>
+ chapter for more info about the filter options.</p>
+ <p>Own Id: OTP-8228</p>
+ <p>Aux Id: Seq 11411</p>
+ </item>
+
+ <item>
+ <p>The MIBs delivered as part of the application is now
+ also available as man pages, section 7. </p>
+ <p>Own Id: OTP-8237</p>
+ <!-- <p>Aux Id: Seq 11383</p> -->
+ </item>
+
+ </list>
+
+ </section>
+
+ <section>
+ <title>Reported Fixed Bugs and Malfunctions</title>
+ <p>-</p>
+
+ <!--
+ <list type="bulleted">
+ <item>
+ <p>[agent] The main agent type header file contained some miss-information
+ regarding the type of the entrytype field of the me-record, causing
+ unneccessary confusion.</p>
+ <p>Own Id: OTP-8116</p>
+ <p>Aux Id: Seq 11312</p>
+ </item>
+
+ </list>
+ -->
+
+ </section>
+
+ <section>
+ <title>Incompatibilities</title>
+ <p>-</p>
+ </section>
+ </section> <!-- 4.14 -->
+
+
+ <section>
+ <title>SNMP Development Toolkit 4.13.5</title>
+
+ <p>Version 4.13.5 supports code replacement in runtime from/to
+ version 4.13.4, 4.13.3, 4.13.2, 4.13.1 and 4.13.</p>
+
+ <section>
+ <title>Improvements and new features</title>
+ <!--
+ <p>-</p>
+ -->
+
+ <list type="bulleted">
+ <item>
+ <p>[agent] Improved the cache handling of the mib server. </p>
+ <p>A number of new functions and config options for the mib server
+ cache has been added. </p>
+ <p>See
+ <seealso marker="snmpa#invalidate_mibs_cache">invalidate_mibs_cache/0,1</seealso>,
+ <seealso marker="snmpa#enable_mibs_cache">enable_mibs_cache/0,1</seealso>,
+ <seealso marker="snmpa#disable_mibs_cache">disable_mibs_cache/0,1</seealso>,
+ <seealso marker="snmpa#gc_mibs_cache">gc_mibs_cache/0,1,2,3</seealso>,
+ <seealso marker="snmpa#enable_mibs_cache_autogc">enable_mibs_cache_autogc/0,1</seealso>,
+ <seealso marker="snmpa#disable_mibs_cache_autogc">disable_mibs_cache_autogc/0,1</seealso>,
+ <seealso marker="snmpa#update_mibs_cache_age">update_mibs_cache_age/1,2</seealso> and
+ <seealso marker="snmpa#update_mibs_cache_gclimit">update_mibs_cache_gclimit/1,2</seealso> for more info. </p>
+ <p>See also the
+ <seealso marker="snmp_app#configuration_params">configuration</seealso>
+ chapter for more info about the mib server cache options.</p>
+ <p>Own Id: OTP-8182</p>
+ <p>Aux Id: Seq 11383</p>
+ </item>
+
+ <item>
+ <p>[agent] A manager could no longer use the SNMPv3 user "initial"
+ as this was interpretated as the first step of the discovery. </p>
+ <p>Introduced a new terminating option, <c>trigger_username</c> to
+ make it possible to configure the username the agent reacts to.
+ Default is <c>""</c>. </p>
+ <p>See the
+ <seealso marker="snmp_app#configuration_params">configuration</seealso>
+ chapter for more info about the discovery options.</p>
+ <p>Own Id: OTP-8120</p>
+ <p>Aux Id: Seq 11361</p>
+ </item>
+
+ </list>
+
+ </section>
+
+ <section>
+ <title>Reported Fixed Bugs and Malfunctions</title>
+ <!--
+ <p>-</p>
+ -->
+ <list type="bulleted">
+ <item>
+ <p>[agent] The main agent type header file contained some miss-information
+ regarding the type of the entrytype field of the me-record, causing
+ unneccessary confusion.</p>
+ <p>Own Id: OTP-8116</p>
+ <p>Aux Id: Seq 11312</p>
+ </item>
+
+ </list>
+
+ </section>
+
+ <section>
+ <title>Incompatibilities</title>
+ <p>-</p>
+ </section>
+ </section> <!-- 4.13.5 -->
+
+
+ <section>
+ <title>SNMP Development Toolkit 4.13.4</title>
+
+ <p>Version 4.13.4 supports code replacement in runtime from/to
+ version 4.13.3, 4.13.2, 4.13.1 and 4.13.</p>
+
+ <section>
+ <title>Improvements and new features</title>
+ <p>-</p>
+
+ <!--
+ <list type="bulleted">
+ <item>
+ <p>[agent] Support for the discovery process. </p>
+ <p>The agent can both initiate discovery itself (see the
+ <seealso marker="snmp_agent_funct_descr#discovery">discovery</seealso> chapter
+ for more info) and respond to discovery initiated by a manager.</p>
+ <p>Own Id: OTP-7571</p>
+ <p>Aux Id: Seq 11053</p>
+ </item>
+
+ </list>
+ -->
+
+ </section>
+
+ <section>
+ <title>Reported Fixed Bugs and Malfunctions</title>
+ <!--
+ <p>-</p>
+ -->
+ <list type="bulleted">
+ <item>
+ <p>[agent] Originating discovery problems. </p>
+ <p>Invalid state variable update during second stage of
+ discovery causes master agent crash. </p>
+ <p>Also the net_if process failed to activate socket
+ ({active, once}) after first discovery response was sent. </p>
+ <p>Own Id: OTP-8044</p>
+ <p>Aux Id: Seq 11295</p>
+ </item>
+
+ <item>
+ <p>[agent] Terminating discovery problem. </p>
+ <p>The reply to the second stage request should include a
+ varbind with <c>usmStatsNotInTimeWindows</c>.</p>
+ <p>Own Id: OTP-8062</p>
+ <p>Aux Id: Seq 11318</p>
+ </item>
+
+ <item>
+ <p>[agent] Originating discovery improvement. </p>
+ <p>Added the ExtraInfo argument to the
+ <seealso marker="snmpa#discovery">discovery</seealso> function.
+ This argument will be passed on to the stage1_finish callback
+ function. Also, the
+ <seealso marker="snmpa#discovery">discovery</seealso> function
+ will now always return <c>{ok, ManagerEngineID}</c> on successful
+ discovery. </p>
+ <p>The <seealso marker="snmpa_discovery_handler">discovery handler</seealso>
+ behaviour updated accordingly. </p>
+ <p>Own Id: OTP-8098</p>
+ <p>Aux Id: Seq 11346</p>
+ </item>
+
+ </list>
+
+ </section>
+
+ <section>
+ <title>Incompatibilities</title>
+ <p>-</p>
+ </section>
+ </section> <!-- 4.13.4 -->
+
+
+ <section>
+ <title>SNMP Development Toolkit 4.13.3</title>
+
+ <p>Version 4.13.3 supports code replacement in runtime from/to
+ version 4.13.2, 4.13.1 and 4.13.</p>
+
+ <section>
+ <title>Improvements and new features</title>
+ <p>-</p>
+
+ <!--
+ <list type="bulleted">
+ <item>
+ <p>[agent] Support for the discovery process. </p>
+ <p>The agent can both initiate discovery itself (see the
+ <seealso marker="snmp_agent_funct_descr#discovery">discovery</seealso> chapter
+ for more info) and respond to discovery initiated by a manager.</p>
+ <p>Own Id: OTP-7571</p>
+ <p>Aux Id: Seq 11053</p>
+ </item>
+
+ </list>
+ -->
+
+ </section>
+
+ <section>
+ <title>Reported Fixed Bugs and Malfunctions</title>
+ <!--
+ <p>-</p>
+ -->
+ <list type="bulleted">
+ <item>
+ <p>[manager] A request for an oid of type BITS was actually
+ returned as OCTET STRING. </p>
+ <p>Values of type BITS are encoded as OCTET STRING,
+ which makes it impossible for the decoder to know that
+ they should really be of type BITS.
+ Instead, this has to be done higher up in the stack, where
+ there is knowledge of the MIB (assuming that the mib has
+ been loaded, there is info about the type of the mibentry). </p>
+ <p>This problem has now been fixed, but requires that the MIB
+ defining this mib-entry is loaded! </p>
+ <p>The utility function
+ <seealso marker="snmpm#oid_to_type">oid_to_type</seealso>
+ has been added, for debug purpose. </p>
+ <p>The utility function(s)
+ <seealso marker="snmp#octet_string_to_bits">octet_string_to_bits</seealso>
+ and
+ <seealso marker="snmp#bits_to_octet_string">bits_to_octet_string</seealso>
+ has also been added. These can be used if the user prefers to
+ handle the conversion on their own. </p>
+ <p>Own Id: OTP-8015</p>
+ <p>Aux Id: Seq 11285</p>
+ </item>
+
+ <item>
+ <p>[agent] Fixed some issues with the discovery handling. </p>
+ <p>Changed the API of the
+ <seealso marker="snmpa#discovery">discovery</seealso>
+ function to solve some
+ of these problems. </p>
+ <p>Introduced various options for controlling the discovery
+ process. See the
+ <seealso marker="snmp_app#configuration_params">configuration</seealso>
+ chapter for more info about the discovery options.</p>
+ <p>Own Id: OTP-8020</p>
+ <p>Aux Id: Seq 11295</p>
+ </item>
+
+ </list>
+
+ </section>
+
+ <section>
+ <title>Incompatibilities</title>
+ <p>-</p>
+ </section>
+ </section> <!-- 4.13.3 -->
+
+
+ <section>
+ <title>SNMP Development Toolkit 4.13.2</title>
+
+ <p>Version 4.13.2 supports code replacement in runtime from/to
+ version 4.13.1 and 4.13.</p>
+
+ <section>
+ <title>Improvements and new features</title>
+ <p>-</p>
+
+ <!--
+ <list type="bulleted">
+ <item>
+ <p>[agent] Support for the discovery process. </p>
+ <p>The agent can both initiate discovery itself (see the
+ <seealso marker="snmp_agent_funct_descr#discovery">discovery</seealso> chapter
+ for more info) and respond to discovery initiated by a manager.</p>
+ <p>Own Id: OTP-7571</p>
+ <p>Aux Id: Seq 11053</p>
+ </item>
+
+ </list>
+ -->
+
+ </section>
+
+ <section>
+ <title>Reported Fixed Bugs and Malfunctions</title>
+ <!--
+ <p>-</p>
+ -->
+ <list type="bulleted">
+ <item>
+ <p>[manager] Failure during downed user cleanup.
+ As part of the cleanup after a crashed user,
+ the manager attempts to unregister the agents
+ registered by this user. This however failed,
+ causing a server crash. </p>
+ <p>Own Id: OTP-7961</p>
+ <p>Aux Id: Seq 11275</p>
+ </item>
+
+ <item>
+ <p>[manager] Incorrectly documented value type for
+ IpAddress (ip). The value type for IpAddress is
+ documented as ip but is actually ia. The value type
+ ip has been added. The old (not documented) value
+ type ia still works. </p>
+ <p>Own Id: OTP-7977</p>
+ <p>Aux Id: Seq 11279</p>
+ </item>
+
+ <item>
+ <p>[manager] EngineId lookup fails when using version-3. </p>
+ <p>Own Id: OTP-7983</p>
+ <p>Aux Id: Seq 11275</p>
+ </item>
+
+ <item>
+ <p>[agent] As of version 4.13 the possible return values
+ of the function
+ <seealso marker="snmpa_mpd#process_packet">snmpa_mpd:process_packet/4</seealso>
+ changed, but this was not documented. </p>
+ <p>Own Id: OTP-7989</p>
+ <p>Aux Id: Seq 11275</p>
+ </item>
+
+ </list>
+
+ </section>
+
+ <section>
+ <title>Incompatibilities</title>
+ <p>-</p>
+ </section>
+ </section> <!-- 4.13.2 -->
+
+ <section>
+ <title>SNMP Development Toolkit 4.13.1</title>
+
+ <p>Version 4.13.1 supports code replacement in runtime from/to
+ version 4.13.</p>
+
+ <section>
+ <title>Improvements and new features</title>
+ <p>-</p>
+
+ <!--
+ <list type="bulleted">
+ <item>
+ <p>[agent] Support for the discovery process. </p>
+ <p>The agent can both initiate discovery itself (see the
+ <seealso marker="snmp_agent_funct_descr#discovery">discovery</seealso> chapter
+ for more info) and respond to discovery initiated by a manager.</p>
+ <p>Own Id: OTP-7571</p>
+ <p>Aux Id: Seq 11053</p>
+ </item>
+
+ </list>
+ -->
+
+ </section>
+
+ <section>
+ <title>Reported Fixed Bugs and Malfunctions</title>
+ <!--
+ <p>-</p>
+ -->
+ <list type="bulleted">
+ <item>
+ <p>[manager] Registration of users had some issues. </p>
+ <p>Not all of the registration functions where actually exported
+ (<seealso marker="snmpm#register_user">register_user/4</seealso>
+ and
+ <seealso marker="snmpm#register_user_monitor">register_user_monitor/4</seealso>).
+ This has now been fixed. </p>
+ <p>Also, the registration did not succeed unless
+ user implemented the *new* behaviour. This has now
+ also been fixed (registration succeeds if the user
+ implements either the new (i.e. updated
+ <seealso marker="snmpm_user">snmpm_user</seealso>)
+ or the old user behaviour (<c>snmpm_user_old</c>)). </p>
+ <p>Own Id: OTP-7902</p>
+ <p>Aux Id: Seq 11240</p>
+ </item>
+
+ </list>
+
+ </section>
+
+ <section>
+ <title>Incompatibilities</title>
+ <p>-</p>
+ </section>
+ </section> <!-- 4.13.1 -->
+
+ <section>
+ <title>SNMP Development Toolkit 4.13</title>
+<!--
+ <p>Version 4.13 supports code replacement in runtime from/to
+ version 4.12.1.</p>
+-->
+
+ <section>
+ <title>Improvements and new features</title>
+ <!--
+ <p>-</p>
+ -->
+ <list type="bulleted">
+ <item>
+ <p>[agent] Support for the discovery process. </p>
+ <p>The agent can both initiate discovery itself (see the
+ <seealso marker="snmp_agent_funct_descr#discovery">discovery</seealso> chapter
+ for more info) and respond to discovery initiated by a manager.</p>
+ <p>Own Id: OTP-7571</p>
+ <p>Aux Id: Seq 11053</p>
+ </item>
+
+ </list>
+
+ </section>
+
+ <section>
+ <title>Reported Fixed Bugs and Malfunctions</title>
+ <!--
+ <p>-</p>
+ -->
+ <list type="bulleted">
+ <item>
+ <p>[agent] Unnecessary use of math:pow/2 could cause problems
+ on systems without floating point support. </p>
+ <p>Per Hedeland</p>
+ <p>Own Id: OTP-7735</p>
+ <!-- <p>Aux Id: Seq 10966</p> -->
+ </item>
+
+ <item>
+ <p>[manager] A major flaw was discovered with the agent handling. </p>
+ <p>First, <c>TargetName</c> was never used as intended, as a unique
+ identifier for the target (agent in this case). </p>
+ <p>Second, <c>TargetName</c> had a <em>default value</em>, which meant
+ that several agents could have the same <c>TargetName</c>, causing
+ unpredictable behaviour in the manager. </p>
+ <p>Third, <c>EngineID</c> was not a mandatory config option and had
+ furthermore also a <em>default value</em>. </p>
+
+ <p>These problems has been solved in the following way: </p>
+ <p>First, a new set of api functions has been introduced (and documented):
+ <seealso marker="snmpm#register_user">register_user/4</seealso>,
+ <seealso marker="snmpm#register_user_monitor">register_user_monitor/4</seealso>,
+ <seealso marker="snmpm#register_agent">register_agent/3</seealso>,
+ <seealso marker="snmpm#unregister_agent">unregister_agent/2</seealso>,
+ <seealso marker="snmpm#agent_info">agent_info/2</seealso>,
+ <seealso marker="snmpm#update_agent_info">update_agent_info/4</seealso>,
+ <seealso marker="snmpm#sync_get">sync_get/3,4,5,6</seealso>,
+ <seealso marker="snmpm#async_get">async_get/3,4,5,6</seealso>,
+ <seealso marker="snmpm#sync_get_next">sync_get_next/3,4,5,6</seealso>,
+ <seealso marker="snmpm#async_get_next">async_get_next/3,4,5,6</seealso>,
+ <seealso marker="snmpm#sync_set">sync_set/3,4,5,6</seealso>,
+ <seealso marker="snmpm#async_set">async_set/3,4,5,6</seealso>,
+ <seealso marker="snmpm#sync_get_bulk">sync_get_bulk/5,6,7,8</seealso> and
+ <seealso marker="snmpm#async_get_bulk">async_get_bulk/5,6,7,8</seealso>
+ that all use <c>TargetName</c> (and not, as previously, <c>Addr</c>
+ and <c>Port</c>) to identify the agent (also the return value of
+ <seealso marker="snmpm#which_agents">which_agents</seealso> has
+ been changed). </p>
+ <p>Second, for backward compatibility, the old functions still
+ exist, but are no longer documented and are now wrappers for the
+ new functions, including erroneous default value for EngineID and
+ all. The TargetName is however generated from the provided
+ <c>Addr</c>, <c>Port</c> and <c>Version</c> config options. </p>
+ <p>Third, the behaviour of the
+ <seealso marker="snmpm_user">SNMP manager user</seealso> has
+ been changed to reflect this, i.e.
+ <seealso marker="snmpm_user#handle_pdu">handle_pdu/4</seealso>,
+ <seealso marker="snmpm_user#handle_trap">handle_trap/3</seealso>,
+ <seealso marker="snmpm_user#handle_inform">handle_inform/3</seealso>,
+ <seealso marker="snmpm_user#handle_report">handle_report/3</seealso>
+ and the return-value of
+ <seealso marker="snmpm_user#handle_agent">handle_agent/4</seealso>.
+ The old (non-documented) callback-functions (using Addr and Port)
+ will still be called if the agent was registered using the old
+ registration functions. </p>
+
+ <p>Own Id: OTP-7836</p>
+ <!-- <p>Aux Id: Seq 10966</p> -->
+ </item>
+
+ </list>
+
+ </section>
+
+ <section>
+ <title>Incompatibilities</title>
+ <p>-</p>
+ </section>
+ </section> <!-- 4.13 -->
+
+ <section>
+ <title>SNMP Development Toolkit 4.12.2</title>
+ <p>Version 4.12.2 supports code replacement in runtime from/to
+ version 4.12.1, 4.12, 4.11.2, 4.11.1 and 4.11.</p>
+
+ <section>
+ <title>Improvements and new features</title>
+ <p>-</p>
+ <!--
+ <list type="bulleted">
+ <item>
+ <item>
+ <p>[agent] Improvement of the inform reporting.
+ It was previously not certain how many acks an
+ application received, 0, 1 or 2. This has now been
+ fixed, so that only 1 (one) ack is issued. </p>
+ <p>Per Hedeland</p>
+ <p>Own Id: OTP-7525</p>
+ </item>
+
+ </list>
+ -->
+
+ </section>
+
+ <section>
+ <title>Reported Fixed Bugs and Malfunctions</title>
+ <!--
+ <p>-</p>
+ -->
+ <list type="bulleted">
+ <item>
+ <p>[agent] Bad session cache (usm+camv-info) invalidation
+ could cause user crash, through call(s) to (a number of)
+ MIB API function(s) (undefined function). </p>
+ <p>Own Id: OTP-7868</p>
+ <!-- <p>Aux Id: Seq 11124</p> -->
+ </item>
+
+ </list>
+
+ </section>
+
+ <section>
+ <title>Incompatibilities</title>
+ <p>-</p>
+ </section>
+ </section> <!-- 4.12.2 -->
+
+ <section>
+ <title>SNMP Development Toolkit 4.12.1</title>
+ <p>Version 4.12.1 supports code replacement in runtime from/to
+ version 4.12, 4.11.2, 4.11.1 and 4.11.</p>
+
+ <section>
+ <title>Improvements and new features</title>
+ <p>-</p>
+ <!--
+ <list type="bulleted">
+ <item>
+ <item>
+ <p>[agent] Improvement of the inform reporting.
+ It was previously not certain how many acks an
+ application received, 0, 1 or 2. This has now been
+ fixed, so that only 1 (one) ack is issued. </p>
+ <p>Per Hedeland</p>
+ <p>Own Id: OTP-7525</p>
+ </item>
+
+ </list>
+ -->
+
+ </section>
+
+ <section>
+ <title>Reported Fixed Bugs and Malfunctions</title>
+ <!--
+ <p>-</p>
+ -->
+ <list type="bulleted">
+ <item>
+ <p>Logging of messages with the GetBulk-request PDU
+ incorrectly produced an erroneous entry in the
+ log: "An error occurred". </p>
+ <p>The reason for this was that the PDU-fields
+ error_status and error_index is re-used for
+ Non-repeaters and Max-repetitions for
+ GetBulk-request PDUs, but this was not handled
+ by the logging code. </p>
+ <p>Own Id: OTP-7695</p>
+ <p>Aux Id: Seq 11124</p>
+ </item>
+
+ <item>
+ <p>[agent] An attempt to set the row status to active for an
+ notReady table row, could result in an "inconsistentValue"
+ error. </p>
+ <p>The same problem existed when attempting to set row status
+ to notInService for a row in notReady. </p>
+ <p>Serge Aleynikov</p>
+ <p>Own Id: OTP-7698</p>
+ <!-- <p>Aux Id: Seq 10966</p> -->
+ </item>
+
+ </list>
+
+ </section>
+
+ <section>
+ <title>Incompatibilities</title>
+ <p>-</p>
+ </section>
+ </section> <!-- 4.12.1 -->
+
+ <section>
+ <title>SNMP Development Toolkit 4.12</title>
+ <p>Version 4.12 supports code replacement in runtime from/to
+ version 4.11.2, 4.11.1 and 4.11.</p>
+
+ <section>
+ <title>Improvements and new features</title>
+ <!--
+ <p>-</p>
+ -->
+ <list type="bulleted">
+ <item>
+ <p>[agent] A simple lookup cache has been added to improve
+ the mib server lookup performance. </p>
+ <p>This can be disabled with the mib_server
+ <seealso marker="snmp_app">cache</seealso> option. </p>
+ <p>Own Id: OTP-7346</p>
+ </item>
+
+ <item>
+ <p>[agent] Improvement of the inform reporting.
+ It was previously not certain how many acks an
+ application received, 0, 1 or 2. This has now been
+ fixed, so that only 1 (one) ack is issued. </p>
+ <p>Per Hedeland</p>
+ <p>Own Id: OTP-7525</p>
+ </item>
+
+ </list>
+
+ </section>
+
+ <section>
+ <title>Reported Fixed Bugs and Malfunctions</title>
+ <p>-</p>
+ <!--
+ <list type="bulleted">
+ <item>
+ <p>[manager] Encryption error when attempting to send
+ version 3 inform-requests. </p>
+ <p>Own Id: OTP-7432</p>
+ <p>Aux Id: Seq 10966</p>
+ </item>
+
+ </list>
+ -->
+
+ </section>
+
+ <section>
+ <title>Incompatibilities</title>
+ <p>-</p>
+ </section>
+ </section> <!-- 4.12 -->
+
+ <section>
+ <title>SNMP Development Toolkit 4.11.2</title>
+ <p>Version 4.11.2 supports code replacement in runtime from/to
+ version 4.11.1 and 4.11. </p>
+
+ <section>
+ <title>Improvements and new features</title>
+ <p>-</p>
+ <!--
+ <list type="bulleted">
+ <item>
+ <p>Added utility functions for transforming DateAndTime
+ as [int()] to strings;
+ <seealso marker="snmp#dat2s">date_and_time_to_string/2</seealso>
+ and
+ <seealso marker="snmp#dat2s2">date_and_time_to_string2/1</seealso>. </p>
+ <p>Also added new validation function
+ <seealso marker="snmp#vdat">validate_date_and_time/2</seealso>. </p>
+ <p>Own Id: OTP-7412</p>
+ <p>Aux Id: Seq 10987</p>
+ </item>
+ </list>
+ -->
+ </section>
+
+ <section>
+ <title>Reported Fixed Bugs and Malfunctions</title>
+ <!--
+ <p>-</p>
+ -->
+ <list type="bulleted">
+ <item>
+ <p>[manager] Erroneous engine-id check when receiving version 3
+ informs. </p>
+ <p>Own Id: OTP-7570</p>
+ <p>Aux Id: Seq 11060</p>
+ </item>
+
+ <item>
+ <p>Receiving an snmp message with a very large version
+ number could cause the erlang node to run out of
+ memory and consequently crash. </p>
+ <p>The standard specifies the snmp version as an
+ (unlimited) INTEGER, but today only
+ 0 (version 1), 1 (version 2) and 3 (version 3) is
+ actually used. So, when decoding a message, a limit
+ has been put on the snmp version integer in order
+ to not allow this kind of a problem. </p>
+ <p>Own Id: OTP-7575</p>
+ <p>Aux Id: Seq 11064</p>
+ </item>
+
+ </list>
+ </section>
+
+ <section>
+ <title>Incompatibilities</title>
+ <p>-</p>
+ </section>
+ </section> <!-- 4.11.2 -->
+
+
+ <section>
+ <title>SNMP Development Toolkit 4.11.1</title>
+ <p>Version 4.11.1 supports code replacement in runtime from/to
+ version 4.11.</p>
+
+ <section>
+ <title>Improvements and new features</title>
+ <!--
+ <p>-</p>
+ -->
+ <list type="bulleted">
+ <item>
+ <p>[compiler] The MIB compiler did not retrieve the REFERENCE part
+ of a SNMP MIB definition. </p>
+ <p>This problem has been partly solved. For SNMP tables,
+ the assocList field of the tables mib-entry record now contains
+ this info (as <c>{reference, string()}</c>), <em>if</em> the
+ MIB was compiled with the compiler option <em>+reference</em>. </p>
+ <p>This solution is temporary, until such time as a permanent
+ solution (and probably not backward compatible) is devised, which
+ retrieves and stores all REFERENCE part(s) of a MIB. </p>
+ <p>See the
+ <seealso marker="snmpc#compiler_opts">compiler options</seealso>
+ for more info. </p>
+
+ <p>Serge Aleynikov</p>
+ <p>Own Id: OTP-7426</p>
+ </item>
+
+ <item>
+ <p>Added utility functions for transforming DateAndTime
+ as [int()] to strings;
+ <seealso marker="snmp#dat2s">date_and_time_to_string/2</seealso>
+ and
+ <seealso marker="snmp#dat2s2">date_and_time_to_string2/1</seealso>. </p>
+ <p>Also added new validation function
+ <seealso marker="snmp#vdat">validate_date_and_time/2</seealso>. </p>
+ <p>Own Id: OTP-7412</p>
+ <p>Aux Id: Seq 10987</p>
+ </item>
+
+ </list>
+
+ </section>
+
+ <section>
+ <title>Reported Fixed Bugs and Malfunctions</title>
+ <!--
+ <p>-</p>
+ -->
+ <list type="bulleted">
+ <item>
+ <p>[manager] Encryption error when attempting to send
+ version 3 inform-requests. </p>
+ <p>Own Id: OTP-7432</p>
+ <p>Aux Id: Seq 10966</p>
+ </item>
+
+ </list>
+ </section>
+
+ <section>
+ <title>Incompatibilities</title>
+ <p>-</p>
+ </section>
+ </section> <!-- 4.11.1 -->
+
+ <section>
+ <title>SNMP Development Toolkit 4.11</title>
+ <p>Version 4.11 supports code replacement in runtime from/to
+ version 4.10.3, 4.10.2, 4.10.1 and 4.10.</p>
+
+ <section>
+ <title>Improvements and new features</title>
+ <!--
+ <p>-</p>
+ -->
+ <list type="bulleted">
+ <item>
+ <p>[agent] Performance improvements in the case when an SNMP
+ manager performs an snmpwalk. </p>
+ <p>Martin Bj&ouml;rklund</p>
+ <p>Own Id: OTP-7201</p>
+ </item>
+
+ <item>
+ <p>The API for sending inform(s) has been improved. Also
+ the documentation has been corrected and updated. See
+ <seealso marker="snmpa#send_notification">snmpa:send_notification</seealso> and
+ <seealso marker="snmpa_notification_delivery_info_receiver">snmpa_notification_delivery_info_receiver</seealso>
+ for more info.</p>
+ <p>Own Id: OTP-7287</p>
+ <p>Aux Id: Seq 10926</p>
+ </item>
+
+ <item>
+ <p>[agent] Performance of the internal database (local-db)
+ has been improved.</p>
+ <p>Own Id: OTP-7319</p>
+ <p>Aux Id: Seq 10942</p>
+ </item>
+
+ <item>
+ <p>[agent] Added utility functions,
+ <seealso marker="snmpa#restart_worker">snmpa:restart_worker/0,1</seealso> and
+ <seealso marker="snmpa#restart_set_worker">snmpa:restart_set_worker/0,1</seealso>,
+ for restarting the agent worker processes (in case the agent is
+ multi-threaded).</p>
+ <p>Own Id: OTP-7369</p>
+ </item>
+
+ <item>
+ <p>Add utility function to
+ <seealso marker="snmp#read_mib">read</seealso>
+ a compiled mib. </p>
+ <p>Own Id: OTP-7371</p>
+ </item>
+
+ </list>
+ </section>
+
+ <section>
+ <title>Reported Fixed Bugs and Malfunctions</title>
+ <!--
+ <p>-</p>
+ -->
+ <list type="bulleted">
+ <item>
+ <p>[manager] Encryption error when attempting to send
+ version 3 inform-requests. </p>
+ <p>Own Id: OTP-7377</p>
+ <p>Aux Id: Seq 10966</p>
+ </item>
+
+ </list>
+ </section>
+
+ <section>
+ <title>Incompatibilities</title>
+ <p>-</p>
+ </section>
+ </section> <!-- 4.11 -->
+
+
+ <section>
<title>SNMP Development Toolkit 4.10.3</title>
<p>Version 4.10.3 supports code replacement in runtime from/to
version 4.10.2, 4.10.1 and 4.10.</p>
diff --git a/lib/snmp/mibs/Makefile.in b/lib/snmp/mibs/Makefile.in
index 3af74eca75..993a67c6f2 100644
--- a/lib/snmp/mibs/Makefile.in
+++ b/lib/snmp/mibs/Makefile.in
@@ -41,8 +41,7 @@ RELSYSDIR = $(RELEASE_PATH)/lib/snmp-$(VSN)
# ----------------------------------------------------
# NOTE:
-# 1) Order is important; some MIBs include others
-# 2) The OTP-REG mib actually belongs to another
+# The OTP-REG mib actually belongs to another
# application (otp_mibs), and is exported by this
# app. But since that app is built later, we have
# to built it here in order to be able to build
@@ -148,6 +147,35 @@ $(ERL_TOP)/lib/snmp/bin/snmp-v2tov1: $(ERL_TOP)/lib/snmp/bin/snmp-v2tov1.src
$(SNMP_BIN_TARGET_DIR)/OTP-REG.bin: $(ERL_TOP)/lib/$(OTP_MIBDIR)/mibs/OTP-REG.mib
$(ERLC) -pa $(SNMP_TOOLKIT)/ebin -I $(SNMP_TOOLKIT)/priv/mibs $(SNMP_FLAGS) -o $(SNMP_BIN_TARGET_DIR) $<
+# To support parallel make, we'll need explicit dependencies
+# to ensure that an imported MIB has been compiled when it's needed.
+
+$(SNMP_BIN_TARGET_DIR)/STANDARD-MIB.bin: \
+ $(SNMP_BIN_TARGET_DIR)/RFC1213-MIB.bin
+
+$(SNMP_BIN_TARGET_DIR)/SNMP-TARGET-MIB.bin: \
+ $(SNMP_BIN_TARGET_DIR)/SNMP-FRAMEWORK-MIB.bin
+
+$(SNMP_BIN_TARGET_DIR)/SNMP-NOTIFICATION-MIB.bin: \
+ $(SNMP_BIN_TARGET_DIR)/SNMP-FRAMEWORK-MIB.bin \
+ $(SNMP_BIN_TARGET_DIR)/SNMP-TARGET-MIB.bin
+
+$(SNMP_BIN_TARGET_DIR)/SNMP-COMMUNITY-MIB.bin: \
+ $(SNMP_BIN_TARGET_DIR)/SNMP-FRAMEWORK-MIB.bin \
+ $(SNMP_BIN_TARGET_DIR)/SNMP-TARGET-MIB.bin
+
+$(SNMP_BIN_TARGET_DIR)/SNMP-USER-BASED-SM-MIB.bin: \
+ $(SNMP_BIN_TARGET_DIR)/SNMP-FRAMEWORK-MIB.bin
+
+$(SNMP_BIN_TARGET_DIR)/SNMP-VIEW-BASED-ACM-MIB.bin: \
+ $(SNMP_BIN_TARGET_DIR)/SNMP-FRAMEWORK-MIB.bin
+
+$(SNMP_BIN_TARGET_DIR)/SNMP-USM-AES-MIB.bin: \
+ $(SNMP_BIN_TARGET_DIR)/SNMP-FRAMEWORK-MIB.bin
+
+$(SNMP_BIN_TARGET_DIR)/OTP-SNMPEA-MIB.bin: \
+ $(SNMP_BIN_TARGET_DIR)/OTP-REG.bin
+
clean:
rm -f $(TARGET_FILES)
@@ -185,7 +213,7 @@ info:
@echo "VSN = $(VSN)"
@echo "RELSYSDIR = $(RELSYSDIR)"
-v1/%.mib.v1: %.mib
+v1/%.mib.v1: %.mib $(ERL_TOP)/lib/snmp/bin/snmp-v2tov1
$(ERL_TOP)/lib/snmp/bin/snmp-v2tov1 -o $@ $<
diff --git a/lib/snmp/src/agent/snmpa_local_db.erl b/lib/snmp/src/agent/snmpa_local_db.erl
index d9d6e633de..df01091d53 100644
--- a/lib/snmp/src/agent/snmpa_local_db.erl
+++ b/lib/snmp/src/agent/snmpa_local_db.erl
@@ -1110,7 +1110,7 @@ table_func(is_set_ok, RowIndex, Cols, NameDb) ->
table_func(set, RowIndex, Cols, NameDb) ->
snmp_generic:table_set_row(NameDb,
nofunc,
- {snmp_generic, table_try_make_consistent},
+ fun snmp_generic:table_try_make_consistent/3,
RowIndex,
Cols);
diff --git a/lib/snmp/src/agent/snmpa_set_lib.erl b/lib/snmp/src/agent/snmpa_set_lib.erl
index 191029f6db..00c77a0cdb 100644
--- a/lib/snmp/src/agent/snmpa_set_lib.erl
+++ b/lib/snmp/src/agent/snmpa_set_lib.erl
@@ -378,15 +378,15 @@ dbg_apply(M,F,A) ->
Res
end,
case Result of
- {'EXIT', {undef, [{M, F, A} | _]}} ->
+ {'EXIT', {undef, [{M, F, A, _} | _]}} ->
{'EXIT', {hook_undef, {M, F, A}}};
- {'EXIT', {function_clause, [{M, F, A} | _]}} ->
+ {'EXIT', {function_clause, [{M, F, A, _} | _]}} ->
{'EXIT', {hook_function_clause, {M, F, A}}};
% XXX: Old format for compatibility
- {'EXIT', {undef, {M, F, A}}} ->
+ {'EXIT', {undef, {M, F, A, _}}} ->
{'EXIT', {hook_undef, {M, F, A}}};
- {'EXIT', {function_clause, {M, F, A}}} ->
+ {'EXIT', {function_clause, {M, F, A, _}}} ->
{'EXIT', {hook_function_clause, {M, F, A}}};
Result ->
diff --git a/lib/snmp/src/app/snmp.appup.src b/lib/snmp/src/app/snmp.appup.src
index 0b6ea93231..af988fda26 100644
--- a/lib/snmp/src/app/snmp.appup.src
+++ b/lib/snmp/src/app/snmp.appup.src
@@ -22,8 +22,18 @@
%% ----- U p g r a d e -------------------------------------------------------
[
+ {"4.21.2",
+ [
+ ]
+ },
+ {"4.21.1",
+ [
+ {update, snmp_note_store, soft, soft_purge, soft_purge, []}
+ ]
+ },
{"4.21",
[
+ {update, snmp_note_store, soft, soft_purge, soft_purge, []},
{load_module, snmp_target_mib, soft_purge, soft_purge, []}
]
},
@@ -40,6 +50,7 @@
{load_module, snmpa_mpd, soft_purge, soft_purge,
[snmp_conf, snmp_config]},
{load_module, snmpa_conf, soft_purge, soft_purge, [snmp_config]},
+ {update, snmp_note_store, soft, soft_purge, soft_purge, []},
{update, snmpa_agent, soft, soft_purge, soft_purge, [snmpa_mpd]},
{update, snmpm_config, soft, soft_purge, soft_purge, [snmp_conf]},
{update, snmpm_server, soft, soft_purge, soft_purge,
@@ -47,76 +58,24 @@
{update, snmpm_net_if, soft, soft_purge, soft_purge,
[snmp_conf, snmpm_mpd, snmpm_config]}
]
- },
- {"4.20",
- [
- {load_module, snmp_view_based_acm_mib, soft_purge, soft_purge, []},
- {load_module, snmp_target_mib, soft_purge, soft_purge, [snmp_conf]},
- {load_module, snmpm, soft_purge, soft_purge,
- [snmpm_server, snmpm_config, snmp_config]},
- {load_module, snmp_conf, soft_purge, soft_purge, []},
- {load_module, snmp_config, soft_purge, soft_purge, []},
- {load_module, snmpm_mpd, soft_purge, soft_purge,
- [snmp_conf, snmp_config, snmpm_config]},
- {load_module, snmpa_mpd, soft_purge, soft_purge,
- [snmp_conf, snmp_config]},
- {load_module, snmpa_conf, soft_purge, soft_purge, [snmp_config]},
- {update, snmpa_agent, soft, soft_purge, soft_purge, [snmpa_mpd]},
- {update, snmpm_config, soft, soft_purge, soft_purge, [snmp_conf]},
- {update, snmpm_server, soft, soft_purge, soft_purge,
- [snmpm_net_if, snmpm_mpd, snmpm_config]},
- {update, snmpm_net_if, soft, soft_purge, soft_purge,
- [snmp_conf, snmpm_mpd, snmpm_config]}
- ]
- },
- {"4.19",
- [
- {load_module, snmpa, soft_purge, soft_purge, []},
- {load_module, snmpm, soft_purge, soft_purge,
- [snmpm_server, snmpm_config, snmp_config]},
- {load_module, snmpa_usm, soft_purge, soft_purge, []},
- {load_module, snmpm_usm, soft_purge, soft_purge, []},
- {load_module, snmp_log, soft_purge, soft_purge, []},
- {load_module, snmp_pdus, soft_purge, soft_purge, []},
- {load_module, snmp_conf, soft_purge, soft_purge, []},
- {load_module, snmpa_conf, soft_purge, soft_purge,
- [snmp_conf, snmp_config]},
- {load_module, snmp_misc, soft_purge, soft_purge, []},
- {load_module, snmp_config, soft_purge, soft_purge, []},
- {load_module, snmpa_mpd, soft_purge, soft_purge,
- [snmp_conf, snmp_config]},
- {load_module, snmpm_mpd, soft_purge, soft_purge,
- [snmp_conf, snmp_config, snmpm_config]},
- {load_module, snmpa_trap, soft_purge, soft_purge,
- [snmpa_mpd, snmp_notification_mib, snmp_target_mib, snmpa_net_if]},
- {load_module, snmpa_acm, soft_purge, soft_purge,
- [snmp_conf, snmpa_mpd, snmp_target_mib]},
- {load_module, snmpa_conf, soft_purge, soft_purge,
- [snmp_config, snmp_notification_mib]},
- {load_module, snmp_view_based_acm_mib, soft_purge, soft_purge, []},
- {load_module, snmp_notification_mib, soft_purge, soft_purge,
- [snmp_conf, snmp_target_mib]},
- {load_module, snmp_community_mib, soft_purge, soft_purge, []},
- {load_module, snmp_target_mib, soft_purge, soft_purge,
- [snmp_conf]},
- {update, snmpm_net_if, soft, soft_purge, soft_purge,
- [snmp_conf, snmpm_mpd, snmpm_config]},
- {update, snmpm_config, soft, soft_purge, soft_purge, [snmp_conf]},
- {update, snmpm_server, soft, soft_purge, soft_purge,
- [snmpm_net_if, snmpm_mpd, snmpm_config]},
- {update, snmpa_net_if, soft, soft_purge, soft_purge,
- [snmp_conf, snmpa_mpd]},
- {update, snmpa_agent, soft, soft_purge, soft_purge,
- [snmpa_acm, snmpa_mpd, snmpa_trap]}
- ]
- }
+ }
],
%% ------D o w n g r a d e ---------------------------------------------------
[
+ {"4.21.2",
+ [
+ ]
+ },
+ {"4.21.1",
+ [
+ {update, snmp_note_store, soft, soft_purge, soft_purge, []}
+ ]
+ },
{"4.21",
[
+ {update, snmp_note_store, soft, soft_purge, soft_purge, []},
{load_module, snmp_target_mib, soft_purge, soft_purge, []}
]
},
@@ -133,6 +92,7 @@
{load_module, snmpa_mpd, soft_purge, soft_purge,
[snmp_conf, snmp_config]},
{load_module, snmpa_conf, soft_purge, soft_purge, [snmp_config]},
+ {update, snmp_note_store, soft, soft_purge, soft_purge, []},
{update, snmpa_agent, soft, soft_purge, soft_purge, [snmpa_mpd]},
{update, snmpm_config, soft, soft_purge, soft_purge, [snmp_conf]},
{update, snmpm_server, soft, soft_purge, soft_purge,
@@ -140,68 +100,6 @@
{update, snmpm_net_if, soft, soft_purge, soft_purge,
[snmp_conf, snmpm_mpd, snmpm_config]}
]
- },
- {"4.20",
- [
- {load_module, snmp_view_based_acm_mib, soft_purge, soft_purge, []},
- {load_module, snmp_target_mib, soft_purge, soft_purge, [snmp_conf]},
- {load_module, snmpm, soft_purge, soft_purge,
- [snmpm_server, snmpm_config, snmp_config]},
- {load_module, snmp_conf, soft_purge, soft_purge, []},
- {load_module, snmp_config, soft_purge, soft_purge, []},
- {load_module, snmpm_mpd, soft_purge, soft_purge,
- [snmp_conf, snmp_config, snmpm_config]},
- {load_module, snmpa_mpd, soft_purge, soft_purge,
- [snmp_conf, snmp_config]},
- {load_module, snmpa_conf, soft_purge, soft_purge, [snmp_config]},
- {update, snmpa_agent, soft, soft_purge, soft_purge, [snmpa_mpd]},
- {update, snmpm_config, soft, soft_purge, soft_purge, [snmp_conf]},
- {update, snmpm_server, soft, soft_purge, soft_purge,
- [snmpm_net_if, snmpm_mpd, snmpm_config]},
- {update, snmpm_net_if, soft, soft_purge, soft_purge,
- [snmp_conf, snmpm_mpd, snmpm_config]}
- ]
- },
- {"4.19",
- [
- {load_module, snmpa, soft_purge, soft_purge, []},
- {load_module, snmpm, soft_purge, soft_purge,
- [snmpm_server, snmpm_config, snmp_config]},
- {load_module, snmpa_usm, soft_purge, soft_purge, []},
- {load_module, snmpm_usm, soft_purge, soft_purge, []},
- {load_module, snmp_log, soft_purge, soft_purge, []},
- {load_module, snmp_pdus, soft_purge, soft_purge, []},
- {load_module, snmp_conf, soft_purge, soft_purge, []},
- {load_module, snmpa_conf, soft_purge, soft_purge,
- [snmp_conf, snmp_config]},
- {load_module, snmp_misc, soft_purge, soft_purge, []},
- {load_module, snmp_config, soft_purge, soft_purge, []},
- {load_module, snmpa_mpd, soft_purge, soft_purge,
- [snmp_conf, snmp_config]},
- {load_module, snmpm_mpd, soft_purge, soft_purge,
- [snmp_conf, snmp_config, snmpm_config]},
- {load_module, snmpa_trap, soft_purge, soft_purge,
- [snmpa_mpd, snmp_notification_mib, snmp_target_mib, snmpa_net_if]},
- {load_module, snmpa_acm, soft_purge, soft_purge,
- [snmp_conf, snmpa_mpd, snmp_target_mib]},
- {load_module, snmpa_conf, soft_purge, soft_purge,
- [snmp_config, snmp_notification_mib]},
- {load_module, snmp_view_based_acm_mib, soft_purge, soft_purge, []},
- {load_module, snmp_notification_mib, soft_purge, soft_purge,
- [snmp_conf, snmp_target_mib]},
- {load_module, snmp_community_mib, soft_purge, soft_purge, []},
- {load_module, snmp_target_mib, soft_purge, soft_purge,
- [snmp_conf]},
- {update, snmpm_net_if, soft, soft_purge, soft_purge,
- [snmp_conf, snmpm_mpd, snmpm_config]},
- {update, snmpm_config, soft, soft_purge, soft_purge, [snmp_conf]},
- {update, snmpm_server, soft, soft_purge, soft_purge,
- [snmpm_net_if, snmpm_mpd, snmpm_config]},
- {update, snmpa_net_if, soft, soft_purge, soft_purge,
- [snmp_conf, snmpa_mpd]},
- {update, snmpa_agent, soft, soft_purge, soft_purge,
- [snmpa_acm, snmpa_mpd, snmpa_trap]}
- ]
}
]
}.
diff --git a/lib/snmp/src/compile/depend.mk b/lib/snmp/src/compile/depend.mk
index f7084f8bcd..3ee8dc4bec 100644
--- a/lib/snmp/src/compile/depend.mk
+++ b/lib/snmp/src/compile/depend.mk
@@ -44,6 +44,6 @@ $(EBIN)/snmpc_mib_gram.$(EMULATOR): \
../../include/snmp_types.hrl \
snmpc_mib_gram.erl
-$(BIN)/snmpc: snmpc.src
+$(BIN)/snmpc: snmpc.src ../../vsn.mk
$(PERL) -p -e 's?%VSN%?$(VSN)? ' < $< > $@
chmod 755 $@
diff --git a/lib/snmp/src/compile/snmpc.src b/lib/snmp/src/compile/snmpc.src
index f993335b89..868e0929b4 100644
--- a/lib/snmp/src/compile/snmpc.src
+++ b/lib/snmp/src/compile/snmpc.src
@@ -74,7 +74,7 @@
%% --rrnac
%% --version
%% --verbosity V
-%% --warnings
+%% --warnings | --W
%% --Werror | --wae | --warnings_as_errors
main(Args) when is_list(Args) ->
case (catch process_args(Args)) of
@@ -221,7 +221,10 @@ process_args([], #state{verbosity = Verbosity0, file = MIB} = State) ->
process_args(["--help"|_Args], _State) ->
ok;
process_args(["--version"|_Args], #state{version = Version, mfv = MFV} = _State) ->
- {ok, lists:flatten(io_lib:format("snmpc ~s (~s)", [Version, MFV]))};
+ OtpVersion = otp_release(),
+ {ok, lists:flatten(
+ io_lib:format("snmpc ~s [Mib format version ~s] (OTP ~s)",
+ [Version, MFV, OtpVersion]))};
process_args(["--verbosity", Verbosity0|Args], #state{verbosity = V} = State)
when (V =:= undefined) ->
Verbosity = list_to_atom(Verbosity0),
@@ -234,7 +237,7 @@ process_args(["--verbosity", Verbosity0|Args], #state{verbosity = V} = State)
process_args(["--verbosity"|_Args], #state{verbosity = V})
when (V =/= undefined) ->
e(lists:flatten(io_lib:format("Verbosity already set to ~w", [V])));
-process_args(["--w"|Args], State) ->
+process_args(["--W"|Args], State) ->
process_args(Args, State#state{warnings = true});
process_args(["--warnings"|Args], State) ->
process_args(Args, State#state{warnings = true});
@@ -398,3 +401,17 @@ usage() ->
e(Reason) ->
throw({error, Reason}).
+
+otp_release() ->
+ system_info(otp_release, string).
+
+system_info(Tag, Type) ->
+ case (catch erlang:system_info(Tag)) of
+ {'EXIT', _} ->
+ "-";
+ Info when is_list(Info) andalso (Type =:= string) ->
+ Info;
+ Info ->
+ lists:flatten(io_lib:format("~w", [Info]))
+ end.
+
diff --git a/lib/snmp/src/misc/snmp_note_store.erl b/lib/snmp/src/misc/snmp_note_store.erl
index a21a6209f1..23fccf8a5f 100644
--- a/lib/snmp/src/misc/snmp_note_store.erl
+++ b/lib/snmp/src/misc/snmp_note_store.erl
@@ -258,10 +258,17 @@ code_change({down, _Vsn}, State, _Extra) ->
{ok, NState};
% upgrade
-code_change(_Vsn, State, _Extra) ->
+code_change(_Vsn, State0, _Extra) ->
process_flag(trap_exit, true),
- NState = restart_timer(State),
- {ok, NState}.
+ State1 =
+ case State0 of
+ #state{timeout = false} ->
+ State0#state{timeout = ?timeout};
+ _ ->
+ State0
+ end,
+ State2 = restart_timer(State1),
+ {ok, State2}.
%%----------------------------------------------------------
@@ -282,7 +289,7 @@ deactivate_timer(#state{timer = Pid, active = true} = State) ->
receive
deactivated -> ok
end,
- State#state{timeout = false};
+ State#state{active = false};
deactivate_timer(State) ->
State.
diff --git a/lib/snmp/test/Makefile b/lib/snmp/test/Makefile
index 5530805bc1..78ffb1c255 100644
--- a/lib/snmp/test/Makefile
+++ b/lib/snmp/test/Makefile
@@ -220,6 +220,10 @@ appup: make
$(MAYBE_ESTOP)
+$(SNMP_BIN_TARGET_DIR)/Klas4.bin: $(SNMP_BIN_TARGET_DIR)/Klas3.bin
+
+$(SNMP_BIN_TARGET_DIR)/SA-MIB.bin: $(SNMP_BIN_TARGET_DIR)/OLD-SNMPEA-MIB.bin
+
# ----------------------------------------------------
# Release Target
# ----------------------------------------------------
diff --git a/lib/snmp/test/snmp_manager_user_old.erl b/lib/snmp/test/snmp_manager_user_old.erl
index edffc80dd4..edffc80dd4 100755..100644
--- a/lib/snmp/test/snmp_manager_user_old.erl
+++ b/lib/snmp/test/snmp_manager_user_old.erl
diff --git a/lib/snmp/vsn.mk b/lib/snmp/vsn.mk
index c95e0a22d1..25e3a9470b 100644
--- a/lib/snmp/vsn.mk
+++ b/lib/snmp/vsn.mk
@@ -17,6 +17,6 @@
#
# %CopyrightEnd%
-SNMP_VSN = 4.21.1
+SNMP_VSN = 4.21.3
PRE_VSN =
APP_VSN = "snmp-$(SNMP_VSN)$(PRE_VSN)"
diff --git a/lib/ssh/doc/src/Makefile b/lib/ssh/doc/src/Makefile
index c4d8d9901c..c97c99cf52 100644
--- a/lib/ssh/doc/src/Makefile
+++ b/lib/ssh/doc/src/Makefile
@@ -29,15 +29,6 @@ VSN=$(SSH_VSN)
APPLICATION=ssh
# ----------------------------------------------------
-# Include dependency
-# ----------------------------------------------------
-
-
-ifndef DOCSUPPORT
-include make.dep
-endif
-
-# ----------------------------------------------------
# Release directory specification
# ----------------------------------------------------
RELSYSDIR = $(RELEASE_PATH)/lib/$(APPLICATION)-$(VSN)
@@ -76,33 +67,10 @@ EXTRA_FILES = \
MAN3_FILES = $(XML_REF3_FILES:%.xml=$(MAN3DIR)/%.3)
-
-ifdef DOCSUPPORT
-
HTML_REF_MAN_FILE = $(HTMLDIR)/index.html
TOP_PDF_FILE = $(PDFDIR)/$(APPLICATION)-$(VSN).pdf
-else
-
-TEX_FILES_BOOK = \
- $(BOOK_FILES:%.xml=%.tex)
-TEX_FILES_REF_MAN = $(XML_REF3_FILES:%.xml=%.tex) \
- $(XML_APPLICATION_FILES:%.xml=%.tex)
-TEX_FILES_USERS_GUIDE = \
- $(XML_CHAPTER_FILES:%.xml=%.tex)
-
-TOP_PDF_FILE = $(APPLICATION)-$(VSN).pdf
-TOP_PS_FILE = $(APPLICATION)-$(VSN).ps
-
-$(TOP_PDF_FILE): book.dvi ../../vsn.mk
- $(DVI2PS) $(DVIPS_FLAGS) -f $< | $(DISTILL) $(DISTILL_FLAGS) > $@
-
-$(TOP_PS_FILE): book.dvi ../../vsn.mk
- $(DVI2PS) $(DVIPS_FLAGS) -f $< > $@
-
-endif
-
# ----------------------------------------------------
# FLAGS
# ----------------------------------------------------
@@ -115,8 +83,6 @@ DVIPS_FLAGS +=
$(HTMLDIR)/%.gif: %.gif
$(INSTALL_DATA) $< $@
-ifdef DOCSUPPORT
-
docs: pdf html man
$(TOP_PDF_FILE): $(XML_FILES)
@@ -131,32 +97,6 @@ clean clean_docs:
rm -f $(TOP_PDF_FILE) $(TOP_PDF_FILE:%.pdf=%.fo)
rm -f errs core *~
-else
-
-ifeq ($(DOCTYPE),pdf)
-docs: pdf
-else
-ifeq ($(DOCTYPE),ps)
-docs: ps
-else
-docs: html man
-endif
-endif
-
-pdf: $(TOP_PDF_FILE)
-
-ps: $(TOP_PS_FILE)
-
-html: $(HTML_FILES)
-
-clean clean_docs clean_tex:
- rm -f $(TEX_FILES_USERS_GUIDE) $(TEX_FILES_REF_MAN) $(TEX_FILES_BOOK)
- rm -f $(HTML_FILES) $(MAN3_FILES)
- rm -f $(TOP_PDF_FILE) $(TOP_PS_FILE)
- rm -f errs core *~ *xmls_output *xmls_errs $(LATEX_CLEAN)
-
-endif
-
man: $(MAN3_FILES)
@@ -168,8 +108,6 @@ debug opt:
# ----------------------------------------------------
include $(ERL_TOP)/make/otp_release_targets.mk
-ifdef DOCSUPPORT
-
release_docs_spec: docs
$(INSTALL_DIR) $(RELSYSDIR)/doc/pdf
$(INSTALL_DATA) $(TOP_PDF_FILE) $(RELSYSDIR)/doc/pdf
@@ -179,28 +117,5 @@ release_docs_spec: docs
$(INSTALL_DATA) $(INFO_FILE) $(RELSYSDIR)
$(INSTALL_DIR) $(RELEASE_PATH)/man/man3
$(INSTALL_DATA) $(MAN3DIR)/* $(RELEASE_PATH)/man/man3
-else
-
-ifeq ($(DOCTYPE),pdf)
-release_docs_spec: pdf
- $(INSTALL_DIR) $(RELEASE_PATH)/pdf
- $(INSTALL_DATA) $(TOP_PDF_FILE) $(RELEASE_PATH)/pdf
-else
-ifeq ($(DOCTYPE),ps)
-release_docs_spec: ps
- $(INSTALL_DIR) $(RELEASE_PATH)/ps
- $(INSTALL_DATA) $(TOP_PS_FILE) $(RELEASE_PATH)/ps
-else
-release_docs_spec: docs
- $(INSTALL_DIR) $(RELSYSDIR)/doc/html
- $(INSTALL_DATA) $(EXTRA_FILES) $(HTML_FILES) \
- $(RELSYSDIR)/doc/html
- $(INSTALL_DATA) $(INFO_FILE) $(RELSYSDIR)
- $(INSTALL_DIR) $(RELEASE_PATH)/man/man3
- $(INSTALL_DATA) $(MAN3_FILES) $(RELEASE_PATH)/man/man3
-endif
-endif
-
-endif
release_spec:
diff --git a/lib/ssh/doc/src/make.dep b/lib/ssh/doc/src/make.dep
deleted file mode 100644
index cfe2f9617b..0000000000
--- a/lib/ssh/doc/src/make.dep
+++ /dev/null
@@ -1,19 +0,0 @@
-# ----------------------------------------------------
-# >>>> Do not edit this file <<<<
-# This file was automaticly generated by
-# /home/otp/bin/docdepend
-# ----------------------------------------------------
-
-
-# ----------------------------------------------------
-# TeX files that the DVI file depend on
-# ----------------------------------------------------
-
-book.dvi: book.tex ref_man.tex ssh.tex ssh_channel.tex \
- ssh_connection.tex ssh_sftp.tex ssh_sftpd.tex
-
-# ----------------------------------------------------
-# Source inlined when transforming from source to LaTeX
-# ----------------------------------------------------
-
-book.tex: ref_man.xml
diff --git a/lib/ssh/src/DSS.asn1 b/lib/ssh/src/DSS.asn1
index 77aca3808b..77aca3808b 100755..100644
--- a/lib/ssh/src/DSS.asn1
+++ b/lib/ssh/src/DSS.asn1
diff --git a/lib/ssh/src/Makefile b/lib/ssh/src/Makefile
index 42880fa80b..e7cf2c6723 100644
--- a/lib/ssh/src/Makefile
+++ b/lib/ssh/src/Makefile
@@ -127,13 +127,10 @@ $(APP_TARGET): $(APP_SRC) ../vsn.mk
$(APPUP_TARGET): $(APPUP_SRC) ../vsn.mk
sed -e 's;%VSN%;$(VSN);' $< > $@
-%.hrl: %.asn1
- erlc $(ASN_FLAGS) $<
+%.erl %.hrl: %.asn1
+ $(ERLC) $(ASN_FLAGS) $<
-DSS.hrl DSS.erl: DSS.asn1
-PKCS-1.hrl PKCS-1.erl: PKCS-1.asn1
-
-$(EBIN)/ssh_file.$(EMULATOR): $(ASN_HRLS)
+$(EBIN)/ssh_file.$(EMULATOR) $(EBIN)/ssh_rsa.$(EMULATOR): $(ASN_HRLS)
docs:
diff --git a/lib/ssh/src/PKCS-1.asn1 b/lib/ssh/src/PKCS-1.asn1
index e7d6b18c63..e7d6b18c63 100755..100644
--- a/lib/ssh/src/PKCS-1.asn1
+++ b/lib/ssh/src/PKCS-1.asn1
diff --git a/lib/ssh/src/ssh_bits.erl b/lib/ssh/src/ssh_bits.erl
index 3f0a06575c..3f0a06575c 100755..100644
--- a/lib/ssh/src/ssh_bits.erl
+++ b/lib/ssh/src/ssh_bits.erl
diff --git a/lib/ssh/src/ssh_connect.hrl b/lib/ssh/src/ssh_connect.hrl
index 34d4ff8fc1..34d4ff8fc1 100755..100644
--- a/lib/ssh/src/ssh_connect.hrl
+++ b/lib/ssh/src/ssh_connect.hrl
diff --git a/lib/ssh/src/ssh_dsa.erl b/lib/ssh/src/ssh_dsa.erl
index 1b9a396f0c..1b9a396f0c 100755..100644
--- a/lib/ssh/src/ssh_dsa.erl
+++ b/lib/ssh/src/ssh_dsa.erl
diff --git a/lib/ssh/src/ssh_file.erl b/lib/ssh/src/ssh_file.erl
index 12180f56bb..12180f56bb 100755..100644
--- a/lib/ssh/src/ssh_file.erl
+++ b/lib/ssh/src/ssh_file.erl
diff --git a/lib/ssh/src/ssh_io.erl b/lib/ssh/src/ssh_io.erl
index 915fd63e4f..915fd63e4f 100755..100644
--- a/lib/ssh/src/ssh_io.erl
+++ b/lib/ssh/src/ssh_io.erl
diff --git a/lib/ssh/src/ssh_math.erl b/lib/ssh/src/ssh_math.erl
index 510eb16aa6..510eb16aa6 100755..100644
--- a/lib/ssh/src/ssh_math.erl
+++ b/lib/ssh/src/ssh_math.erl
diff --git a/lib/ssh/src/ssh_rsa.erl b/lib/ssh/src/ssh_rsa.erl
index 91b8285b2e..91b8285b2e 100755..100644
--- a/lib/ssh/src/ssh_rsa.erl
+++ b/lib/ssh/src/ssh_rsa.erl
diff --git a/lib/ssh/src/ssh_sftp.erl b/lib/ssh/src/ssh_sftp.erl
index f000558100..f000558100 100755..100644
--- a/lib/ssh/src/ssh_sftp.erl
+++ b/lib/ssh/src/ssh_sftp.erl
diff --git a/lib/ssh/src/ssh_userauth.hrl b/lib/ssh/src/ssh_userauth.hrl
index 8eb2d46ed1..8eb2d46ed1 100755..100644
--- a/lib/ssh/src/ssh_userauth.hrl
+++ b/lib/ssh/src/ssh_userauth.hrl
diff --git a/lib/ssh/src/ssh_xfer.hrl b/lib/ssh/src/ssh_xfer.hrl
index 4a4f1a4291..4a4f1a4291 100755..100644
--- a/lib/ssh/src/ssh_xfer.hrl
+++ b/lib/ssh/src/ssh_xfer.hrl
diff --git a/lib/ssl/Makefile b/lib/ssl/Makefile
index daad7dc3e6..a7a95004a6 100644
--- a/lib/ssl/Makefile
+++ b/lib/ssl/Makefile
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 1999-2010. All Rights Reserved.
+# Copyright Ericsson AB 1999-2011. All Rights Reserved.
#
# The contents of this file are subject to the Erlang Public License,
# Version 1.1, (the "License"); you may not use this file except in
@@ -25,7 +25,7 @@ include $(ERL_TOP)/make/$(TARGET)/otp.mk
# Macros
#
-SUB_DIRECTORIES = src c_src doc/src examples/certs examples/src
+SUB_DIRECTORIES = src doc/src examples/certs examples/src
include vsn.mk
VSN = $(SSL_VSN)
diff --git a/lib/ssl/c_src/Makefile.dist b/lib/ssl/c_src/Makefile.dist
deleted file mode 100644
index 2468468921..0000000000
--- a/lib/ssl/c_src/Makefile.dist
+++ /dev/null
@@ -1,33 +0,0 @@
-#
-# %CopyrightBegin%
-#
-# Copyright Ericsson AB 1999-2009. All Rights Reserved.
-#
-# The contents of this file are subject to the Erlang Public License,
-# Version 1.1, (the "License"); you may not use this file except in
-# compliance with the License. You should have received a copy of the
-# Erlang Public License along with this software. If not, it can be
-# retrieved online at http://www.erlang.org/.
-#
-# Software distributed under the License is distributed on an "AS IS"
-# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
-# the License for the specific language governing rights and limitations
-# under the License.
-#
-# %CopyrightEnd%
-#
-
-# Makefile for SSL on Unix
-#
-# Placed in obj directory.
-#
-CC = gcc
-
-BINDIR = %BINDIR%
-LIBS = %LIBS%
-SSL_LIBDIR = %SSL_LIBDIR%
-OBJS = %OBJS%
-
-$(BINDIR)/ssl_esock: $(OBJS)
- $(CC) -L$(SSL_LIBDIR) -Wl,-R$(SSL_LIBDIR) -o $@ $^ \
- $(LIBS) -lssl -lcrypto
diff --git a/lib/ssl/c_src/Makefile.in b/lib/ssl/c_src/Makefile.in
deleted file mode 100644
index 6e413e7e8e..0000000000
--- a/lib/ssl/c_src/Makefile.in
+++ /dev/null
@@ -1,215 +0,0 @@
-#
-# %CopyrightBegin%
-#
-# Copyright Ericsson AB 1999-2011. All Rights Reserved.
-#
-# The contents of this file are subject to the Erlang Public License,
-# Version 1.1, (the "License"); you may not use this file except in
-# compliance with the License. You should have received a copy of the
-# Erlang Public License along with this software. If not, it can be
-# retrieved online at http://www.erlang.org/.
-#
-# Software distributed under the License is distributed on an "AS IS"
-# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
-# the License for the specific language governing rights and limitations
-# under the License.
-#
-# %CopyrightEnd%
-#
-
-#
-# Makefile only for Unix and Win32/Cygwin.
-#
-
-include $(ERL_TOP)/make/target.mk
-include $(ERL_TOP)/make/$(TARGET)/otp.mk
-# ----------------------------------------------------
-# SSL locations and include options from configure
-# ----------------------------------------------------
-SSL_LIBDIR = @SSL_LIBDIR@
-SSL_INCLUDE = @SSL_INCLUDE@
-SSL_CRYPTO_LIBNAME = @SSL_CRYPTO_LIBNAME@
-SSL_SSL_LIBNAME = @SSL_SSL_LIBNAME@
-
-# ----------------------------------------------------
-# Application version
-# ----------------------------------------------------
-include ../vsn.mk
-VSN=$(SSL_VSN)
-
-# ----------------------------------------------------
-# Commands
-# ----------------------------------------------------
-CC = @CC@
-LD = @LD@
-SHELL = /bin/sh
-LIBS = @LIBS@
-PLAIN_CFLAGS = @CFLAGS@
-
-# ----------------------------------------------------
-# Includes and libs
-# ----------------------------------------------------
-
-ALL_CFLAGS = @WFLAGS@ @CFLAGS@ @DEFS@ $(TYPE_FLAGS)
-TARGET = @host@
-
-ifeq ($(TYPE),debug)
-TYPEMARKER = .debug
-TYPE_FLAGS = -g -DDEBUG @DEBUG_FLAGS@
-else
-TYPEMARKER =
-TYPE_FLAGS = -O2
-endif
-
-PRIVDIR = ../priv
-BINDIR = $(PRIVDIR)/bin/$(TARGET)
-OBJDIR = $(PRIVDIR)/obj/$(TARGET)
-
-# ----------------------------------------------------
-# File suffixes
-# ----------------------------------------------------
-exe = @EXEEXT@
-obj = .@OBJEXT@
-
-# ----------------------------------------------------
-# Release directory specification
-# ----------------------------------------------------
-RELSYSDIR = $(RELEASE_PATH)/lib/ssl-$(VSN)
-
-# ----------------------------------------------------
-# Common Macros
-# ----------------------------------------------------
-OBJS = $(OBJDIR)/esock$(obj) \
- $(OBJDIR)/debuglog$(obj) \
- $(OBJDIR)/esock_poll$(obj) \
- $(OBJDIR)/esock_osio$(obj) \
- $(OBJDIR)/esock_utils$(obj) \
- $(OBJDIR)/esock_posix_str$(obj) \
- $(OBJDIR)/esock_openssl$(obj)
-
-PORT_PROGRAM = $(BINDIR)/ssl_esock$(exe)
-
-SKIP_BUILDING_BINARIES := false
-
-# Try to be BC for R10
-ifeq ($(findstring @SSL_,@SSL_DYNAMIC_ONLY@),@SSL_)
-DYNAMIC_CRYPTO_LIB=yes
-else
-DYNAMIC_CRYPTO_LIB=@SSL_DYNAMIC_ONLY@
-endif
-
-
-ifeq ($(DYNAMIC_CRYPTO_LIB),yes)
-
-ifneq ($(findstring win32,$(TARGET)),win32)
-SSL_MAKEFILE = $(OBJDIR)/Makefile
-else
-SSL_MAKEFILE =
-endif
-
-CC_R_FLAG=@CFLAG_RUNTIME_LIBRARY_PATH@
-
-ifeq ($(findstring @,$(CC_R_FLAG)),@)
-# Old erts configure used which hasn't replaced @CFLAG_RUNTIME_LIBRARY_PATH@;
-# we try our best here instead...
-
-ifeq ($(findstring darwin,$(TARGET)),darwin) # darwin: no flag
-CC_R_FLAG =
-else
-ifeq ($(findstring osf,$(TARGET)),osf) # osf1: -Wl,-rpath,
-CC_R_FLAG = -Wl,-rpath,
-else # Default: -Wl,-R
-CC_R_FLAG = -Wl,-R
-endif
-endif
-endif
-
-ifeq ($(strip $(CC_R_FLAG)),)
-CC_R_OPT =
-else
-CC_R_OPT = $(CC_R_FLAG)$(SSL_LIBDIR)
-endif
-
-SSL_CC_RUNTIME_LIBRARY_PATH=@SSL_CC_RUNTIME_LIBRARY_PATH@
-# Sigh...
-ifeq ($(findstring @,$(SSL_CC_RUNTIME_LIBRARY_PATH)),@)
-SSL_CC_RUNTIME_LIBRARY_PATH = $(CC_R_OPT)
-endif
-
-SSL_LINK_LIB=-L$(SSL_LIBDIR) -l$(SSL_SSL_LIBNAME) -l$(SSL_CRYPTO_LIBNAME)
-else
-# not dynamic crypto lib (default from R11B-5)
-NEED_KERBEROS=@SSL_LINK_WITH_KERBEROS@
-NEED_ZLIB=@SSL_LINK_WITH_ZLIB@
-SSL_MAKEFILE =
-CC_R_OPT =
-SSL_CC_RUNTIME_LIBRARY_PATH=
-SSL_LINK_LIB = $(SSL_LIBDIR)/lib$(SSL_SSL_LIBNAME).a $(SSL_LIBDIR)/lib$(SSL_CRYPTO_LIBNAME).a
-ifeq ($(NEED_KERBEROS),yes)
-SSL_LINK_LIB += @STATIC_KERBEROS_LIBS@
-endif
-ifeq ($(NEED_ZLIB),yes)
-SSL_LINK_LIB += @STATIC_ZLIB_LIBS@
-endif
-endif
-
-# ----------------------------------------------------
-# Targets
-# ----------------------------------------------------
-
-debug opt: $(OBJDIR) $(BINDIR) $(OBJS) $(PORT_PROGRAM) $(SSL_MAKEFILE)
-
-$(OBJDIR):
- -@mkdir -p $(OBJDIR)
-
-$(BINDIR):
- -@mkdir -p $(BINDIR)
-
-$(OBJDIR)/esock_openssl$(obj): esock_openssl.c
- $(CC) -c -o $@ $(ALL_CFLAGS) $(SSL_INCLUDE) $<
-
-$(OBJDIR)/%$(obj): %.c
- $(CC) -c -o $@ $(ALL_CFLAGS) $<
-
-# Unix
-$(BINDIR)/ssl_esock: $(OBJS)
- $(CC) $(PLAIN_CFLAGS) $(LDFLAGS) -o $@ $^ $(LIBS) $(SSL_CC_RUNTIME_LIBRARY_PATH) $(SSL_LINK_LIB)
-
-# Win32/Cygwin
-$(BINDIR)/ssl_esock.exe: $(OBJS)
- $(LD) $(SSL_CC_RUNTIME_LIBRARY_PATH) -L$(SSL_LIBDIR) -o $@ $^ -lwsock32 -l$(SSL_CRYPTO_LIBNAME) -l$(SSL_SSL_LIBNAME)
-
-# Unix only, and only when linking statically
-$(SSL_MAKEFILE):
- sed -e "s;%BINDIR%;../../bin/$(TARGET);" \
- -e "s;%SSL_LIBDIR%;$(SSL_LIBDIR);" \
- -e "s;%OBJS;$(OBJS);" \
- -e "s;%LIBS%;$(LIBS);" ./Makefile.dist \
- > $(OBJDIR)/Makefile
-
-
-clean:
- rm -f $(PORT_PROGRAM) $(OBJS) core *~ $(SSL_MAKEFILE)
-
-docs:
-
-# ----------------------------------------------------
-# Release Target
-# ----------------------------------------------------
-include $(ERL_TOP)/make/otp_release_targets.mk
-
-release_spec: opt
- $(INSTALL_DIR) $(RELSYSDIR)/priv/bin
- $(INSTALL_PROGRAM) $(PORT_PROGRAM) $(RELSYSDIR)/priv/bin
-ifneq ($(SSL_MAKEFILE),)
- $(INSTALL_DIR) $(RELSYSDIR)/priv/obj
- $(INSTALL_DATA) $(OBJS) $(RELSYSDIR)/priv/obj
- sed -e "s;%BINDIR%;../bin;" \
- -e "s;%SSL_LIBDIR%;$(SSL_LIBDIR);" \
- -e "s;%OBJS;$(OBJS);" \
- -e "s;%LIBS%;$(LIBS);" ./Makefile.dist \
- > $(RELSYSDIR)/priv/obj/Makefile
-endif
-
-release_docs_spec:
-
diff --git a/lib/ssl/c_src/Makefile.win32 b/lib/ssl/c_src/Makefile.win32
deleted file mode 100644
index 668cd2a28d..0000000000
--- a/lib/ssl/c_src/Makefile.win32
+++ /dev/null
@@ -1,147 +0,0 @@
-#
-# %CopyrightBegin%
-#
-# Copyright Ericsson AB 1999-2009. All Rights Reserved.
-#
-# The contents of this file are subject to the Erlang Public License,
-# Version 1.1, (the "License"); you may not use this file except in
-# compliance with the License. You should have received a copy of the
-# Erlang Public License along with this software. If not, it can be
-# retrieved online at http://www.erlang.org/.
-#
-# Software distributed under the License is distributed on an "AS IS"
-# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
-# the License for the specific language governing rights and limitations
-# under the License.
-#
-# %CopyrightEnd%
-#
-
-#
-# SSL - Makefile for Windows NT
-#
-# It is assumed that the following environment variables have been set:
-#
-# INCLUDE X:\MSDEV\INCLUDE
-# LIB X:\MSDEV\LIB
-#
-# so that standard include files, and the socket library can be found.
-#
-# When ssl_esock.exe is run, the PATH environment variable must contain
-# the name of a directory that contains ssleay32.dll and libeay32.dll,
-# and windows socket dll.
-#
-
-# Roots
-!ifndef OPENSSL_ROOT
-! error "Makefile.win32: ssl: OPENSSL_ROOT not set"
-!endif
-
-TARGET = win32
-
-BINDIR = ..\priv\bin\$(TARGET)
-OBJDIR = ..\priv\obj\$(TARGET)
-
-!if !exist($(BINDIR))
-! if [mkdir $(BINDIR)]
-! error "SSL: cannot create BINDIR"
-! endif
-!endif
-
-!if !exist($(OBJDIR))
-! if [mkdir $(OBJDIR)]
-! error "SSL: cannot create OBJDIR"
-! endif
-!endif
-
-# Includes
-#
-OPENSSL_INCLUDE = $(OPENSSL_ROOT)\inc32
-
-INCLUDES = /I. /I$(OPENSSL_INCLUDE)
-
-# Libraries
-#
-OPENSSL_LIBDIR = $(OPENSSL_ROOT)\out32dll
-OPENSSL_LIBS = \
- $(OPENSSL_LIBDIR)\ssleay32.lib \
- $(OPENSSL_LIBDIR)\libeay32.lib
-
-!ifdef ESOCK_WINSOCK2
-WINSOCK_LIB = ws2_32.lib
-DEFS = -DESOCK_WINSOCK2
-!else
-WINSOCK_LIB = wsock32.lib
-!endif
-
-# Compiler options
-#
-# NOTE: Size of fd_set is set in esock_winsock.h but can be overridden
-# with a -D option here.
-#
-OPTS = /MDd /G5 /Ox /O2 /Ob2 /Z7
-DEFS = -D__WIN32__ -DWIN32 $(DEFS)
-CFLAGS = $(INCLUDES) /nologo $(OPTS) $(DEFS)
-
-# Object files
-#
-SSL_BASE_OBJS = \
- $(OBJDIR)\esock.obj \
- $(OBJDIR)\debuglog.obj \
- $(OBJDIR)\esock_poll$(obj) \
- $(OBJDIR)\esock_osio.obj \
- $(OBJDIR)\esock_utils.obj \
- $(OBJDIR)\esock_posix_str.obj
-
-OPENSSL_OBJS = \
- $(OBJDIR)\esock_openssl.obj
-
-#
-# Targets
-#
-
-all: $(SSL_BASE_OBJS) $(OPENSSL_OBJS) $(BINDIR)\ssl_esock.exe
-
-clean:
- del $(BINDIR)\*.exe
- del $(OBJDIR)\*.obj
-
-# Inference rule .c.obj:
-#
-{.}.c{$(OBJDIR)}.obj:
- $(CC) $(CFLAGS) /c /Fo$@ $(*B).c
-
-# Binary
-#
-$(BINDIR)\ssl_esock.exe: $(SSL_BASE_OBJS) $(OPENSSL_OBJS)
- $(CC) /nologo $(SSL_BASE_OBJS) $(OPENSSL_OBJS) $(OPENSSL_LIBS) \
- $(WINSOCK_LIB) /Fe$(BINDIR)\ssl_esock.exe
-
-
-
-# Dependencies
-#
-$(OBJDIR)\esock.o: esock.h debuglog.h esock_ssl.h esock_osio.h \
- esock_utils.h esock_winsock.h
-$(OBJDIR)\debuglog.o: debuglog.h esock_ssl.h esock_utils.h
-$(OBJDIR)\esock_osio.o: esock_osio.h esock.h debuglog.h esock_utils.h \
- esock_winsock.h
-$(OBJDIR)\esock_utils.o: esock_utils.h
-$(OBJDIR)\esock_posix_str.o: esock_posix_str.h esock_winsock.h
-
-$(OBJDIR)\esock_openssl.o: esock.h esock_ssl.h debuglog.h esock_utils.h \
- $(OPENSSL_INCLUDE)\crypto.h \
- $(OPENSSL_INCLUDE)\ssl.h \
- $(OPENSSL_INCLUDE)\err.h
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/lib/ssl/c_src/Makefile.win32.dist b/lib/ssl/c_src/Makefile.win32.dist
deleted file mode 100644
index 8510c44e08..0000000000
--- a/lib/ssl/c_src/Makefile.win32.dist
+++ /dev/null
@@ -1,45 +0,0 @@
-#
-# %CopyrightBegin%
-#
-# Copyright Ericsson AB 1999-2009. All Rights Reserved.
-#
-# The contents of this file are subject to the Erlang Public License,
-# Version 1.1, (the "License"); you may not use this file except in
-# compliance with the License. You should have received a copy of the
-# Erlang Public License along with this software. If not, it can be
-# retrieved online at http://www.erlang.org/.
-#
-# Software distributed under the License is distributed on an "AS IS"
-# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
-# the License for the specific language governing rights and limitations
-# under the License.
-#
-# %CopyrightEnd%
-#
-
-# Makefile.win32.dist for SSL
-#
-# To be placed in obj directory.
-#
-
-CC = cl
-
-BINDIR = %BINDIR%
-
-OPENSSL_LIBS = \
- $(BINDIR)\ssleay32.lib \
- $(BINDIR)\libeay32.lib
-
-WINSOCK_LIB = ws2_32.lib
-
-SSL_BASE_OBJS = esock.obj debuglog.obj esock_osio.obj esock_utils.obj \
- esock_posix_str.obj
-
-OPENSSL_OBJS = esock_openssl.obj
-
-$(BINDIR)\ssl_esock.exe: $(SSL_BASE_OBJS) $(OPENSSL_OBJS)
- $(CC) /nologo $(SSL_BASE_OBJS) $(OPENSSL_OBJS) $(OPENSSL_LIBS) \
- $(WINSOCK_LIB) /Fe$(BINDIR)\ssl_esock.exe
-
-
-
diff --git a/lib/ssl/c_src/debuglog.c b/lib/ssl/c_src/debuglog.c
deleted file mode 100644
index e2e55df4b2..0000000000
--- a/lib/ssl/c_src/debuglog.c
+++ /dev/null
@@ -1,251 +0,0 @@
-/*<copyright>
- * <year>1999-2008</year>
- * <holder>Ericsson AB, All Rights Reserved</holder>
- *</copyright>
- *<legalnotice>
- * The contents of this file are subject to the Erlang Public License,
- * Version 1.1, (the "License"); you may not use this file except in
- * compliance with the License. You should have received a copy of the
- * Erlang Public License along with this software. If not, it can be
- * retrieved online at http://www.erlang.org/.
- *
- * Software distributed under the License is distributed on an "AS IS"
- * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
- * the License for the specific language governing rights and limitations
- * under the License.
- *
- * The Initial Developer of the Original Code is Ericsson AB.
- *</legalnotice>
- */
-/*
- * Purpose: Various routines for debug printouts and logs.
- */
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <stdarg.h>
-#include <string.h>
-#include <ctype.h>
-#include <time.h>
-#include "debuglog.h"
-#include "esock_utils.h"
-
-#ifndef __WIN32__
-static char tr_format_buf[256];
-static char *tr_format(const char *format);
-static int vfprintclistf(FILE *fp, const char *format, va_list args);
-#endif
-
-int debug = 0;
-int debugmsg = 0;
-FILE *ssllogfp = NULL;
-FILE *__locallogfp = NULL;
-
-void open_ssllog(char *path)
-{
- ssllogfp = openlog(path);
-}
-
-void close_ssllog(void)
-{
- if (ssllogfp)
- closelog(ssllogfp);
-}
-
-FILE *openlog(char *s)
-{
- FILE *fp;
- time_t t = time(NULL);
-
- if ((fp = fopen(s, "a"))) {
- setbuf(fp, NULL);
- fprintf(fp, "===== Opened [%s] %s", s, ctime(&t));
- }
- return fp;
-}
-
-void closelog(FILE *fp)
-{
- time_t t = time(NULL);
-
- if (fp) {
- fprintf(fp, "Closed %s", ctime(&t));
- fclose(fp);
- }
-}
-
-int __debugprintf(const char *format, ...)
-{
- va_list args;
- int ret;
-#ifndef __WIN32__
- char *newformat;
-
- va_start(args, format);
- newformat = tr_format(format);
- ret = vfprintf(stderr, newformat, args);
- if (newformat != format && newformat != tr_format_buf)
- esock_free(newformat);
-#else
- va_start(args, format);
- ret = vfprintf(stderr, format, args);
-#endif
- va_end(args);
- if (ssllogfp) {
- va_start(args, format);
- vfprintf(ssllogfp, format, args);
- va_end(args);
- }
- return ret;
-}
-
-int __debugprintclistf(const char *format, ...)
-{
- va_list args;
- int ret;
-#ifndef __WIN32__
- char *newformat;
-
- va_start(args, format);
- newformat = tr_format(format);
- ret = vfprintclistf(stderr, newformat, args);
- if (newformat != format && newformat != tr_format_buf)
- esock_free(newformat);
-#else
- va_start(args, format);
- ret = vfprintclistf(stderr, format, args);
-#endif
- if (ssllogfp)
- vfprintclistf(ssllogfp, format, args);
- va_end(args);
- return ret;
-}
-
-int __debuglogf(const char *format, ...)
-{
- va_list args;
- int ret;
-
- va_start(args, format);
- ret = vfprintf(__locallogfp, format, args);
- va_end(args);
- return ret;
-}
-
-#ifndef __WIN32__
-
-/* Insert `\r' before each `\n' i format */
-static char *tr_format(const char *format)
-{
- char *newformat, *s, *t;
- int len;
-
- len = strlen(format);
- if ((newformat = (len > 127) ? esock_malloc(len) : tr_format_buf)) {
- for (s = (char *)format, t = newformat; *s; *t++ = *s++)
- if (*s == '\n')
- *t++ = '\r';
- *t = '\0';
- } else
- newformat = (char *)format;
- return newformat;
-}
-
-#endif
-
-/* This function is for printing arrays of characters with formats
- * %FPa or %FPb, where F and P are the ordinary specifiers for
- * field width and precision, respectively.
- *
- * The conversion specifier `a' implies hex-string output, while
- * the `b' specifier provides character output (for non-printable
- * characters a `.' is written.
- *
- * The F specifier contains the width for each character. The
- * P specifier tells how many characters to print.
- *
- * Example: Suppose we have a function myprintf(char *format, ...)
- * that calls our vfprintclistf(), and that
- *
- * char buf[] = "h\r\n";
- * len = 3;
- *
- * Then
- *
- * myprintf("%.2b", buf) prints "h."
- * myprintf("%2.3b", buf) prints "h . . "
- * myprintf("%3.*a", len, buf) prints "68 0d 0a"
- *
- */
-
-static int vfprintclistf(FILE *fp, const char *format, va_list args)
-{
-
- int i, len, width, prec, written = 0;
- char *s, *prevs, *fstart;
- unsigned char *buf;
-
- if (!format || !*format)
- return 0;
-
- /* %{[0-9]*|\*}{.{[0-9]*|\*}{a|b} */
-
- prevs = (char *)format; /* format is const */
- s = strchr(format, '%');
- while (s && *s) {
- if (s - prevs > 0)
- written += fprintf(fp, "%.*s", s - prevs, prevs);
- width = prec = 0;
- fstart = s;
- s++;
- if (*s != '%') { /* otherwise it is not a format */
- if (*s == '*') { /* width in arg */
- s++;
- width = va_arg(args, int);
- } else if ((len = strspn(s, "0123456789"))) { /* const width */
- width = atoi(s);
- s += len;
- } else
- width = 0;
- if (*s == '.') { /* precision specified */
- s++;
- if (*s == '*') { /* precision in arg */
- s++;
- prec = va_arg(args, int);
- } else if ((len = strspn(s, "0123456789"))) { /* const prec */
- prec = atoi(s);
- s += len;
- } else /* no precision value, defaults to zero */
- prec = 0;
- } else
- prec = 0; /* no precision defaults to zero */
- if (*s == 'a' || *s == 'b') { /* only valid specifiers */
- buf = va_arg(args, unsigned char *);
- if (*s == 'a') {
- for (i = 0; i < prec; i++)
- written += fprintf(fp, "%*.2x", width, buf[i]);
- }else if (*s == 'b') {
- for (i = 0; i < prec; i++) {
- if (isprint(buf[i]))
- written += fprintf(fp, "%*c", width, buf[i]);
- else
- written += fprintf(fp, "%*c", width, '.');
- }
- }
- } else {
- fprintf(stderr, "fprintclistf: format \"%s\" invalid.\n",
- format);
- va_end(args);
- return written;
- }
- }
- s++;
- /* Now s points to the next character after the format */
- prevs = s;
- s = strchr(s, '%');
- }
- if (format + strlen(format) + 1 - prevs > 0)
- written += fprintf(fp, "%s", prevs);
- return written;
-}
-
diff --git a/lib/ssl/c_src/debuglog.h b/lib/ssl/c_src/debuglog.h
deleted file mode 100644
index 5699e6b495..0000000000
--- a/lib/ssl/c_src/debuglog.h
+++ /dev/null
@@ -1,50 +0,0 @@
-/*<copyright>
- * <year>1998-2008</year>
- * <holder>Ericsson AB, All Rights Reserved</holder>
- *</copyright>
- *<legalnotice>
- * The contents of this file are subject to the Erlang Public License,
- * Version 1.1, (the "License"); you may not use this file except in
- * compliance with the License. You should have received a copy of the
- * Erlang Public License along with this software. If not, it can be
- * retrieved online at http://www.erlang.org/.
- *
- * Software distributed under the License is distributed on an "AS IS"
- * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
- * the License for the specific language governing rights and limitations
- * under the License.
- *
- * The Initial Developer of the Original Code is Ericsson AB.
- *</legalnotice>
- */
-/*
- * Purpose: Debug functions and macros.
- *
- */
-
-#ifndef __DEBUGLOG_H_
-#define __DEBUGLOG_H_
-
-#include <stdio.h>
-#include "esock_ssl.h"
-
-#define DEBUGF(x) if (debug) __debugprintf x;
-#define DEBUGMSGF(x) if (debugmsg) __debugprintclistf x;
-#define LOGF(fp, x) if (fp) { __locallogfp = fp; __debuglogf x; }
-#define SSLDEBUGF() if (debug) { esock_ssl_print_errors_fp(stderr); \
- if (ssllogfp) esock_ssl_print_errors_fp(ssllogfp); }
-
-int debug;
-int debugmsg;
-FILE *ssllogfp;
-FILE *__locallogfp;
-
-void open_ssllog(char *path);
-void close_ssllog(void);
-FILE *openlog(char *);
-void closelog(FILE *);
-int __debugprintf(const char *, ...);
-int __debugprintclistf(const char *, ...);
-int __debuglogf(const char *, ...);
-
-#endif
diff --git a/lib/ssl/c_src/esock.c b/lib/ssl/c_src/esock.c
deleted file mode 100644
index 78d08f7c29..0000000000
--- a/lib/ssl/c_src/esock.c
+++ /dev/null
@@ -1,1904 +0,0 @@
-/*<copyright>
- * <year>1999-2008</year>
- * <holder>Ericsson AB, All Rights Reserved</holder>
- *</copyright>
- *<legalnotice>
- * The contents of this file are subject to the Erlang Public License,
- * Version 1.1, (the "License"); you may not use this file except in
- * compliance with the License. You should have received a copy of the
- * Erlang Public License along with this software. If not, it can be
- * retrieved online at http://www.erlang.org/.
- *
- * Software distributed under the License is distributed on an "AS IS"
- * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
- * the License for the specific language governing rights and limitations
- * under the License.
- *
- * The Initial Developer of the Original Code is Ericsson AB.
- *</legalnotice>
- */
-
-/*
- * Purpose: Implementation of Secure Socket Layer (SSL).
- *
- * This is an "SSL proxy" for Erlang in the form of a port
- * program.
- *
- * The implementation has borrowed somewhat from the original
- * implementation of `socket' by Claes Wikstr�m, and the former
- * implementation of `ssl_socket' by Helen Ariyan.
- *
- * All I/O is now non-blocking.
- *
- * When a connection (cp) is in the state JOINED we have the following
- * picture:
- *
- * proxy->fd fd
- * | |
- * proxy->eof | --------> wq -----------> | bp
- * | |
- * Erlang | | SSL
- * | |
- * proxy->bp | <------ proxy->wq --------- | eof
- * | |
- *
- * We read from Erlang (proxy->fd) and write to SSL (fd); and read from
- * SSL (fd) and write to Erlang (proxy->fd).
- *
- * The variables bp (broken pipe) and eof (end of file) take the
- * values 0 and 1.
- *
- * What has been read and cannot be immediately written is put in a
- * write queue (wq). A wq is emptied before reads are continued, which
- * means that at most one chunk that is read can be in a wq.
- *
- * The proxy-to-ssl part of a cp is valid iff
- *
- * !bp && (wq.len > 0 || !proxy->eof).
- *
- * The ssl-to-proxy part of a cp is valid iff
- *
- * !proxy->bp && (proxy->wq.len > 0 || !eof).
- *
- * The connection is valid if any of the above parts are valid, i.e.
- * invalid if both parts are invalid.
- *
- * Every SELECT_TIMEOUT second we try to write to those file
- * descriptors that have non-empty wq's (the only way to detect that a
- * far end has gone away is to write to it).
- *
- * STATE TRANSITIONS
- *
- * Below (*) means that the corresponding file descriptor is published
- * (i.e. kwown outside this port program) when the state is entered,
- * and thus cannot be closed without synchronization with the
- * ssl_server.
- *
- * Listen:
- *
- * STATE_NONE ---> (*) PASSIVE_LISTENING <---> ACTIVE_LISTENING
- *
- * Accept:
- *
- * STATE_NONE ---> SSL_ACCEPT ---> (*) CONNECTED ---> JOINED --->
- * ---> SSL_SHUTDOWN ---> DEFUNCT
- *
- * Connect:
- *
- * STATE_NONE ---> (*) WAIT_CONNECT ---> SSL_CONNECT ---> CONNECTED --->
- * ---> JOINED ---> SSL_SHUTDOWN ---> DEFUNCT
- *
- * In states where file descriptors has been published, and where
- * something goes wrong, the state of the connection is set to
- * DEFUNCT. A connection in such a state can only be closed by a CLOSE
- * message from Erlang (a reception of such a message is registered in
- * cp->closed). The possible states are: WAIT_CONNECT, SSL_CONNECT,
- * CONNECTED, JOINED, and SSL_SHUTDOWN.
- *
- * A connection in state SSL_ACCEPT can be closed and removed without
- * synchronization.
- *
- */
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-#ifdef __WIN32__
-#include "esock_winsock.h"
-#endif
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <stdarg.h>
-#include <string.h>
-#include <time.h>
-#include <ctype.h>
-#include <sys/types.h>
-#include <errno.h>
-
-#ifdef __WIN32__
-#include <process.h>
-#else
-#include <unistd.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <netinet/tcp.h>
-#include <sys/time.h>
-#include <netdb.h>
-#include <arpa/inet.h>
-#include <fcntl.h>
-#endif
-
-#ifndef INADDR_NONE
-#define INADDR_NONE 0xffffffff /* Should be in <netinet/in.h>. */
-#endif
-
-#include "esock.h"
-#include "debuglog.h"
-#include "esock_utils.h"
-#include "esock_ssl.h"
-#include "esock_osio.h"
-#include "esock_posix_str.h"
-#include "esock_poll.h"
-
-#define MAJOR_VERSION 2
-#define MINOR_VERSION 0
-#define MAXREPLYBUF 256
-#define RWBUFLEN (32*1024)
-#define IS_CLIENT 0
-#define IS_SERVER 1
-#define SELECT_TIMEOUT 2 /* seconds */
-
-#define psx_errstr() esock_posix_str(sock_errno())
-#define ssl_errstr() esock_ssl_errstr
-
-#define PROXY_TO_SSL_VALID(cp) (!(cp)->bp && \
- ((cp)->wq.len > 0 || !(cp)->proxy->eof))
-
-#define SSL_TO_PROXY_VALID(cp) (!(cp)->proxy->bp && \
- ((cp)->proxy->wq.len > 0 || !(cp)->eof))
-
-#define JOINED_STATE_INVALID(cp) (!(PROXY_TO_SSL_VALID(cp)) && \
- !(SSL_TO_PROXY_VALID(cp)))
-static int loop(void);
-static int set_poll_conns(Connection *cp, EsockPoll *ep, int verbose);
-static Connection *next_polled_conn(Connection *cp, Connection **cpnext,
- EsockPoll *ep, int set_wq_fds);
-
-static void leave_joined_state(Connection *cp);
-static void do_shutdown(Connection *cp);
-static void close_and_remove_connection(Connection *cp);
-static int reply(int cmd, char *fmt, ...);
-static int input(char *fmt, ...);
-static int put_pars(unsigned char *buf, char *fmt, va_list args);
-static int get_pars(unsigned char *buf, char *fmt, va_list args);
-static FD do_connect(char *lipstring, int lport, char *fipstring, int fport);
-static FD do_listen(char *ipstring, int lport, int backlog, int *aport);
-static FD do_accept(FD listensock, struct sockaddr *saddr, int *len);
-static void print_connections(void);
-static void dump_connections(void);
-static int check_num_sock_fds(FD fd);
-static void safe_close(FD fd);
-static Connection *new_connection(int state, FD fd);
-static Connection *get_connection(FD fd);
-static void remove_connection(Connection *conn);
-static Proxy *get_proxy_by_peerport(int port);
-static Proxy *new_proxy(FD fd);
-static void remove_proxy(Proxy *proxy);
-static void ensure_write_queue(WriteQueue *wq, int size);
-static void clean_up(void);
-
-static Connection *connections = NULL;
-static int num_sock_fds; /* On UNIX all file descriptors */
-static Proxy *proxies = NULL;
-static int proxy_listensock = INVALID_FD;
-static int proxy_listenport = 0;
-static int proxy_backlog = 128;
-static int proxysock_last_err = 0;
-static int proxysock_err_cnt = 0;
-static char rwbuf[RWBUFLEN];
-static unsigned char *ebuf = NULL; /* Set by read_ctrl() */
-
-static char *connstr[] = {
- "STATE_NONE",
- "ACTIVE_LISTENING",
- "PASSIVE_LISTENING",
- "CONNECTED",
- "WAIT_CONNECT",
- "SSL_CONNECT",
- "SSL_ACCEPT",
- "TRANSPORT_ACCEPT",
- "JOINED",
- "SSL_SHUTDOWN",
- "DEFUNCT"
-};
-
-static char *originstr[] = {
- "listen",
- "accept",
- "connect"
-};
-
-int main(int argc, char **argv)
-{
- char *logfile = NULL;
- int i;
- esock_version *vsn;
- char *ciphers;
-#ifdef __WIN32__
- int pid;
- WORD version;
- WSADATA wsa_data;
-
- set_binary_mode();
- setvbuf(stderr, NULL, _IONBF, 0);
- /* Two sockets for the stdin socket pipe (local thread). */
- num_sock_fds = 2;
-#else
- pid_t pid;
- num_sock_fds = 3; /* 0, 1, 2 */
-#endif
-
- pid = getpid();
- i = 1;
- while (i < argc) {
- if (strcmp(argv[i], "-d") == 0) {
- debug = 1;
- i++;
- } else if (strcmp(argv[i], "-dm") == 0) {
- debugmsg = 1;
- i++;
- } else if (strcmp(argv[i], "-pp") == 0) {
- i++;
- proxy_listenport = atoi(argv[i]);
- i++;
- } else if (strcmp(argv[i], "-pb") == 0) {
- i++;
- proxy_backlog = atoi(argv[i]);
- i++;
- } else if (strcmp(argv[i], "-pv") == 0) {
- i++;
- protocol_version = atoi(argv[i]);
- i++;
- } else if (strcmp(argv[i], "-dd") == 0) {
- i++;
- logfile = esock_malloc(strlen(argv[i]) + 64);
- sprintf(logfile, "%s/ssl_esock.%d.log", argv[i], (int)pid);
- i++;
- } else if (strcmp(argv[i], "-ersa") == 0) {
- ephemeral_rsa = 1;
- i++;
- } else if (strcmp(argv[i], "-edh") == 0) {
- ephemeral_dh = 1;
- i++;
- }
- }
- if (debug || debugmsg) {
- DEBUGF(("Starting ssl_esock\n"));
- if (logfile) {
- open_ssllog(logfile);
-#ifndef __WIN32__
- num_sock_fds++;
-#endif
- }
- atexit(close_ssllog);
- DEBUGF(("pid = %d\n", getpid()));
- }
- if (esock_ssl_init() < 0) {
- fprintf(stderr, "esock: Could not do esock_ssl_init\n");
- exit(EXIT_FAILURE);
- }
-
- atexit(esock_ssl_finish);
-
-#ifdef __WIN32__
- /* Start Windows' sockets */
- version = MAKEWORD(MAJOR_VERSION, MINOR_VERSION);
- if (WSAStartup(version, &wsa_data) != 0) {
- fprintf(stderr, "esock: Could not start up Windows' sockets\n");
- exit(EXIT_FAILURE);
- }
- atexit((void (*)(void))WSACleanup);
- if (LOBYTE(wsa_data.wVersion) < MAJOR_VERSION ||
- (LOBYTE(wsa_data.wVersion) == MAJOR_VERSION &&
- HIBYTE(wsa_data.wVersion) < MINOR_VERSION)) {
- fprintf(stderr, "esock: Windows socket version error. "
- "Requested version:"
- "%d.%d, version found: %d.%d\n", MAJOR_VERSION,
- MINOR_VERSION, LOBYTE(wsa_data.wVersion),
- HIBYTE(wsa_data.wVersion));
- exit(EXIT_FAILURE);
- }
- DEBUGF(("Using Windows socket version: %d.%d\n",
- LOBYTE(wsa_data.wVersion), HIBYTE(wsa_data.wVersion)));
- DEBUGF(("Maximum number of sockets available: %d\n",
- wsa_data.iMaxSockets));
-
- if (esock_osio_init() < 0) {
- fprintf(stderr, "esock: Could not init osio\n");
- exit(EXIT_FAILURE);
- }
- atexit(esock_osio_finish);
-#endif
-
- /* Create the local proxy listen socket and set it to non-blocking */
- proxy_listensock = do_listen("127.0.0.1", proxy_listenport,
- proxy_backlog, &proxy_listenport);
- if (proxy_listensock == INVALID_FD) {
- fprintf(stderr, "esock: Cannot create local listen socket\n");
- exit(EXIT_FAILURE);
- }
- SET_NONBLOCKING(proxy_listensock);
- DEBUGF(("Local proxy listen socket: fd = %d, port = %d\n",
- proxy_listensock, proxy_listenport));
-
- vsn = esock_ssl_version();
- ciphers = esock_ssl_ciphers();
-
- /* Report: port number of the local proxy listen socket, the native
- * os pid, the compile and lib versions of the ssl library, and
- * the list of available ciphers. */
- reply(ESOCK_PROXY_PORT_REP, "24sss", proxy_listenport, (int)pid,
- vsn->compile_version, vsn->lib_version, ciphers);
-
- atexit(clean_up);
-
- loop();
-
- if (logfile)
- esock_free(logfile);
- exit(EXIT_SUCCESS);
-}
-
-
-/*
- * Local functions
- *
- */
-
-static int loop(void)
-{
- EsockPoll pollfd;
- FD fd, msgsock, listensock, connectsock, proxysock;
- int cc, wc, fport, lport, pport, length, backlog, intref, op;
- int value;
- char *lipstring, *fipstring;
- char *flags;
- char *protocol_vsn, *cipher;
- unsigned char *cert, *bin;
- int certlen, binlen;
- struct sockaddr_in iserv_addr;
- int sret = 1;
- Connection *cp, *cpnext, *newcp;
- Proxy *pp;
- time_t last_time = 0, now = 0;
- int set_wq_fds;
-
- esock_poll_init(&pollfd);
-
- while(1) {
- esock_poll_zero(&pollfd);
- esock_poll_fd_set_read(&pollfd, proxy_listensock);
- esock_poll_fd_set_read(&pollfd, local_read_fd);
-
- set_wq_fds = 0;
-
- if (sret) /* sret == 1 the first time. */
- DEBUGF(("==========LOOP=============\n"));
-
- cc = set_poll_conns(connections, &pollfd, sret) + 1;
-
- if (sret) {
- print_connections();
- DEBUGF(("Before poll/select: %d descriptor%s (total %d)\n",
- cc, (cc == 1) ? "" : "s", num_sock_fds));
- }
-
- sret = esock_poll(&pollfd, SELECT_TIMEOUT);
- if (sret < 0) {
- DEBUGF(("select/poll error: %s\n", psx_errstr()));
- continue;
- }
-
- time(&now);
- if (now >= last_time + SELECT_TIMEOUT) {
- set_wq_fds = 1;
- last_time = now;
- }
- /*
- * First accept as many connections as possible on the
- * proxy listen socket. We record the peer port, which
- * is later used as a reference for joining a proxy
- * connection with a network connection.
- */
-
- if (esock_poll_fd_isset_read(&pollfd, proxy_listensock)) {
- while (1) {
- length = sizeof(iserv_addr);
- proxysock = do_accept(proxy_listensock,
- (struct sockaddr *)&iserv_addr,
- (int*)&length);
- if(proxysock == INVALID_FD) {
- if (sock_errno() != ERRNO_BLOCK) {
- /* We can here for example get the error
- * EMFILE, i.e. no more file descriptors
- * available, but we do not have any specific
- * connection to report the error to. We
- * increment the error counter and saves the
- * last err.
- */
- proxysock_err_cnt++;
- proxysock_last_err = sock_errno();
- DEBUGF(("accept error (proxy_listensock): %s\n",
- psx_errstr()));
- }
- break;
- } else {
- /* Get peer port number */
-/* length = sizeof(iserv_addr); */
-/* if (getpeername(proxysock, (struct sockaddr *)&iserv_addr, */
-/* &length) < 0) { */
-/* DEBUGF(("Can't get peername of proxy socket")); */
-/* safe_close(proxysock); */
-/* } else { */
- /* Add to pending proxy connections */
- SET_NONBLOCKING(proxysock);
- pp = new_proxy(proxysock);
- pp->peer_port = ntohs(iserv_addr.sin_port);
- DEBUGF(("-----------------------------------\n"));
- DEBUGF(("[PROXY_LISTEN_SOCK] conn accepted: "
- "proxyfd = %d, "
- "peer port = %d\n", proxysock, pp->peer_port));
-/* } */
- }
- }
- }
-
- /*
- * Read control messages from Erlang
- */
- if (esock_poll_fd_isset_read(&pollfd, local_read_fd)) {
- cc = read_ctrl(&ebuf);
- if ( cc < 0 ) {
- DEBUGF(("Read loop -1 or 0\n"));
- return -1;
- } else if (cc == 0) { /* not eof */
- DEBUGF(("GOT empty string \n"));
-
- } else {
-
- switch((int)*ebuf) {
-
- case ESOCK_SET_SEED_CMD:
- /*
- * ebuf = {cmd(1), binary(N) }
- */
- input("b", &binlen, &bin);
- DEBUGF(("[SET_SEED_CMD]\n"));
- esock_ssl_seed(bin, binlen);
- /* no reply */
- break;
-
- case ESOCK_GETPEERNAME_CMD:
- /*
- * ebuf = {cmd(1), fd(4)}
- */
- input("4", &fd);
- DEBUGF(("[GETPEERNAME_CMD] fd = %d\n", fd));
- cp = get_connection(fd);
- length = sizeof(iserv_addr);
- if (!cp) {
- sock_set_errno(ERRNO_NOTSOCK);
- reply(ESOCK_GETPEERNAME_ERR, "4s", fd, psx_errstr());
- } else if (getpeername(fd,
- (struct sockaddr *) &iserv_addr,
- &length) < 0) {
- reply(ESOCK_GETPEERNAME_ERR, "4s", fd, psx_errstr());
- } else {
- /*
- * reply = {cmd(1), fd(4), port(2),
- * ipstring(N), 0(1)}
- */
- reply(ESOCK_GETPEERNAME_REP, "42s", fd,
- ntohs(iserv_addr.sin_port),
- inet_ntoa(iserv_addr.sin_addr));
- }
- break;
-
- case ESOCK_GETSOCKNAME_CMD:
- /*
- * ebuf = {cmd(1), fd(4)}
- */
- input("4", &fd);
- DEBUGF(("[GETSOCKNAME_CMD] fd = %d\n", fd));
- cp = get_connection(fd);
- length = sizeof(iserv_addr);
- if (!cp) {
- sock_set_errno(ERRNO_NOTSOCK);
- reply(ESOCK_GETSOCKNAME_ERR, "4s", fd, psx_errstr());
- } else if (getsockname(fd,
- (struct sockaddr *)&iserv_addr,
- &length) < 0) {
- reply(ESOCK_GETSOCKNAME_ERR, "4s", fd, psx_errstr());
- } else {
- /*
- * reply = {cmd(1), fd(4), port(2),
- * ipstring(N), 0(1)}
- */
- reply(ESOCK_GETSOCKNAME_REP, "42s", fd,
- ntohs(iserv_addr.sin_port),
- inet_ntoa(iserv_addr.sin_addr));
- }
- break;
-
- case ESOCK_GETCONNINFO_CMD:
- /*
- * ebuf = {cmd(1), fd(4)}
- */
- input("4", &fd);
- DEBUGF(("[GETCONNINFO_CMD] fd = %d\n", fd));
- cp = get_connection(fd);
- if (!cp) {
- sock_set_errno(ERRNO_NOTSOCK);
- reply(ESOCK_GETCONNINFO_ERR, "4s", fd, psx_errstr());
- } else {
- if (esock_ssl_getprotocol_version(cp,
- &protocol_vsn) < 0)
- reply(ESOCK_GETCONNINFO_ERR, "4s", fd, psx_errstr());
- else if (esock_ssl_getcipher(cp, &cipher) < 0)
- reply(ESOCK_GETCONNINFO_ERR, "4s", fd, psx_errstr());
- else
- /*
- * reply = {cmd(1), fd(4), protocol(N), 0(1),
- * cipher(N), 0(1)}
- */
- reply(ESOCK_GETCONNINFO_REP, "4ss", fd,
- protocol_vsn, cipher);
- }
- break;
-
- case ESOCK_GETPEERCERT_CMD:
- /*
- * ebuf = {cmd(1), fd(4)}
- */
- input("4", &fd);
- DEBUGF(("[GETPEERCERT_CMD] fd = %d\n", fd));
- cp = get_connection(fd);
- if (!cp) {
- sock_set_errno(ERRNO_NOTSOCK);
- reply(ESOCK_GETPEERCERT_ERR, "4s", fd, psx_errstr());
- } else {
- if ((certlen = esock_ssl_getpeercert(cp, &cert)) < 0)
- reply(ESOCK_GETPEERCERT_ERR, "4s", fd, psx_errstr());
- else {
- /*
- * reply = {cmd(1), fd(4), certlen(4), cert(N)}
- */
- reply(ESOCK_GETPEERCERT_REP, "4b", fd,
- certlen, cert);
- esock_free(cert);
- }
- }
- break;
-
- case ESOCK_CONNECT_CMD:
- /*
- * ebuf = {cmd(1), intref(4),
- * lport(2), lipstring(N), 0(1), -- local
- * fport(2), fipstring(N), 0(1), -- foreign
- * flags(N), 0(1)}
- */
- input("42s2ss", &intref, &lport, &lipstring,
- &fport, &fipstring, &flags);
- DEBUGF(("[CONNECT_CMD] intref = %d, "
- "lipstring = %s lport = %d, "
- "fipstring = %s fport = %d, "
- "flags = %s\n", intref, lipstring, lport,
- fipstring, fport, flags));
- connectsock = do_connect(lipstring, lport,
- fipstring, fport);
- if(connectsock == INVALID_FD) {
- reply(ESOCK_CONNECT_SYNC_ERR, "4s", intref, psx_errstr());
- break;
- }
- DEBUGF((" fd = %d\n", connectsock));
- cp = new_connection(ESOCK_WAIT_CONNECT, connectsock);
- cp->origin = ORIG_CONNECT;
- length = strlen(flags);
- cp->flags = esock_malloc(length + 1);
- strcpy(cp->flags, flags);
- DEBUGF(("-> WAIT_CONNECT fd = %d\n", connectsock));
- /* Publish connectsock */
- reply(ESOCK_CONNECT_WAIT_REP, "44", intref, connectsock);
- break;
-
- case ESOCK_TERMINATE_CMD:
- /*
- * ebuf = {cmd(1)}
- */
- exit(EXIT_SUCCESS);
- break;
-
- case ESOCK_CLOSE_CMD:
- /*
- * ebuf = {cmd(1), fd(4)}
- */
- input("4", &fd);
- if ((cp = get_connection(fd))) {
- DEBUGF(("%s[CLOSE_CMD]: fd = %d\n",
- connstr[cp->state], fd));
- if (cp->proxy)
- cp->proxy->bp = 1;
- switch (cp->state) {
- case ESOCK_JOINED:
- cp->close = 1;
- if (JOINED_STATE_INVALID(cp))
- leave_joined_state(cp);
- break;
- case ESOCK_SSL_SHUTDOWN:
- cp->close = 1;
- DEBUGF((" close flag set\n"));
- break;
- default:
- DEBUGF(("-> (removal)\n"));
- close_and_remove_connection(cp);
- }
- } else
- DEBUGF(("[CLOSE_CMD]: ERROR: fd = %d not found\n", fd));
- break;
-
- case ESOCK_SET_SOCKOPT_CMD:
- /*
- * ebuf = {cmd(1), fd(4), op(1), on(1)}
- */
- input("411", &fd, &op, &value);
- switch(op) {
- case ESOCK_SET_TCP_NODELAY:
- if(setsockopt(fd, IPPROTO_TCP, TCP_NODELAY,
- (void *)&value, sizeof(value)) < 0) {
- DEBUGF(("Error: setsockopt TCP_NODELAY\n"));
- reply(ESOCK_IOCTL_ERR, "4s", fd, psx_errstr());
- } else {
- reply(ESOCK_IOCTL_OK, "4", fd);
- }
- break;
- default:
- DEBUGF(("Error: set_sock_opt - Not implemented\n"));
- sock_set_errno(ERRNO_OPNOTSUPP);
- reply(ESOCK_IOCTL_ERR, "4", fd, psx_errstr());
- break;
- }
- break;
-
- case ESOCK_LISTEN_CMD:
- /*
- * ebuf = {cmd(1), intref(4), lport(2), ipstring(N), 0(1),
- * backlog(2), flags(N), 0(1)}
- */
- input("42s2s", &intref, &lport, &lipstring, &backlog,
- &flags);
- DEBUGF(("[LISTEN_CMD] intref = %d, port = %d, "
- "ipstring = %s, backlog = %d, flags = %s\n",
- intref, lport, lipstring, backlog, flags));
-
- listensock = do_listen(lipstring, lport, backlog, &lport);
- if(listensock == INVALID_FD) {
- reply(ESOCK_LISTEN_SYNC_ERR, "4s", intref, psx_errstr());
- break;
- }
- cp = new_connection(ESOCK_PASSIVE_LISTENING, listensock);
- /* Flags may be an empty string */
- length = strlen(flags);
- cp->flags = esock_malloc(length + 1);
- strcpy(cp->flags, flags);
-
- cp->origin = ORIG_LISTEN;
- if (esock_ssl_listen_init(cp) < 0) {
- DEBUGF(("esock_ssl_listen_init() failed.\n"));
- reply(ESOCK_LISTEN_SYNC_ERR, "4s", intref,
- ssl_errstr());
- close_and_remove_connection(cp);
- break;
- }
- DEBUGF(("-> PASSIVE_LISTENING (fd = %d)\n", listensock));
- /* Publish listensock */
- reply(ESOCK_LISTEN_REP, "442", intref, listensock,
- ntohs(iserv_addr.sin_port));
- break;
-
- case ESOCK_TRANSPORT_ACCEPT_CMD:
- /*
- * ebuf = { op(1), fd(4), flags(N), 0(1)}
- */
- input("4s", &fd, &flags);
- DEBUGF(("[TRANSPORT_ACCEPT_CMD] listenfd = %d, flags = %s\n", fd,
- flags));
- cp = get_connection(fd);
- if (cp) {
- /* We store the flags in the listen socket's
- * connection, and overwrite previous flags.
- */
- if ((length = strlen(flags)) > 0) {
- if (cp->flags)
- cp->flags = esock_realloc(cp->flags,
- length + 1);
- else
- cp->flags = esock_malloc(length + 1);
- strcpy(cp->flags, flags);
- }
- if (cp->flags && cp->flags[0] != '\0') {
- cp->acceptors++;
- cp->state = ESOCK_ACTIVE_LISTENING;
- DEBUGF(("-> ACTIVE_LISTENING\n"));
- break;
- }
- DEBUGF(("ERROR: flags empty\n"));
- }
- reply(ESOCK_TRANSPORT_ACCEPT_ERR, "4s", fd, "ebadf");
- break;
-
- case ESOCK_SSL_ACCEPT_CMD:
- input("4s", &fd, &flags);
- DEBUGF(("[SSL_ACCEPT_CMD] fd = %d, flags = %s\n", fd, flags));
- cp = get_connection(fd);
- if (cp)
- cp->state = ESOCK_SSL_ACCEPT;
- //reply(ESOCK_SSL_ACCEPT_REP, "4", fd);
- break;
-
- case ESOCK_NOACCEPT_CMD:
- /*
- * ebuf = {cmd(1), fd(4)}
- */
- input("4", &fd);
- DEBUGF(("[NOACCEPT_CMD] listenfd = %d\n", fd));
- cp = get_connection(fd);
- if (cp && (--cp->acceptors <= 0)) {
- cp->acceptors = 0;
- cp->state = ESOCK_PASSIVE_LISTENING;
- esock_poll_clear_event(&pollfd, fd);
- DEBUGF(("-> PASSIVE_LISTENING\n"));
- }
- break;
-
- case ESOCK_PROXY_JOIN_CMD:
- /*
- * ebuf = {cmd(1), fd(4), portnum(2)}
- *
- * fd - file descriptor of a connection in state
- * CONNECTED
- * portnum - port number of the Erlang proxy peer
- */
- input("42", &fd, &pport);
- cp = get_connection(fd);
- pp = get_proxy_by_peerport(pport);
- if (cp && cp->state == ESOCK_CONNECTED && pp) {
- DEBUGF(("CONNECTED[PROXY_JOIN_CMD] fd = %d "
- "portnum = %d\n", fd, pport));
- cp->proxy = pp;
- pp->conn = cp;
- reply(ESOCK_PROXY_JOIN_REP, "4", fd);
- cp->state = ESOCK_JOINED;
- DEBUGF(("-> JOINED\n"));
- break;
- }
- if (!cp) {
- DEBUGF(("[PROXY_JOIN_CMD] ERROR: No connection "
- "having fd = %d\n", fd));
- reply(ESOCK_PROXY_JOIN_ERR, "4s", fd, "ebadsocket");
- } else if (cp->state != ESOCK_CONNECTED) {
- DEBUGF(("%s[PROXY_JOIN_CMD] ERROR: Bad state: "
- "fd = %d\n", connstr[cp->state], cp->fd));
- reply(ESOCK_PROXY_JOIN_ERR, "4s", fd, "ebadstate");
- } else {
- DEBUGF(("ERROR: No proxy: fd = %d, pport = %d\n",
- fd, pport));
- if (proxysock_err_cnt > 0) {
- proxysock_err_cnt--;
- reply(ESOCK_PROXY_JOIN_ERR, "4s", fd,
- esock_posix_str(proxysock_last_err));
- } else {
- reply(ESOCK_PROXY_JOIN_ERR, "4s", fd,
- "enoproxysocket");
- }
- cp->state = ESOCK_DEFUNCT;
- }
- break;
-
- case ESOCK_DUMP_STATE_CMD:
- dump_connections();
- break;
-
- case ESOCK_SET_DEBUG_CMD:
- /*
- * ebuf = {cmd(1), debug(1)}
- */
- input("1", &debug);
- break;
-
- case ESOCK_SET_DEBUGMSG_CMD:
- /*
- * ebuf = {cmd(1), debugmsg(1)}
- */
- input("1", &debugmsg);
- break;
-
- default:
- fprintf(stderr, "esock: default value in loop %c\n",
- *ebuf);
- exit(EXIT_FAILURE);
- break;
- }
- }
- }
-
- /* Go through all connections that have their file descriptors
- set. */
-
- /* Note: We may remove the current connection (cp). Thus we
- * must be careful not to read cp->next after cp has been
- * removed. */
- for (cp = next_polled_conn(connections, &cpnext, &pollfd, set_wq_fds);
- cp != NULL;
- cp = next_polled_conn(cpnext, &cpnext, &pollfd, set_wq_fds)
- ) {
-
- switch(cp->state) {
-
- case ESOCK_PASSIVE_LISTENING:
- DEBUGF(("-----------------------------------\n"));
- fprintf(stderr, "esock: Got connect request while PASSIVE\n");
- exit(EXIT_FAILURE);
- break;
-
- case ESOCK_ACTIVE_LISTENING:
- /* new connect from network */
- DEBUGF(("-----------------------------------\n"));
- DEBUGF(("ACTIVE_LISTENING - trying to accept on %d\n",
- cp->fd));
- length = sizeof(iserv_addr);
- msgsock = do_accept(cp->fd, (struct sockaddr*)&iserv_addr,
- (int*)&length);
- if(msgsock == INVALID_FD) {
- DEBUGF(("accept error: %s\n", psx_errstr()));
- reply(ESOCK_TRANSPORT_ACCEPT_ERR, "4s", cp->fd, psx_errstr());
- break;
- }
- SET_NONBLOCKING(msgsock);
- if (--cp->acceptors <= 0) {
- cp->acceptors = 0;
- cp->state = ESOCK_PASSIVE_LISTENING;
- DEBUGF(("-> PASSIVE_LISTENING\n"));
- }
- DEBUGF(("server accepted connection on fd %d\n", msgsock));
- newcp = new_connection(ESOCK_TRANSPORT_ACCEPT, msgsock);
- newcp->origin = ORIG_ACCEPT;
- reply(ESOCK_TRANSPORT_ACCEPT_REP, "44", cp->fd, msgsock);
- newcp->listen_fd = cp->fd; /* Needed for ESOCK_ACCEPT_ERR */
- length = strlen(cp->flags);
- /* XXX new flags are not needed */
- newcp->flags = esock_malloc(length + 1);
- strcpy(newcp->flags, cp->flags); /* XXX Why? */
- if (esock_ssl_accept_init(newcp, cp->opaque) < 0) {
- cp->errstr = ssl_errstr();
- break;
- }
- newcp->ssl_want = ESOCK_SSL_WANT_READ;
- break;
-
- case ESOCK_SSL_ACCEPT:
- /* SSL accept handshake. msgsock is *not* published yet. */
- msgsock = cp->fd;
- DEBUGF(("-----------------------------------\n"));
- DEBUGF(("SSL_ACCEPT fd = %d\n", msgsock));
- if (cp->errstr != NULL) { /* this means we got an error in ssl_accept_init */
- /* N.B.: The *listen fd* is reported. */
- reply(ESOCK_SSL_ACCEPT_ERR, "4s", msgsock, cp->errstr);
- close_and_remove_connection(cp);
- break;
- }
- if (esock_ssl_accept(cp) < 0) {
- if (sock_errno() != ERRNO_BLOCK) {
- /* Handshake failed. */
- reply(ESOCK_SSL_ACCEPT_ERR, "4s", msgsock,
- ssl_errstr());
- DEBUGF(("ERROR: handshake: %s\n", ssl_errstr()));
- close_and_remove_connection(cp);
- }
- } else {
- /* SSL handshake successful: publish */
- reply(ESOCK_SSL_ACCEPT_REP, "4", msgsock);
- DEBUGF(("-> CONNECTED\n"));
- DEBUGF((" Session was %sreused.\n",
- (esock_ssl_session_reused(cp)) ? "" : "NOT "));
- cp->state = ESOCK_CONNECTED;
- }
- break;
-
- case ESOCK_CONNECTED:
- /* Should not happen. We do not read or write until
- the connection is in state JOINED. */
- DEBUGF(("-----------------------------------\n"));
- DEBUGF(("CONNECTED: Error: should not happen. fd = %d\n",
- cp->fd));
- break;
-
- case ESOCK_JOINED:
- /*
- * Reading from Proxy, writing to SSL
- */
- if (esock_poll_fd_isset_write(&pollfd, cp->fd)) {
- /* If there is a write queue, write to ssl only */
- if (cp->wq.len > 0) {
- /* The write retry semantics of SSL_write in
- * the OpenSSL package is strange. Partial
- * writes never occur, only complete writes or
- * failures. A failure, however, still
- * consumes all data written, although not all
- * encrypted data could be written to the
- * underlying socket. To retry a write we have
- * to provide the same buf and length as in
- * the original call, in our case rwbuf and
- * the original buffer length. Hence the
- * strange memcpy(). Note that wq.offset will
- * always be zero when we use OpenSSL.
- */
- DEBUGF(("-----------------------------------\n"));
- DEBUGF(("JOINED: writing to ssl "
- "fd = %d, from write queue only, wc = %d\n",
- cp->fd, cp->wq.len - cp->wq.offset));
- memcpy(rwbuf, cp->wq.buf, cp->wq.len - cp->wq.offset);
-
- /* esock_ssl_write sets cp->eof, cp->bp when return
- * value is zero */
- wc = esock_ssl_write(cp, rwbuf,
- cp->wq.len - cp->wq.offset);
- if (wc < 0) {
- if (sock_errno() != ERRNO_BLOCK) {
- /* Assume broken SSL pipe */
- DEBUGF(("broken SSL pipe\n"));
- cp->bp = 1;
- shutdown(cp->proxy->fd, SHUTDOWN_READ);
- cp->proxy->eof = 1;
- if (JOINED_STATE_INVALID(cp)) {
- leave_joined_state(cp);
- break;
- }
- }
- } else if (wc == 0) {
- /* SSL broken pipe */
- DEBUGF(("broken SSL pipe\n"));
- cp->bp = 1;
- shutdown(cp->proxy->fd, SHUTDOWN_READ);
- cp->proxy->eof = 1;
- if (JOINED_STATE_INVALID(cp)) {
- leave_joined_state(cp);
- break;
- }
- } else {
- cp->wq.offset += wc;
- if (cp->wq.offset == cp->wq.len)
- cp->wq.len = 0;
- }
- }
- } else if (esock_poll_fd_isset_read(&pollfd, cp->proxy->fd)) {
- /* Read from proxy and write to SSL */
- DEBUGF(("-----------------------------------\n"));
- DEBUGF(("JOINED: reading from proxy, "
- "proxyfd = %d\n", cp->proxy->fd));
- cc = sock_read(cp->proxy->fd, rwbuf, RWBUFLEN);
- DEBUGF(("read from proxyfd = %d, cc = %d\n",
- cp->proxy->fd, cc));
- if (cc > 0) {
- /* esock_ssl_write sets cp->eof, cp->bp when return
- * value is zero */
- wc = esock_ssl_write(cp, rwbuf, cc);
- if (wc < 0) {
- if (sock_errno() != ERRNO_BLOCK) {
- /* Assume broken pipe */
- DEBUGF(("broken SSL pipe\n"));
- cp->bp = 1;
- shutdown(cp->proxy->fd, SHUTDOWN_READ);
- cp->proxy->eof = 1;
- if (JOINED_STATE_INVALID(cp)) {
- leave_joined_state(cp);
- break;
- }
- } else {
- /* add to write queue */
- DEBUGF(("adding all to write queue "
- "%d bytes\n", cc));
- ensure_write_queue(&cp->wq, cc);
- memcpy(cp->wq.buf, rwbuf, cc);
- cp->wq.len = cc;
- cp->wq.offset = 0;
- }
- } else if (wc == 0) {
- /* Broken SSL pipe */
- DEBUGF(("broken SSL pipe\n"));
- cp->bp = 1;
- shutdown(cp->proxy->fd, SHUTDOWN_READ);
- cp->proxy->eof = 1;
- if (JOINED_STATE_INVALID(cp)) {
- leave_joined_state(cp);
- break;
- }
- } else if (wc < cc) {
- /* add remainder to write queue */
- DEBUGF(("adding remainder to write queue "
- "%d bytes\n", cc - wc));
- ensure_write_queue(&cp->wq, cc - wc);
- memcpy(cp->wq.buf, rwbuf + wc, cc - wc);
- cp->wq.len = cc - wc;
- cp->wq.offset = 0;
- }
- } else {
- /* EOF proxy or error */
- DEBUGF(("proxy eof or error %d\n", errno));
- cp->proxy->eof = 1;
- if (cp->wq.len == 0) {
- esock_ssl_shutdown(cp);
- cp->bp = 1;
- }
- if (JOINED_STATE_INVALID(cp)) {
- leave_joined_state(cp);
- break;
- }
- }
- }
- /*
- * Reading from SSL, writing to proxy
- */
- if (esock_poll_fd_isset_write(&pollfd, cp->proxy->fd)) {
- /* If there is a write queue, write to proxy only */
- if (cp->proxy->wq.len > 0) {
- DEBUGF(("-----------------------------------\n"));
- DEBUGF(("JOINED: writing to proxyfd = %d, "
- "from write queue only, wc = %d\n",
- cp->proxy->fd, cp->proxy->wq.len -
- cp->proxy->wq.offset));
- wc = sock_write(cp->proxy->fd, cp->proxy->wq.buf +
- cp->proxy->wq.offset,
- cp->proxy->wq.len -
- cp->proxy->wq.offset);
- if (wc < 0) {
- if (sock_errno() != ERRNO_BLOCK) {
- /* Assume broken pipe */
- DEBUGF(("broken proxy pipe\n"));
- cp->proxy->bp = 1;
- /* There is no SSL shutdown for read */
- cp->eof = 1;
- if (JOINED_STATE_INVALID(cp)) {
- leave_joined_state(cp);
- break;
- }
- }
- } else {
- cp->proxy->wq.offset += wc;
- if (cp->proxy->wq.offset == cp->proxy->wq.len)
- cp->proxy->wq.len = 0;
- }
- }
- } else if (esock_poll_fd_isset_read(&pollfd, cp->fd)) {
- /* Read from SSL and write to proxy */
- DEBUGF(("-----------------------------------\n"));
- DEBUGF(("JOINED: read from ssl fd = %d\n",
- cp->fd));
- cc = esock_ssl_read(cp, rwbuf, RWBUFLEN);
- DEBUGF(("read from fd = %d, cc = %d\n", cp->fd, cc));
- if (cc > 0) {
- wc = sock_write(cp->proxy->fd, rwbuf, cc);
- if (wc < 0) {
- if (sock_errno() != ERRNO_BLOCK) {
- DEBUGF(("broken proxy pipe\n"));
- /* Assume broken pipe */
- cp->proxy->bp = 1;
- /* There is no SSL shutdown for read */
- cp->eof = 1;
- if (JOINED_STATE_INVALID(cp)) {
- leave_joined_state(cp);
- break;
- }
- } else {
- /* add all to write queue */
- DEBUGF(("adding to write queue %d bytes\n",
- cc));
- ensure_write_queue(&cp->proxy->wq, cc);
- memcpy(cp->proxy->wq.buf, rwbuf, cc);
- cp->proxy->wq.len = cc;
- cp->proxy->wq.offset = 0;
- }
- } else if (wc < cc) {
- /* add to write queue */
- DEBUGF(("adding to write queue %d bytes\n",
- cc - wc));
- ensure_write_queue(&cp->proxy->wq, cc - wc);
- memcpy(cp->proxy->wq.buf, rwbuf + wc, cc - wc);
- cp->proxy->wq.len = cc - wc;
- cp->proxy->wq.offset = 0;
- }
- } else if (cc == 0) {
- /* SSL eof */
- DEBUGF(("SSL eof\n"));
- cp->eof = 1;
- if (cp->proxy->wq.len == 0) {
- shutdown(cp->proxy->fd, SHUTDOWN_WRITE);
- cp->proxy->bp = 1;
- }
- if (JOINED_STATE_INVALID(cp)) {
- leave_joined_state(cp);
- break;
- }
- } else {
- /* This may very well happen when reading from SSL. */
- DEBUGF(("NOTE: readmask set, cc < 0, fd = %d, "
- "is ok\n", cp->fd));
- }
- }
- break;
-
- case ESOCK_SSL_SHUTDOWN:
- DEBUGF(("-----------------------------------\n"));
- DEBUGF(("SSL_SHUTDOWN: fd = %d\n", cp->fd));
- do_shutdown(cp);
- break;
-
- case ESOCK_DEFUNCT:
- DEBUGF(("-----------------------------------\n"));
- DEBUGF(("DEFUNCT: ERROR: should not happen. fd = %d\n",
- cp->fd));
- break;
-
- case ESOCK_WAIT_CONNECT:
- /* New connection shows up */
- connectsock = cp->fd;/* Is published */
- DEBUGF(("-----------------------------------\n"));
- DEBUGF(("WAIT_CONNECT fd = %d\n", connectsock));
-
- /* If the connection did succeed it's possible to
- * fetch the peer name (UNIX); or failure shows in
- * exceptmask (WIN32). Sorry for the mess below, but
- * we have to have balanced paren's in #ifdefs in
- * order not to confuse Emacs' indentation. */
- length = sizeof(iserv_addr);
- if (
-#ifdef __WIN32__
- esock_poll_fd_isset_exception(&pollfd, connectsock)
-#else
- getpeername(connectsock, (struct sockaddr *)&iserv_addr,
- &length) < 0
-#endif
- ) {
- sock_set_errno(ERRNO_CONNREFUSED);
- DEBUGF(("connect error: %s\n", psx_errstr()));
- reply(ESOCK_CONNECT_ERR, "4s", connectsock, psx_errstr());
- cp->state = ESOCK_DEFUNCT;
- break;
- }
- if (esock_ssl_connect_init(cp) < 0) {
- DEBUGF(("esock_ssl_connect_init() failed\n"));
- reply(ESOCK_CONNECT_ERR, "4s", connectsock, ssl_errstr());
- cp->state = ESOCK_DEFUNCT;
- break;
- }
- DEBUGF(("-> SSL_CONNECT\n"));
- cp->state = ESOCK_SSL_CONNECT;
- cp->ssl_want = ESOCK_SSL_WANT_WRITE;
- break;
-
- case ESOCK_SSL_CONNECT:
- /* SSL connect handshake. connectsock is published. */
- connectsock = cp->fd;
- DEBUGF(("-----------------------------------\n"));
- DEBUGF(("SSL_CONNECT fd = %d\n", connectsock));
- if (esock_ssl_connect(cp) < 0) {
- if (sock_errno() != ERRNO_BLOCK) {
- /* Handshake failed */
- DEBUGF(("ERROR: handshake: %s\n", ssl_errstr()));
- reply(ESOCK_CONNECT_ERR, "4s", connectsock,
- ssl_errstr());
- cp->state = ESOCK_DEFUNCT;
- }
- } else {
- /* SSL connect handshake successful */
- DEBUGF(("-> CONNECTED\n"));
- reply(ESOCK_CONNECT_REP, "4", connectsock);
- cp->state = ESOCK_CONNECTED;
- }
- break;
-
- default:
- DEBUGF(("ERROR: Connection in unknown state.\n"));
- }
- }
- }
-}
-
-static int set_poll_conns(Connection *cp, EsockPoll *ep, int verbose)
-{
- int i = 0;
-
- if (verbose)
- DEBUGF(("MASKS SET FOR FD: "));
- while (cp) {
- switch (cp->state) {
- case ESOCK_ACTIVE_LISTENING:
- if (verbose)
- DEBUGF(("%d (read) ", cp->fd));
- esock_poll_fd_set_read(ep, cp->fd);
- break;
- case ESOCK_WAIT_CONNECT:
- if (verbose)
- DEBUGF(("%d (write) ", cp->fd));
- esock_poll_fd_set_write(ep, cp->fd);
-#ifdef __WIN32__
- esock_poll_fd_set_exception(ep, cp->fd); /* Failure shows in exceptions */
-#endif
- break;
- case ESOCK_SSL_CONNECT:
- case ESOCK_SSL_ACCEPT:
- if (cp->ssl_want == ESOCK_SSL_WANT_READ) {
- if (verbose)
- DEBUGF(("%d (read) ", cp->fd));
- esock_poll_fd_set_read(ep, cp->fd);
- } else if (cp->ssl_want == ESOCK_SSL_WANT_WRITE) {
- if (verbose)
- DEBUGF(("%d (write) ", cp->fd));
- esock_poll_fd_set_write(ep, cp->fd);
- }
- break;
- case ESOCK_JOINED:
- if (!cp->bp) {
- if (cp->wq.len) {
- if (verbose)
- DEBUGF(("%d (write) ", cp->fd));
- esock_poll_fd_set_write(ep, cp->fd);
- } else if (!cp->proxy->eof) {
- if (verbose)
- DEBUGF(("%d (read) ", cp->proxy->fd));
- esock_poll_fd_set_read(ep, cp->proxy->fd);
- }
- }
- if (!cp->proxy->bp) {
- if (cp->proxy->wq.len) {
- if (verbose)
- DEBUGF(("%d (write) ", cp->proxy->fd));
- esock_poll_fd_set_write(ep, cp->proxy->fd);
- } else if (!cp->eof) {
- if (verbose)
- DEBUGF(("%d (read) ", cp->fd));
- esock_poll_fd_set_read(ep, cp->fd);
- }
- }
- break;
- case ESOCK_SSL_SHUTDOWN:
- if (cp->ssl_want == ESOCK_SSL_WANT_READ) {
- if (verbose)
- DEBUGF(("%d (read) ", cp->fd));
- esock_poll_fd_set_read(ep, cp->fd);
- } else if (cp->ssl_want == ESOCK_SSL_WANT_WRITE) {
- if (verbose)
- DEBUGF(("%d (write) ", cp->fd));
- esock_poll_fd_set_write(ep, cp->fd);
- }
- break;
- default:
- break;
- }
- i++;
- cp = cp->next;
- }
- if (verbose)
- DEBUGF(("\n"));
- return i;
-}
-
-
-static Connection *next_polled_conn(Connection *cp, Connection **cpnext,
- EsockPoll *ep, int set_wq_fds)
-{
- while(cp) {
- if (esock_poll_fd_isset_read(ep, cp->fd) ||
- (cp->proxy && esock_poll_fd_isset_read(ep, cp->proxy->fd)) ||
- (esock_poll_fd_isset_write(ep, cp->fd)) ||
- (cp->proxy && esock_poll_fd_isset_write(ep, cp->proxy->fd))
-#ifdef __WIN32__
- || esock_poll_fd_isset_exception(ep, cp->fd) /* Connect failure in WIN32 */
-#endif
- || (set_wq_fds && (cp->wq.len ||
- (cp->proxy && cp->proxy->wq.len)))
- || cp->errstr != NULL) {
- *cpnext = cp->next;
- return cp;
- }
- cp = cp->next;
- }
- *cpnext = NULL;
- return NULL;
-}
-
-static void leave_joined_state(Connection *cp)
-{
- shutdown(cp->proxy->fd, SHUTDOWN_ALL);
- if (((cp->bp || cp->eof) && cp->clean) ||
- (!cp->bp && !cp->eof)) {
- DEBUGF(("-> SSL_SHUTDOWN\n"));
- cp->state = ESOCK_SSL_SHUTDOWN;
- cp->ssl_want = ESOCK_SSL_WANT_WRITE;
- do_shutdown(cp);
- } else if (cp->close) {
- DEBUGF(("-> (removal)\n"));
- close_and_remove_connection(cp);
- } else {
- DEBUGF(("-> DEFUNCT\n"));
- cp->state = ESOCK_DEFUNCT;
- }
-}
-
-/* We are always in state SHUTDOWN here */
-static void do_shutdown(Connection *cp)
-{
- int ret;
-
- ret = esock_ssl_shutdown(cp);
- if (ret < 0) {
- if (sock_errno() == ERRNO_BLOCK) {
- return;
- } else {
- /* Something is wrong -- close and remove or move to DEFUNCT */
- DEBUGF(("Error in SSL shutdown\n"));
- if (cp->close) {
- DEBUGF(("-> (removal)\n"));
- close_and_remove_connection(cp);
- } else {
- DEBUGF(("-> DEFUNCT\n"));
- cp->state = ESOCK_DEFUNCT;
- }
- }
- } else if (ret == 0) {
- /* `close_notify' has been sent. Wait for reception of
- same. */
- return;
- } else if (ret == 1) {
- /* `close_notify' has been sent, and received. */
- if (cp->close) {
- DEBUGF(("-> (removal)\n"));
- close_and_remove_connection(cp);
- } else {
- DEBUGF(("-> DEFUNCT\n"));
- cp->state = ESOCK_DEFUNCT;
- }
- }
-}
-
-static void close_and_remove_connection(Connection *cp)
-{
- safe_close(cp->fd);
- remove_connection(cp);
-}
-
-static int reply(int cmd, char *fmt, ...)
-{
- static unsigned char replybuf[MAXREPLYBUF];
- unsigned char *buf = replybuf;
- va_list args;
- int len;
-
- va_start(args, fmt);
- len = put_pars(NULL, fmt, args);
- va_end(args);
- len++;
- if (len > sizeof(replybuf))
- buf = esock_malloc(len);
-
- PUT_INT8(cmd, buf);
- va_start(args, fmt);
- (void) put_pars(buf + 1, fmt, args);
- va_end(args);
- write_ctrl(buf, len);
- if (buf != replybuf)
- esock_free(buf);
- return len;
-}
-
-static int input(char *fmt, ...)
-{
- va_list args;
- int len;
-
- va_start(args, fmt);
- len = get_pars(ebuf + 1, fmt, args);
- va_end(args);
- return len + 1;
-}
-
-static int put_pars(unsigned char *buf, char *fmt, va_list args)
-{
- char *s, *str, *bin;
- int val, len, pos = 0;
-
- s = fmt;
- while (*s) {
- switch (*s) {
- case '1':
- val = va_arg(args, int);
- if (buf)
- PUT_INT8(val, buf + pos);
- pos++;
- break;
- case '2':
- val = va_arg(args, int);
- if (buf)
- PUT_INT16(val, buf + pos);
- pos += 2;
- break;
- case '4':
- val = va_arg(args, int);
- if (buf)
- PUT_INT32(val, buf + pos);
- pos += 4;
- break;
- case 's': /* string */
- str = va_arg(args, char *);
- if (buf)
- strcpy((char *)(buf + pos), str);
- pos += strlen(str) + 1;
- break;
- case 'b': /* binary */
- len = va_arg(args, int);
- if (buf)
- PUT_INT32(len, buf + pos);
- pos += 4;
- bin = va_arg(args, char *);
- if (buf)
- memcpy(buf + pos, bin, len);
- pos += len;
- break;
- default:
- fprintf(stderr, "esock: Invalid format character: %c\n", *s);
- exit(EXIT_FAILURE);
- break;
- }
- s++;
- }
- return pos;
-}
-
-
-static int get_pars(unsigned char *buf, char *fmt, va_list args)
-{
- int *ip;
- char *s, **strp, **bin;
- int pos = 0;
-
- s = fmt;
- while (*s) {
- switch (*s) {
- case '1':
- ip = va_arg(args, int *);
- *ip = GET_INT8(buf + pos);
- pos++;
- break;
- case '2':
- ip = va_arg(args, int *);
- *ip = GET_INT16(buf + pos);
- pos += 2;
- break;
- case '4':
- ip = va_arg(args, int *);
- *ip = GET_INT32(buf + pos);
- pos += 4;
- break;
- case 's':
- strp = va_arg(args, char **);
- *strp = (char *)(buf + pos);
- pos += strlen(*strp) + 1;
- break;
- case 'b':
- ip = va_arg(args, int *);
- *ip = GET_INT32(buf + pos);
- pos += 4;
- bin = va_arg(args, char **);
- *bin = (char *)(buf + pos);
- pos += *ip;
- break;
- default:
- fprintf(stderr, "esock: Invalid format character: %c\n", *s);
- exit(EXIT_FAILURE);
- break;
- }
- s++;
- }
- return pos;
-}
-
-static FD do_connect(char *lipstring, int lport, char *fipstring, int fport)
-{
- struct sockaddr_in sock_addr;
- long inaddr;
- FD fd;
-
- if ((fd = socket(AF_INET, SOCK_STREAM, 0)) == INVALID_FD) {
- DEBUGF(("Error calling socket()\n"));
- return fd;
- }
- if (check_num_sock_fds(fd) < 0)
- return INVALID_FD;
- DEBUGF((" fd = %d\n", fd));
-
- /* local */
- if ((inaddr = inet_addr(lipstring)) == INADDR_NONE) {
- DEBUGF(("Error in inet_addr(): lipstring = %s\n", lipstring));
- safe_close(fd);
- sock_set_errno(ERRNO_ADDRNOTAVAIL);
- return INVALID_FD;
- }
- memset(&sock_addr, 0, sizeof(sock_addr));
- sock_addr.sin_family = AF_INET;
- sock_addr.sin_addr.s_addr = inaddr;
- sock_addr.sin_port = htons(lport);
- if(bind(fd, (struct sockaddr*) &sock_addr, sizeof(sock_addr)) < 0) {
- DEBUGF(("Error in bind()\n"));
- safe_close(fd);
- /* XXX Set error code for bind error */
- return INVALID_FD;
- }
-
- /* foreign */
- if ((inaddr = inet_addr(fipstring)) == INADDR_NONE) {
- DEBUGF(("Error in inet_addr(): fipstring = %s\n", fipstring));
- safe_close(fd);
- sock_set_errno(ERRNO_ADDRNOTAVAIL);
- return INVALID_FD;
- }
- memset(&sock_addr, 0, sizeof(sock_addr));
- sock_addr.sin_family = AF_INET;
- sock_addr.sin_addr.s_addr = inaddr;
- sock_addr.sin_port = htons(fport);
-
- SET_NONBLOCKING(fd);
-
- if(connect(fd, (struct sockaddr*)&sock_addr, sizeof(sock_addr)) < 0) {
- if (sock_errno() != ERRNO_PROGRESS && /* UNIX */
- sock_errno() != ERRNO_BLOCK) { /* WIN32 */
- DEBUGF(("Error in connect()\n"));
- safe_close(fd);
- return INVALID_FD;
- }
- }
- return fd;
-}
-
-static FD do_listen(char *ipstring, int lport, int backlog, int *aport)
-{
- static int one = 1; /* Type must be int, not long */
- struct sockaddr_in sock_addr;
- long inaddr;
- int length;
- FD fd;
-
- if ((fd = socket(AF_INET, SOCK_STREAM, 0)) == INVALID_FD) {
- DEBUGF(("Error calling socket()\n"));
- return fd;
- }
- if (check_num_sock_fds(fd) < 0)
- return INVALID_FD;
- DEBUGF((" fd = %d\n", fd));
- if ((inaddr = inet_addr(ipstring)) == INADDR_NONE) {
- DEBUGF(("Error in inet_addr(): ipstring = %s\n", ipstring));
- safe_close(fd);
- sock_set_errno(ERRNO_ADDRNOTAVAIL);
- return INVALID_FD;
- }
- memset(&sock_addr, 0, sizeof(sock_addr));
- sock_addr.sin_family = AF_INET;
- sock_addr.sin_addr.s_addr = inaddr;
- sock_addr.sin_port = htons(lport);
-
- setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (void *)&one, sizeof(one));
-
- if(bind(fd, (struct sockaddr*) &sock_addr, sizeof(sock_addr)) < 0) {
- DEBUGF(("Error in bind()\n"));
- safe_close(fd);
- return INVALID_FD;
- }
- if (listen(fd, backlog) < 0) {
- DEBUGF(("Error in listen()\n"));
- safe_close(fd);
- return INVALID_FD;
- }
- /* find out assigned local port number */
- length = sizeof(sock_addr);
- if (getsockname(fd, (struct sockaddr *)&sock_addr, &length) < 0) {
- DEBUGF(("Error in getsockname()\n"));
- safe_close(fd);
- return INVALID_FD;
- }
- if (aport)
- *aport = ntohs(sock_addr.sin_port);
- return fd;
-}
-
-static FD do_accept(FD listensock, struct sockaddr *saddr, int *len)
-{
- FD fd;
-
- if ((fd = accept(listensock, saddr, len)) == INVALID_FD) {
- DEBUGF(("Error calling accept()\n"));
- return fd;
- }
- if (check_num_sock_fds(fd) < 0)
- return INVALID_FD;
- return fd;
-}
-
-static Connection *new_connection(int state, FD fd)
-{
- Connection *cp;
-
- if (!(cp = esock_malloc(sizeof(Connection))))
- return NULL;
- cp->state = state;
- cp->acceptors = 0;
- cp->fd = fd;
- cp->listen_fd = INVALID_FD;
- cp->proxy = NULL;
- cp->opaque = NULL;
- cp->ssl_want = 0;
- cp->eof = 0;
- cp->bp = 0;
- cp->clean = 0; /* XXX Used? */
- cp->close = 0;
- cp->origin = -1;
- cp->flags = NULL;
- cp->logfp = NULL;
- cp->wq.size = 0;
- cp->wq.buf = NULL;
- cp->wq.len = 0;
- cp->wq.offset = 0;
- cp->next = connections;
- cp->errstr = NULL;
- connections = cp;
- return cp;
-}
-
-
-static void print_connections(void)
-{
- if (debug) {
- Connection *cp = connections;
- DEBUGF(("CONNECTIONS:\n"));
- while (cp) {
- if (cp->state == ESOCK_JOINED) {
- DEBUGF((" - %s [%8p] (origin = %s)\n"
- " (fd = %d, eof = %d, wq = %d, bp = %d)\n"
- " (proxyfd = %d, eof = %d, wq = %d, bp = %d)\n",
- connstr[cp->state], cp, originstr[cp->origin],
- cp->fd, cp->eof, cp->wq.len, cp->bp,
- cp->proxy->fd, cp->proxy->eof, cp->proxy->wq.len,
- cp->proxy->bp));
- } else if (cp->state == ESOCK_ACTIVE_LISTENING) {
- DEBUGF((" - %s [%8p] (fd = %d, acceptors = %d)\n",
- connstr[cp->state], cp, cp->fd, cp->acceptors));
- } else {
- DEBUGF((" - %s [%8p] (fd = %d)\n", connstr[cp->state], cp,
- cp->fd));
- }
- cp= cp->next;
- }
- }
-}
-
-static void dump_connections(void)
-{
- Connection *cp = connections;
- Proxy *pp = proxies;
- time_t t = time(NULL);
- int length = 0;
- struct sockaddr_in iserv_addr;
-
- __debugprintf("CONNECTIONS %s", ctime(&t));
- while (cp) {
- if (cp->state == ESOCK_JOINED) {
- __debugprintf(" - %s [%8p] (origin = %s)\n"
- " (fd = %d, eof = %d, wq = %d, bp = %d), close = %d\n"
- " (proxyfd = %d, eof = %d, wq = %d, bp = %d)\n",
- connstr[cp->state], cp, originstr[cp->origin],
- cp->fd, cp->eof, cp->wq.len, cp->bp, cp->close,
- cp->proxy->fd, cp->proxy->eof, cp->proxy->wq.len,
- cp->proxy->bp);
- } else if (cp->state == ESOCK_ACTIVE_LISTENING) {
- __debugprintf(" - %s [%8p] (fd = %d, acceptors = %d)\n",
- connstr[cp->state], cp, cp->fd, cp->acceptors);
- } else {
- __debugprintf(" - %s [%8p] (fd = %d)\n", connstr[cp->state], cp,
- cp->fd);
- }
- length = sizeof(iserv_addr);
- if ((cp->state == ESOCK_ACTIVE_LISTENING) ||
- (cp->state == ESOCK_PASSIVE_LISTENING)) {
- getsockname(cp->fd, (struct sockaddr *) &iserv_addr, &length);
- __debugprintf(" (ip = %s, port = %d)\n",
- inet_ntoa(iserv_addr.sin_addr),
- ntohs(iserv_addr.sin_port));
- }
- else {
- getsockname(cp->fd, (struct sockaddr *) &iserv_addr, &length);
- __debugprintf(" (local_ip = %s, local_port = %d)\n",
- inet_ntoa(iserv_addr.sin_addr),
- ntohs(iserv_addr.sin_port));
- length = sizeof(iserv_addr);
- getpeername(cp->fd, (struct sockaddr *) &iserv_addr, &length);
- __debugprintf(" (remote_ip = %s, remote_port = %d)\n",
- inet_ntoa(iserv_addr.sin_addr),
- ntohs(iserv_addr.sin_port));
- }
- cp=cp->next;
- }
-
- __debugprintf("PROXIES\n");
- while (pp) {
- __debugprintf(" - fd = %d [%8p] (external_fd = %d, peer_port = %d,"
- " eof = %d)\n", pp->fd, pp, pp->conn->fd, pp->peer_port,
- pp->eof);
-
- pp= pp->next;
- }
-}
-
-static Connection *get_connection(FD fd)
-{
- Connection *cp = connections;
-
- while(cp) {
- if(cp->fd == fd)
- return cp;
- cp = cp->next;
- }
- return NULL;
-}
-
-/*
- * Remove a connection from the list of connection, close the proxy
- * socket and free all resources. The main socket (fd) is *not*
- * closed here, because the closing of that socket has to be synchronized
- * with the Erlang process controlling this port program.
- */
-static void remove_connection(Connection *conn)
-{
- Connection **prev = &connections;
- Connection *cp = connections;
-
- while (cp) {
- if(cp == conn) {
- DEBUGF(("remove_connection: fd = %d\n", cp->fd));
- esock_ssl_free(cp); /* frees cp->opaque only */
- esock_free(cp->flags);
- closelog(cp->logfp); /* XXX num_sock_fds */
- esock_free(cp->wq.buf);
- if (cp->proxy) {
- safe_close(cp->proxy->fd);
- remove_proxy(cp->proxy);
- }
- *prev = cp->next;
- esock_free(cp);
- return;
- }
- prev = &cp->next;
- cp = cp->next;
- }
-}
-
-static Proxy *get_proxy_by_peerport(int port)
-{
- Proxy *p = proxies;
-
- while(p) {
- if (p->peer_port == port)
- return p;
- p = p->next;
- }
- return NULL;
-}
-
-static Proxy *new_proxy(FD fd)
-{
- Proxy *p;
-
- if (!(p = esock_malloc(sizeof(Proxy))))
- return NULL;
-
- p->fd = fd;
- p->peer_port = -1;
- p->eof = 0;
- p->bp = 0;
- p->conn = NULL;
- p->wq.size = 0;
- p->wq.buf = NULL;
- p->wq.len = 0;
- p->wq.offset = 0;
- p->next = proxies;
- proxies = p;
- return p;
-}
-
-static void remove_proxy(Proxy *proxy)
-{
- Proxy *p = proxies, **pp = &proxies;
-
- while(p) {
- if (p == proxy) {
- DEBUGF(("remove_proxyfd = %d\n", p->fd));
- esock_free(p->wq.buf);
- *pp = p->next;
- esock_free(p);
- return;
- }
- pp = &p->next;
- p = p->next;
- }
-}
-
-static int check_num_sock_fds(FD fd)
-{
- num_sock_fds++; /* fd is valid */
-#ifdef USE_SELECT
- if (num_sock_fds > FD_SETSIZE) {
- num_sock_fds--;
- sock_set_errno(ERRNO_MFILE);
- safe_close(fd);
- return -1;
- }
-#endif
- return 0;
-}
-
-static void safe_close(FD fd)
-{
- int err;
-
- err = sock_errno();
- DEBUGF(("safe_close fd = %d\n", fd));
- if (sock_close(fd) < 0) {
- DEBUGF(("safe_close failed\n"));
- } else {
- num_sock_fds--;
- }
- sock_set_errno(err);
-}
-
-static void clean_up(void)
-{
- Connection *cp, *cpnext;
- Proxy *pp, *ppnext;
-
- cp = connections;
- while (cp) {
- safe_close(cp->fd);
- cpnext = cp->next;
- remove_connection(cp);
- cp = cpnext;
- }
-
- pp = proxies;
- while (pp) {
- safe_close(pp->fd);
- ppnext = pp->next;
- remove_proxy(pp);
- pp = ppnext;
- }
-}
-
-static void ensure_write_queue(WriteQueue *wq, int size)
-{
- if (wq->size < size) {
- wq->buf = esock_realloc(wq->buf, size);
- wq->size = size;
- }
-}
-
-
-
-
-
-
-
diff --git a/lib/ssl/c_src/esock.h b/lib/ssl/c_src/esock.h
deleted file mode 100644
index 16c9faa530..0000000000
--- a/lib/ssl/c_src/esock.h
+++ /dev/null
@@ -1,273 +0,0 @@
-/*<copyright>
- * <year>1999-2008</year>
- * <holder>Ericsson AB, All Rights Reserved</holder>
- *</copyright>
- *<legalnotice>
- * The contents of this file are subject to the Erlang Public License,
- * Version 1.1, (the "License"); you may not use this file except in
- * compliance with the License. You should have received a copy of the
- * Erlang Public License along with this software. If not, it can be
- * retrieved online at http://www.erlang.org/.
- *
- * Software distributed under the License is distributed on an "AS IS"
- * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
- * the License for the specific language governing rights and limitations
- * under the License.
- *
- * The Initial Developer of the Original Code is Ericsson AB.
- *</legalnotice>
- */
-/*
- * Purpose: Implementation of Secure Socket Layer (SSL).
- *
- */
-
-#ifndef ESOCK_H
-#define ESOCK_H
-
-#ifdef __WIN32__
-#include "esock_winsock.h"
-#endif
-#include <stdio.h>
-
-#ifdef __WIN32__
-#define INVALID_FD INVALID_SOCKET
-
-#define sock_read(fd, buf, len) recv((fd), (buf), (len), 0)
-#define sock_write(fd, buf, len) send((fd), (buf), (len), 0)
-#define sock_close(fd) closesocket(fd)
-#define sock_errno() WSAGetLastError()
-#define sock_set_errno(err) WSASetLastError(err)
-
-#define ERRNO_NONE 0
-#define ERRNO_BLOCK WSAEWOULDBLOCK
-#define ERRNO_CONNREFUSED WSAECONNREFUSED
-#define ERRNO_PROGRESS WSAEINPROGRESS
-#define ERRNO_PROTONOSUPPORT WSAEPROTONOSUPPORT
-#define ERRNO_INVAL WSAEINVAL
-#define ERRNO_ADDRNOTAVAIL WSAEADDRNOTAVAIL
-#define ERRNO_NOTSOCK WSAENOTSOCK
-#define ERRNO_OPNOTSUPP WSAEOPNOTSUPP
-#define ERRNO_MFILE WSAEMFILE
-#define SET_BLOCKING(fd) do { \
- unsigned long zeroval = 0; \
- ioctlsocket((fd), FIONBIO, &zeroval); \
- } while (0)
-#define SET_NONBLOCKING(fd) do { \
- unsigned long oneval = 1; \
- ioctlsocket((fd), FIONBIO, &oneval); \
- } while (0)
-#else
-#define INVALID_FD (-1)
-
-#define sock_read(fd, buf, len) read((fd), (buf), (len))
-#define sock_write(fd, buf, len) write((fd), (buf), (len))
-#define sock_close(fd) close(fd)
-#define sock_errno() errno
-#define sock_set_errno(err) do {errno = (err);} while(0)
-
-#define ERRNO_NONE 0
-#define ERRNO_BLOCK EAGAIN
-#define ERRNO_CONNREFUSED ECONNREFUSED
-#define ERRNO_PROGRESS EINPROGRESS
-#define ERRNO_PROTONOSUPPORT EPROTONOSUPPORT
-#define ERRNO_INVAL EINVAL
-#define ERRNO_ADDRNOTAVAIL EADDRNOTAVAIL
-#define ERRNO_NOTSOCK ENOTSOCK
-#define ERRNO_OPNOTSUPP EOPNOTSUPP
-#define ERRNO_MFILE EMFILE
-#define SET_BLOCKING(fd) fcntl((fd), F_SETFL, \
- fcntl((fd), F_GETFL, 0) & ~O_NONBLOCK)
-#define SET_NONBLOCKING(fd) fcntl((fd), F_SETFL, \
- fcntl((fd), F_GETFL, 0) | O_NONBLOCK)
-#endif
-
-#define GET_INT8(s) ((s)[0])
-#define GET_INT16(s) (((s)[0] << 8) | (s)[1])
-#define GET_INT32(s) (((s)[0] << 24) | ((s)[1] << 16) | \
- ((s)[2] << 8) | (s)[3])
-
-#define PUT_INT8(x, s) do { (s)[0] = x; } while(0)
-#define PUT_INT16(x, s) do { (s)[0] = ((x) >> 8) & 0xff; \
- (s)[1] = ((x) & 0xff); } while(0)
-#define PUT_INT32(x, s) do { (s)[0] = ((x) >> 24) & 0xff; \
- (s)[1] = ((x) >> 16) & 0xff; \
- (s)[2] = ((x) >> 8) & 0xff; \
- (s)[3] = (x) & 0xff; } while(0)
-
-/* type for Connections */
-#define ESOCK_STATE_NONE 0
-#define ESOCK_ACTIVE_LISTENING 1
-#define ESOCK_PASSIVE_LISTENING 2
-#define ESOCK_CONNECTED 3
-#define ESOCK_WAIT_CONNECT 4
-#define ESOCK_SSL_CONNECT 5
-#define ESOCK_SSL_ACCEPT 6
-#define ESOCK_TRANSPORT_ACCEPT 7
-#define ESOCK_JOINED 8
-#define ESOCK_SSL_SHUTDOWN 9
-#define ESOCK_DEFUNCT 10
-
-#ifdef __WIN32__
- typedef SOCKET FD;
-#else
- typedef int FD;
-#endif
-
-/* For the shutdown(fd, how) call */
-#ifdef __WIN32__
-#define SHUTDOWN_READ SD_RECEIVE
-#define SHUTDOWN_WRITE SD_SEND
-#define SHUTDOWN_ALL SD_BOTH
-#else
-#define SHUTDOWN_READ 0
-#define SHUTDOWN_WRITE 1
-#define SHUTDOWN_ALL 2
-#endif
-
-#define ORIG_LISTEN 0
-#define ORIG_ACCEPT 1
-#define ORIG_CONNECT 2
-
-typedef struct {
- int size; /* Total size of buf */
- unsigned char *buf;
- int len; /* Current number of bytes in buf */
- int offset; /* Bytes already written */
-} WriteQueue;
-
-typedef struct _proxy Proxy;
-
-typedef struct Connection {
- FD fd;
- FD listen_fd; /* Needed for async listen error */
- unsigned char state;
- int acceptors; /* Count acceptors for listen socket */
- Proxy *proxy;
- void *opaque; /* Any suitable ssl structure */
- int ssl_want; /* read/write flags */
- int eof; /* end of file (read) */
- int bp; /* broken pipe (write) */
- int clean; /* Clean SSL shutdown initiated */
- int close; /* Close if set */
- int origin; /* listen, accept or connect */
- int encrypted; /* 1 = SSL encrypted, 0 = normal, unencrypted tcp */
- char *flags; /* ssl parameters */
- FILE *logfp; /* connection log file (not used) */
- WriteQueue wq;
- struct Connection* next;
- const char* errstr; /* only used to report errors from ssl_accept_init in SSL_ACCEPT */
-} Connection;
-
-struct _proxy {
- FD fd;
- int peer_port;
- int eof; /* end of file (read) */
- int bp; /* broken pipe (write) */
- Connection *conn;
- WriteQueue wq;
- Proxy *next;
-};
-
-/* Commands, replies, and error responses */
-
-#define ESOCK_CONNECT_CMD 1
-#define ESOCK_CONNECT_WAIT_REP 2
-#define ESOCK_CONNECT_REP 3
-#define ESOCK_CONNECT_ERR 4
-
-#define ESOCK_TERMINATE_CMD 5
-#define ESOCK_CLOSE_CMD 6
-
-#define ESOCK_LISTEN_CMD 7
-#define ESOCK_LISTEN_REP 8
-#define ESOCK_LISTEN_ERR 9
-
-#define ESOCK_TRANSPORT_ACCEPT_CMD 10
-#define ESOCK_NOACCEPT_CMD 11
-#define ESOCK_TRANSPORT_ACCEPT_REP 12
-#define ESOCK_TRANSPORT_ACCEPT_ERR 13
-
-#define ESOCK_FROMNET_CLOSE_REP 14
-
-#define ESOCK_CONNECT_SYNC_ERR 15
-#define ESOCK_LISTEN_SYNC_ERR 16
-
-#define ESOCK_PROXY_PORT_REP 23
-#define ESOCK_PROXY_JOIN_CMD 24
-#define ESOCK_PROXY_JOIN_REP 25
-#define ESOCK_PROXY_JOIN_ERR 26
-
-#define ESOCK_SET_SOCKOPT_CMD 27
-#define ESOCK_IOCTL_OK 28
-#define ESOCK_IOCTL_ERR 29
-
-#define ESOCK_GETPEERNAME_CMD 30
-#define ESOCK_GETPEERNAME_REP 31
-#define ESOCK_GETPEERNAME_ERR 32
-
-#define ESOCK_GETSOCKNAME_CMD 33
-#define ESOCK_GETSOCKNAME_REP 34
-#define ESOCK_GETSOCKNAME_ERR 35
-
-#define ESOCK_GETPEERCERT_CMD 36
-#define ESOCK_GETPEERCERT_REP 37
-#define ESOCK_GETPEERCERT_ERR 38
-
-#define ESOCK_GETVERSION_CMD 39
-#define ESOCK_GETVERSION_REP 40
-
-#define ESOCK_SET_SEED_CMD 41
-
-#define ESOCK_GETCONNINFO_CMD 42
-#define ESOCK_GETCONNINFO_REP 43
-#define ESOCK_GETCONNINFO_ERR 44
-
-#define ESOCK_SSL_ACCEPT_CMD 45
-#define ESOCK_SSL_ACCEPT_REP 46
-#define ESOCK_SSL_ACCEPT_ERR 47
-
-#define ESOCK_DUMP_STATE_CMD 48
-#define ESOCK_SET_DEBUG_CMD 49
-#define ESOCK_SET_DEBUGMSG_CMD 50
-
-
-/* Option codes for ESOCK_SET_SOCKOPT_CMD */
-#define ESOCK_SET_TCP_NODELAY 1
-
-/* SSL want to read or write */
-#define ESOCK_SSL_WANT_READ 1
-#define ESOCK_SSL_WANT_WRITE 2
-
-/* Protocol version according to ssl_server */
-#define ESOCK_SSLv2 1
-#define ESOCK_SSLv3 2
-#define ESOCK_TLSv1 4
-
-
-#endif
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/lib/ssl/c_src/esock_openssl.c b/lib/ssl/c_src/esock_openssl.c
deleted file mode 100644
index 0bc42958f0..0000000000
--- a/lib/ssl/c_src/esock_openssl.c
+++ /dev/null
@@ -1,1213 +0,0 @@
-/*<copyright>
- * <year>1999-2008</year>
- * <holder>Ericsson AB, All Rights Reserved</holder>
- *</copyright>
- *<legalnotice>
- * The contents of this file are subject to the Erlang Public License,
- * Version 1.1, (the "License"); you may not use this file except in
- * compliance with the License. You should have received a copy of the
- * Erlang Public License along with this software. If not, it can be
- * retrieved online at http://www.erlang.org/.
- *
- * Software distributed under the License is distributed on an "AS IS"
- * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
- * the License for the specific language governing rights and limitations
- * under the License.
- *
- * The Initial Developer of the Original Code is Ericsson AB.
- *</legalnotice>
- */
-/*
- * Purpose: Adaptions for the OpenSSL package.
- *
- * This file implements the functions defined in esock_ssl.h for
- * the OpenSSL package.
- *
- * The following holds true for non-blockling I/O:
- *
- * Function Return values
- * -------- -------------
- * SSL_accept() success: 1, failure: =<0
- * SSL_connect() success: 1, failure: =<0
- * SSL_read() success: >0, eof: 0, failure: <0
- * SSL_write() success: > 0, failure: =<0
- * SSL_shutdown() success: 1, not finished: 0
- *
- * If the return value of any of the above functions is `ret' and the
- * ssl connection is `ssl', the call
- *
- * ssl_error = SSL_get_error(ssl, ret);
- *
- * returns one of the following eight values:
- *
- * SSL_ERROR_NONE ret > 0
- * SSL_ERROR_ZERO_RETURN ret = 0
- * SSL_ERROR_WANT_READ ret < 0 and ssl wants to read
- * SSL_ERROR_WANT_WRITE ret < 0 and ssl wants to write
- * SSL_ERROR_SYSCALL ret < 0 or ret = 0
- * SSL_ERROR_SSL if there was an ssl internal error
- * SSL_ERROR_WANT_X509_LOOKUP ret < 0 and ssl wants x509 lookup
- * SSL_ERROR_WANT_CONNECT ret < 0 and ssl wants connect
- *
- * It is the case that SSL_read() sometimes returns -1, even when the
- * underlying file descriptor is ready for reading.
- *
- * Also, sometimes we may have SSL_ERROR_SSL in SSL_accept() and SSL_connect()
- * when a retry should be done.
- *
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <errno.h>
-#ifndef __WIN32__
-# include <fcntl.h>
-# include <unistd.h>
-#endif
-
-#include "esock.h"
-#include "esock_ssl.h"
-#include "debuglog.h"
-#include "esock_utils.h"
-#include "esock_posix_str.h"
-
-#include <openssl/crypto.h>
-#include <openssl/ssl.h>
-#include <openssl/err.h>
-#include <openssl/rand.h>
-
-int ephemeral_rsa = 0;
-int ephemeral_dh = 0; /* XXX Not used yet */
-int protocol_version = 0;
-
-char *esock_ssl_errstr = "";
-
-#define FLAGSBUFSIZE 512
-#define X509BUFSIZE 256
-#define DEFAULT_VERIFY_DEPTH 1
-
-#define SET_WANT(cp, ssl_error) \
- switch((ssl_error)) { \
- case SSL_ERROR_WANT_READ: \
- (cp)->ssl_want = ESOCK_SSL_WANT_READ; \
- break; \
- case SSL_ERROR_WANT_WRITE: \
- (cp)->ssl_want = ESOCK_SSL_WANT_WRITE; \
- break; \
- default: \
- (cp)->ssl_want = 0; \
- break; \
- }
-
-#define RESET_ERRSTR() \
- esock_ssl_errstr = "";
-
-#define MAYBE_SET_ERRSTR(s) \
- if (!esock_ssl_errstr[0]) \
- esock_ssl_errstr = (s);
-
-typedef struct {
- int code;
- char *text;
-} err_entry;
-
-typedef struct {
- SSL_CTX *ctx;
- char *passwd;
- int verify_depth;
-} callback_data;
-
-static char *ssl_error_str(int error);
-static void end_ssl_call(int ret, Connection *cp, int ssl_error);
-static void check_shutdown(Connection *cp);
-static int set_ssl_parameters(Connection *cp, SSL_CTX *ctx);
-static int verify_callback(int ok, X509_STORE_CTX *ctx);
-static int passwd_callback(char *buf, int num, int rwflag, void *userdata);
-static void info_callback(const SSL *ssl, int where, int ret);
-static void callback_data_free(void *parent, void *ptr,
- CRYPTO_EX_DATA *ad,
- int idx, long arg1, void *argp);
-static RSA *tmp_rsa_callback(SSL *ssl, int is_export, int keylen);
-static void restrict_protocols(SSL_CTX *ctx);
-
-static err_entry errs[] = {
- {SSL_ERROR_NONE, "SSL_ERROR_NONE"},
- {SSL_ERROR_ZERO_RETURN, "SSL_ERROR_ZERO_RETURN"},
- {SSL_ERROR_WANT_READ, "SSL_ERROR_WANT_READ"},
- {SSL_ERROR_WANT_WRITE, "SSL_ERROR_WANT_WRITE"},
- {SSL_ERROR_SYSCALL, "SSL_ERROR_SYSCALL"},
- {SSL_ERROR_SSL, "SSL_ERROR_SSL"},
- {SSL_ERROR_WANT_X509_LOOKUP, "SSL_ERROR_WANT_X509_LOOKUP"},
- {SSL_ERROR_WANT_CONNECT, "SSL_ERROR_WANT_CONNECT"}
-};
-
-static SSL_METHOD *method; /* for listen and connect init */
-static char x509_buf[X509BUFSIZE]; /* for verify_callback */
-static int callback_data_index = -1; /* for ctx ex_data */
-static unsigned char randvec[1024]; /* XXX */
-
-#if defined(__WIN32__) || OPEN_MAX > 256
-# define FOPEN_WORKAROUND(var, expr) var = (expr)
-# define VOID_FOPEN_WORKAROUND(expr) expr
-#else
-/*
- * This is an ugly workaround. On Solaris, fopen() will return NULL if
- * it gets a file descriptor > 255. To avoid that, we'll make sure that
- * there is always one low-numbered file descriptor available when
- * fopen() is called.
- */
-static int reserved_fd; /* Reserve a low-numbered file descriptor */
-# define USE_FOPEN_WORKAROUND 1
-
-# define FOPEN_WORKAROUND(var, expr) \
-do { \
- close(reserved_fd); \
- var = (expr); \
- reserved_fd = open("/dev/null", O_RDONLY); \
-} while (0)
-
-# define VOID_FOPEN_WORKAROUND(expr) \
-do { \
- close(reserved_fd); \
- expr; \
- reserved_fd = open("/dev/null", O_RDONLY); \
-} while (0)
-#endif
-
-esock_version *esock_ssl_version(void)
-{
- static esock_version vsn;
-
- vsn.compile_version = OPENSSL_VERSION_TEXT;
- vsn.lib_version = SSLeay_version(SSLEAY_VERSION);
- return &vsn;
-}
-
-char *esock_ssl_ciphers(void)
-{
- SSL_CTX *ctx;
- SSL *ssl;
- char *ciphers;
- const char *cp;
- int i = 0, used = 0, len, incr = 1024;
-
- if (!(ctx = SSL_CTX_new(method)))
- return NULL;
- restrict_protocols(ctx);
- if (!(ssl = SSL_new(ctx))) {
- SSL_CTX_free(ctx);
- return NULL;
- }
-
- ciphers = esock_malloc(incr);
- len = incr;
- *ciphers = '\0';
-
- while (1) {
- if (!(cp = SSL_get_cipher_list(ssl, i)))
- break;
- if (i > 0) {
- if (used == len) {
- len += incr;
- ciphers = esock_realloc(ciphers, len);
- }
- strcat(ciphers, ":");
- used++;
- }
- if (strlen(cp) + used >= len) {
- len += incr;
- ciphers = esock_realloc(ciphers, len);
- }
- strcat(ciphers, cp);
- used += strlen(cp);
- i++;
- }
- SSL_free(ssl);
- SSL_CTX_free(ctx);
- return ciphers;
-}
-
-void esock_ssl_seed(void *buf, int len)
-{
- RAND_seed(buf, len);
-
- /* XXX Maybe we should call RAND_status() and check if we have got
- * enough randomness.
- */
-}
-
-int esock_ssl_init(void)
-{
- method = SSLv23_method(); /* SSLv2, SSLv3 and TLSv1, may be restricted
- in listen and connect */
- SSL_load_error_strings();
- SSL_library_init();
- esock_ssl_seed(randvec, sizeof(randvec));
- callback_data_index = SSL_CTX_get_ex_new_index(0, "callback_data",
- NULL, NULL,
- callback_data_free);
-#ifdef USE_FOPEN_WORKAROUND
- reserved_fd = open("/dev/null", O_RDONLY);
- DEBUGF(("init: reserved_fd=%d\r\n", reserved_fd));
-#endif
- return 0;
-}
-
-
-void esock_ssl_finish(void)
-{
- /* Nothing */
-}
-
-
-void esock_ssl_free(Connection *cp)
-{
- SSL *ssl = cp->opaque;
- SSL_CTX *ctx;
-
- if (ssl) {
- ctx = SSL_get_SSL_CTX(ssl);
- SSL_free(ssl);
- if (cp->origin != ORIG_ACCEPT)
- SSL_CTX_free(ctx);
- cp->opaque = NULL;
- }
-}
-
-
-/*
- * Print SSL specific errors.
- */
-void esock_ssl_print_errors_fp(FILE *fp)
-{
- ERR_print_errors_fp(fp);
-}
-
-
-int esock_ssl_accept_init(Connection *cp, void *listenssl)
-{
- SSL_CTX *listenctx;
- SSL *ssl;
-
- RESET_ERRSTR();
- MAYBE_SET_ERRSTR("esslacceptinit");
-
- if(!listenssl) {
- DEBUGF(("esock_ssl_accept_init: listenssl null\n"));
- return -1;
- }
- if (!(listenctx = SSL_get_SSL_CTX(listenssl))) {
- DEBUGF(("esock_ssl_accept_init: SSL_get_SSL_CTX\n"));
- return -1;
- }
- if (!(ssl = cp->opaque = SSL_new(listenctx))) {
- DEBUGF(("esock_ssl_accept_init: SSL_new(listenctx)\n"));
- return -1;
- }
- SSL_set_fd(ssl, cp->fd);
- return 0;
-
-}
-
-
-int esock_ssl_connect_init(Connection *cp)
-{
- SSL_CTX *ctx;
- SSL *ssl;
-
- RESET_ERRSTR();
- MAYBE_SET_ERRSTR("esslconnectinit");
-
- if (!(ctx = SSL_CTX_new(method)))
- return -1;
- if (set_ssl_parameters(cp, ctx) < 0) {
- SSL_CTX_free(ctx);
- return -1;
- }
- restrict_protocols(ctx);
- if (!(ssl = cp->opaque = SSL_new(ctx))) {
- SSL_CTX_free(ctx);
- return -1;
- }
- SSL_set_fd(ssl, cp->fd);
- return 0;
-}
-
-
-int esock_ssl_listen_init(Connection *cp)
-{
- SSL_CTX *ctx;
- SSL *ssl;
-
- RESET_ERRSTR();
- MAYBE_SET_ERRSTR("essllisteninit");
-
- if (!(ctx = SSL_CTX_new(method)))
- return -1;
- if (set_ssl_parameters(cp, ctx) < 0) {
- SSL_CTX_free(ctx);
- return -1;
- }
- restrict_protocols(ctx);
-
- /* The allocation of ctx is for setting ssl parameters, so that
- * accepts can inherit them. We allocate ssl to be able to
- * refer to it via cp->opaque, but will not be used otherwise.
- */
- if (!(ssl = cp->opaque = SSL_new(ctx))) {
- SSL_CTX_free(ctx);
- return -1;
- }
- /* Set callback for temporary ephemeral RSA key generation.
- * Note: for servers only. */
- SSL_CTX_set_tmp_rsa_callback(ctx, tmp_rsa_callback);
- return 0;
-}
-
-/*
- * esock_ssl_accept(Connection *cp)
- *
- */
-int esock_ssl_accept(Connection *cp)
-{
- int ret, ssl_error;
- SSL *ssl = cp->opaque;
-
- RESET_ERRSTR();
-
- DEBUGF(("esock_ssl_accept: calling SSL_accept fd = %d\n"
- " state before: %s\n", cp->fd, SSL_state_string(ssl)));
- ret = SSL_accept(ssl);
- DEBUGF((" sock_errno %d errno %d \n", sock_errno(), errno));
- ssl_error = SSL_get_error(ssl, ret);
- DEBUGF((" SSL_accept = %d\n"
- " ssl_error: %s\n"
- " state after: %s\n",
- ret, ssl_error_str(ssl_error), SSL_state_string(ssl)));
- DEBUGF((" ret %d os error %s\n", ret, strerror(errno)));
- if (ret > 0)
- return ret;
- else if (ret == 0) {
- const char* f; int l; unsigned int e;
- while ((e = ERR_get_error_line(&f, &l))) {
- DEBUGF((" error %s:%d %s\n", f, l, ssl_error_str(e)));
- }
- /* permanent accept error */
- sock_set_errno(ERRNO_NONE);
- MAYBE_SET_ERRSTR("esslaccept");
- return -1;
- }
- end_ssl_call(ret, cp, ssl_error);
- return ret;
-}
-
-/*
- * esock_ssl_connect(Connection *cp)
- *
- */
-int esock_ssl_connect(Connection *cp)
-{
- int ret, ssl_error;
- SSL *ssl = cp->opaque;
-
- RESET_ERRSTR();
-
- DEBUGF(("esock_ssl_connect: calling SSL_connect fd = %d\n"
- " state before: %s\n", cp->fd, SSL_state_string(ssl)));
- ret = SSL_connect(ssl);
- ssl_error = SSL_get_error(ssl, ret);
- DEBUGF((" SSL_connect() = %d\n"
- " ssl_error: %s\n"
- " state after: %s\n",
- ret, ssl_error_str(ssl_error), SSL_state_string(ssl)));
- if (ret > 0)
- return ret;
- else if (ret == 0) {
- /* permanent connect error */
- sock_set_errno(ERRNO_NONE);
- MAYBE_SET_ERRSTR("esslconnect");
- return -1;
- }
- end_ssl_call(ret, cp, ssl_error);
- return ret;
-}
-
-
-int esock_ssl_session_reused(Connection *cp)
-{
- SSL *ssl = cp->opaque;
-
- return SSL_session_reused(ssl);
-}
-
-
-/* esock_ssl_read(Connection *cp, char *buf, int len)
- *
- * Read at most `len' chars into `buf'. Returns number of chars
- * read ( > 0), or 0 at EOF, or -1 on error. Sets cp->eof, cp->bp if
- * appropriate.
- */
-
-int esock_ssl_read(Connection *cp, char *buf, int len)
-{
- int ret, ssl_error;
- SSL *ssl = cp->opaque;
-
- RESET_ERRSTR();
- DEBUGF(("esock_ssl_read: calling SSL_read fd = %d\n"
- " state before: %s\n", cp->fd, SSL_state_string(ssl)));
-
- ret = SSL_read(ssl, buf, len);
- ssl_error = SSL_get_error(ssl, ret);
-
- DEBUGF((" SSL_read = %d\n"
- " ssl_error: %s\n"
- " state after: %s\n",
- ret, ssl_error_str(ssl_error), SSL_state_string(ssl)));
-
- if (ssl_error == SSL_ERROR_NONE) {
- DEBUGMSGF(("message (hex) : [%3.*a]\n", ret, buf));
- DEBUGMSGF(("message (char): [%3.*b]\n", ret, buf));
- }
- if (ret > 0)
- return ret;
- if (ret == 0) {
- check_shutdown(cp);
- return ret;
- }
- end_ssl_call(ret, cp, ssl_error);
- return ret;
-}
-
-/*
- * esock_ssl_write(Connection *cp, char *buf, int len)
- *
- * Writes at most `len' chars from `buf'. Returns number of chars
- * written, or -1 on error.
- */
-int esock_ssl_write(Connection *cp, char *buf, int len)
-{
- int ret, ssl_error;
- SSL *ssl = cp->opaque;
-
- RESET_ERRSTR();
- DEBUGF(("esock_ssl_write: calling SSL_write fd = %d\n"
- " state before: %s\n", cp->fd, SSL_state_string(ssl)));
- ret = SSL_write(ssl, buf, len);
- ssl_error = SSL_get_error(ssl, ret);
- DEBUGF((" SSL_write = %d\n"
- " ssl_error: %s\n"
- " state after: %s\n",
- ret, ssl_error_str(ssl_error), SSL_state_string(ssl)));
- if (ssl_error == SSL_ERROR_NONE) {
- DEBUGMSGF(("message (hex) : [%3.*a]\n", ret, buf));
- DEBUGMSGF(("message (char): [%3.*b]\n", ret, buf));
- }
- if (ret > 0)
- return ret;
- if (ret == 0) {
- check_shutdown(cp);
- return ret;
- }
- end_ssl_call(ret, cp, ssl_error);
- return ret;
-}
-
-
-int esock_ssl_shutdown(Connection *cp)
-{
- int ret, ssl_error;
- SSL *ssl = cp->opaque;
-
- RESET_ERRSTR();
- DEBUGF(("esock_ssl_shutdown: calling SSL_shutdown fd = %d\n"
- " state before: %s\n", cp->fd, SSL_state_string(ssl)));
- ret = SSL_shutdown(ssl);
- ssl_error = SSL_get_error(ssl, ret);
- DEBUGF((" SSL_shutdown = %d\n"
- " ssl_error: %s\n"
- " state after: %s\n",
- ret, ssl_error_str(ssl_error), SSL_state_string(ssl)));
- if (ret >= 0) {
- check_shutdown(cp);
- return ret;
- }
- end_ssl_call(ret, cp, ssl_error);
- return ret;
-}
-
-
-/* Returns total number of bytes in DER encoded cert pointed to by
- * *buf, which is allocated by this function, unless return < 0.
- * XXX X509_free ??
- */
-int esock_ssl_getpeercert(Connection *cp, unsigned char **buf)
-{
- int len;
- SSL *ssl = cp->opaque;
- X509 *x509;
- unsigned char *tmp;
-
- RESET_ERRSTR();
- if((x509 = SSL_get_peer_certificate(ssl)) == NULL) {
- MAYBE_SET_ERRSTR("enopeercert"); /* XXX doc */
- return -1;
- }
-
- if ((len = i2d_X509(x509, NULL)) <= 0) {
- MAYBE_SET_ERRSTR("epeercert");
- return -1;
- }
-
- tmp = *buf = esock_malloc(len);
-
- /* We must use a temporary value here, since i2d_X509(X509 *x,
- * unsigned char **out) increments *out.
- */
- if (i2d_X509(x509, &tmp) < 0) {
- esock_free(tmp);
- MAYBE_SET_ERRSTR("epeercert");
- return -1;
- }
- return len;
-}
-
-/* Returns total number of bytes in chain of certs. Each cert begins
- * with a 4-bytes length. The last cert is ended with 4-bytes of
- * zeros. The result is returned in *buf, which is allocated unless
- * the return value is < 0.
- * XXX X509_free ? sk_X509_free ?
- * XXX X509_free is reference counting.
- */
-int esock_ssl_getpeercertchain(Connection *cp, unsigned char **buf)
-{
- SSL *ssl = cp->opaque;
- STACK_OF(X509) *x509_stack;
- X509 *x509;
- int num, i, totlen, pos, *der_len;
- unsigned char *vbuf;
-
- RESET_ERRSTR();
- if((x509_stack = SSL_get_peer_cert_chain(ssl)) == NULL) {
- MAYBE_SET_ERRSTR("enopeercertchain"); /* XXX doc */
- return -1;
- }
-
- num = sk_X509_num(x509_stack);
- der_len = esock_malloc(num * sizeof(int));
- totlen = 0;
-
- for (i = 0; i < num; i++) {
- x509 = sk_X509_value(x509_stack, i);
- totlen += 4;
- if ((der_len[i] = i2d_X509(x509, NULL)) < 0) {
- MAYBE_SET_ERRSTR("epeercertchain");
- esock_free(der_len);
- return -1;
- }
- totlen += der_len[i];
- }
- totlen += 4;
-
- vbuf = *buf = esock_malloc(totlen);
- pos = 0;
-
- for (i = 0; i < num; i++) {
- x509 = sk_X509_value(x509_stack, i);
- PUT_INT32(der_len[i], vbuf);
- vbuf += 4;
- /* Note: i2d_X509 increments vbuf */
- if (i2d_X509(x509, &vbuf) < 0) {
- MAYBE_SET_ERRSTR("epeercertchain");
- esock_free(*buf);
- esock_free(der_len);
- return -1;
- }
- }
- esock_free(der_len);
- return totlen;
-}
-
-
-int esock_ssl_getprotocol_version(Connection *cp, char **buf)
-{
- SSL *ssl = cp->opaque;
-
- RESET_ERRSTR();
- if (!ssl) {
- MAYBE_SET_ERRSTR("enoent");
- return -1;
- }
- *buf = (char *) SSL_get_version(ssl);
-
- return 0;
-}
-
-
-int esock_ssl_getcipher(Connection *cp, char **buf)
-{
- SSL *ssl = cp->opaque;
-
- RESET_ERRSTR();
- if (!ssl) {
- MAYBE_SET_ERRSTR("enoent");
- return -1;
- }
- *buf = (char *) SSL_get_cipher(ssl);
-
- return 0;
-}
-
-/* Local functions */
-
-static char *ssl_error_str(int ssl_error)
-{
- int i;
- static char buf[128];
-
- for (i = 0; i < sizeof(errs)/sizeof(err_entry); i ++) {
- if (ssl_error == errs[i].code)
- return errs[i].text;
- }
- sprintf(buf, "esock_openssl: SSL_error unknown: %d", ssl_error);
- return buf;
-}
-
-void end_ssl_call(int ret, Connection *cp, int ssl_error)
-{
- SET_WANT(cp, ssl_error);
- switch (ssl_error) {
- case SSL_ERROR_SYSCALL:
- /* Typically sock_errno() is equal to ERRNO_BLOCK */
- MAYBE_SET_ERRSTR(esock_posix_str(sock_errno()));
- break;
- case SSL_ERROR_SSL:
- sock_set_errno(ERRNO_NONE);
- MAYBE_SET_ERRSTR("esslerrssl");
- break;
- case SSL_ERROR_WANT_X509_LOOKUP:
- SSLDEBUGF();
- sock_set_errno(ERRNO_NONE);
- MAYBE_SET_ERRSTR("ex509lookup");
- break;
- case SSL_ERROR_WANT_CONNECT:
- SSLDEBUGF();
- sock_set_errno(ERRNO_NONE);
- MAYBE_SET_ERRSTR("ewantconnect");
- break;
- default:
- break;
- }
-}
-
-void check_shutdown(Connection *cp)
-{
- int sd_mode;
- SSL *ssl = cp->opaque;
-
- sd_mode = SSL_get_shutdown(ssl);
- if (sd_mode & SSL_RECEIVED_SHUTDOWN)
- cp->eof = 1;
- if (sd_mode & SSL_SENT_SHUTDOWN) {
- DEBUGF(("check_shutdown SSL_SENT_SHUTDOWN\n"));
- cp->bp = 1;
- }
-}
-
-/*
- * set_ssl_parameters
- *
- * Set ssl parameters from connection structure. Only called for
- * listen and connect.
- *
- * Note: The -cacertdir option is not documented.
- */
-static int set_ssl_parameters(Connection *cp, SSL_CTX *ctx)
-{
- char *cacertfile = NULL, *cacertdir = NULL, *certfile = NULL;
- char *keyfile = NULL, *ciphers = NULL, *password = NULL;
- int verify = 0, verify_depth = DEFAULT_VERIFY_DEPTH, verify_mode;
- int i, argc;
- char **argv;
- callback_data *cb_data;
-
- RESET_ERRSTR();
-
- argc = esock_build_argv(cp->flags, &argv);
-
- DEBUGF(("Argv:\n"));
- for (i = 0; i < argc; i++) {
- DEBUGF(("%d: %s\n", i, argv[i]));
- }
-
- for (i = 0; i < argc; i++) {
- if (strcmp(argv[i], "-verify") == 0) {
- verify = atoi(argv[++i]);
- } else if (strcmp(argv[i], "-depth") == 0) {
- verify_depth = atoi(argv[++i]);
- } else if (strcmp(argv[i], "-log") == 0) {
- /* XXX ignored: logging per connection not supported */
- i++;
- } else if (strcmp(argv[i], "-certfile") == 0) {
- certfile = argv[++i];
- } else if (strcmp(argv[i], "-keyfile") == 0) {
- keyfile = argv[++i];
- } else if (strcmp(argv[i], "-password") == 0) {
- password = argv[++i];
- } else if (strcmp(argv[i], "-cacertfile") == 0) {
- cacertfile = argv[++i];
- } else if (strcmp(argv[i], "-cacertdir") == 0) {
- cacertdir = argv[++i];
- } else if (strcmp(argv[i], "-d") == 0) {
- /* XXX ignored: debug per connection not supported */
- i++;
- } else if (strcmp(argv[i], "-ciphers") == 0) {
- ciphers = argv[++i];
- } else {
- /* XXX Error: now ignored */
- }
- }
- DEBUGF(("set_ssl_parameters: all arguments read\n"));
-
- if (cp->origin == ORIG_LISTEN && !certfile) {
- DEBUGF(("ERROR: Server must have certificate\n"));
- MAYBE_SET_ERRSTR("enoservercert");
- goto err_end;
- }
-
- /* Define callback data */
- /* XXX Check for NULL */
- cb_data = esock_malloc(sizeof(callback_data));
- cb_data->ctx = ctx;
- if (password) {
- cb_data->passwd = esock_malloc(strlen(password) + 1);
- strcpy(cb_data->passwd, password);
- } else
- cb_data->passwd = NULL;
- cb_data->verify_depth = verify_depth;
- SSL_CTX_set_ex_data(ctx, callback_data_index, cb_data);
-
- /* password callback */
- SSL_CTX_set_default_passwd_cb(ctx, passwd_callback);
- SSL_CTX_set_default_passwd_cb_userdata(ctx, cb_data);
-
- /* Set location for "trusted" certificates */
- if (cacertfile || cacertdir) {
- int res;
- DEBUGF(("set_ssl_parameters: SSL_CTX_load_verify_locations\n"));
- FOPEN_WORKAROUND(res, SSL_CTX_load_verify_locations(ctx, cacertfile,
- cacertdir));
- if (!res) {
- DEBUGF(("ERROR: Cannot load verify locations\n"));
- MAYBE_SET_ERRSTR("ecacertfile");
- goto err_end;
- }
- } else {
- int res;
- DEBUGF(("set_ssl_parameters: SSL_CTX_set_default_verify_paths\n"));
- FOPEN_WORKAROUND(res, SSL_CTX_set_default_verify_paths(ctx));
- if (!res) {
- DEBUGF(("ERROR: Cannot set default verify paths\n"));
- MAYBE_SET_ERRSTR("ecacertfile");
- goto err_end;
- }
- }
-
- /* For a server the following sets the list of CA distinguished
- * names that it sends to its client when it requests the
- * certificate from the client.
- * XXX The names of certs in cacertdir ignored.
- */
- if (cp->origin == ORIG_LISTEN && cacertfile) {
- DEBUGF(("set_ssl_parameters: SSL_CTX_set_client_CA_list\n"));
- VOID_FOPEN_WORKAROUND(SSL_CTX_set_client_CA_list(ctx,
- SSL_load_client_CA_file(cacertfile)));
- if (!SSL_CTX_get_client_CA_list(ctx)) {
- DEBUGF(("ERROR: Cannot set client CA list\n"));
- MAYBE_SET_ERRSTR("ecacertfile");
- goto err_end;
- }
- }
-
- /* Use certificate file if key file has not been set. */
- if (!keyfile)
- keyfile = certfile;
-
- if (certfile) {
- int res;
- DEBUGF(("set_ssl_parameters: SSL_CTX_use_certificate_file\n"));
- FOPEN_WORKAROUND(res, SSL_CTX_use_certificate_file(ctx, certfile,
- SSL_FILETYPE_PEM));
- if (res <= 0) {
- DEBUGF(("ERROR: Cannot set certificate file\n"));
- MAYBE_SET_ERRSTR("ecertfile");
- goto err_end;
- }
- }
- if (keyfile) {
- int res;
- DEBUGF(("set_ssl_parameters: SSL_CTX_use_PrivateKey_file\n"));
- FOPEN_WORKAROUND(res, SSL_CTX_use_PrivateKey_file(ctx, keyfile,
- SSL_FILETYPE_PEM));
- if (res <= 0) {
- DEBUGF(("ERROR: Cannot set private key file\n"));
- MAYBE_SET_ERRSTR("ekeyfile");
- goto err_end;
- }
- }
- if(certfile && keyfile) {
- DEBUGF(("set_ssl_parameters: SSL_CTX_check_private_key\n"));
- if (!SSL_CTX_check_private_key(ctx)) {
- DEBUGF(("ERROR: Private key does not match the certificate\n"));
- MAYBE_SET_ERRSTR("ekeymismatch");
- goto err_end;
- }
- }
-
- /* Ciphers */
- if (ciphers) {
- DEBUGF(("set_ssl_parameters: SSL_CTX_set_cipher_list\n"));
- if (!SSL_CTX_set_cipher_list(ctx, ciphers)) {
- DEBUGF(("ERROR: Cannot set cipher list\n"));
- MAYBE_SET_ERRSTR("ecipher");
- goto err_end;
- }
- }
-
- /* Verify depth */
- DEBUGF(("set_ssl_parameters: SSL_CTX_set_verify_depth (depth = %d)\n",
- verify_depth));
- SSL_CTX_set_verify_depth(ctx, verify_depth);
-
- /* Verify mode and callback */
- /* XXX Why precisely these modes? */
- switch (verify) {
- case 0:
- verify_mode = SSL_VERIFY_NONE;
- break;
- case 1:
- verify_mode = SSL_VERIFY_PEER|SSL_VERIFY_CLIENT_ONCE;
- break;
- case 2:
- verify_mode = SSL_VERIFY_PEER|SSL_VERIFY_CLIENT_ONCE|
- SSL_VERIFY_FAIL_IF_NO_PEER_CERT;
- break;
- default:
- verify_mode = SSL_VERIFY_NONE;
- }
- DEBUGF(("set_ssl_parameters: SSL_CTX_set_verify (verify = %d)\n",
- verify));
- SSL_CTX_set_verify(ctx, verify_mode, verify_callback);
-
- /* Session id context. Should be an option really. */
- if (cp->origin == ORIG_LISTEN) {
- unsigned char *sid = "Erlang/OTP/ssl";
- SSL_CTX_set_session_id_context(ctx, sid, strlen(sid));
- }
-
- /* info callback */
- if (debug)
- SSL_CTX_set_info_callback(ctx, info_callback);
-
- DEBUGF(("set_ssl_parameters: done\n"));
- /* Free arg list */
- for (i = 0; argv[i]; i++)
- esock_free(argv[i]);
- esock_free(argv);
- return 0;
-
- err_end:
- DEBUGF(("set_ssl_parameters: error\n"));
- /* Free arg list */
- for (i = 0; argv[i]; i++)
- esock_free(argv[i]);
- esock_free(argv);
- return -1;
-}
-
-/* Call back functions */
-
-static int verify_callback(int ok, X509_STORE_CTX *x509_ctx)
-{
- X509 *cert;
- int cert_err, depth;
- SSL *ssl;
- SSL_CTX *ctx;
- callback_data *cb_data;
-
- cert = X509_STORE_CTX_get_current_cert(x509_ctx);
- cert_err = X509_STORE_CTX_get_error(x509_ctx);
- depth = X509_STORE_CTX_get_error_depth(x509_ctx);
-
- ssl = X509_STORE_CTX_get_ex_data(x509_ctx,
- SSL_get_ex_data_X509_STORE_CTX_idx());
- ctx = SSL_get_SSL_CTX(ssl);
- cb_data = SSL_CTX_get_ex_data(ctx, callback_data_index);
-
- X509_NAME_oneline(X509_get_subject_name(cert), x509_buf, sizeof(x509_buf));
- DEBUGF((" +vfy: depth = %d\n", depth));
- DEBUGF((" subject = %s\n", x509_buf));
- X509_NAME_oneline(X509_get_issuer_name(cert), x509_buf, sizeof(x509_buf));
- DEBUGF((" issuer = %s\n", x509_buf));
-
- if (!ok) {
- DEBUGF((" +vfy: error = %d [%s]\n", cert_err,
- X509_verify_cert_error_string(cert_err)));
- if (depth >= cb_data->verify_depth)
- ok = 1;
- }
-
- switch (cert_err) {
- case X509_V_OK:
- case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT:
- ok = 1;
- break;
- case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT:
- case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY:
- MAYBE_SET_ERRSTR("enoissuercert");
- break;
- case X509_V_ERR_CERT_HAS_EXPIRED:
- MAYBE_SET_ERRSTR("epeercertexpired");
- break;
- case X509_V_ERR_CERT_NOT_YET_VALID:
- case X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD:
- case X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD:
- MAYBE_SET_ERRSTR("epeercertinvalid");
- break;
- case X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN:
- MAYBE_SET_ERRSTR("eselfsignedcert");
- break;
- case X509_V_ERR_CERT_CHAIN_TOO_LONG:
- MAYBE_SET_ERRSTR("echaintoolong");
- break;
- default:
- MAYBE_SET_ERRSTR("epeercert");
- break;
- }
- DEBUGF((" +vfy: return = %d\n",ok));
- return ok;
-}
-
-static int passwd_callback(char *buf, int num, int rwflag, void *userdata)
-{
- callback_data *cb_data = userdata;
- int len;
-
- if (cb_data && cb_data->passwd) {
- DEBUGF((" +passwd: %s\n", cb_data->passwd));
- strncpy(buf, cb_data->passwd, num);
- len = strlen(cb_data->passwd);
- return len;
- }
- DEBUGF((" +passwd: ERROR: No password set.\n"));
- return 0;
-}
-
-static void info_callback(const SSL *ssl, int where, int ret)
-{
- char *str;
-
- if (where & SSL_CB_LOOP) {
- DEBUGF((" info: %s\n",SSL_state_string_long(ssl)));
- } else if (where & SSL_CB_ALERT) {
- str = (where & SSL_CB_READ) ? "read" : "write";
- DEBUGF((" info: SSL3 alert %s:%s:%s\n", str,
- SSL_alert_type_string_long(ret),
- SSL_alert_desc_string_long(ret)));
- } else if (where & SSL_CB_EXIT) {
- if (ret == 0) {
- DEBUGF((" info: failed in %s\n", SSL_state_string_long(ssl)));
- } else if (ret < 0) {
- DEBUGF((" info: error in %s\n", SSL_state_string_long(ssl)));
- }
- }
-}
-
-/* This function is called whenever an SSL_CTX *ctx structure is
- * freed.
-*/
-static void callback_data_free(void *parent, void *ptr, CRYPTO_EX_DATA *ad,
- int idx, long arg1, void *argp)
-{
- callback_data *cb_data = ptr;
-
- if (cb_data) {
- if (cb_data->passwd)
- esock_free(cb_data->passwd);
- esock_free(cb_data);
- }
-}
-
-static RSA *tmp_rsa_callback(SSL *ssl, int is_export, int keylen)
-{
- static RSA *rsa512 = NULL;
- static RSA *rsa1024 = NULL;
-
- switch (keylen) {
- case 512:
- if (!rsa512)
- rsa512 = RSA_generate_key(keylen, RSA_F4, NULL, NULL);
- return rsa512;
- break;
- case 1024:
- if (!rsa1024)
- rsa1024 = RSA_generate_key(keylen, RSA_F4, NULL, NULL);
- return rsa1024;
- break;
- default:
- if (rsa1024)
- return rsa1024;
- if (rsa512)
- return rsa512;
- rsa512 = RSA_generate_key(keylen, RSA_F4, NULL, NULL);
- return rsa512;
- }
-}
-
-/* Restrict protocols (SSLv2, SSLv3, TLSv1) */
-static void restrict_protocols(SSL_CTX *ctx)
-{
- long options = 0;
-
- if (protocol_version) {
- if ((protocol_version & ESOCK_SSLv2) == 0)
- options |= SSL_OP_NO_SSLv2;
- if ((protocol_version & ESOCK_SSLv3) == 0)
- options |= SSL_OP_NO_SSLv3;
- if ((protocol_version & ESOCK_TLSv1) == 0)
- options |= SSL_OP_NO_TLSv1;
- SSL_CTX_set_options(ctx, options);
- }
-}
-
-
-static unsigned char randvec [] = {
- 181, 177, 237, 240, 107, 24, 43, 148,
- 105, 4, 248, 13, 199, 255, 23, 58,
- 71, 181, 57, 151, 156, 25, 165, 7,
- 73, 80, 80, 231, 70, 110, 96, 162,
- 24, 205, 178, 178, 67, 122, 210, 180,
- 92, 6, 156, 182, 84, 159, 85, 6,
- 175, 66, 165, 167, 137, 34, 179, 237,
- 77, 90, 87, 185, 21, 106, 92, 115,
- 137, 65, 233, 42, 164, 153, 208, 133,
- 160, 172, 129, 202, 46, 220, 98, 66,
- 115, 66, 46, 28, 226, 200, 140, 145,
- 207, 194, 58, 71, 56, 203, 113, 34,
- 221, 116, 63, 114, 188, 210, 45, 238,
- 200, 123, 35, 150, 2, 78, 160, 22,
- 226, 167, 162, 10, 182, 75, 109, 97,
- 86, 252, 93, 125, 117, 214, 220, 37,
- 105, 160, 56, 158, 97, 57, 22, 14,
- 73, 169, 111, 190, 222, 176, 14, 82,
- 111, 42, 87, 90, 136, 236, 22, 209,
- 156, 207, 40, 251, 88, 141, 51, 211,
- 31, 158, 153, 91, 119, 83, 255, 60,
- 55, 94, 5, 115, 119, 210, 224, 185,
- 163, 163, 5, 3, 197, 106, 110, 206,
- 109, 132, 50, 190, 177, 133, 175, 129,
- 225, 161, 156, 244, 77, 150, 99, 38,
- 17, 111, 46, 230, 152, 64, 50, 164,
- 19, 78, 3, 164, 169, 175, 104, 97,
- 103, 158, 91, 168, 186, 191, 73, 88,
- 118, 112, 41, 188, 219, 0, 198, 209,
- 206, 7, 5, 169, 127, 180, 80, 74,
- 124, 4, 4, 108, 197, 67, 204, 29,
- 101, 95, 174, 147, 64, 163, 89, 160,
- 10, 5, 56, 134, 209, 69, 209, 55,
- 214, 136, 45, 212, 113, 85, 159, 133,
- 141, 249, 75, 40, 175, 91, 142, 13,
- 179, 179, 51, 0, 136, 63, 148, 175,
- 103, 162, 8, 214, 4, 24, 59, 71,
- 9, 185, 48, 127, 159, 165, 8, 8,
- 135, 151, 92, 214, 132, 151, 204, 169,
- 24, 112, 229, 59, 236, 81, 238, 64,
- 150, 196, 97, 213, 140, 159, 20, 24,
- 79, 210, 191, 53, 130, 33, 157, 87,
- 16, 180, 175, 217, 56, 123, 115, 196,
- 130, 6, 155, 37, 220, 80, 232, 129,
- 240, 57, 199, 249, 196, 152, 28, 111,
- 124, 192, 59, 46, 29, 21, 178, 51,
- 156, 17, 248, 61, 254, 80, 201, 131,
- 203, 59, 227, 191, 71, 121, 134, 181,
- 55, 79, 130, 225, 246, 36, 179, 224,
- 189, 243, 200, 75, 73, 41, 251, 41,
- 71, 251, 78, 146, 99, 101, 104, 69,
- 18, 122, 65, 24, 232, 84, 246, 242,
- 209, 18, 241, 114, 3, 65, 177, 99,
- 49, 99, 215, 59, 9, 175, 195, 11,
- 25, 46, 43, 120, 109, 179, 159, 250,
- 239, 246, 135, 78, 2, 238, 214, 237,
- 64, 170, 50, 44, 68, 67, 111, 232,
- 225, 230, 224, 124, 76, 32, 52, 158,
- 151, 54, 184, 135, 122, 66, 211, 215,
- 121, 90, 124, 158, 55, 73, 116, 137,
- 240, 15, 38, 31, 183, 86, 93, 49,
- 148, 184, 125, 250, 155, 216, 84, 246,
- 27, 172, 141, 54, 80, 158, 227, 254,
- 189, 164, 238, 229, 68, 26, 231, 11,
- 198, 222, 15, 141, 98, 8, 124, 219,
- 60, 125, 170, 213, 114, 24, 189, 65,
- 80, 186, 71, 126, 223, 153, 20, 141,
- 110, 73, 173, 218, 214, 63, 205, 177,
- 132, 115, 184, 28, 122, 232, 210, 72,
- 237, 41, 93, 17, 152, 95, 242, 138,
- 79, 98, 47, 197, 36, 17, 137, 230,
- 15, 73, 193, 1, 181, 123, 0, 186,
- 185, 135, 142, 200, 139, 78, 57, 145,
- 191, 32, 98, 250, 113, 188, 71, 32,
- 205, 81, 219, 99, 60, 87, 42, 95,
- 249, 252, 121, 125, 246, 230, 74, 162,
- 73, 59, 179, 142, 178, 47, 163, 161,
- 236, 14, 123, 219, 18, 6, 102, 140,
- 215, 210, 76, 9, 119, 147, 252, 63,
- 13, 51, 161, 172, 180, 116, 212, 129,
- 116, 237, 38, 64, 213, 222, 35, 14,
- 183, 237, 78, 204, 250, 250, 5, 41,
- 142, 5, 207, 154, 65, 183, 108, 82,
- 1, 43, 149, 233, 89, 195, 25, 233,
- 4, 34, 19, 122, 16, 58, 121, 5,
- 118, 168, 22, 213, 49, 226, 163, 169,
- 21, 78, 179, 232, 125, 216, 198, 147,
- 245, 196, 199, 138, 185, 167, 179, 82,
- 175, 53, 6, 162, 5, 141, 180, 212,
- 95, 201, 234, 169, 111, 175, 138, 197,
- 177, 246, 154, 41, 185, 201, 134, 187,
- 88, 99, 231, 23, 190, 36, 72, 174,
- 244, 185, 205, 50, 230, 226, 210, 119,
- 175, 107, 109, 244, 12, 122, 84, 51,
- 146, 95, 68, 74, 76, 212, 221, 103,
- 244, 71, 63, 133, 149, 233, 48, 3,
- 176, 168, 6, 98, 88, 226, 120, 190,
- 205, 249, 38, 157, 205, 148, 250, 203,
- 147, 62, 195, 229, 219, 109, 177, 119,
- 120, 43, 165, 99, 253, 210, 180, 32,
- 227, 180, 174, 64, 156, 139, 251, 53,
- 205, 132, 210, 208, 3, 199, 115, 64,
- 59, 27, 249, 164, 224, 191, 124, 241,
- 142, 10, 19, 120, 227, 46, 174, 231,
- 48, 65, 41, 56, 51, 38, 185, 95,
- 250, 182, 100, 40, 196, 124, 173, 119,
- 162, 148, 170, 34, 51, 68, 175, 60,
- 242, 201, 225, 34, 146, 157, 159, 0,
- 144, 148, 82, 72, 149, 53, 201, 10,
- 248, 206, 154, 126, 33, 153, 56, 48,
- 5, 90, 194, 22, 251, 173, 211, 202,
- 203, 253, 112, 147, 188, 200, 142, 206,
- 206, 175, 233, 76, 93, 104, 125, 41,
- 64, 145, 202, 53, 130, 251, 23, 90,
- 28, 199, 13, 128, 185, 154, 53, 194,
- 195, 55, 80, 56, 151, 216, 195, 138,
- 7, 170, 143, 236, 74, 141, 229, 174,
- 32, 165, 131, 68, 174, 104, 35, 143,
- 183, 41, 80, 191, 120, 79, 166, 240,
- 123, 55, 60, 2, 128, 56, 4, 199,
- 122, 85, 90, 76, 246, 29, 13, 6,
- 126, 229, 14, 203, 244, 73, 121, 42,
- 169, 35, 44, 202, 18, 69, 153, 120,
- 141, 77, 124, 191, 215, 18, 115, 187,
- 108, 246, 135, 151, 225, 192, 50, 89,
- 128, 45, 39, 253, 149, 234, 203, 84,
- 51, 174, 15, 237, 17, 57, 76, 81,
- 39, 107, 40, 36, 22, 52, 92, 39};
diff --git a/lib/ssl/c_src/esock_osio.c b/lib/ssl/c_src/esock_osio.c
deleted file mode 100644
index 41c5271c16..0000000000
--- a/lib/ssl/c_src/esock_osio.c
+++ /dev/null
@@ -1,328 +0,0 @@
-/*<copyright>
- * <year>1999-2008</year>
- * <holder>Ericsson AB, All Rights Reserved</holder>
- *</copyright>
- *<legalnotice>
- * The contents of this file are subject to the Erlang Public License,
- * Version 1.1, (the "License"); you may not use this file except in
- * compliance with the License. You should have received a copy of the
- * Erlang Public License along with this software. If not, it can be
- * retrieved online at http://www.erlang.org/.
- *
- * Software distributed under the License is distributed on an "AS IS"
- * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
- * the License for the specific language governing rights and limitations
- * under the License.
- *
- * The Initial Developer of the Original Code is Ericsson AB.
- *</legalnotice>
- */
-/*
- * Purpose: Std filedescriptors, break handler
- *
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#ifdef __WIN32__
-#include "esock_winsock.h"
-#include <process.h>
-#include <io.h>
-#include <fcntl.h>
-#else
-#include <unistd.h>
-#include <signal.h>
-#endif
-
-#include "esock.h"
-#include "debuglog.h"
-#include "esock_utils.h"
-#include "esock_osio.h"
-
-#ifdef __WIN32__
-#define write _write
-#define read _read
-#define LOCALHOSTADDR "127.0.0.1"
-#define LOCBUFSIZE 1024
-#endif
-
-#define PACKET_SIZE 4
-#define EBUFSIZE 256
-
-FD local_read_fd = 0;
-
-static int inc_rbuf(int size);
-static void free_rbuf(void);
-static int read_fill(unsigned char *buf, int len);
-#ifdef __WIN32__
-static int create_local_thread(void);
-static DWORD WINAPI local_thread(LPVOID lpvParam);
-static BOOL WINAPI signal_handler(DWORD ctrl);
-#endif
-
-static unsigned char *rbuf = NULL;
-static int rbuf_malloced = 0;
-#ifdef __WIN32__
-static unsigned long one = 1, zero = 0;
-static int local_portno;
-static char *local_buf;
-#endif
-
-int set_break_handler(void)
-{
-#ifndef __WIN32__
- struct sigaction act;
-
- /* Ignore SIGPIPE signal */
- sigemptyset(&act.sa_mask);
- act.sa_flags = 0;
- act.sa_handler = SIG_IGN;
- sigaction(SIGPIPE, &act, NULL);
- return 0;
-#else
- SetConsoleCtrlHandler(signal_handler, TRUE);
- return 0;
-#endif
-}
-
-
-#ifdef __WIN32__
-
-int set_binary_mode(void)
-{
- _setmode(0, _O_BINARY);
- _setmode(1, _O_BINARY);
- return 0;
-}
-
-int esock_osio_init(void)
-{
- return create_local_thread();
-}
-
-void esock_osio_finish(void)
-{
- sock_close(local_read_fd);
-}
-
-#endif
-
-int read_ctrl(unsigned char **ebufp)
-{
- int tbh, cc;
- unsigned char *mbuf;
-
- if (inc_rbuf(EBUFSIZE) < 0) {
- fprintf(stderr, "read_ctrl: cannot alloc rbuf\n");
- return -1;
- }
- cc = read_fill(rbuf, PACKET_SIZE);
- if (cc < 0) {
- free_rbuf();
- return -1;
- }
- if (cc == 0) {
- free_rbuf();
- return -1; /* XXX 0 ?? */
- }
- tbh = GET_INT32(rbuf);
-
- if (tbh > rbuf_malloced - 4) {
- if (inc_rbuf(tbh + 4) < 0)
- return -1;
- }
-
- mbuf = rbuf + PACKET_SIZE;
- cc = read_fill(mbuf, tbh);
- DEBUGF(("-----------------------------------\n"));
- DEBUGF(("read_ctrl: cc = %d\n", cc));
- if(cc > 0) {
- DEBUGMSGF(("message (hex) : [%3.*a]\n", cc, mbuf));
- DEBUGMSGF(("message (char): [%3.*b]\n", cc, mbuf));
- }
- *ebufp = mbuf;
- return cc;
-}
-
-int write_ctrl(unsigned char *buf, int len)
-{
- unsigned char lb[4];
-
- PUT_INT32(len, lb);
- DEBUGF(("write_ctrl: len = %d\n", len));
- DEBUGMSGF(("message (hex) : [%3.*a] [%3.*a]\n", PACKET_SIZE, lb,
- len, buf));
- DEBUGMSGF(("message (char): [%3.*b] [%3.*b]\n", PACKET_SIZE, lb,
- len, buf));
-
- if (write(1, lb, PACKET_SIZE) != PACKET_SIZE) { /* XXX */
- fprintf(stderr, "write_ctrl: Bad write \n");
- return -1;
- }
- if (write(1, buf, len) != len) { /* XXX */
- fprintf(stderr, "write_ctrl: Bad write \n");
- return -1;
- }
- return len;
-}
-
-
-/*
- * Local functions
- *
- */
-
-static int inc_rbuf(int size)
-{
- unsigned char *nbuf;
-
- if (rbuf_malloced >= size)
- return 0;
- if (rbuf != NULL)
- nbuf = esock_realloc(rbuf, size);
- else
- nbuf = esock_malloc(size);
- if(nbuf != NULL) {
- rbuf = nbuf;
- rbuf_malloced = size;
- return 0;
- }
- return -1;
-}
-
-static void free_rbuf(void)
-{
- if (rbuf != NULL) {
- esock_free(rbuf);
- rbuf = NULL;
- rbuf_malloced = 0;
- }
-}
-
-/* Fill buffer, return buffer length, 0 for EOF, < 0 for error. */
-
-static int read_fill(unsigned char *buf, int len)
-{
- int i, got = 0;
-
- do {
- if ((i = sock_read(local_read_fd, buf+got, len-got)) <= 0)
- return i;
- got += i;
- } while (got < len);
- return len;
-}
-
-
-#ifdef __WIN32__
-
-/*
- * This routine creates a local thread, which reads from standard input
- * and writes to a socket.
- */
-
-static int create_local_thread(void)
-{
- struct sockaddr_in iserv_addr;
- SOCKET tmpsock;
- int length;
- unsigned threadaddr;
-
- local_buf = esock_malloc(LOCBUFSIZE);
- if ((tmpsock = socket(AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
- fprintf(stderr, "create_local_thread could not create socket.\n");
- return -1;
- }
- memset(&iserv_addr, 0, sizeof(iserv_addr));
- iserv_addr.sin_family = AF_INET;
- iserv_addr.sin_addr.s_addr = inet_addr(LOCALHOSTADDR);
- iserv_addr.sin_port = htons(0); /* Have any port */
-
- if (bind(tmpsock, (struct sockaddr *) &iserv_addr,
- sizeof(iserv_addr)) < 0) {
- fprintf(stderr, "create_local_thread could not bind.\n");
- closesocket(tmpsock);
- return -1;
- }
- listen(tmpsock, 1);
- length = sizeof(iserv_addr);
- if (getsockname(tmpsock, (struct sockaddr *) &iserv_addr, &length) < 0) {
- fprintf(stderr, "create_local_thread could not getsockname.\n");
- closesocket(tmpsock);
- return -1;
- }
- local_portno = ntohs(iserv_addr.sin_port);
-
- if (_beginthreadex(NULL, 0, local_thread, NULL, 0, &threadaddr) == 0) {
- fprintf(stderr, "create_local_thread could not _beginthreadex().\n");
- closesocket(tmpsock);
- return -1;
- }
- local_read_fd = accept(tmpsock, (struct sockaddr *) NULL, (int *) NULL);
- if (local_read_fd == INVALID_FD) {
- fprintf(stderr, "create_local_thread could not accept.\n");
- closesocket(tmpsock);
- return -1;
- }
- closesocket(tmpsock);
- return 0;
-}
-
-static DWORD WINAPI local_thread(LPVOID lpvParam)
-{
- SOCKET sock;
- struct hostent *host;
- char hostname[64];
- struct sockaddr_in iserv_addr;
- unsigned long addr;
- int len;
- HANDLE thread;
-
- sock = socket(AF_INET, SOCK_STREAM, 0);
- memset(&iserv_addr, 0, sizeof(struct sockaddr_in));
- iserv_addr.sin_family = AF_INET;
- iserv_addr.sin_addr.s_addr = inet_addr(LOCALHOSTADDR);
- iserv_addr.sin_port = htons(local_portno);
- if(connect(sock, (struct sockaddr*)&iserv_addr, sizeof iserv_addr) ==
- SOCKET_ERROR) {
- fprintf(stderr, "local_thread thread could not connect\n");
- closesocket(sock);
- return 0;
- }
- setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, &one, sizeof(one));
-
- /* read from 0 and write to sock */
- while (1) {
- if ((len = read(0, local_buf, LOCBUFSIZE)) <= 0) {
- closesocket(sock);
- close(0);
- return 0;
- }
- if (send(sock, local_buf, len, 0) != len ) {
- closesocket(sock);
- close(0);
- return 0;
- }
- }
- return 0;
-}
-
-/* Signal handler */
-
-static BOOL WINAPI signal_handler(DWORD ctrl)
-{
- switch (ctrl) {
- case CTRL_C_EVENT:
- case CTRL_BREAK_EVENT:
- break;
- case CTRL_LOGOFF_EVENT:
- if (!getenv("ERLSRV_SERVICE_NAME"))
- return FALSE;
- break;
- default:
- exit(1);
- }
- return TRUE;
-}
-
-#endif
diff --git a/lib/ssl/c_src/esock_osio.h b/lib/ssl/c_src/esock_osio.h
deleted file mode 100644
index 8742c3b05b..0000000000
--- a/lib/ssl/c_src/esock_osio.h
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * %CopyrightBegin%
- *
- * Copyright Ericsson AB 1999-2009. All Rights Reserved.
- *
- * The contents of this file are subject to the Erlang Public License,
- * Version 1.1, (the "License"); you may not use this file except in
- * compliance with the License. You should have received a copy of the
- * Erlang Public License along with this software. If not, it can be
- * retrieved online at http://www.erlang.org/.
- *
- * Software distributed under the License is distributed on an "AS IS"
- * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
- * the License for the specific language governing rights and limitations
- * under the License.
- *
- * %CopyrightEnd%
- */
-
-#ifndef ESOCK_OSIO_H
-#define ESOCK_OSIO_H
-
-extern FD local_read_fd;
-
-#ifdef __WIN32__
-int set_binary_mode(void);
-int esock_osio_init(void);
-void esock_osio_finish(void);
-#endif
-int set_break_handler(void);
-int read_ctrl(unsigned char **ebufp);
-int write_ctrl(unsigned char *buf, int len);
-
-#endif
diff --git a/lib/ssl/c_src/esock_poll.c b/lib/ssl/c_src/esock_poll.c
deleted file mode 100644
index e982eba881..0000000000
--- a/lib/ssl/c_src/esock_poll.c
+++ /dev/null
@@ -1,222 +0,0 @@
-/*<copyright>
- * <year>2005-2008</year>
- * <holder>Ericsson AB, All Rights Reserved</holder>
- *</copyright>
- *<legalnotice>
- * The contents of this file are subject to the Erlang Public License,
- * Version 1.1, (the "License"); you may not use this file except in
- * compliance with the License. You should have received a copy of the
- * Erlang Public License along with this software. If not, it can be
- * retrieved online at http://www.erlang.org/.
- *
- * Software distributed under the License is distributed on an "AS IS"
- * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
- * the License for the specific language governing rights and limitations
- * under the License.
- *
- * The Initial Developer of the Original Code is Ericsson AB.
- *</legalnotice>
- */
-
-/*
- * Purpose: Hide poll() and select() behind an API so that we
- * can use either one.
- */
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-#ifdef __WIN32__
-#include "esock_winsock.h"
-#endif
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <stdarg.h>
-#include <string.h>
-#include <time.h>
-#include <ctype.h>
-#include <sys/types.h>
-#include <errno.h>
-
-#ifdef __WIN32__
-#include <process.h>
-#else
-#include <unistd.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <netinet/tcp.h>
-#include <sys/time.h>
-#include <netdb.h>
-#include <arpa/inet.h>
-#include <fcntl.h>
-#endif
-
-#include "esock.h"
-#include "esock_ssl.h"
-#include "esock_utils.h"
-#include "esock_poll.h"
-#include "debuglog.h"
-
-#if !defined(USE_SELECT)
-
-/* At least on FreeBSD, we need POLLRDNORM for normal files, not POLLIN. */
-/* Whether this is a bug in FreeBSD, I don't know. */
-#ifdef POLLRDNORM
-#define POLL_INPUT (POLLIN | POLLRDNORM)
-#else
-#define POLL_INPUT POLLIN
-#endif
-
-static void poll_fd_set(EsockPoll *ep, FD fd, short events)
-{
- int i, j;
- int prev_num_fds = ep->num_fds;
-
- if (ep->num_fds <= fd) {
- ep->num_fds = fd + 64;
- ep->fd_to_poll = (int *) esock_realloc(ep->fd_to_poll,
- ep->num_fds*sizeof(int));
- for (j = prev_num_fds; j < ep->num_fds; j++)
- ep->fd_to_poll[j] = -1;
- }
- i = ep->fd_to_poll[fd];
- if (i > 0 && i < ep->active && ep->fds[i].fd == fd) {
- /* Already present in poll array */
- ep->fds[i].events |= events;
- } else {
- /* Append to poll array */
- if (ep->active >= ep->allocated) {
- ep->allocated *= 2;
- ep->fds = (struct pollfd *)
- esock_realloc(ep->fds, ep->allocated*sizeof(struct pollfd));
- }
- ep->fd_to_poll[fd] = ep->active;
- ep->fds[ep->active].fd = fd;
- ep->fds[ep->active].events = events;
- ep->fds[ep->active].revents = 0;
- ep->active++;
- }
-}
-
-static int poll_is_set(EsockPoll *ep, FD fd, short mask)
-{
- if (fd >= ep->num_fds) {
- return 0;
- } else {
- int i = ep->fd_to_poll[fd];
- return 0 <= i && i < ep->active && ep->fds[i].fd == fd &&
- (ep->fds[i].revents & mask) != 0;
- }
-}
-
-#endif
-
-void esock_poll_init(EsockPoll *ep)
-{
-#ifdef USE_SELECT
- /* Nothing to do here */
-#else
- ep->allocated = 2;
- ep->fds = (struct pollfd *) esock_malloc(ep->allocated*sizeof(struct pollfd));
- ep->num_fds = 1;
- ep->fd_to_poll = esock_malloc(ep->num_fds*sizeof(int));
-#endif
-}
-
-void esock_poll_zero(EsockPoll *ep)
-{
-#ifdef USE_SELECT
- FD_ZERO(&ep->readmask);
- FD_ZERO(&ep->writemask);
- FD_ZERO(&ep->exceptmask);
-#else
- int i;
-
- for (i = 0; i < ep->num_fds; i++)
- ep->fd_to_poll[i] = -1;
- ep->active = 0;
-#endif
-}
-
-void esock_poll_fd_set_read(EsockPoll *ep, FD fd)
-{
-#ifdef USE_SELECT
- FD_SET(fd, &ep->readmask);
-#else
- poll_fd_set(ep, fd, POLL_INPUT);
-#endif
-}
-
-void esock_poll_fd_set_write(EsockPoll *ep, FD fd)
-{
-#ifdef USE_SELECT
- FD_SET(fd, &ep->writemask);
-#else
- poll_fd_set(ep, fd, POLLOUT);
-#endif
-}
-
-int esock_poll_fd_isset_read(EsockPoll *ep, FD fd)
-{
-#ifdef USE_SELECT
- return FD_ISSET(fd, &ep->readmask);
-#else
- return poll_is_set(ep, fd, (POLL_INPUT|POLLHUP|POLLERR|POLLNVAL));
-#endif
-}
-
-int esock_poll_fd_isset_write(EsockPoll *ep, FD fd)
-{
-#ifdef USE_SELECT
- return FD_ISSET(fd, &ep->writemask);
-#else
- return poll_is_set(ep, fd, (POLLOUT|POLLHUP|POLLERR|POLLNVAL));
-#endif
-}
-
-#ifdef __WIN32__
-void esock_poll_fd_set_exception(EsockPoll *ep, FD fd)
-{
- FD_SET(fd, &ep->exceptmask);
-}
-
-int esock_poll_fd_isset_exception(EsockPoll *ep, FD fd)
-{
- return FD_ISSET(fd, &ep->exceptmask);
-}
-#endif
-
-int esock_poll(EsockPoll *ep, int seconds)
-{
- int sret;
-
-#ifdef USE_SELECT
- struct timeval tv;
-
- tv.tv_sec = seconds;
- tv.tv_usec = 0;
- sret = select(FD_SETSIZE, &ep->readmask, &ep->writemask, &ep->exceptmask, &tv);
- if (sret == 0) {
- FD_ZERO(&ep->readmask);
- FD_ZERO(&ep->writemask);
- FD_ZERO(&ep->exceptmask);
- }
-#else
- sret = poll(ep->fds, ep->active, 1000*seconds);
-#endif
- return sret;
-}
-
-void esock_poll_clear_event(EsockPoll* ep, FD fd)
-{
-#ifdef USE_SELECT
- FD_CLR(fd, &ep->readmask);
- FD_CLR(fd, &ep->writemask);
- FD_CLR(fd, &ep->exceptmask);
-#else
- int i = ep->fd_to_poll[fd];
- if (i > 0 && ep->fds[i].fd == fd)
- ep->fds[i].revents = 0;
-#endif
-}
diff --git a/lib/ssl/c_src/esock_poll.h b/lib/ssl/c_src/esock_poll.h
deleted file mode 100644
index 639976dfa9..0000000000
--- a/lib/ssl/c_src/esock_poll.h
+++ /dev/null
@@ -1,60 +0,0 @@
-/*<copyright>
- * <year>2005-2008</year>
- * <holder>Ericsson AB, All Rights Reserved</holder>
- *</copyright>
- *<legalnotice>
- * The contents of this file are subject to the Erlang Public License,
- * Version 1.1, (the "License"); you may not use this file except in
- * compliance with the License. You should have received a copy of the
- * Erlang Public License along with this software. If not, it can be
- * retrieved online at http://www.erlang.org/.
- *
- * Software distributed under the License is distributed on an "AS IS"
- * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
- * the License for the specific language governing rights and limitations
- * under the License.
- *
- * The Initial Developer of the Original Code is Ericsson AB.
- *</legalnotice>
- */
-#ifndef ESOCK_POLL_SELECT_H
-#define ESOCK_POLL_SELECT_H
-
-#if !defined(USE_SELECT)
-#include <poll.h>
-#endif
-
-typedef struct esock_poll {
-#ifdef USE_SELECT
- fd_set readmask;
- fd_set writemask;
- fd_set exceptmask;
-#else
- int* fd_to_poll; /* Map from fd to index into poll
- * descriptor array.
- */
- int num_fds; /* Number of entries in fd_to_poll. */
- struct pollfd* fds; /* Array of poll descriptors. */
- int allocated; /* Allocated number of fds. */
- int active; /* Active number of fds */
-#endif
-} EsockPoll;
-
-void esock_poll_init(EsockPoll *ep);
-void esock_poll_zero(EsockPoll *ep);
-
-void esock_poll_fd_set_read(EsockPoll *ep, FD fd);
-void esock_poll_fd_set_write(EsockPoll *ep, FD fd);
-
-void esock_poll_clear_event(EsockPoll *ep, FD fd);
-
-int esock_poll_fd_isset_read(EsockPoll *ep, FD fd);
-int esock_poll_fd_isset_write(EsockPoll *ep, FD fd);
-
-#ifdef __WIN32__
-void esock_poll_fd_set_exception(EsockPoll *ep, FD fd);
-int esock_poll_fd_isset_exception(EsockPoll *ep, FD fd);
-#endif
-
-int esock_poll(EsockPoll *ep, int seconds);
-#endif
diff --git a/lib/ssl/c_src/esock_posix_str.c b/lib/ssl/c_src/esock_posix_str.c
deleted file mode 100644
index 31062baaaf..0000000000
--- a/lib/ssl/c_src/esock_posix_str.c
+++ /dev/null
@@ -1,642 +0,0 @@
-/*
- * %ExternalCopyright%
- */
-
-/*
- * Original: tclPosixStr.c --
- *
- * This file contains procedures that generate strings
- * corresponding to various POSIX-related codes, such
- * as errno and signals.
- *
- * Copyright (c) 1991-1994 The Regents of the University of California.
- * Copyright (c) 1994-1996 Sun Microsystems, Inc.
- *
- * See the file "license.terms" for information on usage and redistribution
- * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
- *
- * SCCS: @(#) tclPosixStr.c 1.32 96/10/10 10:09:42
- */
-
-/* Copy of erl_posix_str.c */
-
-#ifdef __WIN32__
-#include "esock_winsock.h"
-#endif
-
-#include <stdio.h>
-#include <errno.h>
-#include "esock_posix_str.h"
-
-/*
- *----------------------------------------------------------------------
- *
- * esock_posix_str --
- *
- * Return a textual identifier for the given errno value.
- *
- * Results:
- * This procedure returns a machine-readable textual identifier
- * that corresponds to the current errno value (e.g. "eperm").
- * The identifier is the same as the #define name in errno.h,
- * except that it is in lowercase.
- *
- *----------------------------------------------------------------------
- */
-
-static char errstrbuf[32];
-
-char *esock_posix_str(int error)
-{
- switch (error) {
-#ifdef E2BIG
- case E2BIG: return "e2big";
-#endif
-#ifdef EACCES
- case EACCES: return "eacces";
-#endif
-#ifdef EADDRINUSE
- case EADDRINUSE: return "eaddrinuse";
-#endif
-#ifdef EADDRNOTAVAIL
- case EADDRNOTAVAIL: return "eaddrnotavail";
-#endif
-#ifdef EADV
- case EADV: return "eadv";
-#endif
-#ifdef EAFNOSUPPORT
- case EAFNOSUPPORT: return "eafnosupport";
-#endif
-#ifdef EAGAIN
- case EAGAIN: return "eagain";
-#endif
-#ifdef EALIGN
- case EALIGN: return "ealign";
-#endif
-#if defined(EALREADY) && (!defined(EBUSY) || (EALREADY != EBUSY ))
- case EALREADY: return "ealready";
-#endif
-#ifdef EBADE
- case EBADE: return "ebade";
-#endif
-#ifdef EBADF
- case EBADF: return "ebadf";
-#endif
-#ifdef EBADFD
- case EBADFD: return "ebadfd";
-#endif
-#ifdef EBADMSG
- case EBADMSG: return "ebadmsg";
-#endif
-#ifdef EBADR
- case EBADR: return "ebadr";
-#endif
-#ifdef EBADRPC
- case EBADRPC: return "ebadrpc";
-#endif
-#ifdef EBADRQC
- case EBADRQC: return "ebadrqc";
-#endif
-#ifdef EBADSLT
- case EBADSLT: return "ebadslt";
-#endif
-#ifdef EBFONT
- case EBFONT: return "ebfont";
-#endif
-#ifdef EBUSY
- case EBUSY: return "ebusy";
-#endif
-#ifdef ECHILD
- case ECHILD: return "echild";
-#endif
-#ifdef ECHRNG
- case ECHRNG: return "echrng";
-#endif
-#ifdef ECOMM
- case ECOMM: return "ecomm";
-#endif
-#ifdef ECONNABORTED
- case ECONNABORTED: return "econnaborted";
-#endif
-#ifdef ECONNREFUSED
- case ECONNREFUSED: return "econnrefused";
-#endif
-#ifdef ECONNRESET
- case ECONNRESET: return "econnreset";
-#endif
-#if defined(EDEADLK) && (!defined(EWOULDBLOCK) || (EDEADLK != EWOULDBLOCK))
- case EDEADLK: return "edeadlk";
-#endif
-#if defined(EDEADLOCK) && (!defined(EDEADLK) || (EDEADLOCK != EDEADLK))
- case EDEADLOCK: return "edeadlock";
-#endif
-#ifdef EDESTADDRREQ
- case EDESTADDRREQ: return "edestaddrreq";
-#endif
-#ifdef EDIRTY
- case EDIRTY: return "edirty";
-#endif
-#ifdef EDOM
- case EDOM: return "edom";
-#endif
-#ifdef EDOTDOT
- case EDOTDOT: return "edotdot";
-#endif
-#ifdef EDQUOT
- case EDQUOT: return "edquot";
-#endif
-#ifdef EDUPPKG
- case EDUPPKG: return "eduppkg";
-#endif
-#ifdef EEXIST
- case EEXIST: return "eexist";
-#endif
-#ifdef EFAULT
- case EFAULT: return "efault";
-#endif
-#ifdef EFBIG
- case EFBIG: return "efbig";
-#endif
-#ifdef EHOSTDOWN
- case EHOSTDOWN: return "ehostdown";
-#endif
-#ifdef EHOSTUNREACH
- case EHOSTUNREACH: return "ehostunreach";
-#endif
-#if defined(EIDRM) && (!defined(EINPROGRESS) || (EIDRM != EINPROGRESS))
- case EIDRM: return "eidrm";
-#endif
-#ifdef EINIT
- case EINIT: return "einit";
-#endif
-#ifdef EINPROGRESS
- case EINPROGRESS: return "einprogress";
-#endif
-#ifdef EINTR
- case EINTR: return "eintr";
-#endif
-#ifdef EINVAL
- case EINVAL: return "einval";
-#endif
-#ifdef EIO
- case EIO: return "eio";
-#endif
-#ifdef EISCONN
- case EISCONN: return "eisconn";
-#endif
-#ifdef EISDIR
- case EISDIR: return "eisdir";
-#endif
-#ifdef EISNAME
- case EISNAM: return "eisnam";
-#endif
-#ifdef ELBIN
- case ELBIN: return "elbin";
-#endif
-#ifdef EL2HLT
- case EL2HLT: return "el2hlt";
-#endif
-#ifdef EL2NSYNC
- case EL2NSYNC: return "el2nsync";
-#endif
-#ifdef EL3HLT
- case EL3HLT: return "el3hlt";
-#endif
-#ifdef EL3RST
- case EL3RST: return "el3rst";
-#endif
-#ifdef ELIBACC
- case ELIBACC: return "elibacc";
-#endif
-#ifdef ELIBBAD
- case ELIBBAD: return "elibbad";
-#endif
-#ifdef ELIBEXEC
- case ELIBEXEC: return "elibexec";
-#endif
-#ifdef ELIBMAX
- case ELIBMAX: return "elibmax";
-#endif
-#ifdef ELIBSCN
- case ELIBSCN: return "elibscn";
-#endif
-#ifdef ELNRNG
- case ELNRNG: return "elnrng";
-#endif
-#if defined(ELOOP) && (!defined(ENOENT) || (ELOOP != ENOENT))
- case ELOOP: return "eloop";
-#endif
-#ifdef EMFILE
- case EMFILE: return "emfile";
-#endif
-#ifdef EMLINK
- case EMLINK: return "emlink";
-#endif
-#ifdef EMSGSIZE
- case EMSGSIZE: return "emsgsize";
-#endif
-#ifdef EMULTIHOP
- case EMULTIHOP: return "emultihop";
-#endif
-#ifdef ENAMETOOLONG
- case ENAMETOOLONG: return "enametoolong";
-#endif
-#ifdef ENAVAIL
- case ENAVAIL: return "enavail";
-#endif
-#ifdef ENET
- case ENET: return "enet";
-#endif
-#ifdef ENETDOWN
- case ENETDOWN: return "enetdown";
-#endif
-#ifdef ENETRESET
- case ENETRESET: return "enetreset";
-#endif
-#ifdef ENETUNREACH
- case ENETUNREACH: return "enetunreach";
-#endif
-#ifdef ENFILE
- case ENFILE: return "enfile";
-#endif
-#ifdef ENOANO
- case ENOANO: return "enoano";
-#endif
-#if defined(ENOBUFS) && (!defined(ENOSR) || (ENOBUFS != ENOSR))
- case ENOBUFS: return "enobufs";
-#endif
-#ifdef ENOCSI
- case ENOCSI: return "enocsi";
-#endif
-#if defined(ENODATA) && (!defined(ECONNREFUSED) || (ENODATA != ECONNREFUSED))
- case ENODATA: return "enodata";
-#endif
-#ifdef ENODEV
- case ENODEV: return "enodev";
-#endif
-#ifdef ENOENT
- case ENOENT: return "enoent";
-#endif
-#ifdef ENOEXEC
- case ENOEXEC: return "enoexec";
-#endif
-#ifdef ENOLCK
- case ENOLCK: return "enolck";
-#endif
-#ifdef ENOLINK
- case ENOLINK: return "enolink";
-#endif
-#ifdef ENOMEM
- case ENOMEM: return "enomem";
-#endif
-#ifdef ENOMSG
- case ENOMSG: return "enomsg";
-#endif
-#ifdef ENONET
- case ENONET: return "enonet";
-#endif
-#ifdef ENOPKG
- case ENOPKG: return "enopkg";
-#endif
-#ifdef ENOPROTOOPT
- case ENOPROTOOPT: return "enoprotoopt";
-#endif
-#ifdef ENOSPC
- case ENOSPC: return "enospc";
-#endif
-#if defined(ENOSR) && (!defined(ENAMETOOLONG) || (ENAMETOOLONG != ENOSR))
- case ENOSR: return "enosr";
-#endif
-#if defined(ENOSTR) && (!defined(ENOTTY) || (ENOTTY != ENOSTR))
- case ENOSTR: return "enostr";
-#endif
-#ifdef ENOSYM
- case ENOSYM: return "enosym";
-#endif
-#ifdef ENOSYS
- case ENOSYS: return "enosys";
-#endif
-#ifdef ENOTBLK
- case ENOTBLK: return "enotblk";
-#endif
-#ifdef ENOTCONN
- case ENOTCONN: return "enotconn";
-#endif
-#ifdef ENOTDIR
- case ENOTDIR: return "enotdir";
-#endif
-#if defined(ENOTEMPTY) && (!defined(EEXIST) || (ENOTEMPTY != EEXIST))
- case ENOTEMPTY: return "enotempty";
-#endif
-#ifdef ENOTNAM
- case ENOTNAM: return "enotnam";
-#endif
-#ifdef ENOTSOCK
- case ENOTSOCK: return "enotsock";
-#endif
-#ifdef ENOTSUP
- case ENOTSUP: return "enotsup";
-#endif
-#ifdef ENOTTY
- case ENOTTY: return "enotty";
-#endif
-#ifdef ENOTUNIQ
- case ENOTUNIQ: return "enotuniq";
-#endif
-#ifdef ENXIO
- case ENXIO: return "enxio";
-#endif
-#if defined(EOPNOTSUPP) && (!defined(ENOTSUP) || EOPNOTSUPP != ENOTSUP)
- case EOPNOTSUPP: return "eopnotsupp";
-#endif
-#ifdef EPERM
- case EPERM: return "eperm";
-#endif
-#if defined(EPFNOSUPPORT) && (!defined(ENOLCK) || (ENOLCK != EPFNOSUPPORT))
- case EPFNOSUPPORT: return "epfnosupport";
-#endif
-#ifdef EPIPE
- case EPIPE: return "epipe";
-#endif
-#ifdef EPROCLIM
- case EPROCLIM: return "eproclim";
-#endif
-#ifdef EPROCUNAVAIL
- case EPROCUNAVAIL: return "eprocunavail";
-#endif
-#ifdef EPROGMISMATCH
- case EPROGMISMATCH: return "eprogmismatch";
-#endif
-#ifdef EPROGUNAVAIL
- case EPROGUNAVAIL: return "eprogunavail";
-#endif
-#ifdef EPROTO
- case EPROTO: return "eproto";
-#endif
-#ifdef EPROTONOSUPPORT
- case EPROTONOSUPPORT: return "eprotonosupport";
-#endif
-#ifdef EPROTOTYPE
- case EPROTOTYPE: return "eprototype";
-#endif
-#ifdef ERANGE
- case ERANGE: return "erange";
-#endif
-#if defined(EREFUSED) && (!defined(ECONNREFUSED) || (EREFUSED != ECONNREFUSED))
- case EREFUSED: return "erefused";
-#endif
-#ifdef EREMCHG
- case EREMCHG: return "eremchg";
-#endif
-#ifdef EREMDEV
- case EREMDEV: return "eremdev";
-#endif
-#ifdef EREMOTE
- case EREMOTE: return "eremote";
-#endif
-#ifdef EREMOTEIO
- case EREMOTEIO: return "eremoteio";
-#endif
-#ifdef EREMOTERELEASE
- case EREMOTERELEASE: return "eremoterelease";
-#endif
-#ifdef EROFS
- case EROFS: return "erofs";
-#endif
-#ifdef ERPCMISMATCH
- case ERPCMISMATCH: return "erpcmismatch";
-#endif
-#ifdef ERREMOTE
- case ERREMOTE: return "erremote";
-#endif
-#ifdef ESHUTDOWN
- case ESHUTDOWN: return "eshutdown";
-#endif
-#ifdef ESOCKTNOSUPPORT
- case ESOCKTNOSUPPORT: return "esocktnosupport";
-#endif
-#ifdef ESPIPE
- case ESPIPE: return "espipe";
-#endif
-#ifdef ESRCH
- case ESRCH: return "esrch";
-#endif
-#ifdef ESRMNT
- case ESRMNT: return "esrmnt";
-#endif
-#ifdef ESTALE
- case ESTALE: return "estale";
-#endif
-#ifdef ESUCCESS
- case ESUCCESS: return "esuccess";
-#endif
-#if defined(ETIME) && (!defined(ELOOP) || (ETIME != ELOOP))
- case ETIME: return "etime";
-#endif
-#if defined(ETIMEDOUT) && (!defined(ENOSTR) || (ETIMEDOUT != ENOSTR))
- case ETIMEDOUT: return "etimedout";
-#endif
-#ifdef ETOOMANYREFS
- case ETOOMANYREFS: return "etoomanyrefs";
-#endif
-#ifdef ETXTBSY
- case ETXTBSY: return "etxtbsy";
-#endif
-#ifdef EUCLEAN
- case EUCLEAN: return "euclean";
-#endif
-#ifdef EUNATCH
- case EUNATCH: return "eunatch";
-#endif
-#ifdef EUSERS
- case EUSERS: return "eusers";
-#endif
-#ifdef EVERSION
- case EVERSION: return "eversion";
-#endif
-#if defined(EWOULDBLOCK) && (!defined(EAGAIN) || (EWOULDBLOCK != EAGAIN))
- case EWOULDBLOCK: return "ewouldblock";
-#endif
-#ifdef EXDEV
- case EXDEV: return "exdev";
-#endif
-#ifdef EXFULL
- case EXFULL: return "exfull";
-#endif
-#ifdef WSAEINTR
- case WSAEINTR: return "eintr";
-#endif
-#ifdef WSAEBADF
- case WSAEBADF: return "ebadf";
-#endif
-#ifdef WSAEACCES
- case WSAEACCES: return "eacces";
-#endif
-#ifdef WSAEFAULT
- case WSAEFAULT: return "efault";
-#endif
-#ifdef WSAEINVAL
- case WSAEINVAL: return "einval";
-#endif
-#ifdef WSAEMFILE
- case WSAEMFILE: return "emfile";
-#endif
-#ifdef WSAEWOULDBLOCK
- case WSAEWOULDBLOCK: return "ewouldblock";
-#endif
-#ifdef WSAEINPROGRESS
- case WSAEINPROGRESS: return "einprogress";
-#endif
-#ifdef WSAEALREADY
- case WSAEALREADY: return "ealready";
-#endif
-#ifdef WSAENOTSOCK
- case WSAENOTSOCK: return "enotsock";
-#endif
-#ifdef WSAEDESTADDRREQ
- case WSAEDESTADDRREQ: return "edestaddrreq";
-#endif
-#ifdef WSAEMSGSIZE
- case WSAEMSGSIZE: return "emsgsize";
-#endif
-#ifdef WSAEPROTOTYPE
- case WSAEPROTOTYPE: return "eprototype";
-#endif
-#ifdef WSAENOPROTOOPT
- case WSAENOPROTOOPT: return "enoprotoopt";
-#endif
-#ifdef WSAEPROTONOSUPPORT
- case WSAEPROTONOSUPPORT: return "eprotonosupport";
-#endif
-#ifdef WSAESOCKTNOSUPPORT
- case WSAESOCKTNOSUPPORT: return "esocktnosupport";
-#endif
-#ifdef WSAEOPNOTSUPP
- case WSAEOPNOTSUPP: return "eopnotsupp";
-#endif
-#ifdef WSAEPFNOSUPPORT
- case WSAEPFNOSUPPORT: return "epfnosupport";
-#endif
-#ifdef WSAEAFNOSUPPORT
- case WSAEAFNOSUPPORT: return "eafnosupport";
-#endif
-#ifdef WSAEADDRINUSE
- case WSAEADDRINUSE: return "eaddrinuse";
-#endif
-#ifdef WSAEADDRNOTAVAIL
- case WSAEADDRNOTAVAIL: return "eaddrnotavail";
-#endif
-#ifdef WSAENETDOWN
- case WSAENETDOWN: return "enetdown";
-#endif
-#ifdef WSAENETUNREACH
- case WSAENETUNREACH: return "enetunreach";
-#endif
-#ifdef WSAENETRESET
- case WSAENETRESET: return "enetreset";
-#endif
-#ifdef WSAECONNABORTED
- case WSAECONNABORTED: return "econnaborted";
-#endif
-#ifdef WSAECONNRESET
- case WSAECONNRESET: return "econnreset";
-#endif
-#ifdef WSAENOBUFS
- case WSAENOBUFS: return "enobufs";
-#endif
-#ifdef WSAEISCONN
- case WSAEISCONN: return "eisconn";
-#endif
-#ifdef WSAENOTCONN
- case WSAENOTCONN: return "enotconn";
-#endif
-#ifdef WSAESHUTDOWN
- case WSAESHUTDOWN: return "eshutdown";
-#endif
-#ifdef WSAETOOMANYREFS
- case WSAETOOMANYREFS: return "etoomanyrefs";
-#endif
-#ifdef WSAETIMEDOUT
- case WSAETIMEDOUT: return "etimedout";
-#endif
-#ifdef WSAECONNREFUSED
- case WSAECONNREFUSED: return "econnrefused";
-#endif
-#ifdef WSAELOOP
- case WSAELOOP: return "eloop";
-#endif
-#ifdef WSAENAMETOOLONG
- case WSAENAMETOOLONG: return "enametoolong";
-#endif
-#ifdef WSAEHOSTDOWN
- case WSAEHOSTDOWN: return "ehostdown";
-#endif
-#ifdef WSAEHOSTUNREACH
- case WSAEHOSTUNREACH: return "ehostunreach";
-#endif
-#ifdef WSAENOTEMPTY
- case WSAENOTEMPTY: return "enotempty";
-#endif
-#ifdef WSAEPROCLIM
- case WSAEPROCLIM: return "eproclim";
-#endif
-#ifdef WSAEUSERS
- case WSAEUSERS: return "eusers";
-#endif
-#ifdef WSAEDQUOT
- case WSAEDQUOT: return "edquot";
-#endif
-#ifdef WSAESTALE
- case WSAESTALE: return "estale";
-#endif
-#ifdef WSAEREMOTE
- case WSAEREMOTE: return "eremote";
-#endif
-#ifdef WSASYSNOTREADY
- case WSASYSNOTREADY: return "sysnotready";
-#endif
-#ifdef WSAVERNOTSUPPORTED
- case WSAVERNOTSUPPORTED: return "vernotsupported";
-#endif
-#ifdef WSANOTINITIALISED
- case WSANOTINITIALISED: return "notinitialised";
-#endif
-#ifdef WSAEDISCON
- case WSAEDISCON: return "ediscon";
-#endif
-#ifdef WSAENOMORE
- case WSAENOMORE: return "enomore";
-#endif
-#ifdef WSAECANCELLED
- case WSAECANCELLED: return "ecancelled";
-#endif
-#ifdef WSAEINVALIDPROCTABLE
- case WSAEINVALIDPROCTABLE: return "einvalidproctable";
-#endif
-#ifdef WSAEINVALIDPROVIDER
- case WSAEINVALIDPROVIDER: return "einvalidprovider";
-#endif
-#ifdef WSAEPROVIDERFAILEDINIT
- case WSAEPROVIDERFAILEDINIT: return "eproviderfailedinit";
-#endif
-#ifdef WSASYSCALLFAILURE
- case WSASYSCALLFAILURE: return "syscallfailure";
-#endif
-#ifdef WSASERVICE_NOT_FOUND
- case WSASERVICE_NOT_FOUND: return "service_not_found";
-#endif
-#ifdef WSATYPE_NOT_FOUND
- case WSATYPE_NOT_FOUND: return "type_not_found";
-#endif
-#ifdef WSA_E_NO_MORE
- case WSA_E_NO_MORE: return "e_no_more";
-#endif
-#ifdef WSA_E_CANCELLED
- case WSA_E_CANCELLED: return "e_cancelled";
-#endif
- default:
- sprintf(errstrbuf, "unknown:%d", error);
- return errstrbuf;
- }
-}
-
diff --git a/lib/ssl/c_src/esock_posix_str.h b/lib/ssl/c_src/esock_posix_str.h
deleted file mode 100644
index 53916c888a..0000000000
--- a/lib/ssl/c_src/esock_posix_str.h
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * %CopyrightBegin%
- *
- * Copyright Ericsson AB 1999-2009. All Rights Reserved.
- *
- * The contents of this file are subject to the Erlang Public License,
- * Version 1.1, (the "License"); you may not use this file except in
- * compliance with the License. You should have received a copy of the
- * Erlang Public License along with this software. If not, it can be
- * retrieved online at http://www.erlang.org/.
- *
- * Software distributed under the License is distributed on an "AS IS"
- * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
- * the License for the specific language governing rights and limitations
- * under the License.
- *
- * %CopyrightEnd%
- */
-
-/* esock_posix_str.h */
-
-#ifndef ESOCK_POSIX_STR_H
-#define ESOCK_POSIX_STR_H
-
-char *esock_posix_str(int error);
-
-#endif
-
diff --git a/lib/ssl/c_src/esock_ssl.h b/lib/ssl/c_src/esock_ssl.h
deleted file mode 100644
index 535e9a6491..0000000000
--- a/lib/ssl/c_src/esock_ssl.h
+++ /dev/null
@@ -1,110 +0,0 @@
-/*<copyright>
- * <year>1999-2008</year>
- * <holder>Ericsson AB, All Rights Reserved</holder>
- *</copyright>
- *<legalnotice>
- * The contents of this file are subject to the Erlang Public License,
- * Version 1.1, (the "License"); you may not use this file except in
- * compliance with the License. You should have received a copy of the
- * Erlang Public License along with this software. If not, it can be
- * retrieved online at http://www.erlang.org/.
- *
- * Software distributed under the License is distributed on an "AS IS"
- * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
- * the License for the specific language governing rights and limitations
- * under the License.
- *
- * The Initial Developer of the Original Code is Ericsson AB.
- *</legalnotice>
- */
-/*
- * Purpose: Header file for adaptions to various SSL packages.
- */
-
-#ifndef ESOCK_SSL_H
-#define ESOCK_SSL_H
-
-#include <sys/types.h>
-#include <stdio.h>
-#include "esock.h"
-
-typedef struct {
- const char *compile_version;/* version of OpenSSL when compiling esock */
- const char *lib_version; /* version of OpenSSL in library */
-} esock_version;
-
-/* Variables to be set by certain functions (see below) */
-char *esock_ssl_errstr;
-
-/* Ephemeral RSA and DH */
-int ephemeral_rsa, ephemeral_dh;
-
-/* Protocol version (sslv2, sslv3, tlsv1) */
-int protocol_version;
-
-/* version info */
-esock_version *esock_ssl_version(void);
-
-/* ciphers info */
-char *esock_ssl_ciphers(void);
-
-/* seeding */
-void esock_ssl_seed(void *buf, int len);
-
-/* Initialization and finalization of SSL */
-
-int esock_ssl_init(void);
-void esock_ssl_finish(void);
-
-/* Freeing of SSL resources for a connection */
-
-void esock_ssl_free(Connection *cp);
-
-/* Print error diagnostics to a file pointer */
-
-void esock_ssl_print_errors_fp(FILE *fp);
-
-/* All functions below have to return >= 0 on success, and < 0 on
- * failure.
- *
- * If the return indicates a failure (return value < 0) and the failure
- * is temporary the error context (sock_errno()/sock_set_errno()) must
- * be set to ERRNO_BLOCK.
- *
- * If the failure is permanent, the error context must be set to something
- * else than ERRNO_BLOCK, and `esock_ssl_errstr' must be set to point to
- * short diagnostic string describing the error.
- */
-
-int esock_ssl_accept_init(Connection *cp, void *listenssl);
-int esock_ssl_connect_init(Connection *cp);
-int esock_ssl_listen_init(Connection *cp);
-
-/* All functions below may involve non-blocking I/O with a temporary
- * failure. Hence they have to have the error context set to
- * ERRNO_BLOCK, or else have esock_ssl_errstr set to point to a
- * diagnostic string, in case the return value is < 0. If the return
- * value is 0, cp->eof and cp->bp are set, if appropritate.
- */
-
-int esock_ssl_accept(Connection *cp);
-int esock_ssl_connect(Connection *cp);
-
-int esock_ssl_read(Connection *cp, char *buf, int len);
-int esock_ssl_write(Connection *cp, char *buf, int len);
-
-int esock_ssl_shutdown(Connection *cp);
-
-/* Peer certificate */
-
-int esock_ssl_getpeercert(Connection *cp, unsigned char **buf);
-int esock_ssl_getpeercertchain(Connection *cp, unsigned char **buf);
-
-/* Sessions */
-int esock_ssl_session_reused(Connection *cp);
-
-/* Protocol version and cipher of established connection */
-int esock_ssl_getprotocol_version(Connection *cp, char **buf);
-int esock_ssl_getcipher(Connection *cp, char **buf);
-
-#endif
diff --git a/lib/ssl/c_src/esock_utils.c b/lib/ssl/c_src/esock_utils.c
deleted file mode 100644
index 0098a4f5f6..0000000000
--- a/lib/ssl/c_src/esock_utils.c
+++ /dev/null
@@ -1,150 +0,0 @@
-/*
- * %CopyrightBegin%
- *
- * Copyright Ericsson AB 1999-2009. All Rights Reserved.
- *
- * The contents of this file are subject to the Erlang Public License,
- * Version 1.1, (the "License"); you may not use this file except in
- * compliance with the License. You should have received a copy of the
- * Erlang Public License along with this software. If not, it can be
- * retrieved online at http://www.erlang.org/.
- *
- * Software distributed under the License is distributed on an "AS IS"
- * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
- * the License for the specific language governing rights and limitations
- * under the License.
- *
- * %CopyrightEnd%
- */
-
-/*
- * Purpose: Safe memory allocation and other utilities.
- *
- */
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include "esock_utils.h"
-
-static char *strtok_quote(char *s1, const char *s2);
-
-
-void *esock_malloc(size_t size)
-{
- void *p;
-
- p = malloc(size);
- if (!p) {
- fprintf(stderr, "esock_malloc: cannot alloc %d bytes\n", size);
- exit(EXIT_FAILURE);
- }
- return p;
-}
-
-void *esock_realloc(void *p, size_t size)
-{
- void *np;
-
- np = realloc(p, size);
- if (!np) {
- fprintf(stderr, "esock_realloc: cannot realloc %d bytes\n", size);
- exit(EXIT_FAILURE);
- }
- return np;
-}
-
-void esock_free(void *p)
-{
- free(p);
-}
-
-/* Builds an argv array from cmd. Spaces and tabs within double quotes
- * are not considered delimiters. Double quotes are removed.
- *
- * The return value is argc, and the pointer to char ** is set. argc
- * is non-negative, argv[0], ..., argv[argc - 1] are pointers to
- * strings, and argv[argc] == NULL. All argv[0], ..., argv[argc - 1]
- * must be freed by the user, and also the argv pointer itself.
- *
- * Example: cmd = abc"/program files/"olle nisse, results in
- * argv[0] = abc/program files/olle, argv[1] = nisse, argc = 2.
- *
- */
-int esock_build_argv(char *cmd, char ***argvp)
-{
- int argvsize = 10, argc = 0;
- char *args, *tokp, *argp;
- char **argv;
-
- argv = esock_malloc(argvsize * sizeof(char *));
- args = esock_malloc(strlen(cmd) + 1);
- strcpy(args, cmd);
- tokp = strtok_quote(args, " \t");
- while (tokp != NULL) {
- if (argc + 1 >= argvsize) {
- argvsize += 10;
- argv = esock_realloc(argv, argvsize * sizeof(char *));
- }
- argp = esock_malloc(strlen(tokp) + 1);
- strcpy(argp, tokp);
- argv[argc++] = argp;
- tokp = strtok_quote(NULL, " \t");
- }
- esock_free(args);
- argv[argc] = NULL;
- *argvp = argv;
- return argc;
-}
-
-/* strtok_quote
- * Works as strtok, but characters within pairs of double quotes are not
- * considered as delimiters. Quotes are removed.
- */
-static char *strtok_quote(char *s1, const char *s2)
-{
- static char *last;
- char *s, *t, *u;
-
- s = (s1) ? s1 : last;
- if (!s)
- return last = NULL;
-
- while (*s != '"' && *s != '\0' && strchr(s2, *s))
- s++;
- t = s;
-
- while (1) {
- if (*t == '"') {
- t++;
- while (*t != '"' && *t != '\0')
- t++;
- if (*t == '\0') {
- last = NULL;
- goto end;
- }
- t++;
- }
- while(*t != '"' && *t != '\0' && !strchr(s2, *t))
- t++;
- if (*t == '\0') {
- last = NULL;
- goto end;
- } else if (*t != '"') {
- *t = '\0';
- last = t + 1;
- goto end;
- }
- }
-end:
- /* Remove quotes */
- u = t = s;
- while (*u) {
- if (*u == '"')
- u++;
- else
- *t++ = *u++;
- }
- *t = '\0';
- return s;
-}
-
diff --git a/lib/ssl/c_src/esock_utils.h b/lib/ssl/c_src/esock_utils.h
deleted file mode 100644
index 99ed6c23e3..0000000000
--- a/lib/ssl/c_src/esock_utils.h
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * %CopyrightBegin%
- *
- * Copyright Ericsson AB 1999-2009. All Rights Reserved.
- *
- * The contents of this file are subject to the Erlang Public License,
- * Version 1.1, (the "License"); you may not use this file except in
- * compliance with the License. You should have received a copy of the
- * Erlang Public License along with this software. If not, it can be
- * retrieved online at http://www.erlang.org/.
- *
- * Software distributed under the License is distributed on an "AS IS"
- * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
- * the License for the specific language governing rights and limitations
- * under the License.
- *
- * %CopyrightEnd%
- */
-
-#ifndef ESOCK_UTILS_H
-#define ESOCK_UTILS_H
-
-#include <stdlib.h>
-
-void *esock_malloc(size_t size);
-void *esock_realloc(void *p, size_t size);
-void esock_free(void *p);
-int esock_build_argv(char *cmd, char ***argvp);
-
-#endif
-
-
diff --git a/lib/ssl/c_src/esock_winsock.h b/lib/ssl/c_src/esock_winsock.h
deleted file mode 100644
index 069782a18d..0000000000
--- a/lib/ssl/c_src/esock_winsock.h
+++ /dev/null
@@ -1,36 +0,0 @@
-/*<copyright>
- * <year>2003-2008</year>
- * <holder>Ericsson AB, All Rights Reserved</holder>
- *</copyright>
- *<legalnotice>
- * The contents of this file are subject to the Erlang Public License,
- * Version 1.1, (the "License"); you may not use this file except in
- * compliance with the License. You should have received a copy of the
- * Erlang Public License along with this software. If not, it can be
- * retrieved online at http://www.erlang.org/.
- *
- * Software distributed under the License is distributed on an "AS IS"
- * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
- * the License for the specific language governing rights and limitations
- * under the License.
- *
- * The Initial Developer of the Original Code is Ericsson AB.
- *</legalnotice>
- */
-/*
- * Purpose: Control winsock version and setting of FD_SETSIZE.
- *
- */
-
-/* Maybe set FD_SETSIZE */
-
-#ifdef ESOCK_WINSOCK2
-#include <winsock2.h>
-#else
-#include <winsock.h>
-/* These are defined in winsock2.h but not in winsock.h */
-#define SD_RECEIVE 0x00
-#define SD_SEND 0x01
-#define SD_BOTH 0x02
-#endif
-
diff --git a/lib/ssl/doc/src/Makefile b/lib/ssl/doc/src/Makefile
index 3119d37af0..5d808d6727 100644
--- a/lib/ssl/doc/src/Makefile
+++ b/lib/ssl/doc/src/Makefile
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 1999-2010. All Rights Reserved.
+# Copyright Ericsson AB 1999-2011. All Rights Reserved.
#
# The contents of this file are subject to the Erlang Public License,
# Version 1.1, (the "License"); you may not use this file except in
@@ -37,7 +37,7 @@ RELSYSDIR = $(RELEASE_PATH)/lib/$(APPLICATION)-$(VSN)
# Target Specs
# ----------------------------------------------------
XML_APPLICATION_FILES = refman.xml
-XML_REF3_FILES = ssl.xml old_ssl.xml ssl_session_cache_api.xml
+XML_REF3_FILES = ssl.xml ssl_session_cache_api.xml
XML_REF6_FILES = ssl_app.xml
XML_PART_FILES = release_notes.xml usersguide.xml
diff --git a/lib/ssl/doc/src/old_ssl.xml b/lib/ssl/doc/src/old_ssl.xml
deleted file mode 100644
index 0d2e1afdbd..0000000000
--- a/lib/ssl/doc/src/old_ssl.xml
+++ /dev/null
@@ -1,709 +0,0 @@
-<?xml version="1.0" encoding="latin1" ?>
-<!DOCTYPE erlref SYSTEM "erlref.dtd">
-
-<erlref>
- <header>
- <copyright>
- <year>1999</year><year>2010</year>
- <holder>Ericsson AB. All Rights Reserved.</holder>
- </copyright>
- <legalnotice>
- The contents of this file are subject to the Erlang Public License,
- Version 1.1, (the "License"); you may not use this file except in
- compliance with the License. You should have received a copy of the
- Erlang Public License along with this software. If not, it can be
- retrieved online at http://www.erlang.org/.
-
- Software distributed under the License is distributed on an "AS IS"
- basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
- the License for the specific language governing rights and limitations
- under the License.
-
- </legalnotice>
-
- <title>ssl</title>
- <prepared>Peter H&ouml;gfeldt</prepared>
- <responsible>Peter H&ouml;gfeldt</responsible>
- <docno></docno>
- <approved>Peter H&ouml;gfeldt</approved>
- <checked></checked>
- <date>2003-03-25</date>
- <rev>D</rev>
- <file>old_ssl.xml</file>
- </header>
- <module>old_ssl</module>
- <modulesummary>Interface Functions for Secure Socket Layer</modulesummary>
- <description>
- <p>This module contains interface functions to the Secure Socket Layer.</p>
- </description>
-
- <section>
- <title>General</title>
-
- <p>This manual page describes functions that are defined
- in the ssl module and represents the old ssl implementation
- that coexists with the new one until it has been
- totally phased out. </p>
-
- <p>The old implementation can be
- accessed by providing the option {ssl_imp, old} to the
- ssl:connect and ssl:listen functions.</p>
-
- <p>The reader is advised to also read the <c>ssl(6)</c> manual page
- describing the SSL application.
- </p>
- <warning>
- <p>It is strongly advised to seed the random generator after
- the ssl application has been started (see <c>seed/1</c>
- below), and before any connections are established. Although
- the port program interfacing to the ssl libraries does a
- "random" seeding of its own in order to make everything work
- properly, that seeding is by no means random for the world
- since it has a constant value which is known to everyone
- reading the source code of the port program.</p>
- </warning>
- </section>
-
- <section>
- <title>Common data types</title>
- <p>The following datatypes are used in the functions below:
- </p>
- <list type="bulleted">
- <item>
- <p><c>options() = [option()]</c></p>
- </item>
- <item>
- <p><c>option() = socketoption() | ssloption()</c></p>
- </item>
- <item>
- <p><c>socketoption() = {mode, list} | {mode, binary} | binary | {packet, packettype()} | {header, integer()} | {nodelay, boolean()} | {active, activetype()} | {backlog, integer()} | {ip, ipaddress()} | {port, integer()}</c></p>
- </item>
- <item>
- <p><c>ssloption() = {verify, code()} | {depth, depth()} | {certfile, path()} | {keyfile, path()} | {password, string()} | {cacertfile, path()} | {ciphers, string()}</c></p>
- </item>
- <item>
- <p><c>packettype()</c> (see inet(3))</p>
- </item>
- <item>
- <p><c>activetype()</c> (see inet(3))</p>
- </item>
- <item>
- <p><c>reason() = atom() | {atom(), string()}</c></p>
- </item>
- <item>
- <p><c>bytes() = [byte()]</c></p>
- </item>
- <item>
- <p><c>string() = [byte()]</c></p>
- </item>
- <item>
- <p><c>byte() = 0 | 1 | 2 | ... | 255</c></p>
- </item>
- <item>
- <p><c>code() = 0 | 1 | 2</c></p>
- </item>
- <item>
- <p><c>depth() = byte()</c></p>
- </item>
- <item>
- <p><c>address() = hostname() | ipstring() | ipaddress()</c></p>
- </item>
- <item>
- <p><c>ipaddress() = ipstring() | iptuple()</c></p>
- </item>
- <item>
- <p><c>hostname() = string()</c></p>
- </item>
- <item>
- <p><c>ipstring() = string()</c></p>
- </item>
- <item>
- <p><c>iptuple() = {byte(), byte(), byte(), byte()}</c></p>
- </item>
- <item>
- <p><c>sslsocket()</c></p>
- </item>
- <item>
- <p><c>protocol() = sslv2 | sslv3 | tlsv1</c></p>
- </item>
- <item>
- <p><c></c></p>
- </item>
- </list>
- <p>The socket option <c>{backlog, integer()}</c> is for
- <c>listen/2</c> only, and the option <c>{port, integer()}</c>
- is for <c>connect/3/4</c> only.
- </p>
- <p>The following socket options are set by default: <c>{mode, list}</c>, <c>{packet, 0}</c>, <c>{header, 0}</c>, <c>{nodelay, false}</c>, <c>{active, true}</c>, <c>{backlog, 5}</c>,
- <c>{ip, {0,0,0,0}}</c>, and <c>{port, 0}</c>.
- </p>
- <p>Note that the options <c>{mode, binary}</c> and <c>binary</c>
- are equivalent. Similarly <c>{mode, list}</c> and the absence of
- option <c>binary</c> are equivalent.
- </p>
- <p>The ssl options are for setting specific SSL parameters as follows:
- </p>
- <list type="bulleted">
- <item>
- <p><c>{verify, code()}</c> Specifies type of verification:
- 0 = do not verify peer; 1 = verify peer, 2 = verify peer,
- fail if no peer certificate. The default value is 0.
- </p>
- </item>
- <item>
- <p><c>{depth, depth()}</c> Specifies the maximum
- verification depth, i.e. how far in a chain of certificates
- the verification process can proceed before the verification
- is considered to fail.
- </p>
- <p>Peer certificate = 0, CA certificate = 1, higher level CA
- certificate = 2, etc. The value 2 thus means that a chain
- can at most contain peer cert, CA cert, next CA cert, and an
- additional CA cert.
- </p>
- <p>The default value is 1.
- </p>
- </item>
- <item>
- <p><c>{certfile, path()}</c> Path to a file containing the
- user's certificate.
- chain of PEM encoded certificates.</p>
- </item>
- <item>
- <p><c>{keyfile, path()}</c> Path to file containing user's
- private PEM encoded key.</p>
- </item>
- <item>
- <p><c>{password, string()}</c> String containing the user's
- password. Only used if the private keyfile is password protected.</p>
- </item>
- <item>
- <p><c>{cacertfile, path()}</c> Path to file containing PEM encoded
- CA certificates (trusted certificates used for verifying a peer
- certificate).</p>
- </item>
- <item>
- <p><c>{ciphers, string()}</c> String of ciphers as a colon
- separated list of ciphers. The function <c>ciphers/0</c> can
- be used to find all available ciphers.</p>
- </item>
- </list>
- <p>The type <c>sslsocket()</c> is opaque to the user.
- </p>
- <p>The owner of a socket is the one that created it by a call to
- <c>transport_accept/[1,2]</c>, <c>connect/[3,4]</c>,
- or <c>listen/2</c>.
- </p>
- <p>When a socket is in active mode (the default), data from the
- socket is delivered to the owner of the socket in the form of
- messages:
- </p>
- <list type="bulleted">
- <item>
- <p><c>{ssl, Socket, Data}</c></p>
- </item>
- <item>
- <p><c>{ssl_closed, Socket}</c></p>
- </item>
- <item>
- <p><c>{ssl_error, Socket, Reason}</c></p>
- </item>
- </list>
- <p>A <c>Timeout</c> argument specifies a timeout in milliseconds. The
- default value for a <c>Timeout</c> argument is <c>infinity</c>.
- </p>
- <p>Functions listed below may return the value <c>{error, closed}</c>, which only indicates that the SSL socket is
- considered closed for the operation in question. It is for
- instance possible to have <c>{error, closed}</c> returned from
- an call to <c>send/2</c>, and a subsequent call to <c>recv/3</c>
- returning <c>{ok, Data}</c>.
- </p>
- <p>Hence a return value of <c>{error, closed}</c> must not be
- interpreted as if the socket was completely closed. On the
- contrary, in order to free all resources occupied by an SSL
- socket, <c>close/1</c> must be called, or else the process owning
- the socket has to terminate.
- </p>
- <p>For each SSL socket there is an Erlang process representing the
- socket. When a socket is opened, that process links to the
- calling client process. Implementations that want to detect
- abnormal exits from the socket process by receiving <c>{'EXIT', Pid, Reason}</c> messages, should use the function <c>pid/1</c>
- to retrieve the process identifier from the socket, in order to
- be able to match exit messages properly.</p>
- </section>
- <funcs>
- <func>
- <name>ciphers() -> {ok, string()} | {error, enotstarted}</name>
- <fsummary>Get supported ciphers.</fsummary>
- <desc>
- <p>Returns a string consisting of colon separated cipher
- designations that are supported by the current SSL library
- implementation.
- </p>
- <p>The SSL application has to be started to return the string
- of ciphers.</p>
- </desc>
- </func>
- <func>
- <name>close(Socket) -> ok | {error, Reason}</name>
- <fsummary>Close a socket returned by <c>transport_accept/[1,2]</c>, <c>connect/3/4</c>, or <c>listen/2</c>.</fsummary>
- <type>
- <v>Socket = sslsocket()</v>
- </type>
- <desc>
- <p>Closes a socket returned by <c>transport_accept/[1,2]</c>,
- <c>connect/[3,4]</c>, or <c>listen/2</c></p>
- </desc>
- </func>
- <func>
- <name>connect(Address, Port, Options) -> {ok, Socket} | {error, Reason}</name>
- <name>connect(Address, Port, Options, Timeout) -> {ok, Socket} | {error, Reason}</name>
- <fsummary>Connect to <c>Port</c>at <c>Address</c>.</fsummary>
- <type>
- <v>Address = address()</v>
- <v>Port = integer()</v>
- <v>Options = [connect_option()]</v>
- <v>connect_option() = {mode, list} | {mode, binary} | binary | {packet, packettype()} | {header, integer()} | {nodelay, boolean()} | {active, activetype()} | {ip, ipaddress()} | {port, integer()} | {verify, code()} | {depth, depth()} | {certfile, path()} | {keyfile, path()} | {password, string()} | {cacertfile, path()} | {ciphers, string()}</v>
- <v>Timeout = integer()</v>
- <v>Socket = sslsocket()</v>
- </type>
- <desc>
- <p>Connects to <c>Port</c> at <c>Address</c>. If the optional
- <c>Timeout</c> argument is specified, and a connection could not
- be established within the given time, <c>{error, timeout}</c> is
- returned. The default value for <c>Timeout</c> is <c>infinity</c>.
- </p>
- <p>The <c>ip</c> and <c>port</c> options are for binding to a
- particular <em>local</em> address and port, respectively.</p>
- </desc>
- </func>
- <func>
- <name>connection_info(Socket) -> {ok, {Protocol, Cipher}} | {error, Reason}</name>
- <fsummary>Get current protocol version and cipher.</fsummary>
- <type>
- <v>Socket = sslsocket()</v>
- <v>Protocol = protocol()</v>
- <v>Cipher = string()</v>
- </type>
- <desc>
- <p>Gets the chosen protocol version and cipher for an established
- connection (accepted och connected). </p>
- </desc>
- </func>
- <func>
- <name>controlling_process(Socket, NewOwner) -> ok | {error, Reason}</name>
- <fsummary>Assign a new controlling process to the socket.</fsummary>
- <type>
- <v>Socket = sslsocket()</v>
- <v>NewOwner = pid()</v>
- </type>
- <desc>
- <p>Assigns a new controlling process to <c>Socket</c>. A controlling
- process is the owner of a socket, and receives all messages from
- the socket.</p>
- </desc>
- </func>
- <func>
- <name>format_error(ErrorCode) -> string()</name>
- <fsummary>Return an error string.</fsummary>
- <type>
- <v>ErrorCode = term()</v>
- </type>
- <desc>
- <p>Returns a diagnostic string describing an error.</p>
- </desc>
- </func>
- <func>
- <name>getopts(Socket, OptionsTags) -> {ok, Options} | {error, Reason}</name>
- <fsummary>Get options set for socket</fsummary>
- <type>
- <v>Socket = sslsocket()</v>
- <v>OptionTags = [optiontag()]()</v>
- </type>
- <desc>
- <p>Returns the options the tags of which are <c>OptionTags</c> for
- for the socket <c>Socket</c>. </p>
- </desc>
- </func>
- <func>
- <name>listen(Port, Options) -> {ok, ListenSocket} | {error, Reason}</name>
- <fsummary>Set up a socket to listen on a port on the local host.</fsummary>
- <type>
- <v>Port = integer()</v>
- <v>Options = [listen_option()]</v>
- <v>listen_option() = {mode, list} | {mode, binary} | binary | {packet, packettype()} | {header, integer()} | {active, activetype()} | {backlog, integer()} | {ip, ipaddress()} | {verify, code()} | {depth, depth()} | {certfile, path()} | {keyfile, path()} | {password, string()} | {cacertfile, path()} | {ciphers, string()}</v>
- <v>ListenSocket = sslsocket()</v>
- </type>
- <desc>
- <p>Sets up a socket to listen on port <c>Port</c> at the local host.
- If <c>Port</c> is zero, <c>listen/2</c> picks an available port
- number (use <c>port/1</c> to retrieve it).
- </p>
- <p>The listen queue size defaults to 5. If a different value is
- wanted, the option <c>{backlog, Size}</c> should be added to the
- list of options.
- </p>
- <p>An empty <c>Options</c> list is considered an error, and
- <c>{error, enooptions}</c> is returned.
- </p>
- <p>The returned <c>ListenSocket</c> can only be used in calls to
- <c>transport_accept/[1,2]</c>.</p>
- </desc>
- </func>
- <func>
- <name>peercert(Socket) -> {ok, Cert} | {error, Reason}</name>
- <fsummary>Return the peer certificate.</fsummary>
- <type>
- <v>Socket = sslsocket()</v>
- <v>Cert = binary()()</v>
- <v>Subject = term()()</v>
- </type>
- <desc>
- <p>Returns the DER encoded peer certificate, the certificate can be decoded with
- <c>public_key:pkix_decode_cert/2</c>.
- </p>
- </desc>
- </func>
- <func>
- <name>peername(Socket) -> {ok, {Address, Port}} | {error, Reason}</name>
- <fsummary>Return peer address and port.</fsummary>
- <type>
- <v>Socket = sslsocket()</v>
- <v>Address = ipaddress()</v>
- <v>Port = integer()</v>
- </type>
- <desc>
- <p>Returns the address and port number of the peer.</p>
- </desc>
- </func>
- <func>
- <name>pid(Socket) -> pid()</name>
- <fsummary>Return the pid of the socket process.</fsummary>
- <type>
- <v>Socket = sslsocket()</v>
- </type>
- <desc>
- <p>Returns the pid of the socket process. The returned pid should
- only be used for receiving exit messages.</p>
- </desc>
- </func>
- <func>
- <name>recv(Socket, Length) -> {ok, Data} | {error, Reason}</name>
- <name>recv(Socket, Length, Timeout) -> {ok, Data} | {error, Reason}</name>
- <fsummary>Receive data on socket.</fsummary>
- <type>
- <v>Socket = sslsocket()</v>
- <v>Length = integer() >= 0</v>
- <v>Timeout = integer()</v>
- <v>Data = bytes() | binary()</v>
- </type>
- <desc>
- <p>Receives data on socket <c>Socket</c> when the socket is in
- passive mode, i.e. when the option <c>{active, false}</c>
- has been specified.
- </p>
- <p>A notable return value is <c>{error, closed}</c> which
- indicates that the socket is closed.
- </p>
- <p>A positive value of the <c>Length</c> argument is only
- valid when the socket is in raw mode (option <c>{packet, 0}</c> is set, and the option <c>binary</c> is <em>not</em>
- set); otherwise it should be set to 0, whence all available
- bytes are returned.
- </p>
- <p>If the optional <c>Timeout</c> parameter is specified, and
- no data was available within the given time, <c>{error, timeout}</c> is returned. The default value for
- <c>Timeout</c> is <c>infinity</c>.</p>
- </desc>
- </func>
- <func>
- <name>seed(Data) -> ok | {error, Reason}</name>
- <fsummary>Seed the ssl random generator.</fsummary>
- <type>
- <v>Data = iolist() | binary()</v>
- </type>
- <desc>
- <p>Seeds the ssl random generator.
- </p>
- <p>It is strongly advised to seed the random generator after
- the ssl application has been started, and before any
- connections are established. Although the port program
- interfacing to the OpenSSL libraries does a "random" seeding
- of its own in order to make everything work properly, that
- seeding is by no means random for the world since it has a
- constant value which is known to everyone reading the source
- code of the seeding.
- </p>
- <p>A notable return value is <c>{error, edata}}</c> indicating that
- <c>Data</c> was not a binary nor an iolist.</p>
- </desc>
- </func>
- <func>
- <name>send(Socket, Data) -> ok | {error, Reason}</name>
- <fsummary>Write data to a socket.</fsummary>
- <type>
- <v>Socket = sslsocket()</v>
- <v>Data = iolist() | binary()</v>
- </type>
- <desc>
- <p>Writes <c>Data</c> to <c>Socket</c>. </p>
- <p>A notable return value is <c>{error, closed}</c> indicating that
- the socket is closed.</p>
- </desc>
- </func>
- <func>
- <name>setopts(Socket, Options) -> ok | {error, Reason}</name>
- <fsummary>Set socket options.</fsummary>
- <type>
- <v>Socket = sslsocket()</v>
- <v>Options = [socketoption]()</v>
- </type>
- <desc>
- <p>Sets options according to <c>Options</c> for the socket
- <c>Socket</c>. </p>
- </desc>
- </func>
- <func>
- <name>ssl_accept(Socket) -> ok | {error, Reason}</name>
- <name>ssl_accept(Socket, Timeout) -> ok | {error, Reason}</name>
- <fsummary>Perform server-side SSL handshake and key exchange</fsummary>
- <type>
- <v>Socket = sslsocket()</v>
- <v>Timeout = integer()</v>
- <v>Reason = atom()</v>
- </type>
- <desc>
- <p>The <c>ssl_accept</c> function establish the SSL connection
- on the server side. It should be called directly after
- <c>transport_accept</c>, in the spawned server-loop.</p>
- <p>Note that the ssl connection is not complete until <c>ssl_accept</c>
- has returned <c>true</c>, and if an error is returned, the socket
- is unavailable and for instance <c>close/1</c> will crash.</p>
- </desc>
- </func>
- <func>
- <name>sockname(Socket) -> {ok, {Address, Port}} | {error, Reason}</name>
- <fsummary>Return the local address and port.</fsummary>
- <type>
- <v>Socket = sslsocket()</v>
- <v>Address = ipaddress()</v>
- <v>Port = integer()</v>
- </type>
- <desc>
- <p>Returns the local address and port number of the socket
- <c>Socket</c>.</p>
- </desc>
- </func>
- <func>
- <name>transport_accept(Socket) -> {ok, NewSocket} | {error, Reason}</name>
- <name>transport_accept(Socket, Timeout) -> {ok, NewSocket} | {error, Reason}</name>
- <fsummary>Accept an incoming connection and prepare for <c>ssl_accept</c></fsummary>
- <type>
- <v>Socket = NewSocket = sslsocket()</v>
- <v>Timeout = integer()</v>
- <v>Reason = atom()</v>
- </type>
- <desc>
- <p>Accepts an incoming connection request on a listen socket.
- <c>ListenSocket</c> must be a socket returned from <c>listen/2</c>.
- The socket returned should be passed to <c>ssl_accept</c> to
- complete ssl handshaking and establishing the connection.</p>
- <warning>
- <p>The socket returned can only be used with <c>ssl_accept</c>,
- no traffic can be sent or received before that call.</p>
- </warning>
- <p>The accepted socket inherits the options set for <c>ListenSocket</c>
- in <c>listen/2</c>.</p>
- <p>The default value for <c>Timeout</c> is <c>infinity</c>. If
- <c>Timeout</c> is specified, and no connection is accepted within
- the given time, <c>{error, timeout}</c> is returned.</p>
- </desc>
- </func>
- <func>
- <name>version() -> {ok, {SSLVsn, CompVsn, LibVsn}}</name>
- <fsummary>Return the version of SSL.</fsummary>
- <type>
- <v>SSLVsn = CompVsn = LibVsn = string()()</v>
- </type>
- <desc>
- <p>Returns the SSL application version (<c>SSLVsn</c>), the library
- version used when compiling the SSL application port program
- (<c>CompVsn</c>), and the actual library version used when
- dynamically linking in runtime (<c>LibVsn</c>).
- </p>
- <p>If the SSL application has not been started, <c>CompVsn</c> and
- <c>LibVsn</c> are empty strings.
- </p>
- </desc>
- </func>
- </funcs>
-
- <section>
- <title>ERRORS</title>
- <p>The possible error reasons and the corresponding diagnostic strings
- returned by <c>format_error/1</c> are either the same as those defined
- in the <c>inet(3)</c> reference manual, or as follows:
- </p>
- <taglist>
- <tag><c>closed</c></tag>
- <item>
- <p>Connection closed for the operation in question.
- </p>
- </item>
- <tag><c>ebadsocket</c></tag>
- <item>
- <p>Connection not found (internal error).
- </p>
- </item>
- <tag><c>ebadstate</c></tag>
- <item>
- <p>Connection not in connect state (internal error).
- </p>
- </item>
- <tag><c>ebrokertype</c></tag>
- <item>
- <p>Wrong broker type (internal error).
- </p>
- </item>
- <tag><c>ecacertfile</c></tag>
- <item>
- <p>Own CA certificate file is invalid.
- </p>
- </item>
- <tag><c>ecertfile</c></tag>
- <item>
- <p>Own certificate file is invalid.
- </p>
- </item>
- <tag><c>echaintoolong</c></tag>
- <item>
- <p>The chain of certificates provided by peer is too long.
- </p>
- </item>
- <tag><c>ecipher</c></tag>
- <item>
- <p>Own list of specified ciphers is invalid.
- </p>
- </item>
- <tag><c>ekeyfile</c></tag>
- <item>
- <p>Own private key file is invalid.
- </p>
- </item>
- <tag><c>ekeymismatch</c></tag>
- <item>
- <p>Own private key does not match own certificate.
- </p>
- </item>
- <tag><c>enoissuercert</c></tag>
- <item>
- <p>Cannot find certificate of issuer of certificate provided
- by peer.
- </p>
- </item>
- <tag><c>enoservercert</c></tag>
- <item>
- <p>Attempt to do accept without having set own certificate.
- </p>
- </item>
- <tag><c>enotlistener</c></tag>
- <item>
- <p>Attempt to accept on a non-listening socket.
- </p>
- </item>
- <tag><c>enoproxysocket</c></tag>
- <item>
- <p>No proxy socket found (internal error).
- </p>
- </item>
- <tag><c>enooptions</c></tag>
- <item>
- <p>The list of options is empty.
- </p>
- </item>
- <tag><c>enotstarted</c></tag>
- <item>
- <p>The SSL application has not been started.
- </p>
- </item>
- <tag><c>eoptions</c></tag>
- <item>
- <p>Invalid list of options.
- </p>
- </item>
- <tag><c>epeercert</c></tag>
- <item>
- <p>Certificate provided by peer is in error.
- </p>
- </item>
- <tag><c>epeercertexpired</c></tag>
- <item>
- <p>Certificate provided by peer has expired.
- </p>
- </item>
- <tag><c>epeercertinvalid</c></tag>
- <item>
- <p>Certificate provided by peer is invalid.
- </p>
- </item>
- <tag><c>eselfsignedcert</c></tag>
- <item>
- <p>Certificate provided by peer is self signed.
- </p>
- </item>
- <tag><c>esslaccept</c></tag>
- <item>
- <p>Server SSL handshake procedure between client and server failed.
- </p>
- </item>
- <tag><c>esslconnect</c></tag>
- <item>
- <p>Client SSL handshake procedure between client and server failed.
- </p>
- </item>
- <tag><c>esslerrssl</c></tag>
- <item>
- <p>SSL protocol failure. Typically because of a fatal alert
- from peer.
- </p>
- </item>
- <tag><c>ewantconnect</c></tag>
- <item>
- <p>Protocol wants to connect, which is not supported in
- this version of the SSL application.
- </p>
- </item>
- <tag><c>ex509lookup</c></tag>
- <item>
- <p>Protocol wants X.509 lookup, which is not supported in
- this version of the SSL application.
- </p>
- </item>
- <tag><c>{badcall, Call}</c></tag>
- <item>
- <p>Call not recognized for current mode (active or passive) and
- state of socket.
- </p>
- </item>
- <tag><c>{badcast, Cast}</c></tag>
- <item>
- <p>Call not recognized for current mode (active or passive) and
- state of socket.
- </p>
- </item>
- <tag><c>{badinfo, Info}</c></tag>
- <item>
- <p>Call not recognized for current mode (active or passive) and
- state of socket.
- </p>
- </item>
- </taglist>
- </section>
-
- <section>
- <title>SEE ALSO</title>
- <p>gen_tcp(3), inet(3) public_key(3) </p>
- </section>
-
-</erlref>
-
-
diff --git a/lib/ssl/doc/src/refman.xml b/lib/ssl/doc/src/refman.xml
index 68f84660f3..011819e82b 100644
--- a/lib/ssl/doc/src/refman.xml
+++ b/lib/ssl/doc/src/refman.xml
@@ -1,10 +1,10 @@
-<?xml version="1.0" encoding="latin1" ?>
+<?xml version="1.0" encoding="iso-8859-1" ?>
<!DOCTYPE application SYSTEM "application.dtd">
<application xmlns:xi="http://www.w3.org/2001/XInclude">
<header>
<copyright>
- <year>1999</year><year>2010</year>
+ <year>1999</year><year>2011</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -45,7 +45,6 @@
</description>
<xi:include href="ssl_app.xml"/>
<xi:include href="ssl.xml"/>
- <xi:include href="old_ssl.xml"/>
<xi:include href="ssl_session_cache_api.xml"/>
</application>
diff --git a/lib/ssl/doc/src/ssl.xml b/lib/ssl/doc/src/ssl.xml
index 47991ca477..50268ae206 100644
--- a/lib/ssl/doc/src/ssl.xml
+++ b/lib/ssl/doc/src/ssl.xml
@@ -71,7 +71,8 @@
{fail_if_no_peer_cert, boolean()}
{depth, integer()} |
{cert, der_encoded()}| {certfile, path()} |
- {key, der_encoded()} | {keyfile, path()} | {password, string()} |
+ {key, {'RSAPrivateKey'| 'DSAPrivateKey' | 'PrivateKeyInfo', der_encoded()}} |
+ {keyfile, path()} | {password, string()} |
{cacerts, [der_encoded()]} | {cacertfile, path()} |
|{dh, der_encoded()} | {dhfile, path()} | {ciphers, ciphers()} |
{ssl_imp, ssl_imp()} | {reuse_sessions, boolean()} | {reuse_session, fun()}
@@ -121,8 +122,6 @@
<p> <c>hash() = md5 | sha
</c></p>
- <p><c>ssl_imp() = new | old - default is new.</c></p>
-
</section>
<section>
@@ -141,7 +140,7 @@
<tag>{certfile, path()}</tag>
<item>Path to a file containing the user's certificate.</item>
- <tag>{key, der_encoded()}</tag>
+ <tag>{key, {'RSAPrivateKey'| 'DSAPrivateKey' | 'PrivateKeyInfo', der_encoded()}}</tag>
<item> The DER encoded users private key. If this option
is supplied it will override the keyfile option.</item>
@@ -177,9 +176,9 @@
by the peer also.
</item>
- <tag>{ssl_imp, ssl_imp()}</tag>
- <item>Specify which ssl implementation you want to use. Defaults to
- new.
+ <tag>{ssl_imp, new | old}</tag>
+ <item>No longer has any meaning as the old implementation has
+ been removed, it will be ignored.
</item>
<tag>{secure_renegotiate, boolean()}</tag>
diff --git a/lib/ssl/doc/src/ssl_distribution.xml b/lib/ssl/doc/src/ssl_distribution.xml
index 7bcc12eb5f..4ae4ead3ee 100644
--- a/lib/ssl/doc/src/ssl_distribution.xml
+++ b/lib/ssl/doc/src/ssl_distribution.xml
@@ -4,7 +4,7 @@
<chapter>
<header>
<copyright>
- <year>2000</year><year>2010</year>
+ <year>2000</year><year>2011</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -33,36 +33,32 @@
</header>
<p>This chapter describes how the Erlang distribution can use
SSL to get additional verification and security.
-
- <note><p>Note this
- documentation is written for the old ssl implementation and
- will be updated for the new one once this functionality is
- supported by the new implementation.</p></note>
</p>
<section>
<title>Introduction</title>
<p>The Erlang distribution can in theory use almost any connection
based protocol as bearer. A module that implements the protocol
- specific parts of connection setup is however needed. The
+ specific parts of the connection setup is however needed. The
default distribution module is <c>inet_tcp_dist</c> which is
included in the Kernel application. When starting an
Erlang node distributed, <c>net_kernel</c> uses this module to
setup listen ports and connections. </p>
- <p>In the SSL application there is an additional distribution
- module, <c>inet_ssl_dist</c> which can be used as an
+
+ <p>In the SSL application there is an additional distribution
+ module, <c>inet_tls_dist</c> which can be used as an
alternative. All distribution connections will be using SSL and
all participating Erlang nodes in a distributed system must use
this distribution module.</p>
- <p>The security depends on how the connections are set up, one can
- use key files or certificates to just get a encrypted
- connection. One can also make the SSL package verify the
- certificates of other nodes to get additional security.
- Cookies are however always used as they can be used to
- differentiate between two different Erlang networks.</p>
+
+ <p>The security level depends on the parameters provided to the
+ SSL connection setup. Erlang node cookies are however always
+ used, as they can be used to differentiate between two different
+ Erlang networks.</p>
<p>Setting up Erlang distribution over SSL involves some simple but
necessary steps:</p>
- <list type="bulleted">
+
+ <list type="bulleted">
<item>Building boot scripts including the SSL application</item>
<item>Specifying the distribution module for net_kernel</item>
<item>Specifying security options and other SSL options</item>
@@ -77,122 +73,135 @@
SASL application. Refer to the SASL documentations
for more information on systools. This is only an example of
what can be done.</p>
- <p>The simplest boot script possible includes only the Kernel
+
+ <p>The simplest boot script possible includes only the Kernel
and STDLIB applications. Such a script is located in the
Erlang distributions bin directory. The source for the script
can be found under the Erlang installation top directory under
- <c><![CDATA[releases/<OTP version>start_clean.rel]]></c>. Copy that
+ <c><![CDATA[releases/<OTP version>/start_clean.rel]]></c>. Copy that
script to another location (and preferably another name)
- and add the SSL application with its current version number
+ and add the applications crypto, public_key and SSL with their current version numbers
after the STDLIB application.</p>
<p>An example .rel file with SSL added may look like this:</p>
+
<code type="none">
-{release, {"OTP APN 181 01","P7A"}, {erts, "5.0"},
- [{kernel,"2.5"},
- {stdlib,"1.8.1"},
- {ssl,"2.2.1"}]}. </code>
- <p>Note that the version numbers surely will differ in your system.
- Whenever one of the applications included in the script is
- upgraded, the script has to be changed.</p>
- <p>Assuming the above .rel file is stored in a file
- <c>start_ssl.rel</c> in the current directory, a boot script
- can be built like this:</p>
- <code type="none">
-1> systools:make_script("start_ssl",[]). </code>
- <p>There will now be a file <c>start_ssl.boot</c> in the current
- directory. To test the boot script, start Erlang with the
- <c>-boot</c> command line parameter specifying this boot script
- (with its full path but without the <c>.boot</c> suffix), in
- Unix it could look like this:</p>
- <p></p>
- <code type="none"><![CDATA[
+ {release, {"OTP APN 181 01","R15A"}, {erts, "5.9"},
+ [{kernel,"2.15"},
+ {stdlib,"1.18"},
+ {crypto, "2.0.3"},
+ {public_key, "0.12"},
+ {ssl, "5.0"}
+ ]}.
+ </code>
+
+ <p>Note that the version numbers surely will differ in your system.
+ Whenever one of the applications included in the script is
+ upgraded, the script has to be changed.</p>
+ <p>Assuming the above .rel file is stored in a file
+ <c>start_ssl.rel</c> in the current directory, a boot script
+ can be built like this:</p>
+
+ <code type="none">
+ 1> systools:make_script("start_ssl",[]). </code>
+
+ <p>There will now be a file <c>start_ssl.boot</c> in the current
+ directory. To test the boot script, start Erlang with the
+ <c>-boot</c> command line parameter specifying this boot script
+ (with its full path but without the <c>.boot</c> suffix), in
+ Unix it could look like this:</p>
+ <p></p>
+
+ <code type="none"><![CDATA[
$ erl -boot /home/me/ssl/start_ssl
Erlang (BEAM) emulator version 5.0
Eshell V5.0 (abort with ^G)
-1> whereis(ssl_server).
-<0.32.0> ]]></code>
+1> whereis(ssl_manager).
+<0.41.0> ]]></code>
<p>The <c>whereis</c> function call verifies that the SSL
application is really started.</p>
- <p>As an alternative to building a bootscript, one can explicitly
- add the path to the ssl <c>ebin</c> directory on the command
+
+ <p>As an alternative to building a bootscript, one can explicitly
+ add the path to the SSL <c>ebin</c> directory on the command
line. This is done with the command line option <c>-pa</c>. This
- works as the ssl application really need not be started for the
- distribution to come up, a primitive version of the ssl server
- is started by the distribution module itself, so as long as the
- primitive code server can reach the code, the distribution will
+ works as the SSL application does not need to be started for the
+ distribution to come up, as a clone of the SSL application is
+ hooked into the kernel application, so as long as the
+ SSL applications code can be reached, the distribution will
start. The <c>-pa</c> method is only recommended for testing
purposes.</p>
+
+ <note><p>Note that the clone of the SSL application is necessary to
+ enable the use of the SSL code in such an early bootstage as
+ needed to setup the distribution, however this will make it
+ impossible to soft upgrade the SSL application.</p></note>
</section>
<section>
<title>Specifying distribution module for net_kernel</title>
- <p>The distribution module for SSL is named <c>inet_ssl_dist</c>
- and is specified on the command line whit the <c>-proto_dist</c>
+ <p>The distribution module for SSL is named <c>inet_tls_dist</c>
+ and is specified on the command line with the <c>-proto_dist</c>
option. The argument to <c>-proto_dist</c> should be the module
name without the <c>_dist</c> suffix, so this distribution
- module is specified with <c>-proto_dist inet_ssl</c> on the
+ module is specified with <c>-proto_dist inet_tls</c> on the
command line.</p>
<p></p>
+
<p>Extending the command line from above gives us the following:</p>
<code type="none">
-$ erl -boot /home/me/ssl/start_ssl -proto_dist inet_ssl </code>
- <p>For the distribution to actually be started, we need to give
- the emulator a name as well:</p>
+$ erl -boot /home/me/ssl/start_ssl -proto_dist inet_tls </code>
+
+<p>For the distribution to actually be started, we need to give
+the emulator a name as well:</p>
<code type="none">
-$ erl -boot /home/me/ssl/start_ssl -proto_dist inet_ssl -sname ssl_test
+$ erl -boot /home/me/ssl/start_ssl -proto_dist inet_tls -sname ssl_test
Erlang (BEAM) emulator version 5.0 [source]
Eshell V5.0 (abort with ^G)
(ssl_test@myhost)1> </code>
<p>Note however that a node started in this way will refuse to talk
- to other nodes, as no certificates or key files are supplied
+ to other nodes, as no ssl parameters are supplied
(see below).</p>
- <p>When the SSL distribution starts, the OTP system is in its
- early boot stage, why neither <c>application</c> nor <c>code</c>
- are usable. As SSL needs to start a port program in this early
- stage, it tries to determine the path to that program from the
- primitive code loaders code path. If this fails, one need to
- specify the directory where the port program resides. This can
- be done either with an environment variable
- <c>ERL_SSL_PORTPROGRAM_DIR</c> or with the command line option
- <c>-ssl_portprogram_dir</c>. The value should be the directory
- where the <c>ssl_esock</c> port program is located. Note that
- this option is never needed in a normal Erlang installation.</p>
</section>
<section>
- <title>Specifying security options and other SSL options</title>
- <p>For SSL to work, you either need certificate files or a
- key file. Certificate files can be specified both when working as
- client and as server (connecting or accepting). </p>
- <p></p>
+ <title>Specifying SSL options</title> <p>For SSL to work, at least
+ a public key and certificate needs to be specified for the server
+ side. In the following example the PEM-files consists of two
+ entries the servers certificate and its private key.</p>
+
<p>On the <c>erl</c> command line one can specify options that the
- ssl distribution will add when creation a socket. It is
- mandatory to specify at least a key file or client and server
- certificates. One can specify any <em>SSL option</em> on the
- command line, but must not specify any socket options (like
- packet size and such). The SSL options are listed in the
- Reference Manual. The only difference between the
- options in the reference manual and the ones that can be
- specified to the distribution on the command line is that
- <c>certfile</c> can (and usually needs to) be specified as
- <c>client_certfile</c> and <c>server_certfile</c>. The
- <c>client_certfile</c> is used when the distribution initiates a
- connection to another node and the <c>server_certfile</c> is used
- when accepting a connection from a remote node. </p>
- <p>The command line argument for specifying the SSL options is named
- <c>-ssl_dist_opt</c> and should be followed by an even number of
- SSL options/option values. The <c>-ssl_dist_opt</c> argument can
- be repeated any number of times.</p>
- <p>An example command line would now look something like this
+ SSL distribution will add when creating a socket.</p>
+
+ <p>One can specify the simpler SSL options certfile, keyfile,
+ password, cacertfile, verify, reuse_sessions,
+ secure_renegotiate, depth, hibernate_after and ciphers (use old
+ string format) by adding the prefix server_ or client_ to the
+ option name. The server can also take the options dhfile and
+ fail_if_no_peer_cert (also prefixed).
+ <c>client_</c>-prfixed options are used when the distribution initiates a
+ connection to another node and the <c>server_</c>-prefixed options are used
+ when accepting a connection from a remote node. </p>
+
+ <p> More complex options such as verify_fun are not available at
+ the moment but a mechanism to handle such options may be added in
+ a future release. </p>
+
+ <p> Raw socket options such as packet and size must not be specified on
+ the command line</p>.
+
+ <p>The command line argument for specifying the SSL options is named
+ <c>-ssl_dist_opt</c> and should be followed by pairs of
+ SSL options and their values. The <c>-ssl_dist_opt</c> argument can
+ be repeated any number of times.</p>
+
+ <p>An example command line would now look something like this
(line breaks in the command are for readability,
they should not be there when typed):</p>
<code type="none">
-$ erl -boot /home/me/ssl/start_ssl -proto_dist inet_ssl
- -ssl_dist_opt client_certfile "/home/me/ssl/erlclient.pem"
+$ erl -boot /home/me/ssl/start_ssl -proto_dist inet_tls
-ssl_dist_opt server_certfile "/home/me/ssl/erlserver.pem"
- -ssl_dist_opt verify 1 depth 1
+ -ssl_dist_opt server_secure_renegotiate true client_secure_renegotiate true
-sname ssl_test
Erlang (BEAM) emulator version 5.0 [source]
@@ -211,12 +220,11 @@ Eshell V5.0 (abort with ^G)
subsequent invocations of Erlang.</p>
<p></p>
<p>In a Unix (Bourne) shell it could look like this (line breaks for
- readability):</p>
+ readability, they should not be there when typed):</p>
<code type="none">
-$ ERL_FLAGS="-boot \\"/home/me/ssl/start_ssl\\" -proto_dist inet_ssl
- -ssl_dist_opt client_certfile \\"/home/me/ssl/erlclient.pem\\"
- -ssl_dist_opt server_certfile \\"/home/me/ssl/erlserver.pem\\"
- -ssl_dist_opt verify 1 -ssl_dist_opt depth 1"
+$ ERL_FLAGS="-boot /home/me/ssl/start_ssl -proto_dist inet_tls
+ -ssl_dist_opt server_certfile /home/me/ssl/erlserver.pem
+ -ssl_dist_opt server_secure_renegotiate true client_secure_renegotiate true"
$ export ERL_FLAGS
$ erl -sname ssl_test
Erlang (BEAM) emulator version 5.0 [source]
@@ -227,15 +235,12 @@ Eshell V5.0 (abort with ^G)
{progname,["erl "]},
{sname,["ssl_test"]},
{boot,["/home/me/ssl/start_ssl"]},
- {proto_dist,["inet_ssl"]},
- {ssl_dist_opt,["client_certfile","/home/me/ssl/erlclient.pem"]},
+ {proto_dist,["inet_tls"]},
{ssl_dist_opt,["server_certfile","/home/me/ssl/erlserver.pem"]},
- {ssl_dist_opt,["verify","1"]},
- {ssl_dist_opt,["depth","1"]},
+ {ssl_dist_opt,["server_secure_renegotiate","true",
+ "client_secure_renegotiate","true"]
{home,["/home/me"]}] </code>
<p>The <c>init:get_arguments()</c> call verifies that the correct
arguments are supplied to the emulator. </p>
</section>
</chapter>
-
-
diff --git a/lib/ssl/doc/src/ssl_protocol.xml b/lib/ssl/doc/src/ssl_protocol.xml
index ff6c769f6c..17268a634d 100644
--- a/lib/ssl/doc/src/ssl_protocol.xml
+++ b/lib/ssl/doc/src/ssl_protocol.xml
@@ -25,18 +25,18 @@
<file>ssl_protocol.xml</file>
</header>
- <p>The erlang ssl application currently supports SSL 3.0 and TLS 1.0
+ <p>The erlang SSL application currently supports SSL 3.0 and TLS 1.0
RFC 2246, and will in the future also support later versions of TLS.
SSL 2.0 is not supported.
</p>
- <p>By default erlang ssl is run over the TCP/IP protocol even
+ <p>By default erlang SSL is run over the TCP/IP protocol even
though you could plug in any other reliable transport protocol
with the same API as gen_tcp.</p>
<p>If a client and server wants to use an upgrade mechanism, such as
- defined by RFC2817, to upgrade a regular TCP/IP connection to an ssl
- connection the erlang ssl API supports this. This can be useful for
+ defined by RFC2817, to upgrade a regular TCP/IP connection to an SSL
+ connection the erlang SSL API supports this. This can be useful for
things such as supporting HTTP and HTTPS on the same port and
implementing virtual hosting.
</p>
@@ -131,7 +131,7 @@
connections. Sessions are used to avoid the expensive negotiation
of new security parameters for each connection."</p>
- <p>Session data is by default kept by the ssl application in a
+ <p>Session data is by default kept by the SSL application in a
memory storage hence session data will be lost at application
restart or takeover. Users may define their own callback module
to handle session data storage if persistent data storage is
@@ -140,8 +140,8 @@
possible to configure the amount of time the session data should be
saved.</p>
- <p>Ssl clients will by default try to reuse an available session,
- ssl servers will by default agree to reuse sessions when clients
+ <p>SSL clients will by default try to reuse an available session,
+ SSL servers will by default agree to reuse sessions when clients
ask to do so.</p>
</section>
diff --git a/lib/ssl/src/Makefile b/lib/ssl/src/Makefile
index 7514ad2aa2..dc69b53b28 100644
--- a/lib/ssl/src/Makefile
+++ b/lib/ssl/src/Makefile
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 1999-2010. All Rights Reserved.
+# Copyright Ericsson AB 1999-2011. All Rights Reserved.
#
# The contents of this file are subject to the Erlang Public License,
# Version 1.1, (the "License"); you may not use this file except in
@@ -41,12 +41,9 @@ MODULES= \
ssl \
ssl_alert \
ssl_app \
- ssl_broker \
- ssl_broker_sup \
- ssl_server \
+ ssl_dist_sup\
ssl_sup \
- ssl_prim \
- inet_ssl_dist \
+ inet_tls_dist \
ssl_certificate\
ssl_certificate_db\
ssl_cipher \
@@ -62,9 +59,10 @@ MODULES= \
ssl_ssl2 \
ssl_ssl3 \
ssl_tls1 \
+ ssl_tls_dist_proxy
INTERNAL_HRL_FILES = \
- ssl_int.hrl ssl_broker_int.hrl ssl_debug.hrl \
+ ssl_debug.hrl \
ssl_alert.hrl ssl_cipher.hrl ssl_handshake.hrl ssl_internal.hrl \
ssl_record.hrl
diff --git a/lib/ssl/src/inet_ssl_dist.erl b/lib/ssl/src/inet_ssl_dist.erl
deleted file mode 100644
index 6c0fbc0618..0000000000
--- a/lib/ssl/src/inet_ssl_dist.erl
+++ /dev/null
@@ -1,456 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2000-2011. All Rights Reserved.
-%%
-%% The contents of this file are subject to the Erlang Public License,
-%% Version 1.1, (the "License"); you may not use this file except in
-%% compliance with the License. You should have received a copy of the
-%% Erlang Public License along with this software. If not, it can be
-%% retrieved online at http://www.erlang.org/.
-%%
-%% Software distributed under the License is distributed on an "AS IS"
-%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
-%% the License for the specific language governing rights and limitations
-%% under the License.
-%%
-%% %CopyrightEnd%
-%%
-
-%%
--module(inet_ssl_dist).
-
-%% Handles the connection setup phase with other Erlang nodes.
-
--export([childspecs/0, listen/1, accept/1, accept_connection/5,
- setup/5, close/1, select/1, is_node_name/1]).
-
-%% internal exports
-
--export([accept_loop/2,do_accept/6,do_setup/6, getstat/1,tick/1]).
-
--import(error_logger,[error_msg/2]).
-
--include("net_address.hrl").
-
-
-
--define(to_port(Socket, Data, Opts),
- case ssl_prim:send(Socket, Data, Opts) of
- {error, closed} ->
- self() ! {ssl_closed, Socket},
- {error, closed};
- R ->
- R
- end).
-
-
--include("dist.hrl").
--include("dist_util.hrl").
-
-%% -------------------------------------------------------------
-%% This function should return a valid childspec, so that
-%% the primitive ssl_server gets supervised
-%% -------------------------------------------------------------
-childspecs() ->
- {ok, [{ssl_server_prim,{ssl_server, start_link_prim, []},
- permanent, 2000, worker, [ssl_server]}]}.
-
-
-%% ------------------------------------------------------------
-%% Select this protocol based on node name
-%% select(Node) => Bool
-%% ------------------------------------------------------------
-
-select(Node) ->
- case split_node(atom_to_list(Node), $@, []) of
- [_,_Host] -> true;
- _ -> false
- end.
-
-%% ------------------------------------------------------------
-%% Create the listen socket, i.e. the port that this erlang
-%% node is accessible through.
-%% ------------------------------------------------------------
-
-listen(Name) ->
- case ssl_prim:listen(0, [{active, false}, {packet,4}] ++
- get_ssl_options(server)) of
- {ok, Socket} ->
- TcpAddress = get_tcp_address(Socket),
- {_,Port} = TcpAddress#net_address.address,
- {ok, Creation} = erl_epmd:register_node(Name, Port),
- {ok, {Socket, TcpAddress, Creation}};
- Error ->
- Error
- end.
-
-%% ------------------------------------------------------------
-%% Accepts new connection attempts from other Erlang nodes.
-%% ------------------------------------------------------------
-
-accept(Listen) ->
- spawn_link(?MODULE, accept_loop, [self(), Listen]).
-
-accept_loop(Kernel, Listen) ->
- process_flag(priority, max),
- case ssl_prim:accept(Listen) of
- {ok, Socket} ->
- Kernel ! {accept,self(),Socket,inet,ssl},
- controller(Kernel, Socket),
- accept_loop(Kernel, Listen);
- Error ->
- exit(Error)
- end.
-
-controller(Kernel, Socket) ->
- receive
- {Kernel, controller, Pid} ->
- flush_controller(Pid, Socket),
- ssl_prim:controlling_process(Socket, Pid),
- flush_controller(Pid, Socket),
- Pid ! {self(), controller};
- {Kernel, unsupported_protocol} ->
- exit(unsupported_protocol)
- end.
-
-flush_controller(Pid, Socket) ->
- receive
- {ssl, Socket, Data} ->
- Pid ! {ssl, Socket, Data},
- flush_controller(Pid, Socket);
- {ssl_closed, Socket} ->
- Pid ! {ssl_closed, Socket},
- flush_controller(Pid, Socket)
- after 0 ->
- ok
- end.
-
-%% ------------------------------------------------------------
-%% Accepts a new connection attempt from another Erlang node.
-%% Performs the handshake with the other side.
-%% ------------------------------------------------------------
-
-accept_connection(AcceptPid, Socket, MyNode, Allowed, SetupTime) ->
- spawn_link(?MODULE, do_accept,
- [self(), AcceptPid, Socket, MyNode,
- Allowed, SetupTime]).
-
-%% Suppress dialyzer warning, we do not really care about old ssl code
-%% as we intend to remove it.
--spec(do_accept(_,_,_,_,_,_) -> no_return()).
-do_accept(Kernel, AcceptPid, Socket, MyNode, Allowed, SetupTime) ->
- process_flag(priority, max),
- receive
- {AcceptPid, controller} ->
- Timer = dist_util:start_timer(SetupTime),
- case check_ip(Socket) of
- true ->
- HSData = #hs_data{
- kernel_pid = Kernel,
- this_node = MyNode,
- socket = Socket,
- timer = Timer,
- this_flags = 0,
- allowed = Allowed,
- f_send = fun(S,D) -> ssl_prim:send(S,D) end,
- f_recv = fun(S,N,T) -> ssl_prim:recv(S,N,T)
- end,
- f_setopts_pre_nodeup =
- fun(S) ->
- ssl_prim:setopts(S,
- [{active, false}])
- end,
- f_setopts_post_nodeup =
- fun(S) ->
- ssl_prim:setopts(S,
- [{deliver, port},
- {active, true}])
- end,
- f_getll = fun(S) ->
- ssl_prim:getll(S)
- end,
- f_address = fun get_remote_id/2,
- mf_tick = fun ?MODULE:tick/1,
- mf_getstat = fun ?MODULE:getstat/1
- },
- dist_util:handshake_other_started(HSData);
- {false,IP} ->
- error_msg("** Connection attempt from "
- "disallowed IP ~w ** ~n", [IP]),
- ?shutdown(no_node)
- end
- end.
-
-%% ------------------------------------------------------------
-%% Get remote information about a Socket.
-%% ------------------------------------------------------------
-
-get_remote_id(Socket, Node) ->
- {ok, Address} = ssl_prim:peername(Socket),
- [_, Host] = split_node(atom_to_list(Node), $@, []),
- #net_address {
- address = Address,
- host = Host,
- protocol = ssl,
- family = inet }.
-
-%% ------------------------------------------------------------
-%% Setup a new connection to another Erlang node.
-%% Performs the handshake with the other side.
-%% ------------------------------------------------------------
-
-setup(Node, Type, MyNode, LongOrShortNames,SetupTime) ->
- spawn_link(?MODULE, do_setup, [self(),
- Node,
- Type,
- MyNode,
- LongOrShortNames,
- SetupTime]).
-
-%% Suppress dialyzer warning, we do not really care about old ssl code
-%% as we intend to remove it.
--spec(do_setup(_,_,_,_,_,_) -> no_return()).
-do_setup(Kernel, Node, Type, MyNode, LongOrShortNames,SetupTime) ->
- process_flag(priority, max),
- ?trace("~p~n",[{inet_ssl_dist,self(),setup,Node}]),
- [Name, Address] = splitnode(Node, LongOrShortNames),
- case inet:getaddr(Address, inet) of
- {ok, Ip} ->
- Timer = dist_util:start_timer(SetupTime),
- case erl_epmd:port_please(Name, Ip) of
- {port, TcpPort, Version} ->
- ?trace("port_please(~p) -> version ~p~n",
- [Node,Version]),
- dist_util:reset_timer(Timer),
- case ssl_prim:connect(Ip, TcpPort,
- [{active, false},
- {packet,4}] ++
- get_ssl_options(client)) of
- {ok, Socket} ->
- HSData = #hs_data{
- kernel_pid = Kernel,
- other_node = Node,
- this_node = MyNode,
- socket = Socket,
- timer = Timer,
- this_flags = 0,
- other_version = Version,
- f_send = fun(S,D) ->
- ssl_prim:send(S,D)
- end,
- f_recv = fun(S,N,T) ->
- ssl_prim:recv(S,N,T)
- end,
- f_setopts_pre_nodeup =
- fun(S) ->
- ssl_prim:setopts
- (S,
- [{active, false}])
- end,
- f_setopts_post_nodeup =
- fun(S) ->
- ssl_prim:setopts
- (S,
- [{deliver, port},{active, true}])
- end,
- f_getll = fun(S) ->
- ssl_prim:getll(S)
- end,
- f_address =
- fun(_,_) ->
- #net_address {
- address = {Ip,TcpPort},
- host = Address,
- protocol = ssl,
- family = inet}
- end,
- mf_tick = fun ?MODULE:tick/1,
- mf_getstat = fun ?MODULE:getstat/1,
- request_type = Type
- },
- dist_util:handshake_we_started(HSData);
- _ ->
- %% Other Node may have closed since
- %% port_please !
- ?trace("other node (~p) "
- "closed since port_please.~n",
- [Node]),
- ?shutdown(Node)
- end;
- _ ->
- ?trace("port_please (~p) "
- "failed.~n", [Node]),
- ?shutdown(Node)
- end;
- _Other ->
- ?trace("inet_getaddr(~p) "
- "failed (~p).~n", [Node,Other]),
- ?shutdown(Node)
- end.
-
-%%
-%% Close a socket.
-%%
-close(Socket) ->
- ssl_prim:close(Socket).
-
-
-%% If Node is illegal terminate the connection setup!!
-splitnode(Node, LongOrShortNames) ->
- case split_node(atom_to_list(Node), $@, []) of
- [Name|Tail] when Tail =/= [] ->
- Host = lists:append(Tail),
- case split_node(Host, $., []) of
- [_] when LongOrShortNames == longnames ->
- error_msg("** System running to use "
- "fully qualified "
- "hostnames **~n"
- "** Hostname ~s is illegal **~n",
- [Host]),
- ?shutdown(Node);
- [_, _ | _] when LongOrShortNames == shortnames ->
- error_msg("** System NOT running to use fully qualified "
- "hostnames **~n"
- "** Hostname ~s is illegal **~n",
- [Host]),
- ?shutdown(Node);
- _ ->
- [Name, Host]
- end;
- [_] ->
- error_msg("** Nodename ~p illegal, no '@' character **~n",
- [Node]),
- ?shutdown(Node);
- _ ->
- error_msg("** Nodename ~p illegal **~n", [Node]),
- ?shutdown(Node)
- end.
-
-split_node([Chr|T], Chr, Ack) -> [lists:reverse(Ack)|split_node(T, Chr, [])];
-split_node([H|T], Chr, Ack) -> split_node(T, Chr, [H|Ack]);
-split_node([], _, Ack) -> [lists:reverse(Ack)].
-
-%% ------------------------------------------------------------
-%% Fetch local information about a Socket.
-%% ------------------------------------------------------------
-get_tcp_address(Socket) ->
- {ok, Address} = ssl_prim:sockname(Socket),
- {ok, Host} = inet:gethostname(),
- #net_address {
- address = Address,
- host = Host,
- protocol = ssl,
- family = inet
- }.
-
-%% ------------------------------------------------------------
-%% Do only accept new connection attempts from nodes at our
-%% own LAN, if the check_ip environment parameter is true.
-%% ------------------------------------------------------------
-check_ip(Socket) ->
- case application:get_env(check_ip) of
- {ok, true} ->
- case get_ifs(Socket) of
- {ok, IFs, IP} ->
- check_ip(IFs, IP);
- _ ->
- ?shutdown(no_node)
- end;
- _ ->
- true
- end.
-
-get_ifs(Socket) ->
- case ssl_prim:peername(Socket) of
- {ok, {IP, _}} ->
- case ssl_prim:getif(Socket) of
- {ok, IFs} -> {ok, IFs, IP};
- Error -> Error
- end;
- Error ->
- Error
- end.
-
-check_ip([{OwnIP, _, Netmask}|IFs], PeerIP) ->
- case {mask(Netmask, PeerIP), mask(Netmask, OwnIP)} of
- {M, M} -> true;
- _ -> check_ip(IFs, PeerIP)
- end;
-check_ip([], PeerIP) ->
- {false, PeerIP}.
-
-mask({M1,M2,M3,M4}, {IP1,IP2,IP3,IP4}) ->
- {M1 band IP1,
- M2 band IP2,
- M3 band IP3,
- M4 band IP4}.
-
-is_node_name(Node) when is_atom(Node) ->
- case split_node(atom_to_list(Node), $@, []) of
- [_, _Host] -> true;
- _ -> false
- end;
-is_node_name(_Node) ->
- false.
-tick(Sock) ->
- ?to_port(Sock,[],[force]).
-getstat(Socket) ->
- case ssl_prim:getstat(Socket, [recv_cnt, send_cnt, send_pend]) of
- {ok, Stat} ->
- split_stat(Stat,0,0,0);
- Error ->
- Error
- end.
-
-split_stat([{recv_cnt, R}|Stat], _, W, P) ->
- split_stat(Stat, R, W, P);
-split_stat([{send_cnt, W}|Stat], R, _, P) ->
- split_stat(Stat, R, W, P);
-split_stat([{send_pend, P}|Stat], R, W, _) ->
- split_stat(Stat, R, W, P);
-split_stat([], R, W, P) ->
- {ok, R, W, P}.
-
-
-get_ssl_options(Type) ->
- case init:get_argument(ssl_dist_opt) of
- {ok, Args} ->
- ssl_options(Type, Args);
- _ ->
- []
- end.
-
-ssl_options(_,[]) ->
- [];
-ssl_options(server, [["server_certfile", Value]|T]) ->
- [{certfile, Value} | ssl_options(server,T)];
-ssl_options(client, [["client_certfile", Value]|T]) ->
- [{certfile, Value} | ssl_options(client,T)];
-ssl_options(server, [["server_cacertfile", Value]|T]) ->
- [{cacertfile, Value} | ssl_options(server,T)];
-ssl_options(server, [["server_keyfile", Value]|T]) ->
- [{keyfile, Value} | ssl_options(server,T)];
-ssl_options(Type, [["client_certfile", _Value]|T]) ->
- ssl_options(Type,T);
-ssl_options(Type, [["server_certfile", _Value]|T]) ->
- ssl_options(Type,T);
-ssl_options(Type, [[Item, Value]|T]) ->
- [{atomize(Item),fixup(Value)} | ssl_options(Type,T)];
-ssl_options(Type, [[Item,Value |T1]|T2]) ->
- ssl_options(atomize(Type),[[Item,Value],T1|T2]);
-ssl_options(_,_) ->
- exit(malformed_ssl_dist_opt).
-
-fixup(Value) ->
- case catch list_to_integer(Value) of
- {'EXIT',_} ->
- Value;
- Int ->
- Int
- end.
-
-atomize(List) when is_list(List) ->
- list_to_atom(List);
-atomize(Atom) when is_atom(Atom) ->
- Atom.
diff --git a/lib/ssl/src/inet_tls_dist.erl b/lib/ssl/src/inet_tls_dist.erl
new file mode 100644
index 0000000000..115527aae0
--- /dev/null
+++ b/lib/ssl/src/inet_tls_dist.erl
@@ -0,0 +1,275 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2011-2011. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+-module(inet_tls_dist).
+
+-export([childspecs/0, listen/1, accept/1, accept_connection/5,
+ setup/5, close/1, select/1, is_node_name/1]).
+
+-include_lib("kernel/include/net_address.hrl").
+-include_lib("kernel/include/dist.hrl").
+-include_lib("kernel/include/dist_util.hrl").
+
+childspecs() ->
+ {ok, [{ssl_dist_sup,{ssl_dist_sup, start_link, []},
+ permanent, 2000, worker, [ssl_dist_sup]}]}.
+
+select(Node) ->
+ case split_node(atom_to_list(Node), $@, []) of
+ [_,_Host] ->
+ true;
+ _ ->
+ false
+ end.
+
+is_node_name(Node) when is_atom(Node) ->
+ select(Node);
+is_node_name(_) ->
+ false.
+
+listen(Name) ->
+ ssl_tls_dist_proxy:listen(Name).
+
+accept(Listen) ->
+ ssl_tls_dist_proxy:accept(Listen).
+
+accept_connection(AcceptPid, Socket, MyNode, Allowed, SetupTime) ->
+ Kernel = self(),
+ spawn_link(fun() -> do_accept(Kernel, AcceptPid, Socket,
+ MyNode, Allowed, SetupTime) end).
+
+setup(Node, Type, MyNode, LongOrShortNames,SetupTime) ->
+ Kernel = self(),
+ spawn(fun() -> do_setup(Kernel, Node, Type, MyNode, LongOrShortNames, SetupTime) end).
+
+do_setup(Kernel, Node, Type, MyNode, LongOrShortNames, SetupTime) ->
+ [Name, Address] = splitnode(Node, LongOrShortNames),
+ case inet:getaddr(Address, inet) of
+ {ok, Ip} ->
+ Timer = dist_util:start_timer(SetupTime),
+ case erl_epmd:port_please(Name, Ip) of
+ {port, TcpPort, Version} ->
+ ?trace("port_please(~p) -> version ~p~n",
+ [Node,Version]),
+ dist_util:reset_timer(Timer),
+ case ssl_tls_dist_proxy:connect(Ip, TcpPort) of
+ {ok, Socket} ->
+ HSData = connect_hs_data(Kernel, Node, MyNode, Socket,
+ Timer, Version, Ip, TcpPort, Address,
+ Type),
+ dist_util:handshake_we_started(HSData);
+ _ ->
+ %% Other Node may have closed since
+ %% port_please !
+ ?trace("other node (~p) "
+ "closed since port_please.~n",
+ [Node]),
+ ?shutdown(Node)
+ end;
+ _ ->
+ ?trace("port_please (~p) "
+ "failed.~n", [Node]),
+ ?shutdown(Node)
+ end;
+ _Other ->
+ ?trace("inet_getaddr(~p) "
+ "failed (~p).~n", [Node,Other]),
+ ?shutdown(Node)
+ end.
+
+close(Socket) ->
+ try
+ erlang:error(foo)
+ catch _:_ ->
+ io:format("close called ~p ~p~n",[Socket, erlang:get_stacktrace()])
+ end,
+ gen_tcp:close(Socket),
+ ok.
+
+do_accept(Kernel, AcceptPid, Socket, MyNode, Allowed, SetupTime) ->
+ process_flag(priority, max),
+ receive
+ {AcceptPid, controller} ->
+ Timer = dist_util:start_timer(SetupTime),
+ case check_ip(Socket) of
+ true ->
+ HSData = accept_hs_data(Kernel, MyNode, Socket, Timer, Allowed),
+ dist_util:handshake_other_started(HSData);
+ {false,IP} ->
+ error_logger:error_msg("** Connection attempt from "
+ "disallowed IP ~w ** ~n", [IP]),
+ ?shutdown(no_node)
+ end
+ end.
+%% ------------------------------------------------------------
+%% Do only accept new connection attempts from nodes at our
+%% own LAN, if the check_ip environment parameter is true.
+%% ------------------------------------------------------------
+check_ip(Socket) ->
+ case application:get_env(check_ip) of
+ {ok, true} ->
+ case get_ifs(Socket) of
+ {ok, IFs, IP} ->
+ check_ip(IFs, IP);
+ _ ->
+ ?shutdown(no_node)
+ end;
+ _ ->
+ true
+ end.
+
+get_ifs(Socket) ->
+ case inet:peername(Socket) of
+ {ok, {IP, _}} ->
+ case inet:getif(Socket) of
+ {ok, IFs} -> {ok, IFs, IP};
+ Error -> Error
+ end;
+ Error ->
+ Error
+ end.
+
+check_ip([{OwnIP, _, Netmask}|IFs], PeerIP) ->
+ case {mask(Netmask, PeerIP), mask(Netmask, OwnIP)} of
+ {M, M} -> true;
+ _ -> check_ip(IFs, PeerIP)
+ end;
+check_ip([], PeerIP) ->
+ {false, PeerIP}.
+
+mask({M1,M2,M3,M4}, {IP1,IP2,IP3,IP4}) ->
+ {M1 band IP1,
+ M2 band IP2,
+ M3 band IP3,
+ M4 band IP4};
+
+mask({M1,M2,M3,M4, M5, M6, M7, M8}, {IP1,IP2,IP3,IP4, IP5, IP6, IP7, IP8}) ->
+ {M1 band IP1,
+ M2 band IP2,
+ M3 band IP3,
+ M4 band IP4,
+ M5 band IP5,
+ M6 band IP6,
+ M7 band IP7,
+ M8 band IP8}.
+
+
+%% If Node is illegal terminate the connection setup!!
+splitnode(Node, LongOrShortNames) ->
+ case split_node(atom_to_list(Node), $@, []) of
+ [Name|Tail] when Tail =/= [] ->
+ Host = lists:append(Tail),
+ check_node(Name, Node, Host, LongOrShortNames);
+ [_] ->
+ error_logger:error_msg("** Nodename ~p illegal, no '@' character **~n",
+ [Node]),
+ ?shutdown(Node);
+ _ ->
+ error_logger:error_msg("** Nodename ~p illegal **~n", [Node]),
+ ?shutdown(Node)
+ end.
+
+check_node(Name, Node, Host, LongOrShortNames) ->
+ case split_node(Host, $., []) of
+ [_] when LongOrShortNames == longnames ->
+ error_logger:error_msg("** System running to use "
+ "fully qualified "
+ "hostnames **~n"
+ "** Hostname ~s is illegal **~n",
+ [Host]),
+ ?shutdown(Node);
+ [_, _ | _] when LongOrShortNames == shortnames ->
+ error_logger:error_msg("** System NOT running to use fully qualified "
+ "hostnames **~n"
+ "** Hostname ~s is illegal **~n",
+ [Host]),
+ ?shutdown(Node);
+ _ ->
+ [Name, Host]
+ end.
+
+split_node([Chr|T], Chr, Ack) ->
+ [lists:reverse(Ack)|split_node(T, Chr, [])];
+split_node([H|T], Chr, Ack) ->
+ split_node(T, Chr, [H|Ack]);
+split_node([], _, Ack) ->
+ [lists:reverse(Ack)].
+
+connect_hs_data(Kernel, Node, MyNode, Socket, Timer, Version, Ip, TcpPort, Address, Type) ->
+ common_hs_data(Kernel, MyNode, Socket, Timer,
+ #hs_data{other_node = Node,
+ other_version = Version,
+ f_address =
+ fun(_,_) ->
+ #net_address{address = {Ip,TcpPort},
+ host = Address,
+ protocol = proxy,
+ family = inet}
+ end,
+ request_type = Type
+ }).
+
+accept_hs_data(Kernel, MyNode, Socket, Timer, Allowed) ->
+ common_hs_data(Kernel, MyNode, Socket, Timer, #hs_data{
+ allowed = Allowed,
+ f_address = fun(S, N) ->
+ ssl_tls_dist_proxy:get_remote_id(S, N)
+ end
+ }).
+
+common_hs_data(Kernel, MyNode, Socket, Timer, HsData) ->
+ HsData#hs_data{
+ kernel_pid = Kernel,
+ this_node = MyNode,
+ socket = Socket,
+ timer = Timer,
+ this_flags = 0,
+ f_send =
+ fun(S,D) ->
+ gen_tcp:send(S,D)
+ end,
+ f_recv =
+ fun(S,N,T) ->
+ gen_tcp:recv(S,N,T)
+ end,
+ f_setopts_pre_nodeup =
+ fun(S) ->
+ inet:setopts(S, [{active, false}, {packet, 4}])
+ end,
+ f_setopts_post_nodeup =
+ fun(S) ->
+ inet:setopts(S, [{deliver, port},{active, true}])
+ end,
+ f_getll =
+ fun(S) ->
+ inet:getll(S)
+ end,
+ mf_tick =
+ fun(S) ->
+ gen_tcp:send(S, <<>>)
+ end,
+ mf_getstat =
+ fun(S) ->
+ {ok, Stats} = inet:getstat(S, [recv_cnt, send_cnt, send_pend]),
+ R = proplists:get_value(recv_cnt, Stats, 0),
+ W = proplists:get_value(send_cnt, Stats, 0),
+ P = proplists:get_value(send_pend, Stats, 0),
+ {ok, R,W,P}
+ end}.
diff --git a/lib/ssl/src/ssl.app.src b/lib/ssl/src/ssl.app.src
index b9716786e6..13d5eaf4d7 100644
--- a/lib/ssl/src/ssl.app.src
+++ b/lib/ssl/src/ssl.app.src
@@ -4,11 +4,9 @@
{modules, [ssl,
ssl_app,
ssl_sup,
- ssl_server,
- ssl_broker,
- ssl_broker_sup,
- ssl_prim,
- inet_ssl_dist,
+ inet_tls_dist,
+ ssl_tls_dist_proxy,
+ ssl_dist_sup,
ssl_tls1,
ssl_ssl3,
ssl_ssl2,
@@ -26,7 +24,7 @@
ssl_certificate,
ssl_alert
]},
- {registered, [ssl_sup, ssl_server, ssl_broker_sup]},
+ {registered, [ssl_sup, ssl_manager]},
{applications, [crypto, public_key, kernel, stdlib]},
{env, []},
{mod, {ssl_app, []}}]}.
diff --git a/lib/ssl/src/ssl.appup.src b/lib/ssl/src/ssl.appup.src
index 29674f30da..1b07e76d6a 100644
--- a/lib/ssl/src/ssl.appup.src
+++ b/lib/ssl/src/ssl.appup.src
@@ -1,6 +1,7 @@
%% -*- erlang -*-
{"%VSN%",
[
+ {"4.1.6", [{restart_application, ssl}]},
{"4.1.5", [{restart_application, ssl}]},
{"4.1.4", [{restart_application, ssl}]},
{"4.1.3", [{restart_application, ssl}]},
@@ -10,6 +11,7 @@
{"4.0.1", [{restart_application, ssl}]}
],
[
+ {"4.1.6", [{restart_application, ssl}]},
{"4.1.5", [{restart_application, ssl}]},
{"4.1.4", [{restart_application, ssl}]},
{"4.1.3", [{restart_application, ssl}]},
diff --git a/lib/ssl/src/ssl.erl b/lib/ssl/src/ssl.erl
index d1ec0c141e..d0693445e0 100644
--- a/lib/ssl/src/ssl.erl
+++ b/lib/ssl/src/ssl.erl
@@ -25,18 +25,15 @@
-export([start/0, start/1, stop/0, transport_accept/1,
transport_accept/2, ssl_accept/1, ssl_accept/2, ssl_accept/3,
- ciphers/0, cipher_suites/0, cipher_suites/1, close/1, shutdown/2,
+ cipher_suites/0, cipher_suites/1, close/1, shutdown/2,
connect/3, connect/2, connect/4, connection_info/1,
- controlling_process/2, listen/2, pid/1, peername/1, recv/2, recv/3,
- send/2, getopts/2, setopts/2, seed/1, sockname/1, peercert/1,
- peercert/2, version/0, versions/0, session_info/1, format_error/1,
+ controlling_process/2, listen/2, pid/1, peername/1, peercert/1,
+ recv/2, recv/3, send/2, getopts/2, setopts/2, sockname/1,
+ versions/0, session_info/1, format_error/1,
renegotiate/1]).
-%% Should be deprecated as soon as old ssl is removed
-%%-deprecated({pid, 1, next_major_release}).
--deprecated({peercert, 2, next_major_release}).
+-deprecated({pid, 1, next_major_release}).
--include("ssl_int.hrl").
-include("ssl_internal.hrl").
-include("ssl_record.hrl").
-include("ssl_cipher.hrl").
@@ -134,20 +131,13 @@ connect(Socket, SslOptions0, Timeout) when is_port(Socket) ->
connect(Host, Port, Options) ->
connect(Host, Port, Options, infinity).
-connect(Host, Port, Options0, Timeout) ->
- case proplists:get_value(ssl_imp, Options0, new) of
- new ->
- new_connect(Host, Port, Options0, Timeout);
- old ->
- %% Allow the option reuseaddr to be present
- %% so that new and old ssl can be run by the same
- %% code, however the option will be ignored by old ssl
- %% that hardcodes reuseaddr to true in its portprogram.
- Options1 = proplists:delete(reuseaddr, Options0),
- Options = proplists:delete(ssl_imp, Options1),
- old_connect(Host, Port, Options, Timeout);
- Value ->
- {error, {eoptions, {ssl_imp, Value}}}
+connect(Host, Port, Options, Timeout) ->
+ try handle_options(Options, client) of
+ {ok, Config} ->
+ do_connect(Host,Port,Config,Timeout)
+ catch
+ throw:Error ->
+ Error
end.
%%--------------------------------------------------------------------
@@ -159,21 +149,19 @@ connect(Host, Port, Options0, Timeout) ->
listen(_Port, []) ->
{error, enooptions};
listen(Port, Options0) ->
- case proplists:get_value(ssl_imp, Options0, new) of
- new ->
- new_listen(Port, Options0);
- old ->
- %% Allow the option reuseaddr to be present
- %% so that new and old ssl can be run by the same
- %% code, however the option will be ignored by old ssl
- %% that hardcodes reuseaddr to true in its portprogram.
- Options1 = proplists:delete(reuseaddr, Options0),
- Options = proplists:delete(ssl_imp, Options1),
- old_listen(Port, Options);
- Value ->
- {error, {eoptions, {ssl_imp, Value}}}
+ try
+ {ok, Config} = handle_options(Options0, server),
+ #config{cb={CbModule, _, _, _},inet_user=Options} = Config,
+ case CbModule:listen(Port, Options) of
+ {ok, ListenSocket} ->
+ {ok, #sslsocket{pid = {ListenSocket, Config}, fd = new_ssl}};
+ Err = {error, _} ->
+ Err
+ end
+ catch
+ Error = {error, _} ->
+ Error
end.
-
%%--------------------------------------------------------------------
-spec transport_accept(#sslsocket{}) -> {ok, #sslsocket{}} |
{error, reason()}.
@@ -185,8 +173,7 @@ listen(Port, Options0) ->
transport_accept(ListenSocket) ->
transport_accept(ListenSocket, infinity).
-transport_accept(#sslsocket{pid = {ListenSocket, #config{cb=CbInfo, ssl=SslOpts}},
- fd = new_ssl}, Timeout) ->
+transport_accept(#sslsocket{pid = {ListenSocket, #config{cb=CbInfo, ssl=SslOpts}}}, Timeout) ->
%% The setopt could have been invoked on the listen socket
%% and options should be inherited.
@@ -208,12 +195,7 @@ transport_accept(#sslsocket{pid = {ListenSocket, #config{cb=CbInfo, ssl=SslOpts}
end;
{error, Reason} ->
{error, Reason}
- end;
-
-transport_accept(#sslsocket{} = ListenSocket, Timeout) ->
- ensure_old_ssl_started(),
- {ok, Pid} = ssl_broker:start_broker(acceptor),
- ssl_broker:transport_accept(Pid, ListenSocket, Timeout).
+ end.
%%--------------------------------------------------------------------
-spec ssl_accept(#sslsocket{}) -> ok | {error, reason()}.
@@ -227,16 +209,11 @@ transport_accept(#sslsocket{} = ListenSocket, Timeout) ->
ssl_accept(ListenSocket) ->
ssl_accept(ListenSocket, infinity).
-ssl_accept(#sslsocket{fd = new_ssl} = Socket, Timeout) ->
+ssl_accept(#sslsocket{} = Socket, Timeout) ->
ssl_connection:handshake(Socket, Timeout);
ssl_accept(ListenSocket, SslOptions) when is_port(ListenSocket) ->
- ssl_accept(ListenSocket, SslOptions, infinity);
-
-%% Old ssl
-ssl_accept(#sslsocket{} = Socket, Timeout) ->
- ensure_old_ssl_started(),
- ssl_broker:ssl_accept(Socket, Timeout).
+ ssl_accept(ListenSocket, SslOptions, infinity).
ssl_accept(Socket, SslOptions, Timeout) when is_port(Socket) ->
EmulatedOptions = emulated_options(),
@@ -257,25 +234,18 @@ ssl_accept(Socket, SslOptions, Timeout) when is_port(Socket) ->
%%
%% Description: Close an ssl connection
%%--------------------------------------------------------------------
-close(#sslsocket{pid = {ListenSocket, #config{cb={CbMod,_, _, _}}}, fd = new_ssl}) ->
+close(#sslsocket{pid = {ListenSocket, #config{cb={CbMod,_, _, _}}}}) ->
CbMod:close(ListenSocket);
-close(#sslsocket{pid = Pid, fd = new_ssl}) ->
- ssl_connection:close(Pid);
-close(Socket = #sslsocket{}) ->
- ensure_old_ssl_started(),
- ssl_broker:close(Socket).
+close(#sslsocket{pid = Pid}) ->
+ ssl_connection:close(Pid).
%%--------------------------------------------------------------------
-spec send(#sslsocket{}, iodata()) -> ok | {error, reason()}.
%%
%% Description: Sends data over the ssl connection
%%--------------------------------------------------------------------
-send(#sslsocket{pid = Pid, fd = new_ssl}, Data) ->
- ssl_connection:send(Pid, Data);
-
-send(#sslsocket{} = Socket, Data) ->
- ensure_old_ssl_started(),
- ssl_broker:send(Socket, Data).
+send(#sslsocket{pid = Pid}, Data) ->
+ ssl_connection:send(Pid, Data).
%%--------------------------------------------------------------------
-spec recv(#sslsocket{}, integer()) -> {ok, binary()| list()} | {error, reason()}.
@@ -286,11 +256,7 @@ send(#sslsocket{} = Socket, Data) ->
recv(Socket, Length) ->
recv(Socket, Length, infinity).
recv(#sslsocket{pid = Pid, fd = new_ssl}, Length, Timeout) ->
- ssl_connection:recv(Pid, Length, Timeout);
-
-recv(Socket = #sslsocket{}, Length, Timeout) ->
- ensure_old_ssl_started(),
- ssl_broker:recv(Socket, Length, Timeout).
+ ssl_connection:recv(Pid, Length, Timeout).
%%--------------------------------------------------------------------
-spec controlling_process(#sslsocket{}, pid()) -> ok | {error, reason()}.
@@ -298,13 +264,8 @@ recv(Socket = #sslsocket{}, Length, Timeout) ->
%% Description: Changes process that receives the messages when active = true
%% or once.
%%--------------------------------------------------------------------
-controlling_process(#sslsocket{pid = Pid, fd = new_ssl}, NewOwner)
- when is_pid(Pid) ->
- ssl_connection:new_user(Pid, NewOwner);
-
-controlling_process(Socket, NewOwner) when is_pid(NewOwner) ->
- ensure_old_ssl_started(),
- ssl_broker:controlling_process(Socket, NewOwner).
+controlling_process(#sslsocket{pid = Pid}, NewOwner) when is_pid(Pid) ->
+ ssl_connection:new_user(Pid, NewOwner).
%%--------------------------------------------------------------------
-spec connection_info(#sslsocket{}) -> {ok, {tls_atom_version(), erl_cipher_suite()}} |
@@ -312,82 +273,31 @@ controlling_process(Socket, NewOwner) when is_pid(NewOwner) ->
%%
%% Description: Returns ssl protocol and cipher used for the connection
%%--------------------------------------------------------------------
-connection_info(#sslsocket{pid = Pid, fd = new_ssl}) ->
- ssl_connection:info(Pid);
+connection_info(#sslsocket{pid = Pid}) ->
+ ssl_connection:info(Pid).
-connection_info(#sslsocket{} = Socket) ->
- ensure_old_ssl_started(),
- ssl_broker:connection_info(Socket).
+%%--------------------------------------------------------------------
+-spec peername(#sslsocket{}) -> {ok, {inet:ip_address(), inet:port_number()}} | {error, reason()}.
+%%
+%% Description: same as inet:peername/1.
+%%--------------------------------------------------------------------
+peername(#sslsocket{pid = Pid}) ->
+ ssl_connection:peername(Pid).
%%--------------------------------------------------------------------
--spec peercert(#sslsocket{}) ->{ok, der_cert()} | {error, reason()}.
+-spec peercert(#sslsocket{}) ->{ok, DerCert::binary()} | {error, reason()}.
%%
%% Description: Returns the peercert.
%%--------------------------------------------------------------------
-peercert(Socket) ->
- peercert(Socket, []).
-
-peercert(#sslsocket{pid = Pid, fd = new_ssl}, Opts) ->
+peercert(#sslsocket{pid = Pid}) ->
case ssl_connection:peer_certificate(Pid) of
{ok, undefined} ->
{error, no_peercert};
- {ok, BinCert} ->
- decode_peercert(BinCert, Opts);
- {error, Reason} ->
- {error, Reason}
- end;
-
-peercert(#sslsocket{} = Socket, Opts) ->
- ensure_old_ssl_started(),
- case ssl_broker:peercert(Socket) of
- {ok, Bin} ->
- decode_peercert(Bin, Opts);
- {error, Reason} ->
- {error, Reason}
- end.
-
-
-decode_peercert(BinCert, Opts) ->
- PKOpts = [case Opt of ssl -> otp; pkix -> plain end ||
- Opt <- Opts, Opt =:= ssl orelse Opt =:= pkix],
- case PKOpts of
- [Opt] ->
- select_part(Opt, public_key:pkix_decode_cert(BinCert, Opt), Opts);
- [] ->
- {ok, BinCert}
- end.
-
-select_part(otp, Cert, Opts) ->
- case lists:member(subject, Opts) of
- true ->
- TBS = Cert#'OTPCertificate'.tbsCertificate,
- {ok, TBS#'OTPTBSCertificate'.subject};
- false ->
- {ok, Cert}
- end;
-
-select_part(plain, Cert, Opts) ->
- case lists:member(subject, Opts) of
- true ->
- TBS = Cert#'Certificate'.tbsCertificate,
- {ok, TBS#'TBSCertificate'.subject};
- false ->
- {ok, Cert}
+ Result ->
+ Result
end.
%%--------------------------------------------------------------------
--spec peername(#sslsocket{}) -> {ok, {inet:ip_address(), inet:port_number()}} | {error, reason()}.
-%%
-%% Description: same as inet:peername/1.
-%%--------------------------------------------------------------------
-peername(#sslsocket{fd = new_ssl, pid = Pid}) ->
- ssl_connection:peername(Pid);
-
-peername(#sslsocket{} = Socket) ->
- ensure_old_ssl_started(),
- ssl_broker:peername(Socket).
-
-%%--------------------------------------------------------------------
-spec cipher_suites() -> [erl_cipher_suite()].
-spec cipher_suites(erlang | openssl) -> [erl_cipher_suite()] | [string()].
@@ -410,9 +320,9 @@ cipher_suites(openssl) ->
%%
%% Description: Gets options
%%--------------------------------------------------------------------
-getopts(#sslsocket{fd = new_ssl, pid = Pid}, OptionTags) when is_pid(Pid), is_list(OptionTags) ->
+getopts(#sslsocket{pid = Pid}, OptionTags) when is_pid(Pid), is_list(OptionTags) ->
ssl_connection:get_opts(Pid, OptionTags);
-getopts(#sslsocket{fd = new_ssl, pid = {ListenSocket, _}}, OptionTags) when is_list(OptionTags) ->
+getopts(#sslsocket{pid = {ListenSocket, _}}, OptionTags) when is_list(OptionTags) ->
try inet:getopts(ListenSocket, OptionTags) of
{ok, _} = Result ->
Result;
@@ -422,18 +332,15 @@ getopts(#sslsocket{fd = new_ssl, pid = {ListenSocket, _}}, OptionTags) when is_l
_:_ ->
{error, {eoptions, {inet_options, OptionTags}}}
end;
-getopts(#sslsocket{fd = new_ssl}, OptionTags) ->
- {error, {eoptions, {inet_options, OptionTags}}};
-getopts(#sslsocket{} = Socket, OptionTags) ->
- ensure_old_ssl_started(),
- ssl_broker:getopts(Socket, OptionTags).
+getopts(#sslsocket{}, OptionTags) ->
+ {error, {eoptions, {inet_options, OptionTags}}}.
%%--------------------------------------------------------------------
-spec setopts(#sslsocket{}, [gen_tcp:option()]) -> ok | {error, reason()}.
%%
%% Description: Sets options
%%--------------------------------------------------------------------
-setopts(#sslsocket{fd = new_ssl, pid = Pid}, Options0) when is_pid(Pid), is_list(Options0) ->
+setopts(#sslsocket{pid = Pid}, Options0) when is_pid(Pid), is_list(Options0) ->
try proplists:expand([{binary, [{mode, binary}]},
{list, [{mode, list}]}], Options0) of
Options ->
@@ -443,7 +350,7 @@ setopts(#sslsocket{fd = new_ssl, pid = Pid}, Options0) when is_pid(Pid), is_list
{error, {eoptions, {not_a_proplist, Options0}}}
end;
-setopts(#sslsocket{fd = new_ssl, pid = {ListenSocket, _}}, Options) when is_list(Options) ->
+setopts(#sslsocket{pid = {ListenSocket, _}}, Options) when is_list(Options) ->
try inet:setopts(ListenSocket, Options) of
ok ->
ok;
@@ -453,20 +360,17 @@ setopts(#sslsocket{fd = new_ssl, pid = {ListenSocket, _}}, Options) when is_list
_:Error ->
{error, {eoptions, {inet_options, Options, Error}}}
end;
-setopts(#sslsocket{fd = new_ssl}, Options) ->
- {error, {eoptions,{not_a_proplist, Options}}};
-setopts(#sslsocket{} = Socket, Options) ->
- ensure_old_ssl_started(),
- ssl_broker:setopts(Socket, Options).
+setopts(#sslsocket{}, Options) ->
+ {error, {eoptions,{not_a_proplist, Options}}}.
%%---------------------------------------------------------------
-spec shutdown(#sslsocket{}, read | write | read_write) -> ok | {error, reason()}.
%%
%% Description: Same as gen_tcp:shutdown/2
%%--------------------------------------------------------------------
-shutdown(#sslsocket{pid = {ListenSocket, #config{cb={CbMod,_, _, _}}}, fd = new_ssl}, How) ->
+shutdown(#sslsocket{pid = {ListenSocket, #config{cb={CbMod,_, _, _}}}}, How) ->
CbMod:shutdown(ListenSocket, How);
-shutdown(#sslsocket{pid = Pid, fd = new_ssl}, How) ->
+shutdown(#sslsocket{pid = Pid}, How) ->
ssl_connection:shutdown(Pid, How).
%%--------------------------------------------------------------------
@@ -474,25 +378,11 @@ shutdown(#sslsocket{pid = Pid, fd = new_ssl}, How) ->
%%
%% Description: Same as inet:sockname/1
%%--------------------------------------------------------------------
-sockname(#sslsocket{fd = new_ssl, pid = {ListenSocket, _}}) ->
+sockname(#sslsocket{pid = {ListenSocket, _}}) ->
inet:sockname(ListenSocket);
-sockname(#sslsocket{fd = new_ssl, pid = Pid}) ->
- ssl_connection:sockname(Pid);
-
-sockname(#sslsocket{} = Socket) ->
- ensure_old_ssl_started(),
- ssl_broker:sockname(Socket).
-
-%%---------------------------------------------------------------
--spec seed(term()) ->term().
-%%
-%% Description: Only used by old ssl.
-%%--------------------------------------------------------------------
-%% TODO: crypto:seed ?
-seed(Data) ->
- ensure_old_ssl_started(),
- ssl_server:seed(Data).
+sockname(#sslsocket{pid = Pid}) ->
+ ssl_connection:sockname(Pid).
%%---------------------------------------------------------------
-spec session_info(#sslsocket{}) -> {ok, list()} | {error, reason()}.
@@ -548,63 +438,6 @@ format_error(esslconnect) ->
format_error({eoptions, Options}) ->
lists:flatten(io_lib:format("Error in options list: ~p~n", [Options]));
-%%%%%%%%%%%% START OLD SSL format_error %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-format_error(ebadsocket) ->
- "Connection not found (internal error).";
-format_error(ebadstate) ->
- "Connection not in connect state (internal error).";
-format_error(ebrokertype) ->
- "Wrong broker type (internal error).";
-format_error(echaintoolong) ->
- "The chain of certificates provided by peer is too long.";
-format_error(ecipher) ->
- "Own list of specified ciphers is invalid.";
-format_error(ekeymismatch) ->
- "Own private key does not match own certificate.";
-format_error(enoissuercert) ->
- "Cannot find certificate of issuer of certificate provided by peer.";
-format_error(enoservercert) ->
- "Attempt to do accept without having set own certificate.";
-format_error(enotlistener) ->
- "Attempt to accept on a non-listening socket.";
-format_error(enoproxysocket) ->
- "No proxy socket found (internal error or max number of file "
- "descriptors exceeded).";
-format_error(enooptions) ->
- "List of options is empty.";
-format_error(enotstarted) ->
- "The SSL application has not been started.";
-format_error(eoptions) ->
- "Invalid list of options.";
-format_error(epeercert) ->
- "Certificate provided by peer is in error.";
-format_error(epeercertexpired) ->
- "Certificate provided by peer has expired.";
-format_error(epeercertinvalid) ->
- "Certificate provided by peer is invalid.";
-format_error(eselfsignedcert) ->
- "Certificate provided by peer is self signed.";
-format_error(esslerrssl) ->
- "SSL protocol failure. Typically because of a fatal alert from peer.";
-format_error(ewantconnect) ->
- "Protocol wants to connect, which is not supported in this "
- "version of the SSL application.";
-format_error(ex509lookup) ->
- "Protocol wants X.509 lookup, which is not supported in this "
- "version of the SSL application.";
-format_error({badcall, _Call}) ->
- "Call not recognized for current mode (active or passive) and state "
- "of socket.";
-format_error({badcast, _Cast}) ->
- "Call not recognized for current mode (active or passive) and state "
- "of socket.";
-
-format_error({badinfo, _Info}) ->
- "Call not recognized for current mode (active or passive) and state "
- "of socket.";
-
-%%%%%%%%%%%%%%%%%% END OLD SSL format_error %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
format_error(Error) ->
case (catch inet:format_error(Error)) of
"unkknown POSIX" ++ _ ->
@@ -618,16 +451,7 @@ format_error(Error) ->
%%%--------------------------------------------------------------
%%% Internal functions
%%%--------------------------------------------------------------------
-new_connect(Address, Port, Options, Timeout) when is_list(Options) ->
- try handle_options(Options, client) of
- {ok, Config} ->
- do_new_connect(Address,Port,Config,Timeout)
- catch
- throw:Error ->
- Error
- end.
-
-do_new_connect(Address, Port,
+do_connect(Address, Port,
#config{cb=CbInfo, inet_user=UserOpts, ssl=SslOpts,
emulated=EmOpts,inet_ssl=SocketOpts},
Timeout) ->
@@ -647,35 +471,9 @@ do_new_connect(Address, Port,
{error, {eoptions, {inet_options, UserOpts}}}
end.
-old_connect(Address, Port, Options, Timeout) ->
- ensure_old_ssl_started(),
- {ok, Pid} = ssl_broker:start_broker(connector),
- ssl_broker:connect(Pid, Address, Port, Options, Timeout).
-
-new_listen(Port, Options0) ->
- try
- {ok, Config} = handle_options(Options0, server),
- #config{cb={CbModule, _, _, _},inet_user=Options} = Config,
- case CbModule:listen(Port, Options) of
- {ok, ListenSocket} ->
- {ok, #sslsocket{pid = {ListenSocket, Config}, fd = new_ssl}};
- Err = {error, _} ->
- Err
- end
- catch
- Error = {error, _} ->
- Error
- end.
-
-old_listen(Port, Options) ->
- ensure_old_ssl_started(),
- {ok, Pid} = ssl_broker:start_broker(listener),
- ssl_broker:listen(Pid, Port, Options).
-
handle_options(Opts0, _Role) ->
Opts = proplists:expand([{binary, [{mode, binary}]},
{list, [{mode, list}]}], Opts0),
-
ReuseSessionFun = fun(_, _, _, _) -> true end,
DefaultVerifyNoneFun =
@@ -742,7 +540,8 @@ handle_options(Opts0, _Role) ->
secure_renegotiate = handle_option(secure_renegotiate, Opts, false),
renegotiate_at = handle_option(renegotiate_at, Opts, ?DEFAULT_RENEGOTIATE_AT),
debug = handle_option(debug, Opts, []),
- hibernate_after = handle_option(hibernate_after, Opts, undefined)
+ hibernate_after = handle_option(hibernate_after, Opts, undefined),
+ erl_dist = handle_option(erl_dist, Opts, false)
},
CbInfo = proplists:get_value(cb_info, Opts, {gen_tcp, tcp, tcp_closed, tcp_error}),
@@ -751,7 +550,7 @@ handle_options(Opts0, _Role) ->
depth, cert, certfile, key, keyfile,
password, cacerts, cacertfile, dh, dhfile, ciphers,
debug, reuse_session, reuse_sessions, ssl_imp,
- cb_info, renegotiate_at, secure_renegotiate, hibernate_after],
+ cb_info, renegotiate_at, secure_renegotiate, hibernate_after, erl_dist],
SockOpts = lists:foldl(fun(Key, PropList) ->
proplists:delete(Key, PropList)
@@ -768,8 +567,6 @@ handle_option(OptionName, Opts, Default) ->
validate_option(versions, Versions) ->
validate_versions(Versions, Versions);
-validate_option(ssl_imp, Value) when Value == new; Value == old ->
- Value;
validate_option(verify, Value)
when Value == verify_none; Value == verify_peer ->
Value;
@@ -811,8 +608,11 @@ validate_option(certfile, Value) when Value == undefined; is_list(Value) ->
validate_option(key, undefined) ->
undefined;
validate_option(key, {KeyType, Value}) when is_binary(Value),
- KeyType == rsa;
- KeyType == dsa ->
+ KeyType == rsa; %% Backwards compatibility
+ KeyType == dsa; %% Backwards compatibility
+ KeyType == 'RSAPrivateKey';
+ KeyType == 'DSAPrivateKey';
+ KeyType == 'PrivateKeyInfo' ->
{KeyType, Value};
validate_option(keyfile, Value) when is_list(Value) ->
Value;
@@ -862,6 +662,9 @@ validate_option(hibernate_after, undefined) ->
undefined;
validate_option(hibernate_after, Value) when is_integer(Value), Value >= 0 ->
Value;
+validate_option(erl_dist,Value) when Value == true;
+ Value == false ->
+ Value;
validate_option(Opt, Value) ->
throw({error, {eoptions, {Opt, Value}}}).
@@ -909,7 +712,6 @@ emulated_options() ->
internal_inet_values() ->
[{packet_size,0},{packet, 0},{header, 0},{active, false},{mode,binary}].
- %%[{packet, ssl},{header, 0},{active, false},{mode,binary}].
socket_options(InetValues) ->
#socket_options{
@@ -970,47 +772,14 @@ cipher_suites(Version, Ciphers0) ->
no_format(Error) ->
lists:flatten(io_lib:format("No format string for error: \"~p\" available.", [Error])).
-
-%% Start old ssl port program if needed.
-ensure_old_ssl_started() ->
- case whereis(ssl_server) of
- undefined ->
- (catch supervisor:start_child(ssl_sup,
- {ssl_server, {ssl_server, start_link, []},
- permanent, 2000, worker, [ssl_server]}));
- _ ->
- ok
- end.
-
-%%%%%%%%%%%%%%%% Deprecated %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-ciphers() ->
- ensure_old_ssl_started(),
- case (catch ssl_server:ciphers()) of
- {'EXIT', _} ->
- {error, enotstarted};
- Res = {ok, _} ->
- Res
- end.
-
-version() ->
- ensure_old_ssl_started(),
- SSLVsn = ?VSN,
- {CompVsn, LibVsn} = case (catch ssl_server:version()) of
- {'EXIT', _} ->
- {"", ""};
- {ok, Vsns} ->
- Vsns
- end,
- {ok, {SSLVsn, CompVsn, LibVsn}}.
-
%% Only used to remove exit messages from old ssl
%% First is a nonsense clause to provide some
%% backward compatibility for orber that uses this
%% function in a none recommended way, but will
%% work correctly if a valid pid is returned.
+%% Deprcated to be removed in r16
pid(#sslsocket{fd = new_ssl}) ->
- whereis(ssl_connection_sup);
+ whereis(ssl_connection_sup);
pid(#sslsocket{pid = Pid}) ->
- Pid.
+ Pid.
diff --git a/lib/ssl/src/ssl_broker.erl b/lib/ssl/src/ssl_broker.erl
deleted file mode 100644
index 7ef88baf2b..0000000000
--- a/lib/ssl/src/ssl_broker.erl
+++ /dev/null
@@ -1,1188 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1999-2010. All Rights Reserved.
-%%
-%% The contents of this file are subject to the Erlang Public License,
-%% Version 1.1, (the "License"); you may not use this file except in
-%% compliance with the License. You should have received a copy of the
-%% Erlang Public License along with this software. If not, it can be
-%% retrieved online at http://www.erlang.org/.
-%%
-%% Software distributed under the License is distributed on an "AS IS"
-%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
-%% the License for the specific language governing rights and limitations
-%% under the License.
-%%
-%% %CopyrightEnd%
-%%
-
-%%
-
-%%% Purpose : SSL broker
-
--module(ssl_broker).
--behaviour(gen_server).
-
-%% This module implements brokers for ssl. A broker is either a connector,
-%% an acceptor, or a listener. All brokers are children to ssl_broker_sup,
-%% to which they are linked. Each broker is also linked to ssl_server, and
-%% to its client.
-%%
-%% The purpose of the broker is to set up SSL connections through calls to
-%% ssl_server and gen_tcp. All control information goes to the server,
-%% while all data is exchanged directly between gen_tcp and the port program
-%% of the ssl_server.
-%%
-%% A broker is created by a call to start_broker/3 (do *not* use start_link/4
-%% - it is for ssl_broker_sup to call that one), and then call listen/3,
-%% accept/4, or connect/5.
-%%
-%% The following table shows all functions dependency on status, active
-%% mode etc.
-%%
-%% Permitted status transitions:
-%%
-%% nil -> open
-%% open -> closing | closed (termination)
-%% closing -> closed (termination)
-%%
-%% We are rather sloppy about nil, and consider open/closing == !closed,
-%% open/closing/closed === any etc.
-%%
-%%
-%% function/ valid mode new
-%% message status state
-%%
-%% calls
-%% -----
-%% recv open passive ditto
-%% send open any ditto
-%% transport_accept nil any open
-%% ssl_accept nil any open
-%% connect nil any open
-%% listen nil any open
-%% peername open/closing any ditto
-%% setopts open/closing any ditto
-%% getopts open/closing any ditto
-%% sockname open/closing any ditto
-%% peercert open/closing any ditto
-%% inhibit any any ditto
-%% release any any ditto
-%% close any any closed (1)
-%%
-%% info
-%% ----
-%% tcp open active ditto
-%% tcp_closed open | closing active closing
-%% tcp_error open | closing active closing
-%%
-%% (1) We just terminate.
-%%
-%% TODO
-%%
-%% XXX Timeouts are not checked (integer or infinity).
-%%
-%% XXX The collector thing is not gen_server compliant.
-%%
-%% NOTE: There are three different "modes": (a) passive or active mode,
-%% specified as {active, bool()}, and (b) list or binary mode, specified
-%% as {mode, list | binary}, and (c) encrypted or clear mode
-%%
-
--include("ssl_int.hrl").
-
-%% External exports
-
--export([start_broker/1, start_broker/2, start_link/3,
- transport_accept/3, ssl_accept/2,
- close/1, connect/5, connection_info/1, controlling_process/2,
- listen/3, recv/3, send/2, getopts/2, getopts/3, setopts/2,
- sockname/1, peername/1, peercert/1]).
-
--export([listen_prim/5, connect_prim/8,
- transport_accept_prim/5, ssl_accept_prim/6]).
-
-%% Internal exports
-
--export([init/1, handle_call/3, handle_cast/2, handle_info/2,
- code_change/3, terminate/2, collector_init/1]).
-
--include("ssl_broker_int.hrl").
-
-%% start_broker(Type) -> {ok, Pid} | {error, Reason}
-%% start_broker(Type, GenOpts) -> {ok, Pid} | {error, Reason}
-%% Type = accept | connect | listen
-%% GenOpts = /standard gen_server options/
-%%
-%% This is the function to be called from the interface module ssl.erl.
-%% Links to the caller.
-%%
-start_broker(Type) ->
- start_broker(Type, []).
-
-start_broker(Type, GenOpts) ->
- case lists:member(Type, [listener, acceptor, connector]) of
- true ->
- case supervisor:start_child(ssl_broker_sup,
- [self(), Type, GenOpts]) of
- {ok, Pid} ->
- link(Pid),
- {ok, Pid};
- {error, Reason} ->
- {error, Reason}
- end;
- false ->
- {error, ebrokertype}
- end.
-
-%% start_link(Client, Type, GenOpts) -> {ok, Pid} | {error, Reason}
-%%
-%% Type = accept | connect | listen
-%% GenOpts = /standard gen_server options/
-%%
-%% This function is called by ssl_broker_sup and must *not* be called
-%% from an interface module (ssl.erl).
-
-start_link(Client, Type, GenOpts) ->
- gen_server:start_link(?MODULE, [Client, Type], GenOpts).
-
-
-%% accept(Pid, ListenSocket, Timeout) -> {ok, Socket} | {error, Reason}
-%%
-%% Types: Pid = pid() of acceptor
-%% ListenSocket = Socket = sslsocket()
-%% Timeout = timeout()
-%%
-%% accept(Pid, ListenSocket, Timeout)
-%% when is_pid(Pid), is_record(ListenSocket, sslsocket) ->
-%% Req = {accept, self(), ListenSocket, Timeout},
-%% gen_server:call(Pid, Req, infinity).
-
-%% transport_accept(Pid, ListenSocket, Timeout) -> {ok, Socket} |
-%% {error, Reason}
-%%
-%% Types: Pid = pid() of acceptor
-%% ListenSocket = Socket = sslsocket()
-%% Timeout = timeout()
-%%
-transport_accept(Pid, #sslsocket{} = ListenSocket, Timeout) when is_pid(Pid) ->
- Req = {transport_accept, self(), ListenSocket, Timeout},
- gen_server:call(Pid, Req, infinity).
-
-%% ssl_accept(Pid, Socket, Timeout) -> {ok, Socket} | {error, Reason}
-%%
-%% Types: Pid = pid() of acceptor
-%% ListenSocket = Socket = sslsocket()
-%% Timeout = timeout()
-%%
-ssl_accept(#sslsocket{pid = Pid} = Socket, Timeout) ->
- Req = {ssl_accept, self(), Socket, Timeout},
- gen_server:call(Pid, Req, infinity).
-
-%% close(Socket) -> ok | {error, Reason}
-%%
-%% Types: Socket = sslsocket() | pid()
-%%
-close(#sslsocket{pid = Pid}) ->
- close(Pid);
-close(Pid) when is_pid(Pid) ->
- gen_server:call(Pid, {close, self()}, infinity).
-
-%% connect(Pid, Address, Port, Opts, Timeout) -> {ok, Socket} | {error, Reason}
-%%
-%% Types: Pid = pid() of connector
-%% Address = string() | {byte(), byte(), byte(), byte()}
-%% Port = int()
-%% Opts = options()
-%% Timeout = timeout()
-%% Socket = sslsocket()
-%%
-connect(Pid, Address, Port, Opts, Timeout) when is_pid(Pid), is_list(Opts) ->
- case are_connect_opts(Opts) of
- true ->
- Req = {connect, self(), Address, Port, Opts, Timeout},
- gen_server:call(Pid, Req, infinity);
- false ->
- {error, eoptions}
- end.
-
-%%
-%% connection_info(Socket) -> {ok, {Protocol, Cipher} | {error, Reason}
-%%
-connection_info(#sslsocket{pid = Pid}) ->
- Req = {connection_info, self()},
- gen_server:call(Pid, Req, infinity).
-
-%% controlling_process(Socket, NewOwner) -> ok | {error, Reason}
-
-controlling_process(#sslsocket{pid = Pid}, NewOwner) when is_pid(NewOwner) ->
- case gen_server:call(Pid, {inhibit_msgs, self()}, infinity) of
- ok ->
- transfer_messages(Pid, NewOwner),
- gen_server:call(Pid, {release_msgs, self(), NewOwner}, infinity);
- Error ->
- Error
- end.
-
-%% listen(Pid, Port, Opts) -> {ok, ListenSocket} | {error, Reason}
-%%
-%% Types: Pid = pid() of listener
-%% Port = int()
-%% Opts = options()
-%% ListenSocket = sslsocket()
-%%
-listen(Pid, Port, Opts) when is_pid(Pid) ->
- case are_listen_opts(Opts) of
- true ->
- Req = {listen, self(), Port, Opts},
- gen_server:call(Pid, Req, infinity);
- false ->
- {error, eoptions}
- end.
-
-
-%%
-%% peername(Socket) -> {ok, {Address, Port}} | {error, Reason}
-%%
-peername(#sslsocket{pid = Pid}) ->
- Req = {peername, self()},
- gen_server:call(Pid, Req, infinity).
-
-
-%% recv(Socket, Length, Timeout) -> {ok, Data} | {error, Reason}
-%%
-%% Types: Socket = sslsocket()
-%% Length = Timeout = integer()
-%% Data = bytes() | binary()
-%%
-recv(#sslsocket{pid = Pid}, Length, Timeout) ->
- Req = {recv, self(), Length, Timeout},
- gen_server:call(Pid, Req, infinity).
-
-
-%% send(Socket, Data) -> ok | {error, Reason}
-%%
-%% Types: Socket = sslsocket()
-%%
-send(#sslsocket{pid = Pid}, Data) ->
- gen_server:call(Pid, {send, self(), Data}, infinity).
-
-
-%% getopts(Socket, OptTags) -> {ok, Opts} | {error, einval}
-%%
-%% Types: Pid = pid() of broker
-%% Timeout = timeout()
-%% OptTags = option_tags()
-%% Opts = options()
-%%
-getopts(Socket, OptTags) ->
- getopts(Socket, OptTags, infinity).
-
-getopts(#sslsocket{pid = Pid}, OptTags, Timeout) when is_list(OptTags) ->
- Req = {getopts, self(), OptTags},
- gen_server:call(Pid, Req, Timeout).
-
-
-%%
-%% setopts(Socket, Opts) -> ok | {error, Reason}
-%%
-setopts(#sslsocket{pid = Pid}, Opts) ->
- Req = {setopts, self(), Opts},
- gen_server:call(Pid, Req, infinity).
-
-%%
-%% sockname(Socket) -> {ok, {Address, Port}} | {error, Reason}
-%%
-sockname(#sslsocket{pid = Pid}) ->
- Req = {sockname, self()},
- gen_server:call(Pid, Req, infinity).
-
-
-%%
-%% peercert(Socket) -> {ok, Cert} | {error, Reason}
-%%
-peercert(#sslsocket{pid = Pid}) ->
- Req = {peercert, self()},
- gen_server:call(Pid, Req, infinity).
-
-%%
-%% INIT
-%%
-
-%% init
-%%
-init([Client, Type]) ->
- process_flag(trap_exit, true),
- link(Client),
- Debug = case application:get_env(ssl, edebug) of
- {ok, true} ->
- true;
- _ ->
- case application:get_env(ssl, debug) of
- {ok, true} ->
- true;
- _ ->
- os:getenv("ERL_SSL_DEBUG") =/= false
- end
- end,
- Server = whereis(ssl_server),
- if
- is_pid(Server) ->
- link(Server),
- debug1(Debug, Type, "in start, client = ~w", [Client]),
- {ok, #st{brokertype = Type, server = Server, client = Client,
- collector = Client, debug = Debug}};
- true ->
- {stop, no_ssl_server}
- end.
-
-
-%%
-%% HANDLE CALL
-%%
-
-%% recv - passive mode
-%%
-handle_call({recv, Client, Length, Timeout}, _From,
- #st{active = false, proxysock = Proxysock, status = Status} = St) ->
- debug(St, "recv: client = ~w~n", [Client]),
- if
- Status =/= open ->
- {reply, {error, closed}, St};
- true ->
- case gen_tcp:recv(Proxysock, Length, Timeout) of
- {ok, Data} ->
- {reply, {ok, Data}, St};
- {error, timeout} ->
- {reply, {error, timeout}, St};
- {error, Reason} ->
- {reply, {error, Reason}, St#st{status = closing}}
- end
- end;
-
-%% send
-%%
-handle_call({send, Client, Data}, _From, St) ->
- debug(St, "send: client = ~w~n", [Client]),
- if
- St#st.status =/= open ->
- {reply, {error, closed}, St};
- true ->
- case gen_tcp:send(St#st.proxysock, Data) of
- ok ->
- {reply, ok, St};
- {error, _Reason} ->
- {reply, {error, closed}, St#st{status = closing}}
- end
- end;
-
-%% transport_accept
-%%
-%% Client = pid of client
-%% ListenSocket = sslsocket()
-%%
-handle_call({transport_accept, Client, ListenSocket, Timeout}, _From, St) ->
- debug(St, "transport_accept: client = ~w, listensocket = ~w~n",
- [Client, ListenSocket]),
- case getopts(ListenSocket, tcp_listen_opt_tags(), ?DEF_TIMEOUT) of
- {ok, LOpts} ->
- case transport_accept_prim(
- ssl_server, ListenSocket#sslsocket.fd, LOpts, Timeout, St) of
- {ok, ThisSocket, NSt} ->
- {reply, {ok, ThisSocket}, NSt};
- {error, Reason, St} ->
- What = what(Reason),
- {stop, normal, {error, What}, St}
- end;
- {error, Reason} ->
- What = what(Reason),
- {stop, normal, {error, What}, St}
- end;
-
-%% ssl_accept
-%%
-%% Client = pid of client
-%% ListenSocket = sslsocket()
-%%
-handle_call({ssl_accept, Client, Socket, Timeout}, _From, St) ->
- debug(St, "ssl_accept: client = ~w, socket = ~w~n", [Client, Socket]),
- case ssl_accept_prim(ssl_server, gen_tcp, Client, St#st.opts, Timeout, St#st{thissock=Socket}) of
- {ok, Socket, NSt} ->
- {reply, ok, NSt};
- {error, Reason, St} ->
- What = what(Reason),
- {stop, normal, {error, What}, St}
- end;
-
-%% connect
-%%
-%% Client = client pid
-%% Address = hostname | ipstring | IP
-%% Port = integer()
-%% Opts = options()
-%%
-handle_call({connect, Client, Address, Port, Opts, Timeout}, _From, St) ->
- debug(St, "connect: client = ~w, address = ~p, port = ~w~n",
- [Client, Address, Port]),
- case connect_prim(ssl_server, gen_tcp, Client, Address, Port, Opts,
- Timeout, St) of
- {ok, Res, NSt} ->
- {reply, {ok, Res}, NSt};
- {error, Reason, NSt} ->
- What = what(Reason),
- {stop, normal, {error, What}, NSt}
- end;
-
-%% connection_info
-%%
-handle_call({connection_info, Client}, _From, St) ->
- debug(St, "connection_info: client = ~w~n", [Client]),
- Reply = ssl_server:connection_info(St#st.fd),
- {reply, Reply, St};
-
-%% close from client
-%%
-handle_call({close, Client}, _From, St) ->
- debug(St, "close: client = ~w~n", [Client]),
- %% Terminate
- {stop, normal, ok, St#st{status = closed}};
-
-%% listen
-%%
-%% Client = pid of client
-%% Port = int()
-%% Opts = options()
-%%
-handle_call({listen, Client, Port, Opts}, _From, St) ->
- debug(St, "listen: client = ~w, port = ~w~n",
- [Client, Port]),
- case listen_prim(ssl_server, Client, Port, Opts, St) of
- {ok, Res, NSt} ->
- {reply, {ok, Res}, NSt};
- {error, Reason, NSt} ->
- What = what(Reason),
- {stop, normal, {error, What}, NSt}
- end;
-
-%% peername
-%%
-handle_call({peername, Client}, _From, St) ->
- debug(St, "peername: client = ~w~n", [Client]),
- Reply = case ssl_server:peername(St#st.fd) of
- {ok, {Address, Port}} ->
- {ok, At} = inet_parse:ipv4_address(Address),
- {ok, {At, Port}};
- Error ->
- Error
- end,
- {reply, Reply, St};
-
-%% setopts
-%%
-handle_call({setopts, Client, Opts0}, _From, St0) ->
- debug(St0, "setopts: client = ~w~n", [Client]),
- OptsOK = case St0#st.brokertype of
- listener ->
- are_opts(fun is_tcp_listen_opt/1, Opts0);
- acceptor ->
- are_opts(fun is_tcp_accept_opt/1, Opts0);
- connector ->
- are_opts(fun is_tcp_connect_opt/1, Opts0)
- end,
- if
- OptsOK =:= false ->
- {reply, {error, eoptions}, St0};
- true ->
- Opts1 = lists:keydelete(nodelay, 1, Opts0),
- case inet:setopts(St0#st.proxysock, Opts1) of
- ok ->
- Opts2 = replace_opts(Opts1, St0#st.opts),
- Active = get_active(Opts2),
- St2 = St0#st{opts = Opts2,
- active = Active},
- case get_nodelay(Opts0) of
- empty ->
- {reply, ok, St2};
- Bool ->
- case setnodelay(ssl_server, St0, Bool) of
- ok ->
- Opts3 = replace_opts([{nodelay, Bool}],
- Opts2),
- St3 = St0#st{opts = Opts3,
- active = Active},
- {reply, ok, St3};
- {error, Reason} ->
- {reply, {error, Reason}, St2}
- end
- end;
- {error, Reason} ->
- {reply, {error, Reason}, St0}
- end
- end;
-
-%% sockname
-%%
-handle_call({sockname, Client}, _From, St) ->
- debug(St, "sockname: client = ~w~n", [Client]),
- Reply = case ssl_server:sockname(St#st.fd) of
- {ok, {Address, Port}} ->
- {ok, At} = inet_parse:ipv4_address(Address),
- {ok, {At, Port}};
- Error ->
- Error
- end,
- {reply, Reply, St};
-
-%% peercert
-%%
-handle_call({peercert, Client}, _From, St) ->
- debug(St, "peercert: client = ~w~n", [Client]),
- Reply = ssl_server:peercert(St#st.fd),
- {reply, Reply, St};
-
-%% inhibit msgs
-%%
-handle_call({inhibit_msgs, Client}, _From, #st{client = Client} = St) ->
- debug(St, "inhibit_msgs: client = ~w~n", [Client]),
- {ok, Collector} = start_collector(),
- {reply, ok, St#st{collector = Collector}};
-
-%% release msgs
-%%
-handle_call({release_msgs, Client, NewClient}, _From,
- #st{client = Client, collector = Collector} = St) ->
- debug(St, "release_msgs: client = ~w~n", [Client]),
- unlink(Client),
- link(NewClient),
- release_collector(Collector, NewClient),
- NSt = St#st{client = NewClient, collector = NewClient},
- {reply, ok, NSt};
-
-%% getopts
-%%
-handle_call({getopts, Client, OptTags}, _From, St) ->
- debug(St, "getopts: client = ~w~n", [Client]),
- Reply = case are_opt_tags(St#st.brokertype, OptTags) of
- true ->
- {ok, extract_opts(OptTags, St#st.opts)};
- _ ->
- {error, einval}
- end,
- {reply, Reply, St};
-
-%% bad call
-%%
-handle_call(Request, _From, St) ->
- debug(St, "++++ ssl_broker: bad call: ~w~n", [Request]),
- {reply, {error, {badcall, Request}}, St}.
-
-%%
-%% HANDLE CAST
-%%
-
-handle_cast(Request, St) ->
- debug(St, "++++ ssl_broker: bad cast: ~w~n", [Request]),
- {stop, {error, {badcast, Request}}, St}.
-
-%%
-%% HANDLE INFO
-%%
-
-%% tcp - active mode
-%%
-%% The collector is different from client only during change of
-%% controlling process.
-%%
-handle_info({tcp, Socket, Data},
- #st{active = Active, collector = Collector, status = open,
- proxysock = Socket, thissock = Thissock} = St)
- when Active =/= false ->
- debug(St, "tcp: socket = ~w~n", [Socket]),
- Msg = {ssl, Thissock, Data},
- Collector ! Msg,
- if
- Active =:= once ->
- {noreply, St#st{active = false}};
- true ->
- {noreply, St}
- end;
-
-%% tcp_closed - from proxy socket, active mode
-%%
-%%
-handle_info({tcp_closed, Socket},
- #st{active = Active, collector = Collector,
- proxysock = Socket, thissock = Thissock} = St)
- when Active =/= false ->
- debug(St, "tcp_closed: socket = ~w~n", [Socket]),
- Msg = {ssl_closed, Thissock},
- Collector ! Msg,
- if
- Active =:= once ->
- {noreply, St#st{status = closing, active = false}};
- true ->
- {noreply, St#st{status = closing}}
- end;
-
-%% tcp_error - from proxy socket, active mode
-%%
-%%
-handle_info({tcp_error, Socket, Reason},
- #st{active = Active, collector = Collector,
- proxysock = Socket} = St)
- when Active =/= false ->
- debug(St, "tcp_error: socket = ~w, reason = ~w~n", [Socket, Reason]),
- Msg = {ssl_error, Socket, Reason},
- Collector ! Msg,
- if
- Active =:= once ->
- {noreply, St#st{status = closing, active = false}};
- true ->
- {noreply, St#st{status = closing}}
- end;
-
-%% EXIT - from client
-%%
-%%
-handle_info({'EXIT', Client, Reason}, #st{client = Client} = St) ->
- debug(St, "exit client: client = ~w, reason = ~w~n", [Client, Reason]),
- {stop, normal, St#st{status = closed}}; % do not make noise
-
-%% EXIT - from server
-%%
-%%
-handle_info({'EXIT', Server, Reason}, #st{server = Server} = St) ->
- debug(St, "exit server: reason = ~w~n", [Reason]),
- {stop, Reason, St};
-
-%% handle info catch all
-%%
-handle_info(Info, St) ->
- debug(St, " bad info: ~w~n", [Info]),
- {stop, {error, {badinfo, Info}}, St}.
-
-
-%% terminate
-%%
-%%
-terminate(Reason, St) ->
- debug(St, "in terminate reason: ~w, state: ~w~n", [Reason, St]),
- ok.
-
-%% code_change
-%%
-%%
-code_change(_OldVsn, State, _Extra) ->
- {ok, State}.
-
-%%
-%% Primitive interface
-%%
-listen_prim(ServerName, Client, Port, Opts, St) ->
- LOpts = get_tcp_listen_opts(Opts),
- SSLOpts = get_ssl_opts(Opts),
- FlagStr =mk_ssl_optstr(SSLOpts),
- BackLog = get_backlog(LOpts),
- IP = get_ip(LOpts),
- case ssl_server:listen_prim(ServerName, IP, Port, FlagStr, BackLog) of
- {ok, ListenFd, _Port0} ->
- ThisSocket = #sslsocket{fd = ListenFd, pid = self()},
- StOpts = add_default_tcp_listen_opts(LOpts) ++
- add_default_ssl_opts(SSLOpts),
- NSt = St#st{fd = ListenFd,
- active = get_active(LOpts), % irrelevant for listen
- opts = StOpts,
- thissock = ThisSocket,
- status = open},
- debug(St, "listen: ok: client = ~w, listenfd = ~w~n",
- [Client, ListenFd]),
- {ok, ThisSocket, NSt};
- {error, Reason} ->
- {error, Reason, St}
- end.
-
-connect_prim(ServerName, TcpModule, Client, FAddress, FPort, Opts,
- Timeout, St) ->
- COpts = get_tcp_connect_opts(Opts),
- SSLOpts = get_ssl_opts(Opts),
- FlagStr = mk_ssl_optstr(SSLOpts),
- case inet:getaddr(FAddress, inet) of
- {ok, FIP} ->
- %% Timeout is gen_server timeout - hence catch
- LIP = get_ip(COpts),
- LPort = get_port(COpts),
- case (catch ssl_server:connect_prim(ServerName,
- LIP, LPort, FIP, FPort,
- FlagStr, Timeout)) of
- {ok, Fd, ProxyPort} ->
- case connect_proxy(ServerName, TcpModule, Fd,
- ProxyPort, COpts, Timeout) of
- {ok, Socket} ->
- ThisSocket = #sslsocket{fd = Fd, pid = self()},
- StOpts = add_default_tcp_connect_opts(COpts) ++
- add_default_ssl_opts(SSLOpts),
- NSt = St#st{fd = Fd,
- active = get_active(COpts),
- opts = StOpts,
- thissock = ThisSocket,
- proxysock = Socket,
- status = open},
- case get_nodelay(COpts) of
- true -> setnodelay(ServerName, NSt, true);
- _ -> ok
- end,
- debug(St, "connect: ok: client = ~w, fd = ~w~n",
- [Client, Fd]),
- {ok, ThisSocket, NSt};
- {error, Reason} ->
- {error, Reason, St}
- end;
- {'EXIT', Reason} ->
- {error, Reason, St};
- {error, Reason} ->
- {error, Reason, St}
- end;
- {error, Reason} ->
- {error, Reason, St}
- end.
-
-transport_accept_prim(ServerName, ListenFd, LOpts, Timeout, St) ->
- AOpts = get_tcp_accept_opts(LOpts),
- FlagStr = "",
- %% Timeout is gen_server timeout - hence catch.
- case (catch ssl_server:transport_accept_prim(ServerName, ListenFd,
- FlagStr, Timeout)) of
- {ok, Fd, ProxyPort} ->
- ThisSocket = #sslsocket{fd = Fd, pid = self()},
- NSt = St#st{fd = Fd,
- active = get_active(AOpts),
- opts = AOpts,
- thissock = ThisSocket,
- proxyport = ProxyPort,
- encrypted = false},
- debug(St, "transport_accept: ok: fd = ~w~n", [Fd]),
- {ok, ThisSocket, NSt};
- {'EXIT', Reason} ->
- debug(St, "transport_accept: EXIT: Reason = ~w~n", [Reason]),
- {error, Reason, St};
- {error, Reason} ->
- debug(St, "transport_accept: error: Reason = ~w~n", [Reason]),
- {error, Reason, St}
- end.
-
-ssl_accept_prim(ServerName, TcpModule, Client, LOpts, Timeout, St) ->
- FlagStr = [],
- SSLOpts = [],
- AOpts = get_tcp_accept_opts(LOpts),
- %% Timeout is gen_server timeout - hence catch.
- debug(St, "ssl_accept_prim: self() ~w Client ~w~n", [self(), Client]),
- Socket = St#st.thissock,
- Fd = Socket#sslsocket.fd,
- A = (catch ssl_server:ssl_accept_prim(ServerName, Fd, FlagStr, Timeout)),
- debug(St, "ssl_accept_prim: ~w~n", [A]),
- case A of
- ok ->
- B = connect_proxy(ServerName, TcpModule, Fd,
- St#st.proxyport, AOpts, Timeout),
- debug(St, "ssl_accept_prim: connect_proxy ~w~n", [B]),
- case B of
- {ok, Socket2} ->
- StOpts = add_default_tcp_accept_opts(AOpts) ++
- add_default_ssl_opts(SSLOpts),
- NSt = St#st{opts = StOpts,
- proxysock = Socket2,
- encrypted = true,
- status = open},
- case get_nodelay(AOpts) of
- true -> setnodelay(ServerName, NSt, true);
- _ -> ok
- end,
- debug(St, "transport_accept: ok: client = ~w, fd = ~w~n",
- [Client, Fd]),
- {ok, St#st.thissock, NSt};
- {error, Reason} ->
- {error, Reason, St}
- end;
- {'EXIT', Reason} ->
- {error, Reason, St};
- {error, Reason} ->
- {error, Reason, St}
- end.
-
-
-%%
-%% LOCAL FUNCTIONS
-%%
-
-%%
-%% connect_proxy(Fd, ProxyPort, TOpts, Timeout) -> {ok, Socket} |
-%% {error, Reason}
-%%
-connect_proxy(ServerName, TcpModule, Fd, ProxyPort, TOpts, Timeout) ->
- case TcpModule:connect({127, 0, 0, 1}, ProxyPort, TOpts, Timeout) of
- {ok, Socket} ->
- {ok, Port} = inet:port(Socket),
- A = ssl_server:proxy_join_prim(ServerName, Fd, Port),
- case A of
- ok ->
- {ok, Socket};
- Error ->
- Error
- end;
- Error ->
- Error
- end.
-
-
-setnodelay(ServerName, St, Bool) ->
- case ssl_server:setnodelay_prim(ServerName, St#st.fd, Bool) of
- ok ->
- case inet:setopts(St#st.proxysock, [{nodelay, Bool}]) of
- ok ->
- ok;
- {error, Reason} ->
- {error, Reason}
- end;
- {error, Reason} ->
- {error, Reason}
- end.
-
-%%
-%% start_collector()
-%%
-%% A collector is a little process that keeps messages during change of
-%% controlling process.
-%% XXX This is not gen_server compliant :-(.
-%%
-start_collector() ->
- Pid = spawn_link(?MODULE, collector_init, [self()]),
- {ok, Pid}.
-
-%%
-%% release_collector(Collector, NewOwner)
-%%
-release_collector(Collector, NewOwner) ->
- Collector ! {release, self(), NewOwner},
- receive
- %% Reap collector
- {'EXIT', Collector, normal} ->
- ok
- end.
-
-%%
-%% collector_init(Broker) -> void()
-%%
-collector_init(Broker) ->
- receive
- {release, Broker, NewOwner} ->
- transfer_messages(Broker, NewOwner)
- end.
-
-%%
-%% transfer_messages(Pid, NewOwner) -> void()
-%%
-transfer_messages(Pid, NewOwner) ->
- receive
- {ssl, Sock, Data} ->
- NewOwner ! {ssl, Sock, Data},
- transfer_messages(Pid, NewOwner);
- {ssl_closed, Sock} ->
- NewOwner ! {ssl_closed, Sock},
- transfer_messages(Pid, NewOwner);
- {ssl_error, Sock, Reason} ->
- NewOwner ! {ssl_error, Sock, Reason},
- transfer_messages(Pid, NewOwner)
- after 0 ->
- ok
- end.
-
-%%
-%% debug(St, Format, Args) -> void() - printouts
-%%
-debug(St, Format, Args) ->
- debug1(St#st.debug, St#st.brokertype, Format, Args).
-
-debug1(true, Type, Format0, Args) ->
- {_MS, S, MiS} = erlang:now(),
- Secs = S rem 100,
- MiSecs = MiS div 1000,
- Format = "++++ ~3..0w:~3..0w ssl_broker (~w)[~w]: " ++ Format0,
- io:format(Format, [Secs, MiSecs, self(), Type| Args]);
-debug1(_, _, _, _) ->
- ok.
-
-%%
-%% what(Reason) -> What
-%%
-what(Reason) when is_atom(Reason) ->
- Reason;
-what({'EXIT', Reason}) ->
- what(Reason);
-what({What, _Where}) when is_atom(What) ->
- What;
-what(Reason) ->
- Reason.
-
-
-%%
-%% OPTIONS
-%%
-%% Note that `accept' has no options when invoked, but get all its options
-%% by inheritance from `listen'.
-%%
-
-are_opt_tags(listener, OptTags) ->
- is_subset(OptTags, listen_opt_tags());
-are_opt_tags(acceptor, OptTags) ->
- is_subset(OptTags, accept_opt_tags());
-are_opt_tags(connector, OptTags) ->
- is_subset(OptTags, connect_opt_tags()).
-
-listen_opt_tags() ->
- tcp_listen_opt_tags() ++ ssl_opt_tags().
-
-accept_opt_tags() ->
- tcp_gen_opt_tags().
-
-connect_opt_tags() ->
- tcp_gen_opt_tags() ++ ssl_opt_tags().
-
-tcp_listen_opt_tags() ->
- tcp_gen_opt_tags() ++ tcp_listen_only_opt_tags().
-
-tcp_gen_opt_tags() ->
- %% All except `reuseaddr' and `deliver'.
- [nodelay, active, packet, mode, header].
-
-tcp_listen_only_opt_tags() ->
- [ip, backlog].
-
-ssl_opt_tags() ->
- %% XXX Should remove cachetimeout.
- [verify, depth, certfile, password, cacertfile, ciphers, cachetimeout].
-
-%% Options
-
-%%
-%% are_*_opts(Opts) -> boolean()
-%%
-are_connect_opts(Opts) ->
- are_opts(fun is_connect_opt/1, Opts).
-
-are_listen_opts(Opts) ->
- are_opts(fun is_listen_opt/1, Opts).
-
-are_opts(F, Opts) ->
- lists:all(F, transform_opts(Opts)).
-
-%%
-%% get_*_opts(Opts) -> Value
-%%
-get_tcp_accept_opts(Opts) ->
- [O || O <- transform_opts(Opts), is_tcp_accept_opt(O)].
-
-get_tcp_connect_opts(Opts) ->
- [O || O <- transform_opts(Opts), is_tcp_connect_opt(O)].
-
-get_tcp_listen_opts(Opts) ->
- [O || O <- transform_opts(Opts), is_tcp_listen_opt(O)].
-
-get_ssl_opts(Opts) ->
- [O || O <- transform_opts(Opts), is_ssl_opt(O)].
-
-get_active(Opts) ->
- get_tagged_opt(active, Opts, true).
-
-get_backlog(Opts) ->
- get_tagged_opt(backlog, Opts, ?DEF_BACKLOG).
-
-get_ip(Opts) ->
- get_tagged_opt(ip, Opts, {0, 0, 0, 0}).
-
-get_port(Opts) ->
- get_tagged_opt(port, Opts, 0).
-
-get_nodelay(Opts) ->
- get_tagged_opt(nodelay, Opts, empty).
-
-%%
-%% add_default_*_opts(Opts) -> NOpts
-%%
-
-add_default_tcp_accept_opts(Opts) ->
- add_default_opts(Opts, default_tcp_accept_opts()).
-
-add_default_tcp_connect_opts(Opts) ->
- add_default_opts(Opts, default_tcp_connect_opts()).
-
-add_default_tcp_listen_opts(Opts) ->
- add_default_opts(Opts, default_tcp_listen_opts()).
-
-add_default_ssl_opts(Opts) ->
- add_default_opts(Opts, default_ssl_opts()).
-
-add_default_opts(Opts, DefOpts) ->
- TOpts = transform_opts(Opts),
- TOpts ++ [DP || {DTag, _DVal} = DP <- DefOpts,
- not lists:keymember(DTag, 1, TOpts)].
-
-default_tcp_accept_opts() ->
- [O || O <- default_opts(), is_tcp_accept_opt(O)].
-
-default_tcp_connect_opts() ->
- [O || O <- default_opts(), is_tcp_connect_opt(O)].
-
-default_tcp_listen_opts() ->
- [O || O <- default_opts(), is_tcp_listen_opt(O)].
-
-default_ssl_opts() ->
- [O || O <- default_opts(), is_ssl_opt(O)].
-
-default_opts() ->
- [{mode, list}, {packet, 0}, {nodelay, false}, {active, true},
- {backlog, ?DEF_BACKLOG}, {ip, {0, 0, 0, 0}},
- {verify, 0}, {depth, 1}].
-
-
-%% Transform from old to new options, and also from old gen_tcp
-%% options to new ones. All returned options are tagged options.
-%%
-transform_opts(Opts) ->
- lists:flatmap(fun transform_opt/1, Opts).
-
-transform_opt(binary) -> [{mode, binary}];
-transform_opt(list) -> [{mode, list}];
-transform_opt({packet, raw}) -> [{packet, 0}];
-transform_opt(raw) -> [];
-transform_opt(Opt) -> [Opt].
-
-%% NOTE: The is_*_opt/1 functions must be applied on transformed options
-%% only.
-
-is_connect_opt(Opt) ->
- is_tcp_connect_opt(Opt) or is_ssl_opt(Opt).
-
-is_listen_opt(Opt) ->
- is_tcp_listen_opt(Opt) or is_ssl_opt(Opt).
-
-is_tcp_accept_opt(Opt) ->
- is_tcp_gen_opt(Opt).
-
-is_tcp_connect_opt(Opt) ->
- is_tcp_gen_opt(Opt) or is_tcp_connect_only_opt(Opt).
-
-is_tcp_listen_opt(Opt) ->
- is_tcp_gen_opt(Opt) or is_tcp_listen_only_opt(Opt).
-
-%% General options supported by gen_tcp: All except `reuseaddr' and
-%% `deliver'.
-is_tcp_gen_opt({mode, list}) -> true;
-is_tcp_gen_opt({mode, binary}) -> true;
-is_tcp_gen_opt({header, Sz}) when is_integer(Sz), 0 =< Sz -> true;
-is_tcp_gen_opt({packet, Sz}) when is_integer(Sz), 0 =< Sz, Sz =< 4-> true;
-is_tcp_gen_opt({packet, sunrm}) -> true;
-is_tcp_gen_opt({packet, asn1}) -> true;
-is_tcp_gen_opt({packet, cdr}) -> true;
-is_tcp_gen_opt({packet, fcgi}) -> true;
-is_tcp_gen_opt({packet, line}) -> true;
-is_tcp_gen_opt({packet, tpkt}) -> true;
-is_tcp_gen_opt({packet, http}) -> true;
-is_tcp_gen_opt({packet, httph}) -> true;
-is_tcp_gen_opt({nodelay, true}) -> true;
-is_tcp_gen_opt({nodelay, false}) -> true;
-is_tcp_gen_opt({active, true}) -> true;
-is_tcp_gen_opt({active, false}) -> true;
-is_tcp_gen_opt({active, once}) -> true;
-is_tcp_gen_opt({keepalive, true}) -> true;
-is_tcp_gen_opt({keepalive, false}) -> true;
-is_tcp_gen_opt({ip, Addr}) -> is_ip_address(Addr);
-is_tcp_gen_opt(_Opt) -> false.
-
-is_tcp_listen_only_opt({backlog, Size}) when is_integer(Size), 0 =< Size ->
- true;
-is_tcp_listen_only_opt({reuseaddr, Bool}) when is_boolean(Bool) ->
- true;
-is_tcp_listen_only_opt(_Opt) -> false.
-
-is_tcp_connect_only_opt({port, Port}) when is_integer(Port), 0 =< Port -> true;
-is_tcp_connect_only_opt(_Opt) -> false.
-
-%% SSL options
-
-is_ssl_opt({verify, Code}) when 0 =< Code, Code =< 2 -> true;
-is_ssl_opt({depth, Depth}) when 0 =< Depth -> true;
-is_ssl_opt({certfile, String}) -> is_string(String);
-is_ssl_opt({keyfile, String}) -> is_string(String);
-is_ssl_opt({password, String}) -> is_string(String);
-is_ssl_opt({cacertfile, String}) -> is_string(String);
-is_ssl_opt({ciphers, String}) -> is_string(String);
-is_ssl_opt({cachetimeout, Timeout}) when Timeout >= 0 -> true;
-is_ssl_opt(_Opt) -> false.
-
-%% Various types
-is_string(String) when is_list(String) ->
- lists:all(fun (C) when is_integer(C), 0 =< C, C =< 255 -> true;
- (_C) -> false end,
- String);
-is_string(_) ->
- false.
-
-is_ip_address(Addr) when tuple_size(Addr) =:= 4 ->
- is_string(tuple_to_list(Addr));
-is_ip_address(Addr) when is_list(Addr) ->
- is_string(Addr);
-is_ip_address(_) ->
- false.
-
-get_tagged_opt(Tag, Opts, Default) ->
- case lists:keysearch(Tag, 1, Opts) of
- {value, {_, Value}} ->
- Value;
- _Other ->
- Default
- end.
-
-%%
-%% mk_ssl_optstr(Opts) -> string()
-%%
-%% Makes a "command line" string of SSL options
-%%
-mk_ssl_optstr(Opts) ->
- lists:flatten([mk_one_ssl_optstr(O) || O <- Opts]).
-
-mk_one_ssl_optstr({verify, Code}) ->
- [" -verify ", integer_to_list(Code)];
-mk_one_ssl_optstr({depth, Depth}) ->
- [" -depth ", integer_to_list(Depth)];
-mk_one_ssl_optstr({certfile, String}) ->
- [" -certfile ", String];
-mk_one_ssl_optstr({keyfile, String}) ->
- [" -keyfile ", String];
-mk_one_ssl_optstr({password, String}) ->
- [" -password ", String];
-mk_one_ssl_optstr({cacertfile, String}) ->
- [" -cacertfile ", String];
-mk_one_ssl_optstr({ciphers, String}) ->
- [" -ciphers ", String];
-mk_one_ssl_optstr({cachetimeout, Timeout}) ->
- [" -cachetimeout ", integer_to_list(Timeout)];
-mk_one_ssl_optstr(_) ->
- "".
-
-extract_opts(OptTags, Opts) ->
- [O || O = {Tag,_} <- Opts, lists:member(Tag, OptTags)].
-
-replace_opts(NOpts, Opts) ->
- lists:foldl(fun({Key, Val}, Acc) ->
- lists:keyreplace(Key, 1, Acc, {Key, Val});
- %% XXX Check. Patch from Chandrashekhar Mullaparthi.
- (binary, Acc) ->
- lists:keyreplace(mode, 1, Acc, {mode, binary})
- end,
- Opts, NOpts).
-
-%% Misc
-
-is_subset(A, B) ->
- [] =:= A -- B.
diff --git a/lib/ssl/src/ssl_broker_int.hrl b/lib/ssl/src/ssl_broker_int.hrl
deleted file mode 100644
index b791485725..0000000000
--- a/lib/ssl/src/ssl_broker_int.hrl
+++ /dev/null
@@ -1,38 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2000-2009. All Rights Reserved.
-%%
-%% The contents of this file are subject to the Erlang Public License,
-%% Version 1.1, (the "License"); you may not use this file except in
-%% compliance with the License. You should have received a copy of the
-%% Erlang Public License along with this software. If not, it can be
-%% retrieved online at http://www.erlang.org/.
-%%
-%% Software distributed under the License is distributed on an "AS IS"
-%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
-%% the License for the specific language governing rights and limitations
-%% under the License.
-%%
-%% %CopyrightEnd%
-%%
-
-%%
-
-%% Purpose: record definitions shared between ssl_prim.erl and ssl_broker.erl
-
--record(st, {brokertype = nil, % connector | listener | acceptor
- server = nil, % pid of ssl_server
- client = nil, % client pid
- collector = nil, % client pid, or collector during change of
- % controlling process
- fd = nil, % fd of "external" socket in port program
- active = true, % true | false | once
- opts = [], % options
- thissock = nil, % this sslsocket
- proxysock = nil, % local proxy socket within Erlang
- proxyport = nil, % local port for proxy within Erlang
- status = nil, % open | closing | closed
- encrypted = false, %
- debug = false %
- }).
diff --git a/lib/ssl/src/ssl_broker_sup.erl b/lib/ssl/src/ssl_broker_sup.erl
deleted file mode 100644
index 6d56a5fcf6..0000000000
--- a/lib/ssl/src/ssl_broker_sup.erl
+++ /dev/null
@@ -1,46 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1999-2009. All Rights Reserved.
-%%
-%% The contents of this file are subject to the Erlang Public License,
-%% Version 1.1, (the "License"); you may not use this file except in
-%% compliance with the License. You should have received a copy of the
-%% Erlang Public License along with this software. If not, it can be
-%% retrieved online at http://www.erlang.org/.
-%%
-%% Software distributed under the License is distributed on an "AS IS"
-%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
-%% the License for the specific language governing rights and limitations
-%% under the License.
-%%
-%% %CopyrightEnd%
-%%
-
-%%
-
-%%% Purpose : Supervisor for brokers
-
--module(ssl_broker_sup).
-
--behaviour(supervisor).
-
--export([start_link/0]).
-
-%% supervisor callbacks
--export([init/1]).
-
-start_link() ->
- supervisor:start_link({local, ssl_broker_sup}, ssl_broker_sup,
- []).
-
-init([]) ->
- {ok, {{simple_one_for_one, 10, 3600},
- [{ssl_broker,
- {ssl_broker, start_link, []},
- temporary,
- 100,
- worker,
- [ssl_broker]}
- ]}}.
-
diff --git a/lib/ssl/src/ssl_certificate.erl b/lib/ssl/src/ssl_certificate.erl
index 422ea6404b..61876e1158 100644
--- a/lib/ssl/src/ssl_certificate.erl
+++ b/lib/ssl/src/ssl_certificate.erl
@@ -66,7 +66,7 @@ trusted_cert_and_path(CertChain, CertDbHandle, CertDbRef) ->
{ok, IssuerId} ->
{other, IssuerId};
{error, issuer_not_found} ->
- case find_issuer(OtpCert, no_candidate, CertDbHandle) of
+ case find_issuer(OtpCert, CertDbHandle) of
{ok, IssuerId} ->
{other, IssuerId};
Other ->
@@ -193,7 +193,7 @@ certificate_chain(OtpCert, _Cert, CertDbHandle, CertsDbRef, Chain) ->
{_, true = SelfSigned} ->
certificate_chain(CertDbHandle, CertsDbRef, Chain, ignore, ignore, SelfSigned);
{{error, issuer_not_found}, SelfSigned} ->
- case find_issuer(OtpCert, no_candidate, CertDbHandle) of
+ case find_issuer(OtpCert, CertDbHandle) of
{ok, {SerialNr, Issuer}} ->
certificate_chain(CertDbHandle, CertsDbRef, Chain,
SerialNr, Issuer, SelfSigned);
@@ -227,17 +227,24 @@ certificate_chain(CertDbHandle, CertsDbRef, Chain, SerialNr, Issuer, _SelfSigned
{ok, lists:reverse(Chain)}
end.
-find_issuer(OtpCert, PrevCandidateKey, CertDbHandle) ->
- case ssl_manager:issuer_candidate(PrevCandidateKey, CertDbHandle) of
- no_more_candidates ->
- {error, issuer_not_found};
- {Key, {_Cert, ErlCertCandidate}} ->
- case public_key:pkix_is_issuer(OtpCert, ErlCertCandidate) of
- true ->
- public_key:pkix_issuer_id(ErlCertCandidate, self);
- false ->
- find_issuer(OtpCert, Key, CertDbHandle)
- end
+find_issuer(OtpCert, CertDbHandle) ->
+ IsIssuerFun = fun({_Key, {_Der, #'OTPCertificate'{} = ErlCertCandidate}}, Acc) ->
+ case public_key:pkix_is_issuer(OtpCert, ErlCertCandidate) of
+ true ->
+ throw(public_key:pkix_issuer_id(ErlCertCandidate, self));
+ false ->
+ Acc
+ end;
+ (_, Acc) ->
+ Acc
+ end,
+
+ try ssl_certificate_db:foldl(IsIssuerFun, issuer_not_found, CertDbHandle) of
+ issuer_not_found ->
+ {error, issuer_not_found}
+ catch
+ {ok, _IssuerId} = Return ->
+ Return
end.
is_valid_extkey_usage(KeyUse, client) ->
diff --git a/lib/ssl/src/ssl_certificate_db.erl b/lib/ssl/src/ssl_certificate_db.erl
index 0560a02110..cb2473576a 100644
--- a/lib/ssl/src/ssl_certificate_db.erl
+++ b/lib/ssl/src/ssl_certificate_db.erl
@@ -26,7 +26,7 @@
-include_lib("public_key/include/public_key.hrl").
-export([create/0, remove/1, add_trusted_certs/3,
- remove_trusted_certs/2, lookup_trusted_cert/4, issuer_candidate/2,
+ remove_trusted_certs/2, lookup_trusted_cert/4, foldl/3,
lookup_cached_certs/2, cache_pem_file/4, uncache_pem_file/2, lookup/2]).
-type time() :: {non_neg_integer(), non_neg_integer(), non_neg_integer()}.
@@ -127,8 +127,6 @@ uncache_pem_file(File, [_CertsDb, _FileToRefDb, PidToFileDb]) ->
exit(Pid, shutdown)
end, Pids).
-
-
%%--------------------------------------------------------------------
-spec remove_trusted_certs(pid(), [db_handle()]) -> term().
@@ -161,37 +159,6 @@ remove_trusted_certs(Pid, [CertsDb, FileToRefDb, PidToFileDb]) ->
end.
%%--------------------------------------------------------------------
--spec issuer_candidate(no_candidate | cert_key() | {file, term()}, term()) ->
- {cert_key(),{der_cert(), #'OTPCertificate'{}}} | no_more_candidates.
-%%
-%% Description: If a certificat does not define its issuer through
-%% the extension 'ce-authorityKeyIdentifier' we can
-%% try to find the issuer in the database over known
-%% certificates.
-%%--------------------------------------------------------------------
-issuer_candidate(no_candidate, Db) ->
- case ets:first(Db) of
- '$end_of_table' ->
- no_more_candidates;
- {file, _} = Key ->
- issuer_candidate(Key, Db);
- Key ->
- [Cert] = lookup(Key, Db),
- {Key, Cert}
- end;
-
-issuer_candidate(PrevCandidateKey, Db) ->
- case ets:next(Db, PrevCandidateKey) of
- '$end_of_table' ->
- no_more_candidates;
- {file, _} = Key ->
- issuer_candidate(Key, Db);
- Key ->
- [Cert] = lookup(Key, Db),
- {Key, Cert}
- end.
-
-%%--------------------------------------------------------------------
-spec lookup(term(), db_handle()) -> term() | undefined.
%%
%% Description: Looks up an element in a certificat <Db>.
@@ -206,7 +173,18 @@ lookup(Key, Db) ->
end,
[Pick(Data) || Data <- Contents]
end.
-
+%%--------------------------------------------------------------------
+-spec foldl(fun(), term(), db_handle()) -> term().
+%%
+%% Description: Calls Fun(Elem, AccIn) on successive elements of the
+%% cache, starting with AccIn == Acc0. Fun/2 must return a new
+%% accumulator which is passed to the next call. The function returns
+%% the final value of the accumulator. Acc0 is returned if the certifate
+%% db is empty.
+%%--------------------------------------------------------------------
+foldl(Fun, Acc0, Cache) ->
+ ets:foldl(Fun, Acc0, Cache).
+
%%--------------------------------------------------------------------
%%% Internal functions
%%--------------------------------------------------------------------
diff --git a/lib/ssl/src/ssl_cipher.erl b/lib/ssl/src/ssl_cipher.erl
index 72f02a4362..95a5efd6d0 100644
--- a/lib/ssl/src/ssl_cipher.erl
+++ b/lib/ssl/src/ssl_cipher.erl
@@ -154,18 +154,23 @@ decipher(?AES, HashSz, CipherState, Fragment, Version) ->
block_decipher(Fun, #cipher_state{key=Key, iv=IV} = CipherState0,
HashSz, Fragment, Version) ->
- try Fun(Key, IV, Fragment) of
- Text ->
- GBC = generic_block_cipher_from_bin(Text, HashSz),
- case is_correct_padding(GBC, Version) of
- true ->
- Content = GBC#generic_block_cipher.content,
- Mac = GBC#generic_block_cipher.mac,
- CipherState1 = CipherState0#cipher_state{iv=next_iv(Fragment, IV)},
- {Content, Mac, CipherState1};
- false ->
- ?ALERT_REC(?FATAL, ?BAD_RECORD_MAC)
- end
+ try
+ Text = Fun(Key, IV, Fragment),
+ GBC = generic_block_cipher_from_bin(Text, HashSz),
+ Content = GBC#generic_block_cipher.content,
+ Mac = GBC#generic_block_cipher.mac,
+ CipherState1 = CipherState0#cipher_state{iv=next_iv(Fragment, IV)},
+ case is_correct_padding(GBC, Version) of
+ true ->
+ {Content, Mac, CipherState1};
+ false ->
+ %% decryption failed or invalid padding,
+ %% intentionally break Content to make
+ %% sure a packet with a an invalid padding
+ %% but otherwise correct data will fail
+ %% the MAC test later
+ {<<16#F0, Content/binary>>, Mac, CipherState1}
+ end
catch
_:_ ->
%% This is a DECRYPTION_FAILED but
@@ -500,14 +505,38 @@ hash_size(md5) ->
hash_size(sha) ->
20.
+%% RFC 5246: 6.2.3.2. CBC Block Cipher
+%%
+%% Implementation note: Canvel et al. [CBCTIME] have demonstrated a
+%% timing attack on CBC padding based on the time required to compute
+%% the MAC. In order to defend against this attack, implementations
+%% MUST ensure that record processing time is essentially the same
+%% whether or not the padding is correct. In general, the best way to
+%% do this is to compute the MAC even if the padding is incorrect, and
+%% only then reject the packet. For instance, if the pad appears to be
+%% incorrect, the implementation might assume a zero-length pad and then
+%% compute the MAC. This leaves a small timing channel, since MAC
+%% performance depends to some extent on the size of the data fragment,
+%% but it is not believed to be large enough to be exploitable, due to
+%% the large block size of existing MACs and the small size of the
+%% timing signal.
+%%
+%% implementation note:
+%% We return the original (possibly invalid) PadLength in any case.
+%% A invalid PadLength will be cought by is_correct_padding/2
+%%
generic_block_cipher_from_bin(T, HashSize) ->
Sz1 = byte_size(T) - 1,
- <<_:Sz1/binary, ?BYTE(PadLength)>> = T,
+ <<_:Sz1/binary, ?BYTE(PadLength0)>> = T,
+ PadLength = if
+ PadLength0 >= Sz1 -> 0;
+ true -> PadLength0
+ end,
CompressedLength = byte_size(T) - PadLength - 1 - HashSize,
<<Content:CompressedLength/binary, Mac:HashSize/binary,
- Padding:PadLength/binary, ?BYTE(PadLength)>> = T,
+ Padding:PadLength/binary, ?BYTE(PadLength0)>> = T,
#generic_block_cipher{content=Content, mac=Mac,
- padding=Padding, padding_length=PadLength}.
+ padding=Padding, padding_length=PadLength0}.
generic_stream_cipher_from_bin(T, HashSz) ->
Sz = byte_size(T),
@@ -516,17 +545,18 @@ generic_stream_cipher_from_bin(T, HashSz) ->
#generic_stream_cipher{content=Content,
mac=Mac}.
-is_correct_padding(_, {3, 0}) ->
- true;
-%% For interoperability reasons we do not check the padding in TLS 1.0 as it
-%% is not strictly required and breaks interopability with for instance
-%% Google.
-is_correct_padding(_, {3, 1}) ->
- true;
+%% For interoperability reasons we do not check the padding content in
+%% SSL 3.0 and TLS 1.0 as it is not strictly required and breaks
+%% interopability with for instance Google.
+is_correct_padding(#generic_block_cipher{padding_length = Len,
+ padding = Padding}, {3, N})
+ when N == 0; N == 1 ->
+ Len == byte_size(Padding);
%% Padding must be check in TLS 1.1 and after
-is_correct_padding(#generic_block_cipher{padding_length = Len, padding = Padding}, _) ->
- list_to_binary(lists:duplicate(Len, Len)) == Padding.
-
+is_correct_padding(#generic_block_cipher{padding_length = Len,
+ padding = Padding}, _) ->
+ Len == byte_size(Padding) andalso
+ list_to_binary(lists:duplicate(Len, Len)) == Padding.
get_padding(Length, BlockSize) ->
get_padding_aux(BlockSize, Length rem BlockSize).
diff --git a/lib/ssl/src/ssl_connection.erl b/lib/ssl/src/ssl_connection.erl
index cec81d551b..d4807704b2 100644
--- a/lib/ssl/src/ssl_connection.erl
+++ b/lib/ssl/src/ssl_connection.erl
@@ -34,7 +34,6 @@
-include("ssl_record.hrl").
-include("ssl_cipher.hrl").
-include("ssl_internal.hrl").
--include("ssl_int.hrl").
-include_lib("public_key/include/public_key.hrl").
%% Internal application API
@@ -88,15 +87,17 @@
bytes_to_read, % integer(), # bytes to read in passive mode
user_data_buffer, % binary()
log_alert, % boolean()
- renegotiation, % {boolean(), From | internal | peer}
- recv_during_renegotiation, %boolean()
- send_queue, % queue()
- terminated = false %
+ renegotiation, % {boolean(), From | internal | peer}
+ recv_from, %
+ send_queue, % queue()
+ terminated = false, %
+ allow_renegotiate = true
}).
-define(DEFAULT_DIFFIE_HELLMAN_PARAMS,
- #'DHParameter'{prime = ?DEFAULT_DIFFIE_HELLMAN_PRIME,
+ #'DHParameter'{prime = ?DEFAULT_DIFFIE_HELLMAN_PRIME,
base = ?DEFAULT_DIFFIE_HELLMAN_GENERATOR}).
+-define(WAIT_TO_ALLOW_RENEGOTIATION, 12000).
-type state_name() :: hello | abbreviated | certify | cipher | connection.
-type gen_fsm_state_return() :: {next_state, state_name(), #state{}} |
@@ -304,12 +305,13 @@ init([Role, Host, Port, Socket, {SSLOpts0, _} = Options,
User, CbInfo]) ->
State0 = initial_state(Role, Host, Port, Socket, Options, User, CbInfo),
Hashes0 = ssl_handshake:init_hashes(),
-
+ TimeStamp = calendar:datetime_to_gregorian_seconds({date(), time()}),
try ssl_init(SSLOpts0, Role) of
{ok, Ref, CertDbHandle, CacheHandle, OwnCert, Key, DHParams} ->
Session = State0#state.session,
State = State0#state{tls_handshake_hashes = Hashes0,
- session = Session#session{own_certificate = OwnCert},
+ session = Session#session{own_certificate = OwnCert,
+ time_stamp = TimeStamp},
cert_db_ref = Ref,
cert_db = CertDbHandle,
session_cache = CacheHandle,
@@ -352,19 +354,18 @@ hello(start, #state{host = Host, port = Port, role = client,
State1 = State0#state{connection_states = CS2,
negotiated_version = Version, %% Requested version
session =
- Session0#session{session_id = Hello#client_hello.session_id,
- is_resumable = false},
+ Session0#session{session_id = Hello#client_hello.session_id},
tls_handshake_hashes = Hashes1},
{Record, State} = next_record(State1),
- next_state(hello, Record, State);
+ next_state(hello, hello, Record, State);
hello(start, #state{role = server} = State0) ->
{Record, State} = next_record(State0),
- next_state(hello, Record, State);
+ next_state(hello, hello, Record, State);
hello(#hello_request{}, #state{role = client} = State0) ->
{Record, State} = next_record(State0),
- next_state(hello, Record, State);
+ next_state(hello, hello, Record, State);
hello(#server_hello{cipher_suite = CipherSuite,
compression_method = Compression} = Hello,
@@ -427,7 +428,7 @@ hello(Msg, State) ->
%%--------------------------------------------------------------------
abbreviated(#hello_request{}, State0) ->
{Record, State} = next_record(State0),
- next_state(hello, Record, State);
+ next_state(abbreviated, hello, Record, State);
abbreviated(#finished{verify_data = Data} = Finished,
#state{role = server,
@@ -480,7 +481,7 @@ abbreviated(Msg, State) ->
%%--------------------------------------------------------------------
certify(#hello_request{}, State0) ->
{Record, State} = next_record(State0),
- next_state(hello, Record, State);
+ next_state(certify, hello, Record, State);
certify(#certificate{asn1_certificates = []},
#state{role = server, negotiated_version = Version,
@@ -488,7 +489,7 @@ certify(#certificate{asn1_certificates = []},
fail_if_no_peer_cert = true}} =
State) ->
Alert = ?ALERT_REC(?FATAL,?HANDSHAKE_FAILURE),
- handle_own_alert(Alert, Version, certify_certificate, State),
+ handle_own_alert(Alert, Version, certify, State),
{stop, normal, State};
certify(#certificate{asn1_certificates = []},
@@ -497,7 +498,7 @@ certify(#certificate{asn1_certificates = []},
fail_if_no_peer_cert = false}} =
State0) ->
{Record, State} = next_record(State0#state{client_certificate_requested = false}),
- next_state(certify, Record, State);
+ next_state(certify, certify, Record, State);
certify(#certificate{} = Cert,
#state{negotiated_version = Version,
@@ -512,7 +513,7 @@ certify(#certificate{} = Cert,
handle_peer_cert(PeerCert, PublicKeyInfo,
State#state{client_certificate_requested = false});
#alert{} = Alert ->
- handle_own_alert(Alert, Version, certify_certificate, State),
+ handle_own_alert(Alert, Version, certify, State),
{stop, normal, State}
end;
@@ -523,10 +524,9 @@ certify(#server_key_exchange{} = KeyExchangeMsg,
case handle_server_key(KeyExchangeMsg, State0) of
#state{} = State1 ->
{Record, State} = next_record(State1),
- next_state(certify, Record, State);
+ next_state(certify, certify, Record, State);
#alert{} = Alert ->
- handle_own_alert(Alert, Version, certify_server_keyexchange,
- State0),
+ handle_own_alert(Alert, Version, certify, State0),
{stop, normal, State0}
end;
@@ -536,7 +536,7 @@ certify(#server_key_exchange{} = Msg,
certify(#certificate_request{}, State0) ->
{Record, State} = next_record(State0#state{client_certificate_requested = true}),
- next_state(certify, Record, State);
+ next_state(certify, certify, Record, State);
%% Master secret was determined with help of server-key exchange msg
certify(#server_hello_done{},
@@ -551,8 +551,7 @@ certify(#server_hello_done{},
State = State0#state{connection_states = ConnectionStates1},
client_certify_and_key_exchange(State);
#alert{} = Alert ->
- handle_own_alert(Alert, Version,
- certify_server_hello_done, State0),
+ handle_own_alert(Alert, Version, certify, State0),
{stop, normal, State0}
end;
@@ -571,8 +570,7 @@ certify(#server_hello_done{},
session = Session},
client_certify_and_key_exchange(State);
#alert{} = Alert ->
- handle_own_alert(Alert, Version,
- certify_server_hello_done, State0),
+ handle_own_alert(Alert, Version, certify, State0),
{stop, normal, State0}
end;
@@ -589,7 +587,7 @@ certify(#client_key_exchange{exchange_keys = Keys},
certify_client_key_exchange(ssl_handshake:decode_client_key(Keys, KeyAlg, Version), State)
catch
#alert{} = Alert ->
- handle_own_alert(Alert, Version, certify_client_key_exchange, State),
+ handle_own_alert(Alert, Version, certify, State),
{stop, normal, State}
end;
@@ -612,10 +610,9 @@ certify_client_key_exchange(#encrypted_premaster_secret{premaster_secret= EncPMS
State1 = State0#state{connection_states = ConnectionStates,
session = Session},
{Record, State} = next_record(State1),
- next_state(cipher, Record, State);
+ next_state(certify, cipher, Record, State);
#alert{} = Alert ->
- handle_own_alert(Alert, Version,
- certify_client_key_exchange, State0),
+ handle_own_alert(Alert, Version, certify, State0),
{stop, normal, State0}
end;
@@ -627,10 +624,9 @@ certify_client_key_exchange(#client_diffie_hellman_public{dh_public = ClientPubl
case dh_master_secret(crypto:mpint(P), crypto:mpint(G), ClientPublicDhKey, ServerDhPrivateKey, State0) of
#state{} = State1 ->
{Record, State} = next_record(State1),
- next_state(cipher, Record, State);
+ next_state(certify, cipher, Record, State);
#alert{} = Alert ->
- handle_own_alert(Alert, Version,
- certify_client_key_exchange, State0),
+ handle_own_alert(Alert, Version, certify, State0),
{stop, normal, State0}
end.
@@ -640,7 +636,7 @@ certify_client_key_exchange(#client_diffie_hellman_public{dh_public = ClientPubl
%%--------------------------------------------------------------------
cipher(#hello_request{}, State0) ->
{Record, State} = next_record(State0),
- next_state(hello, Record, State);
+ next_state(cipher, hello, Record, State);
cipher(#certificate_verify{signature = Signature},
#state{role = server,
@@ -653,7 +649,7 @@ cipher(#certificate_verify{signature = Signature},
Version, MasterSecret, Hashes) of
valid ->
{Record, State} = next_record(State0),
- next_state(cipher, Record, State);
+ next_state(cipher, cipher, Record, State);
#alert{} = Alert ->
handle_own_alert(Alert, Version, cipher, State0),
{stop, normal, State0}
@@ -706,10 +702,26 @@ connection(#hello_request{}, #state{host = Host, port = Port,
{Record, State} = next_record(State0#state{connection_states =
ConnectionStates1,
tls_handshake_hashes = Hashes1}),
- next_state(hello, Record, State);
-connection(#client_hello{} = Hello, #state{role = server} = State) ->
- hello(Hello, State);
-
+ next_state(connection, hello, Record, State);
+connection(#client_hello{} = Hello, #state{role = server, allow_renegotiate = true} = State) ->
+ %% Mitigate Computational DoS attack
+ %% http://www.educatedguesswork.org/2011/10/ssltls_and_computational_dos.html
+ %% http://www.thc.org/thc-ssl-dos/ Rather than disabling client
+ %% initiated renegotiation we will disallow many client initiated
+ %% renegotiations immediately after each other.
+ erlang:send_after(?WAIT_TO_ALLOW_RENEGOTIATION, self(), allow_renegotiate),
+ hello(Hello, State#state{allow_renegotiate = false});
+
+connection(#client_hello{}, #state{role = server, allow_renegotiate = false,
+ connection_states = ConnectionStates0,
+ socket = Socket, transport_cb = Transport,
+ negotiated_version = Version} = State0) ->
+ Alert = ?ALERT_REC(?WARNING, ?NO_RENEGOTIATION),
+ {BinMsg, ConnectionStates} =
+ encode_alert(Alert, Version, ConnectionStates0),
+ Transport:send(Socket, BinMsg),
+ next_state_connection(connection, State0#state{connection_states = ConnectionStates});
+
connection(timeout, State) ->
{next_state, connection, State, hibernate};
@@ -738,37 +750,12 @@ handle_event(_Event, StateName, State) ->
%% gen_fsm:sync_send_all_state_event/2,3, this function is called to handle
%% the event.
%%--------------------------------------------------------------------
-handle_sync_event({application_data, Data0}, From, connection,
- #state{socket = Socket,
- negotiated_version = Version,
- transport_cb = Transport,
- connection_states = ConnectionStates0,
- send_queue = SendQueue,
- socket_options = SockOpts,
- ssl_options = #ssl_options{renegotiate_at = RenegotiateAt}}
- = State) ->
+handle_sync_event({application_data, Data}, From, connection, State) ->
%% We should look into having a worker process to do this to
%% parallize send and receive decoding and not block the receiver
%% if sending is overloading the socket.
try
- Data = encode_packet(Data0, SockOpts),
- case encode_data(Data, Version, ConnectionStates0, RenegotiateAt) of
- {Msgs, [], ConnectionStates} ->
- Result = Transport:send(Socket, Msgs),
- {reply, Result,
- connection, State#state{connection_states = ConnectionStates},
- get_timeout(State)};
- {Msgs, RestData, ConnectionStates} ->
- if
- Msgs =/= [] ->
- Transport:send(Socket, Msgs);
- true ->
- ok
- end,
- renegotiate(State#state{connection_states = ConnectionStates,
- send_queue = queue:in_r({From, RestData}, SendQueue),
- renegotiation = {true, internal}})
- end
+ write_application_data(Data, From, State)
catch throw:Error ->
{reply, Error, connection, State, get_timeout(State)}
end;
@@ -825,14 +812,12 @@ handle_sync_event({shutdown, How0}, _, StateName,
end;
handle_sync_event({recv, N}, From, connection = StateName, State0) ->
- passive_receive(State0#state{bytes_to_read = N, from = From}, StateName);
+ passive_receive(State0#state{bytes_to_read = N, recv_from = From}, StateName);
%% Doing renegotiate wait with handling request until renegotiate is
-%% finished. Will be handled by next_state_connection/2.
+%% finished. Will be handled by next_state_is_connection/2.
handle_sync_event({recv, N}, From, StateName, State) ->
- {next_state, StateName,
- State#state{bytes_to_read = N, from = From,
- recv_during_renegotiation = true},
+ {next_state, StateName, State#state{bytes_to_read = N, recv_from = From},
get_timeout(State)};
handle_sync_event({new_user, User}, _From, StateName,
@@ -870,7 +855,7 @@ handle_sync_event({set_opts, Opts0}, _From, StateName,
Buffer =:= <<>>, Opts1#socket_options.active =:= false ->
%% Need data, set active once
{Record, State2} = next_record_if_active(State1),
- case next_state(StateName, Record, State2) of
+ case next_state(StateName, StateName, Record, State2) of
{next_state, StateName, State, Timeout} ->
{reply, Reply, StateName, State, Timeout};
{stop, Reason, State} ->
@@ -880,11 +865,11 @@ handle_sync_event({set_opts, Opts0}, _From, StateName,
%% Active once already set
{reply, Reply, StateName, State1, get_timeout(State1)};
true ->
- case application_data(<<>>, State1) of
+ case read_application_data(<<>>, State1) of
Stop = {stop,_,_} ->
Stop;
{Record, State2} ->
- case next_state(StateName, Record, State2) of
+ case next_state(StateName, StateName, Record, State2) of
{next_state, StateName, State, Timeout} ->
{reply, Reply, StateName, State, Timeout};
{stop, Reason, State} ->
@@ -932,22 +917,18 @@ handle_sync_event(peer_certificate, _, StateName,
%% raw data from TCP, unpack records
handle_info({Protocol, _, Data}, StateName,
- #state{data_tag = Protocol,
- negotiated_version = Version} = State0) ->
+ #state{data_tag = Protocol} = State0) ->
case next_tls_record(Data, State0) of
{Record, State} ->
- next_state(StateName, Record, State);
+ next_state(StateName, StateName, Record, State);
#alert{} = Alert ->
- handle_own_alert(Alert, Version, StateName, State0),
+ handle_normal_shutdown(Alert, StateName, State0),
{stop, normal, State0}
end;
-handle_info({CloseTag, Socket}, _StateName,
+handle_info({CloseTag, Socket}, StateName,
#state{socket = Socket, close_tag = CloseTag,
- negotiated_version = Version,
- socket_options = Opts,
- user_application = {_Mon,Pid}, from = From,
- role = Role} = State) ->
+ negotiated_version = Version} = State) ->
%% Note that as of TLS 1.1,
%% failure to properly close a connection no longer requires that a
%% session not be resumed. This is a change from TLS 1.0 to conform
@@ -962,8 +943,7 @@ handle_info({CloseTag, Socket}, _StateName,
%%invalidate_session(Role, Host, Port, Session)
ok
end,
- alert_user(Opts#socket_options.active, Pid, From,
- ?ALERT_REC(?WARNING, ?CLOSE_NOTIFY), Role),
+ handle_normal_shutdown(?ALERT_REC(?FATAL, ?CLOSE_NOTIFY), StateName, State),
{stop, normal, State};
handle_info({ErrorTag, Socket, econnaborted}, StateName,
@@ -972,18 +952,20 @@ handle_info({ErrorTag, Socket, econnaborted}, StateName,
alert_user(User, ?ALERT_REC(?FATAL, ?HANDSHAKE_FAILURE), Role),
{stop, normal, State};
-handle_info({ErrorTag, Socket, Reason}, _,
- #state{socket = Socket, from = User,
- role = Role, error_tag = ErrorTag} = State) ->
+handle_info({ErrorTag, Socket, Reason}, StateName, #state{socket = Socket,
+ error_tag = ErrorTag} = State) ->
Report = io_lib:format("SSL: Socket error: ~p ~n", [Reason]),
error_logger:info_report(Report),
- alert_user(User, ?ALERT_REC(?FATAL, ?CLOSE_NOTIFY), Role),
+ handle_normal_shutdown(?ALERT_REC(?FATAL, ?CLOSE_NOTIFY), StateName, State),
{stop, normal, State};
handle_info({'DOWN', MonitorRef, _, _, _}, _,
State = #state{user_application={MonitorRef,_Pid}}) ->
{stop, normal, State};
+handle_info(allow_renegotiate, StateName, State) ->
+ {next_state, StateName, State#state{allow_renegotiate = true}, get_timeout(State)};
+
handle_info(Msg, StateName, State) ->
Report = io_lib:format("SSL: Got unexpected info: ~p ~n", [Msg]),
error_logger:info_report(Report),
@@ -1033,7 +1015,8 @@ code_change(_OldVsn, StateName, State, _Extra) ->
%%--------------------------------------------------------------------
%%% Internal functions
%%--------------------------------------------------------------------
-start_fsm(Role, Host, Port, Socket, Opts, User, {CbModule, _,_, _} = CbInfo,
+start_fsm(Role, Host, Port, Socket, {#ssl_options{erl_dist = false},_} = Opts,
+ User, {CbModule, _,_, _} = CbInfo,
Timeout) ->
try
{ok, Pid} = ssl_connection_sup:start_child([Role, Host, Port, Socket,
@@ -1044,9 +1027,26 @@ start_fsm(Role, Host, Port, Socket, Opts, User, {CbModule, _,_, _} = CbInfo,
catch
error:{badmatch, {error, _} = Error} ->
Error
+ end;
+
+start_fsm(Role, Host, Port, Socket, {#ssl_options{erl_dist = true},_} = Opts,
+ User, {CbModule, _,_, _} = CbInfo,
+ Timeout) ->
+ try
+ {ok, Pid} = ssl_connection_sup:start_child_dist([Role, Host, Port, Socket,
+ Opts, User, CbInfo]),
+ {ok, SslSocket} = socket_control(Socket, Pid, CbModule),
+ ok = handshake(SslSocket, Timeout),
+ {ok, SslSocket}
+ catch
+ error:{badmatch, {error, _} = Error} ->
+ Error
end.
ssl_init(SslOpts, Role) ->
+
+ init_manager_name(SslOpts#ssl_options.erl_dist),
+
{ok, CertDbRef, CertDbHandle, CacheHandle, OwnCert} = init_certificates(SslOpts, Role),
PrivateKey =
init_private_key(CertDbHandle, SslOpts#ssl_options.key, SslOpts#ssl_options.keyfile,
@@ -1054,6 +1054,10 @@ ssl_init(SslOpts, Role) ->
DHParams = init_diffie_hellman(CertDbHandle, SslOpts#ssl_options.dh, SslOpts#ssl_options.dhfile, Role),
{ok, CertDbRef, CertDbHandle, CacheHandle, OwnCert, PrivateKey, DHParams}.
+init_manager_name(false) ->
+ put(ssl_manager, ssl_manager);
+init_manager_name(true) ->
+ put(ssl_manager, ssl_manager_dist).
init_certificates(#ssl_options{cacerts = CaCerts,
cacertfile = CACertFile,
@@ -1105,18 +1109,38 @@ init_private_key(DbHandle, undefined, KeyFile, Password, _) ->
{ok, List} = ssl_manager:cache_pem_file(KeyFile, DbHandle),
[PemEntry] = [PemEntry || PemEntry = {PKey, _ , _} <- List,
PKey =:= 'RSAPrivateKey' orelse
- PKey =:= 'DSAPrivateKey'],
- public_key:pem_entry_decode(PemEntry, Password)
+ PKey =:= 'DSAPrivateKey' orelse
+ PKey =:= 'PrivateKeyInfo'
+ ],
+ private_key(public_key:pem_entry_decode(PemEntry, Password))
catch
Error:Reason ->
handle_file_error(?LINE, Error, Reason, KeyFile, ekeyfile,
erlang:get_stacktrace())
end;
+%% First two clauses are for backwards compatibility
init_private_key(_,{rsa, PrivateKey}, _, _,_) ->
- public_key:der_decode('RSAPrivateKey', PrivateKey);
+ init_private_key('RSAPrivateKey', PrivateKey);
init_private_key(_,{dsa, PrivateKey},_,_,_) ->
- public_key:der_decode('DSAPrivateKey', PrivateKey).
+ init_private_key('DSAPrivateKey', PrivateKey);
+init_private_key(_,{Asn1Type, PrivateKey},_,_,_) ->
+ private_key(init_private_key(Asn1Type, PrivateKey)).
+
+init_private_key(Asn1Type, PrivateKey) ->
+ public_key:der_decode(Asn1Type, PrivateKey).
+
+private_key(#'PrivateKeyInfo'{privateKeyAlgorithm =
+ #'PrivateKeyInfo_privateKeyAlgorithm'{algorithm = ?'rsaEncryption'},
+ privateKey = Key}) ->
+ public_key:der_decode('RSAPrivateKey', iolist_to_binary(Key));
+
+private_key(#'PrivateKeyInfo'{privateKeyAlgorithm =
+ #'PrivateKeyInfo_privateKeyAlgorithm'{algorithm = ?'id-dsa'},
+ privateKey = Key}) ->
+ public_key:der_decode('DSAPrivateKey', iolist_to_binary(Key));
+private_key(Key) ->
+ Key.
-spec(handle_file_error(_,_,_,_,_,_) -> no_return()).
handle_file_error(Line, Error, {badmatch, Reason}, File, Throw, Stack) ->
@@ -1177,7 +1201,7 @@ handle_peer_cert(PeerCert, PublicKeyInfo,
Session#session{peer_certificate = PeerCert},
public_key_info = PublicKeyInfo},
{Record, State} = next_record(State1),
- next_state(certify, Record, State).
+ next_state(certify, certify, Record, State).
certify_client(#state{client_certificate_requested = true, role = client,
connection_states = ConnectionStates0,
@@ -1219,8 +1243,7 @@ verify_client_cert(#state{client_certificate_requested = true, role = client,
ignore ->
State;
#alert{} = Alert ->
- handle_own_alert(Alert, Version, certify, State)
-
+ throw(Alert)
end;
verify_client_cert(#state{client_certificate_requested = false} = State) ->
State.
@@ -1252,7 +1275,7 @@ do_server_hello(Type, #state{negotiated_version = Version,
ConnectionStates,
tls_handshake_hashes = Hashes},
{Record, State} = next_record(State3),
- next_state(abbreviated, Record, State);
+ next_state(hello, abbreviated, Record, State);
#alert{} = Alert ->
handle_own_alert(Alert, Version, hello, State1),
{stop, normal, State1}
@@ -1272,7 +1295,7 @@ new_server_hello(#server_hello{cipher_suite = CipherSuite,
cipher_suite = CipherSuite,
compression_method = Compression},
{Record, State} = next_record(State2#state{session = Session}),
- next_state(certify, Record, State)
+ next_state(hello, certify, Record, State)
catch
#alert{} = Alert ->
handle_own_alert(Alert, Version, hello, State0),
@@ -1284,7 +1307,7 @@ handle_new_session(NewId, CipherSuite, Compression, #state{session = Session0} =
cipher_suite = CipherSuite,
compression_method = Compression},
{Record, State} = next_record(State0#state{session = Session}),
- next_state(certify, Record, State).
+ next_state(hello, certify, Record, State).
handle_resumed_session(SessId, #state{connection_states = ConnectionStates0,
negotiated_version = Version,
@@ -1299,7 +1322,7 @@ handle_resumed_session(SessId, #state{connection_states = ConnectionStates0,
next_record(State0#state{
connection_states = ConnectionStates1,
session = Session}),
- next_state(abbreviated, Record, State);
+ next_state(hello, abbreviated, Record, State);
#alert{} = Alert ->
handle_own_alert(Alert, Version, hello, State0),
{stop, normal, State0}
@@ -1316,10 +1339,10 @@ client_certify_and_key_exchange(#state{negotiated_version = Version} =
client_certificate_requested = false,
tls_handshake_hashes = Hashes},
{Record, State} = next_record(State2),
- next_state(cipher, Record, State)
+ next_state(certify, cipher, Record, State)
catch
- #alert{} = Alert ->
- handle_own_alert(Alert, Version, client_certify_and_key_exchange, State0),
+ throw:#alert{} = Alert ->
+ handle_own_alert(Alert, Version, certify, State0),
{stop, normal, State0}
end.
@@ -1630,15 +1653,12 @@ encode_packet(Data, #socket_options{packet=Packet}) ->
end.
encode_size_packet(Bin, Size, Max) ->
- Len = byte_size(Bin),
+ Len = erlang:byte_size(Bin),
case Len > Max of
true -> throw({error, {badarg, {packet_to_large, Len, Max}}});
false -> <<Len:Size, Bin/binary>>
end.
-encode_data(Data, Version, ConnectionStates, RenegotiateAt) ->
- ssl_record:encode_data(Data, Version, ConnectionStates, RenegotiateAt).
-
decode_alerts(Bin) ->
decode_alerts(Bin, []).
@@ -1652,20 +1672,20 @@ passive_receive(State0 = #state{user_data_buffer = Buffer}, StateName) ->
case Buffer of
<<>> ->
{Record, State} = next_record(State0),
- next_state(StateName, Record, State);
+ next_state(StateName, StateName, Record, State);
_ ->
- case application_data(<<>>, State0) of
+ case read_application_data(<<>>, State0) of
Stop = {stop, _, _} ->
Stop;
{Record, State} ->
- next_state(StateName, Record, State)
+ next_state(StateName, StateName, Record, State)
end
end.
-application_data(Data, #state{user_application = {_Mon, Pid},
+read_application_data(Data, #state{user_application = {_Mon, Pid},
socket_options = SOpts,
bytes_to_read = BytesToRead,
- from = From,
+ recv_from = From,
user_data_buffer = Buffer0} = State0) ->
Buffer1 = if
Buffer0 =:= <<>> -> Data;
@@ -1676,7 +1696,7 @@ application_data(Data, #state{user_application = {_Mon, Pid},
{ok, ClientData, Buffer} -> % Send data
SocketOpt = deliver_app_data(SOpts, ClientData, Pid, From),
State = State0#state{user_data_buffer = Buffer,
- from = undefined,
+ recv_from = undefined,
bytes_to_read = 0,
socket_options = SocketOpt
},
@@ -1686,7 +1706,7 @@ application_data(Data, #state{user_application = {_Mon, Pid},
%% Active and empty, get more data
next_record_if_active(State);
true -> %% We have more data
- application_data(<<>>, State)
+ read_application_data(<<>>, State)
end;
{more, Buffer} -> % no reply, we need more data
next_record(State0#state{user_data_buffer = Buffer});
@@ -1695,6 +1715,39 @@ application_data(Data, #state{user_application = {_Mon, Pid},
{stop, normal, State0}
end.
+write_application_data(Data0, From, #state{socket = Socket,
+ negotiated_version = Version,
+ transport_cb = Transport,
+ connection_states = ConnectionStates0,
+ send_queue = SendQueue,
+ socket_options = SockOpts,
+ ssl_options = #ssl_options{renegotiate_at = RenegotiateAt}} = State) ->
+ Data = encode_packet(Data0, SockOpts),
+
+ case time_to_renegotiate(Data, ConnectionStates0, RenegotiateAt) of
+ true ->
+ renegotiate(State#state{send_queue = queue:in_r({From, Data}, SendQueue),
+ renegotiation = {true, internal}});
+ false ->
+ {Msgs, ConnectionStates} = ssl_record:encode_data(Data, Version, ConnectionStates0),
+ Result = Transport:send(Socket, Msgs),
+ {reply, Result,
+ connection, State#state{connection_states = ConnectionStates}, get_timeout(State)}
+ end.
+
+time_to_renegotiate(_Data, #connection_states{current_write =
+ #connection_state{sequence_number = Num}}, RenegotiateAt) ->
+
+ %% We could do test:
+ %% is_time_to_renegotiate((erlang:byte_size(_Data) div ?MAX_PLAIN_TEXT_LENGTH) + 1, RenegotiateAt),
+ %% but we chose to have a some what lower renegotiateAt and a much cheaper test
+ is_time_to_renegotiate(Num, RenegotiateAt).
+
+is_time_to_renegotiate(N, M) when N < M->
+ false;
+is_time_to_renegotiate(_,_) ->
+ true.
+
%% Picks ClientData
get_data(_, _, <<>>) ->
{more, <<>>};
@@ -1796,6 +1849,10 @@ header(N, Binary) ->
send_or_reply(false, _Pid, From, Data) when From =/= undefined ->
gen_fsm:reply(From, Data);
+%% Can happen when handling own alert or tcp error/close and there is
+%% no outstanding gen_fsm sync events
+send_or_reply(false, no_pid, _, _) ->
+ ok;
send_or_reply(_, Pid, _From, Data) ->
send_user(Pid, Data).
@@ -1820,18 +1877,18 @@ handle_tls_handshake(Handle, StateName, #state{tls_packets = [Packet | Packets]}
Stop
end.
-next_state(_, #alert{} = Alert, #state{negotiated_version = Version} = State) ->
- handle_own_alert(Alert, Version, decipher_error, State),
+next_state(Current,_, #alert{} = Alert, #state{negotiated_version = Version} = State) ->
+ handle_own_alert(Alert, Version, Current, State),
{stop, normal, State};
-next_state(Next, no_record, State) ->
+next_state(_,Next, no_record, State) ->
{next_state, Next, State, get_timeout(State)};
-next_state(Next, #ssl_tls{type = ?ALERT, fragment = EncAlerts}, State) ->
+next_state(_,Next, #ssl_tls{type = ?ALERT, fragment = EncAlerts}, State) ->
Alerts = decode_alerts(EncAlerts),
handle_alerts(Alerts, {next_state, Next, State, get_timeout(State)});
-next_state(StateName, #ssl_tls{type = ?HANDSHAKE, fragment = Data},
+next_state(Current, Next, #ssl_tls{type = ?HANDSHAKE, fragment = Data},
State0 = #state{tls_handshake_buffer = Buf0, negotiated_version = Version}) ->
Handle =
fun({#hello_request{} = Packet, _}, {next_state, connection = SName, State}) ->
@@ -1857,30 +1914,30 @@ next_state(StateName, #ssl_tls{type = ?HANDSHAKE, fragment = Data},
try
{Packets, Buf} = ssl_handshake:get_tls_handshake(Data,Buf0),
State = State0#state{tls_packets = Packets, tls_handshake_buffer = Buf},
- handle_tls_handshake(Handle, StateName, State)
+ handle_tls_handshake(Handle, Next, State)
catch throw:#alert{} = Alert ->
- handle_own_alert(Alert, Version, StateName, State0),
+ handle_own_alert(Alert, Version, Current, State0),
{stop, normal, State0}
end;
-next_state(StateName, #ssl_tls{type = ?APPLICATION_DATA, fragment = Data}, State0) ->
- case application_data(Data, State0) of
+next_state(_, StateName, #ssl_tls{type = ?APPLICATION_DATA, fragment = Data}, State0) ->
+ case read_application_data(Data, State0) of
Stop = {stop,_,_} ->
Stop;
{Record, State} ->
- next_state(StateName, Record, State)
+ next_state(StateName, StateName, Record, State)
end;
-next_state(StateName, #ssl_tls{type = ?CHANGE_CIPHER_SPEC, fragment = <<1>>} =
+next_state(Current, Next, #ssl_tls{type = ?CHANGE_CIPHER_SPEC, fragment = <<1>>} =
_ChangeCipher,
#state{connection_states = ConnectionStates0} = State0) ->
ConnectionStates1 =
ssl_record:activate_pending_connection_state(ConnectionStates0, read),
{Record, State} = next_record(State0#state{connection_states = ConnectionStates1}),
- next_state(StateName, Record, State);
-next_state(StateName, #ssl_tls{type = _Unknown}, State0) ->
+ next_state(Current, Next, Record, State);
+next_state(Current, Next, #ssl_tls{type = _Unknown}, State0) ->
%% Ignore unknown type
{Record, State} = next_record(State0),
- next_state(StateName, Record, State).
+ next_state(Current, Next, Record, State).
next_tls_record(Data, #state{tls_record_buffer = Buf0,
tls_cipher_texts = CT0} = State0) ->
@@ -1919,63 +1976,49 @@ next_state_connection(StateName, #state{send_queue = Queue0,
negotiated_version = Version,
socket = Socket,
transport_cb = Transport,
- connection_states = ConnectionStates0,
- ssl_options = #ssl_options{renegotiate_at = RenegotiateAt}
+ connection_states = ConnectionStates0
} = State) ->
- %% Send queued up data
+ %% Send queued up data that was queued while renegotiating
case queue:out(Queue0) of
{{value, {From, Data}}, Queue} ->
- case encode_data(Data, Version, ConnectionStates0, RenegotiateAt) of
- {Msgs, [], ConnectionStates} ->
- Result = Transport:send(Socket, Msgs),
- gen_fsm:reply(From, Result),
- next_state_connection(StateName,
- State#state{connection_states = ConnectionStates,
- send_queue = Queue});
- %% This is unlikely to happen. User configuration of the
- %% undocumented test option renegotiation_at can make it more likely.
- {Msgs, RestData, ConnectionStates} ->
- if
- Msgs =/= [] ->
- Transport:send(Socket, Msgs);
- true ->
- ok
- end,
- renegotiate(State#state{connection_states = ConnectionStates,
- send_queue = queue:in_r({From, RestData}, Queue),
- renegotiation = {true, internal}})
- end;
+ {Msgs, ConnectionStates} =
+ ssl_record:encode_data(Data, Version, ConnectionStates0),
+ Result = Transport:send(Socket, Msgs),
+ gen_fsm:reply(From, Result),
+ next_state_connection(StateName,
+ State#state{connection_states = ConnectionStates,
+ send_queue = Queue});
{empty, Queue0} ->
- next_state_is_connection(State)
+ next_state_is_connection(StateName, State)
end.
%% In next_state_is_connection/1: clear tls_handshake_hashes,
%% premaster_secret and public_key_info (only needed during handshake)
%% to reduce memory foot print of a connection.
-next_state_is_connection(State =
- #state{recv_during_renegotiation = true, socket_options =
- #socket_options{active = false}}) ->
- passive_receive(State#state{recv_during_renegotiation = false,
- premaster_secret = undefined,
+next_state_is_connection(_, State =
+ #state{recv_from = From,
+ socket_options =
+ #socket_options{active = false}}) when From =/= undefined ->
+ passive_receive(State#state{premaster_secret = undefined,
public_key_info = undefined,
tls_handshake_hashes = {<<>>, <<>>}}, connection);
-next_state_is_connection(State0) ->
+next_state_is_connection(StateName, State0) ->
{Record, State} = next_record_if_active(State0),
- next_state(connection, Record, State#state{premaster_secret = undefined,
+ next_state(StateName, connection, Record, State#state{premaster_secret = undefined,
public_key_info = undefined,
tls_handshake_hashes = {<<>>, <<>>}}).
-register_session(_, _, _, #session{is_resumable = true} = Session) ->
- Session; %% Already registered
-register_session(client, Host, Port, Session0) ->
+register_session(client, Host, Port, #session{is_resumable = new} = Session0) ->
Session = Session0#session{is_resumable = true},
ssl_manager:register_session(Host, Port, Session),
Session;
-register_session(server, _, Port, Session0) ->
+register_session(server, _, Port, #session{is_resumable = new} = Session0) ->
Session = Session0#session{is_resumable = true},
ssl_manager:register_session(Port, Session),
- Session.
+ Session;
+register_session(_, _, _, Session) ->
+ Session. %% Already registered
invalidate_session(client, Host, Port, Session) ->
ssl_manager:invalidate_session(Host, Port, Session);
@@ -1999,7 +2042,7 @@ initial_state(Role, Host, Port, Socket, {SSLOptions, SocketOptions}, User,
%% We do not want to save the password in the state so that
%% could be written in the clear into error logs.
ssl_options = SSLOptions#ssl_options{password = undefined},
- session = #session{is_resumable = false},
+ session = #session{is_resumable = new},
transport_cb = CbModule,
data_tag = DataTag,
close_tag = CloseTag,
@@ -2018,7 +2061,7 @@ initial_state(Role, Host, Port, Socket, {SSLOptions, SocketOptions}, User,
log_alert = true,
session_cache_cb = SessionCacheCb,
renegotiation = {false, first},
- recv_during_renegotiation = false,
+ recv_from = undefined,
send_queue = queue:new()
}.
@@ -2131,16 +2174,14 @@ handle_alert(#alert{level = ?FATAL} = Alert, StateName,
{stop, normal, State};
handle_alert(#alert{level = ?WARNING, description = ?CLOSE_NOTIFY} = Alert,
- StateName, #state{from = From, role = Role,
- user_application = {_Mon, Pid}, socket_options = Opts} = State) ->
- alert_user(StateName, Opts, Pid, From, Alert, Role),
+ StateName, State) ->
+ handle_normal_shutdown(Alert, StateName, State),
{stop, normal, State};
handle_alert(#alert{level = ?WARNING, description = ?NO_RENEGOTIATION} = Alert, StateName,
- #state{log_alert = Log, renegotiation = {true, internal}, from = From,
- role = Role} = State) ->
+ #state{log_alert = Log, renegotiation = {true, internal}} = State) ->
log_alert(Log, StateName, Alert),
- alert_user(From, Alert, Role),
+ handle_normal_shutdown(Alert, StateName, State),
{stop, normal, State};
handle_alert(#alert{level = ?WARNING, description = ?NO_RENEGOTIATION} = Alert, StateName,
@@ -2148,13 +2189,13 @@ handle_alert(#alert{level = ?WARNING, description = ?NO_RENEGOTIATION} = Alert,
log_alert(Log, StateName, Alert),
gen_fsm:reply(From, {error, renegotiation_rejected}),
{Record, State} = next_record(State0),
- next_state(connection, Record, State);
+ next_state(StateName, connection, Record, State);
handle_alert(#alert{level = ?WARNING, description = ?USER_CANCELED} = Alert, StateName,
#state{log_alert = Log} = State0) ->
log_alert(Log, StateName, Alert),
{Record, State} = next_record(State0),
- next_state(StateName, Record, State).
+ next_state(StateName, StateName, Record, State).
alert_user(connection, Opts, Pid, From, Alert, Role) ->
alert_user(Opts#socket_options.active, Pid, From, Alert, Role);
@@ -2186,13 +2227,11 @@ log_alert(true, Info, Alert) ->
log_alert(false, _, _) ->
ok.
-handle_own_alert(Alert, Version, Info,
+handle_own_alert(Alert, Version, StateName,
#state{transport_cb = Transport,
socket = Socket,
- from = User,
- role = Role,
connection_states = ConnectionStates,
- log_alert = Log}) ->
+ log_alert = Log} = State) ->
try %% Try to tell the other side
{BinMsg, _} =
encode_alert(Alert, Version, ConnectionStates),
@@ -2202,12 +2241,20 @@ handle_own_alert(Alert, Version, Info,
ignore
end,
try %% Try to tell the local user
- log_alert(Log, Info, Alert),
- alert_user(User, Alert, Role)
+ log_alert(Log, StateName, Alert),
+ handle_normal_shutdown(Alert,StateName, State)
catch _:_ ->
ok
end.
+handle_normal_shutdown(Alert, _, #state{from = User, role = Role, renegotiation = {false, first}}) ->
+ alert_user(User, Alert, Role);
+
+handle_normal_shutdown(Alert, StateName, #state{socket_options = Opts,
+ user_application = {_Mon, Pid},
+ from = User, role = Role}) ->
+ alert_user(StateName, Opts, Pid, User, Alert, Role).
+
handle_unexpected_message(Msg, Info, #state{negotiated_version = Version} = State) ->
Alert = ?ALERT_REC(?FATAL,?UNEXPECTED_MESSAGE),
handle_own_alert(Alert, Version, {Info, Msg}, State),
@@ -2220,7 +2267,7 @@ make_premaster_secret(_, _) ->
undefined.
mpint_binary(Binary) ->
- Size = byte_size(Binary),
+ Size = erlang:byte_size(Binary),
<<?UINT32(Size), Binary/binary>>.
@@ -2257,7 +2304,7 @@ renegotiate(#state{role = server,
{Record, State} = next_record(State0#state{connection_states =
ConnectionStates,
tls_handshake_hashes = Hs0}),
- next_state(hello, Record, State).
+ next_state(connection, hello, Record, State#state{allow_renegotiate = true}).
notify_senders(SendQueue) ->
lists:foreach(fun({From, _}) ->
diff --git a/lib/ssl/src/ssl_connection_sup.erl b/lib/ssl/src/ssl_connection_sup.erl
index e9328d5f7c..78cfda5e63 100644
--- a/lib/ssl/src/ssl_connection_sup.erl
+++ b/lib/ssl/src/ssl_connection_sup.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2007-2009. All Rights Reserved.
+%% Copyright Ericsson AB 2007-2011. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -26,8 +26,8 @@
-behaviour(supervisor).
%% API
--export([start_link/0]).
--export([start_child/1]).
+-export([start_link/0, start_link_dist/0]).
+-export([start_child/1, start_child_dist/1]).
%% Supervisor callback
-export([init/1]).
@@ -38,9 +38,15 @@
start_link() ->
supervisor:start_link({local, ?MODULE}, ?MODULE, []).
+start_link_dist() ->
+ supervisor:start_link({local, ssl_connection_sup_dist}, ?MODULE, []).
+
start_child(Args) ->
supervisor:start_child(?MODULE, Args).
+start_child_dist(Args) ->
+ supervisor:start_child(ssl_connection_sup_dist, Args).
+
%%%=========================================================================
%%% Supervisor callback
%%%=========================================================================
diff --git a/lib/ssl/src/ssl_dist_sup.erl b/lib/ssl/src/ssl_dist_sup.erl
new file mode 100644
index 0000000000..c1912401d7
--- /dev/null
+++ b/lib/ssl/src/ssl_dist_sup.erl
@@ -0,0 +1,84 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2011-2011. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+
+-module(ssl_dist_sup).
+
+-behaviour(supervisor).
+
+%% API
+-export([start_link/0]).
+
+%% Supervisor callback
+-export([init/1]).
+
+%%%=========================================================================
+%%% API
+%%%=========================================================================
+
+-spec start_link() -> {ok, pid()} | ignore | {error, term()}.
+
+start_link() ->
+ supervisor:start_link({local, ?MODULE}, ?MODULE, []).
+
+%%%=========================================================================
+%%% Supervisor callback
+%%%=========================================================================
+-spec init([]) -> {ok, {SupFlags :: tuple(), [ChildSpec :: tuple()]}}.
+
+init([]) ->
+ SessionCertManager = session_and_cert_manager_child_spec(),
+ ConnetionManager = connection_manager_child_spec(),
+ ProxyServer = proxy_server_child_spec(),
+
+ {ok, {{one_for_all, 10, 3600}, [SessionCertManager, ConnetionManager,
+ ProxyServer]}}.
+
+%%--------------------------------------------------------------------
+%%% Internal functions
+%%--------------------------------------------------------------------
+session_and_cert_manager_child_spec() ->
+ Opts = ssl_sup:manager_opts(),
+ Name = ssl_manager_dist,
+ StartFunc = {ssl_manager, start_link_dist, [Opts]},
+ Restart = permanent,
+ Shutdown = 4000,
+ Modules = [ssl_manager],
+ Type = worker,
+ {Name, StartFunc, Restart, Shutdown, Type, Modules}.
+
+connection_manager_child_spec() ->
+ Name = ssl_connection_dist,
+ StartFunc = {ssl_connection_sup, start_link_dist, []},
+ Restart = permanent,
+ Shutdown = 4000,
+ Modules = [ssl_connection],
+ Type = supervisor,
+ {Name, StartFunc, Restart, Shutdown, Type, Modules}.
+
+proxy_server_child_spec() ->
+ Name = ssl_tls_dist_proxy,
+ StartFunc = {ssl_tls_dist_proxy, start_link, []},
+ Restart = permanent,
+ Shutdown = 4000,
+ Modules = [ssl_tls_dist_proxy],
+ Type = worker,
+ {Name, StartFunc, Restart, Shutdown, Type, Modules}.
+
diff --git a/lib/ssl/src/ssl_handshake.erl b/lib/ssl/src/ssl_handshake.erl
index f873a6a913..371f475c85 100644
--- a/lib/ssl/src/ssl_handshake.erl
+++ b/lib/ssl/src/ssl_handshake.erl
@@ -447,7 +447,7 @@ server_hello_done() ->
-spec encode_handshake(tls_handshake(), tls_version()) -> iolist().
%%
%% Description: Encode a handshake packet to binary
-%%--------------------------------------------------------------------
+%%--------------------------------------------------------------------x
encode_handshake(Package, Version) ->
{MsgType, Bin} = enc_hs(Package, Version),
Len = byte_size(Bin),
@@ -1092,18 +1092,12 @@ certificate_authorities(CertDbHandle, CertDbRef) ->
list_to_binary([Enc(Cert) || {_, Cert} <- Authorities]).
certificate_authorities_from_db(CertDbHandle, CertDbRef) ->
- certificate_authorities_from_db(CertDbHandle, CertDbRef, no_candidate, []).
-
-certificate_authorities_from_db(CertDbHandle,CertDbRef, PrevKey, Acc) ->
- case ssl_manager:issuer_candidate(PrevKey, CertDbHandle) of
- no_more_candidates ->
- lists:reverse(Acc);
- {{CertDbRef, _, _} = Key, Cert} ->
- certificate_authorities_from_db(CertDbHandle, CertDbRef, Key, [Cert|Acc]);
- {Key, _Cert} ->
- %% skip certs not from this ssl connection
- certificate_authorities_from_db(CertDbHandle, CertDbRef, Key, Acc)
- end.
+ ConnectionCerts = fun({{Ref, _, _}, Cert}, Acc) when Ref == CertDbRef ->
+ [Cert | Acc];
+ (_, Acc) ->
+ Acc
+ end,
+ ssl_certificate_db:foldl(ConnectionCerts, [], CertDbHandle).
digitally_signed(Hash, #'RSAPrivateKey'{} = Key) ->
public_key:encrypt_private(Hash, Key,
diff --git a/lib/ssl/src/ssl_int.hrl b/lib/ssl/src/ssl_int.hrl
deleted file mode 100644
index 3686deffce..0000000000
--- a/lib/ssl/src/ssl_int.hrl
+++ /dev/null
@@ -1,99 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1999-2009. All Rights Reserved.
-%%
-%% The contents of this file are subject to the Erlang Public License,
-%% Version 1.1, (the "License"); you may not use this file except in
-%% compliance with the License. You should have received a copy of the
-%% Erlang Public License along with this software. If not, it can be
-%% retrieved online at http://www.erlang.org/.
-%%
-%% Software distributed under the License is distributed on an "AS IS"
-%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
-%% the License for the specific language governing rights and limitations
-%% under the License.
-%%
-%% %CopyrightEnd%
-%%
-
-%%
-
-%% op codes commands are in capital and reply codes in lower case
-
--define(CONNECT, 1).
--define(CONNECT_WAIT, 2).
--define(CONNECT_REP, 3).
--define(CONNECT_ERR, 4).
-
--define(TERMINATE, 5).
--define(CLOSE, 6).
-
--define(LISTEN, 7).
--define(LISTEN_REP, 8).
--define(LISTEN_ERR, 9).
-
--define(TRANSPORT_ACCEPT, 10).
--define(NOACCEPT, 11).
--define(TRANSPORT_ACCEPT_REP, 12).
--define(TRANSPORT_ACCEPT_ERR, 13).
-
--define(FROMNET_CLOSE, 14).
-
--define(CONNECT_SYNC_ERR, 15).
--define(LISTEN_SYNC_ERR, 16).
-
--define(PROXY_PORT, 23).
--define(PROXY_JOIN, 24).
--define(PROXY_JOIN_REP, 25).
--define(PROXY_JOIN_ERR, 26).
-
--define(SET_SOCK_OPT, 27).
--define(IOCTL_OK, 28).
--define(IOCTL_ERR, 29).
-
--define(GETPEERNAME, 30).
--define(GETPEERNAME_REP, 31).
--define(GETPEERNAME_ERR, 32).
-
--define(GETSOCKNAME, 33).
--define(GETSOCKNAME_REP, 34).
--define(GETSOCKNAME_ERR, 35).
-
--define(GETPEERCERT, 36).
--define(GETPEERCERT_REP, 37).
--define(GETPEERCERT_ERR, 38).
-
--define(GETVERSION, 39).
--define(GETVERSION_REP, 40).
-
--define(SET_SEED, 41).
-
--define(GETCONNINFO, 42).
--define(GETCONNINFO_REP, 43).
--define(GETCONNINFO_ERR, 44).
-
--define(SSL_ACCEPT, 45).
--define(SSL_ACCEPT_REP, 46).
--define(SSL_ACCEPT_ERR, 47).
-
--define(DUMP_CMD, 48).
--define(DEBUG_CMD, 49).
--define(DEBUGMSG_CMD, 50).
-
-%% --------------
-
--define(SSLv2, 1).
--define(SSLv3, 2).
--define(TLSv1, 4).
-
-
-%% Set socket options codes 'SET_SOCK_OPT'
--define(SET_TCP_NODELAY, 1).
-
--define(DEF_BACKLOG, 128).
-
--define(DEF_TIMEOUT, 10000).
-
--record(sslsocket, { fd = nil, pid = nil}).
-
diff --git a/lib/ssl/src/ssl_internal.hrl b/lib/ssl/src/ssl_internal.hrl
index 6bf1edc452..18cfcdcd68 100644
--- a/lib/ssl/src/ssl_internal.hrl
+++ b/lib/ssl/src/ssl_internal.hrl
@@ -24,6 +24,9 @@
-include_lib("public_key/include/public_key.hrl").
+%% Looks like it does for backwards compatibility reasons
+-record(sslsocket, {fd = nil, pid = nil}).
+
-type reason() :: term().
-type reply() :: term().
-type msg() :: term().
@@ -98,10 +101,12 @@
renegotiate_at,
secure_renegotiate,
debug,
- hibernate_after % undefined if not hibernating,
+ hibernate_after,% undefined if not hibernating,
% or number of ms of inactivity
% after which ssl_connection will
% go into hibernation
+ %% This option should only be set to true by inet_tls_dist
+ erl_dist = false
}).
-record(socket_options,
diff --git a/lib/ssl/src/ssl_manager.erl b/lib/ssl/src/ssl_manager.erl
index 725a085d1f..6a44ef8c3e 100644
--- a/lib/ssl/src/ssl_manager.erl
+++ b/lib/ssl/src/ssl_manager.erl
@@ -27,10 +27,10 @@
-include("ssl_internal.hrl").
%% Internal application API
--export([start_link/1,
+-export([start_link/1, start_link_dist/1,
connection_init/2, cache_pem_file/2,
- lookup_trusted_cert/4, issuer_candidate/2, client_session_id/4,
- server_session_id/4,
+ lookup_trusted_cert/4,
+ client_session_id/4, server_session_id/4,
register_session/2, register_session/3, invalidate_session/2,
invalidate_session/3]).
@@ -66,10 +66,20 @@
%%--------------------------------------------------------------------
-spec start_link(list()) -> {ok, pid()} | ignore | {error, term()}.
%%
-%% Description: Starts the server
+%% Description: Starts the ssl manager that takes care of sessions
+%% and certificate caching.
%%--------------------------------------------------------------------
start_link(Opts) ->
- gen_server:start_link({local, ?MODULE}, ?MODULE, [Opts], []).
+ gen_server:start_link({local, ?MODULE}, ?MODULE, [?MODULE, Opts], []).
+
+%%--------------------------------------------------------------------
+-spec start_link_dist(list()) -> {ok, pid()} | ignore | {error, term()}.
+%%
+%% Description: Starts a special instance of the ssl manager to
+%% be used by the erlang distribution. Note disables soft upgrade!
+%%--------------------------------------------------------------------
+start_link_dist(Opts) ->
+ gen_server:start_link({local, ssl_manager_dist}, ?MODULE, [ssl_manager_dist, Opts], []).
%%--------------------------------------------------------------------
-spec connection_init(string()| {der, list()}, client | server) ->
@@ -102,16 +112,7 @@ cache_pem_file(File, DbHandle) ->
%% --------------------------------------------------------------------
lookup_trusted_cert(DbHandle, Ref, SerialNumber, Issuer) ->
ssl_certificate_db:lookup_trusted_cert(DbHandle, Ref, SerialNumber, Issuer).
-%%--------------------------------------------------------------------
--spec issuer_candidate(cert_key() | no_candidate, term()) ->
- {cert_key(),
- {der_cert(),
- #'OTPCertificate'{}}} | no_more_candidates.
-%%
-%% Description: Return next issuer candidate.
-%%--------------------------------------------------------------------
-issuer_candidate(PrevCandidateKey, DbHandle) ->
- ssl_certificate_db:issuer_candidate(PrevCandidateKey, DbHandle).
+
%%--------------------------------------------------------------------
-spec client_session_id(host(), inet:port_number(), #ssl_options{},
der_cert() | undefined) -> session_id().
@@ -166,7 +167,8 @@ invalidate_session(Port, Session) ->
%%
%% Description: Initiates the server
%%--------------------------------------------------------------------
-init([Opts]) ->
+init([Name, Opts]) ->
+ put(ssl_manager, Name),
process_flag(trap_exit, true),
CacheCb = proplists:get_value(session_cb, Opts, ssl_session_cache),
SessionLifeTime =
@@ -267,25 +269,16 @@ handle_cast({register_session, Port, Session},
CacheCb:update(Cache, {Port, NewSession#session.session_id}, NewSession),
{noreply, State};
-%%% When a session is invalidated we need to wait a while before deleting
-%%% it as there might be pending connections that rightfully needs to look
-%%% up the session data but new connections should not get to use this session.
handle_cast({invalidate_session, Host, Port,
#session{session_id = ID} = Session},
#state{session_cache = Cache,
session_cache_cb = CacheCb} = State) ->
- CacheCb:update(Cache, {{Host, Port}, ID}, Session#session{is_resumable = false}),
- TRef =
- erlang:send_after(delay_time(), self(), {delayed_clean_session, {{Host, Port}, ID}}),
- {noreply, State#state{last_delay_timer = TRef}};
+ invalidate_session(Cache, CacheCb, {{Host, Port}, ID}, Session, State);
handle_cast({invalidate_session, Port, #session{session_id = ID} = Session},
#state{session_cache = Cache,
session_cache_cb = CacheCb} = State) ->
- CacheCb:update(Cache, {Port, ID}, Session#session{is_resumable = false}),
- TRef =
- erlang:send_after(delay_time(), self(), {delayed_clean_session, {Port, ID}}),
- {noreply, State#state{last_delay_timer = TRef}};
+ invalidate_session(Cache, CacheCb, {Port, ID}, Session, State);
handle_cast({recache_pem, File, LastWrite, Pid, From},
#state{certificate_db = [_, FileToRefDb, _]} = State0) ->
@@ -309,7 +302,7 @@ handle_cast({recache_pem, File, LastWrite, Pid, From},
%% {stop, reason(), #state{}}.
%%
%% Description: Handling all non call/cast messages
-%%--------------------------------------------------------------------
+%%-------------------------------------------------------------------
handle_info(validate_sessions, #state{session_cache_cb = CacheCb,
session_cache = Cache,
session_lifetime = LifeTime
@@ -376,10 +369,10 @@ code_change(_OldVsn, State, _Extra) ->
%%% Internal functions
%%--------------------------------------------------------------------
call(Msg) ->
- gen_server:call(?MODULE, {Msg, self()}, infinity).
+ gen_server:call(get(ssl_manager), {Msg, self()}, infinity).
cast(Msg) ->
- gen_server:cast(?MODULE, Msg).
+ gen_server:cast(get(ssl_manager), Msg).
validate_session(Host, Port, Session, LifeTime) ->
case ssl_session:valid_session(Session, LifeTime) of
@@ -399,9 +392,10 @@ validate_session(Port, Session, LifeTime) ->
start_session_validator(Cache, CacheCb, LifeTime) ->
spawn_link(?MODULE, init_session_validator,
- [[Cache, CacheCb, LifeTime]]).
+ [[get(ssl_manager), Cache, CacheCb, LifeTime]]).
-init_session_validator([Cache, CacheCb, LifeTime]) ->
+init_session_validator([SslManagerName, Cache, CacheCb, LifeTime]) ->
+ put(ssl_manager, SslManagerName),
CacheCb:foldl(fun session_validation/2,
LifeTime, Cache).
@@ -432,3 +426,20 @@ delay_time() ->
_ ->
?CLEAN_SESSION_DB
end.
+
+invalidate_session(Cache, CacheCb, Key, Session, State) ->
+ case CacheCb:lookup(Cache, Key) of
+ undefined -> %% Session is already invalidated
+ {noreply, State};
+ #session{is_resumable = new} ->
+ CacheCb:delete(Cache, Key),
+ {noreply, State};
+ _ ->
+ %% When a registered session is invalidated we need to wait a while before deleting
+ %% it as there might be pending connections that rightfully needs to look
+ %% up the session data but new connections should not get to use this session.
+ CacheCb:update(Cache, Key, Session#session{is_resumable = false}),
+ TRef =
+ erlang:send_after(delay_time(), self(), {delayed_clean_session, Key}),
+ {noreply, State#state{last_delay_timer = TRef}}
+ end.
diff --git a/lib/ssl/src/ssl_prim.erl b/lib/ssl/src/ssl_prim.erl
deleted file mode 100644
index e3140a89d1..0000000000
--- a/lib/ssl/src/ssl_prim.erl
+++ /dev/null
@@ -1,173 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2000-2009. All Rights Reserved.
-%%
-%% The contents of this file are subject to the Erlang Public License,
-%% Version 1.1, (the "License"); you may not use this file except in
-%% compliance with the License. You should have received a copy of the
-%% Erlang Public License along with this software. If not, it can be
-%% retrieved online at http://www.erlang.org/.
-%%
-%% Software distributed under the License is distributed on an "AS IS"
-%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
-%% the License for the specific language governing rights and limitations
-%% under the License.
-%%
-%% %CopyrightEnd%
-%%
-
-%%
-
-%% Purpose: Primitive interface to SSL, without broker process (used by
-%% SSL distribution).
-
--module(ssl_prim).
-
--export([listen/2, connect/3, accept/1, close/1, send/2, send/3, recv/2, recv/3,
- getll/1, getstat/2, setopts/2, controlling_process/2, peername/1,
- sockname/1, getif/1]).
-
--include("ssl_int.hrl").
--include("ssl_broker_int.hrl").
-
-%-define(filter(Call), filter((catch Call))).
--define(filter(Call), filter(Call)).
-
-listen(Port, Opts) ->
- St = newstate(listener),
- ?filter(ssl_broker:listen_prim(ssl_server_prim, self(), Port, nonactive(Opts), St)).
-
-connect(Address, Port, Opts) ->
- St = newstate(connector),
- ?filter(ssl_broker:connect_prim(ssl_server_prim, inet_tcp, self(), Address,
- Port, nonactive(Opts), infinity, St)).
-
-accept(#st{} = ListenSt0) ->
- case transport_accept(ListenSt0) of
- {ok, ListenSt1} ->
- ssl_accept(ListenSt0, ListenSt1);
- Error ->
- Error
- end.
-
-transport_accept(#st{opts = ListenOpts, thissock = ListenSocket}) ->
- NewSt = newstate(acceptor),
- ListenFd = ListenSocket#sslsocket.fd,
- ?filter(ssl_broker:transport_accept_prim(ssl_server_prim, ListenFd,
- ListenOpts, infinity, NewSt)).
-
-ssl_accept(#st{opts = LOpts}, ListenSt1) ->
- ?filter(ssl_broker:ssl_accept_prim(ssl_server_prim, gen_tcp, self(),
- LOpts, infinity, ListenSt1)).
-
-close(#st{fd = Fd}) when is_integer(Fd) ->
- ssl_server:close_prim(ssl_server_prim, Fd),
- ok;
-close(_) ->
- ok.
-
-send(St, Data) ->
- send(St, Data, []).
-
-send(#st{proxysock = Proxysock, status = open}, Data, Opts) ->
- case inet_tcp:send(Proxysock, Data, Opts) of
- ok ->
- ok;
- {error, _} ->
- {error, closed}
- end;
-send(#st{}, _Data, _Opts) ->
- {error, closed}.
-
-recv(St, Length) ->
- recv(St, Length, infinity).
-
-recv(#st{proxysock = Proxysock, status = open}, Length, Tmo) ->
- inet_tcp:recv(Proxysock, Length, Tmo);
-recv(#st{}, _Length, _Tmo) ->
- {error, closed}.
-
-getll(#st{proxysock = Proxysock, status = open}) ->
- inet:getll(Proxysock);
-getll(#st{}) ->
- {error, closed}.
-
-getstat(#st{proxysock = Proxysock, status = open}, Opts) ->
- inet:getstat(Proxysock, Opts);
-getstat(#st{}, _Opts) ->
- {error, closed}.
-
-setopts(#st{proxysock = Proxysock, status = open}, Opts) ->
- case remove_supported(Opts) of
- [] ->
- inet:setopts(Proxysock, Opts);
- _ ->
- {error, enotsup}
- end;
-setopts(#st{}, _Opts) ->
- {error, closed}.
-
-
-controlling_process(#st{proxysock = Proxysock, status = open}, Pid)
- when is_pid(Pid) ->
- inet_tcp:controlling_process(Proxysock, Pid);
-controlling_process(#st{}, Pid) when is_pid(Pid) ->
- {error, closed}.
-
-peername(#st{fd = Fd, status = open}) ->
- case ssl_server:peername_prim(ssl_server_prim, Fd) of
- {ok, {Address, Port}} ->
- {ok, At} = inet_parse:ipv4_address(Address),
- {ok, {At, Port}};
- Error ->
- Error
- end;
-peername(#st{}) ->
- {error, closed}.
-
-sockname(#st{fd = Fd, status = open}) ->
- case ssl_server:sockname_prim(ssl_server_prim, Fd) of
- {ok, {Address, Port}} ->
- {ok, At} = inet_parse:ipv4_address(Address),
- {ok, {At, Port}};
- Error ->
- Error
- end;
-sockname(#st{}) ->
- {error, closed}.
-
-getif(#st{proxysock = Proxysock, status = open}) ->
- inet:getif(Proxysock);
-getif(#st{}) ->
- {error, closed}.
-
-remove_supported([{active, _}|T]) ->
- remove_supported(T);
-remove_supported([{packet,_}|T]) ->
- remove_supported(T);
-remove_supported([{deliver,_}|T]) ->
- remove_supported(T);
-remove_supported([H|T]) ->
- [H | remove_supported(T)];
-remove_supported([]) ->
- [].
-
-filter(Result) ->
- case Result of
- {ok, _Sock,St} ->
- {ok, St};
- {error, Reason, _St} ->
- {error,Reason}
- end.
-
-nonactive([{active,_}|T]) ->
- nonactive(T);
-nonactive([H|T]) ->
- [H | nonactive(T)];
-nonactive([]) ->
- [{active, false}].
-
-newstate(Type) ->
- #st{brokertype = Type, server = whereis(ssl_server_prim),
- client = undefined, collector = undefined, debug = false}.
diff --git a/lib/ssl/src/ssl_record.erl b/lib/ssl/src/ssl_record.erl
index 72091fdd5f..f52d2f961c 100644
--- a/lib/ssl/src/ssl_record.erl
+++ b/lib/ssl/src/ssl_record.erl
@@ -48,7 +48,7 @@
%% Encoding records
-export([encode_handshake/3, encode_alert_record/3,
- encode_change_cipher_spec/2, encode_data/4]).
+ encode_change_cipher_spec/2, encode_data/3]).
%% Decoding
-export([decode_cipher_text/2]).
@@ -503,36 +503,14 @@ decode_cipher_text(CipherText, ConnnectionStates0) ->
Alert
end.
%%--------------------------------------------------------------------
--spec encode_data(iolist(), tls_version(), #connection_states{}, integer()) ->
- {iolist(), iolist(), #connection_states{}}.
+-spec encode_data(binary(), tls_version(), #connection_states{}) ->
+ {iolist(), #connection_states{}}.
%%
%% Description: Encodes data to send on the ssl-socket.
%%--------------------------------------------------------------------
-encode_data(Frag, Version, ConnectionStates, RenegotiateAt)
- when byte_size(Frag) < (?MAX_PLAIN_TEXT_LENGTH - 2048) ->
- case encode_plain_text(?APPLICATION_DATA,Version,Frag,ConnectionStates, RenegotiateAt) of
- {renegotiate, Data} ->
- {[], Data, ConnectionStates};
- {Msg, CS} ->
- {Msg, [], CS}
- end;
-
-encode_data(Frag, Version, ConnectionStates, RenegotiateAt) when is_binary(Frag) ->
- Data = split_bin(Frag, ?MAX_PLAIN_TEXT_LENGTH - 2048),
- encode_data(Data, Version, ConnectionStates, RenegotiateAt);
-
-encode_data(Data, Version, ConnectionStates0, RenegotiateAt) when is_list(Data) ->
- {ConnectionStates, EncodedMsg, NotEncdedData} =
- lists:foldl(fun(B, {CS0, Encoded, Rest}) ->
- case encode_plain_text(?APPLICATION_DATA,
- Version, B, CS0, RenegotiateAt) of
- {renegotiate, NotEnc} ->
- {CS0, Encoded, [NotEnc | Rest]};
- {Enc, CS1} ->
- {CS1, [Enc | Encoded], Rest}
- end
- end, {ConnectionStates0, [], []}, Data),
- {lists:reverse(EncodedMsg), lists:reverse(NotEncdedData), ConnectionStates}.
+encode_data(Frag, Version, ConnectionStates) ->
+ Data = split_bin(Frag, ?MAX_PLAIN_TEXT_LENGTH, Version),
+ encode_iolist(?APPLICATION_DATA, Data, Version, ConnectionStates).
%%--------------------------------------------------------------------
-spec encode_handshake(iolist(), tls_version(), #connection_states{}) ->
@@ -566,6 +544,14 @@ encode_change_cipher_spec(Version, ConnectionStates) ->
%%--------------------------------------------------------------------
%%% Internal functions
%%--------------------------------------------------------------------
+encode_iolist(Type, Data, Version, ConnectionStates0) ->
+ {ConnectionStates, EncodedMsg} =
+ lists:foldl(fun(Text, {CS0, Encoded}) ->
+ {Enc, CS1} = encode_plain_text(Type, Version, Text, CS0),
+ {CS1, [Enc | Encoded]}
+ end, {ConnectionStates0, []}, Data),
+ {lists:reverse(EncodedMsg), ConnectionStates}.
+
highest_protocol_version() ->
highest_protocol_version(supported_protocol_versions()).
@@ -602,29 +588,23 @@ record_protocol_role(client) ->
record_protocol_role(server) ->
?SERVER.
-split_bin(Bin, ChunkSize) ->
- split_bin(Bin, ChunkSize, []).
+%% 1/n-1 splitting countermeasure Rizzo/Duong-Beast
+split_bin(<<FirstByte:8, Rest/binary>>, ChunkSize, Version) when {3, 1} == Version orelse
+ {3, 0} == Version ->
+ do_split_bin(Rest, ChunkSize, [[FirstByte]]);
+split_bin(Bin, ChunkSize, _) ->
+ do_split_bin(Bin, ChunkSize, []).
-split_bin(<<>>, _, Acc) ->
+do_split_bin(<<>>, _, Acc) ->
lists:reverse(Acc);
-split_bin(Bin, ChunkSize, Acc) ->
+do_split_bin(Bin, ChunkSize, Acc) ->
case Bin of
<<Chunk:ChunkSize/binary, Rest/binary>> ->
- split_bin(Rest, ChunkSize, [Chunk | Acc]);
+ do_split_bin(Rest, ChunkSize, [Chunk | Acc]);
_ ->
lists:reverse(Acc, [Bin])
end.
-encode_plain_text(Type, Version, Data, ConnectionStates, RenegotiateAt) ->
- #connection_states{current_write =
- #connection_state{sequence_number = Num}} = ConnectionStates,
- case renegotiate(Num, RenegotiateAt) of
- false ->
- encode_plain_text(Type, Version, Data, ConnectionStates);
- true ->
- {renegotiate, Data}
- end.
-
encode_plain_text(Type, Version, Data, ConnectionStates) ->
#connection_states{current_write=#connection_state{
compression_state=CompS0,
@@ -637,11 +617,6 @@ encode_plain_text(Type, Version, Data, ConnectionStates) ->
CTBin = encode_tls_cipher_text(Type, Version, CipherText),
{CTBin, ConnectionStates#connection_states{current_write = CS2}}.
-renegotiate(N, M) when N < M->
- false;
-renegotiate(_,_) ->
- true.
-
encode_tls_cipher_text(Type, {MajVer, MinVer}, Fragment) ->
Length = erlang:iolist_size(Fragment),
[<<?BYTE(Type), ?BYTE(MajVer), ?BYTE(MinVer), ?UINT16(Length)>>, Fragment].
diff --git a/lib/ssl/src/ssl_record.hrl b/lib/ssl/src/ssl_record.hrl
index 5fb0070b91..282d642138 100644
--- a/lib/ssl/src/ssl_record.hrl
+++ b/lib/ssl/src/ssl_record.hrl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2007-2010. All Rights Reserved.
+%% Copyright Ericsson AB 2007-2011. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -70,9 +70,10 @@
-define(MAX_SEQENCE_NUMBER, 18446744073709552000). %% math:pow(2, 64) - 1 = 1.8446744073709552e19
%% Sequence numbers can not wrap so when max is about to be reached we should renegotiate.
%% We will renegotiate a little before so that there will be sequence numbers left
-%% for the rehandshake and a little data.
--define(MARGIN, 100).
--define(DEFAULT_RENEGOTIATE_AT, ?MAX_SEQENCE_NUMBER - ?MARGIN).
+%% for the rehandshake and a little data. Currently we decided to renegotiate a little more
+%% often as we can have a cheaper test to check if it is time to renegotiate. It will still
+%% be fairly seldom.
+-define(DEFAULT_RENEGOTIATE_AT, 268435456). %% math:pow(2, 28)
%% ConnectionEnd
-define(SERVER, 0).
diff --git a/lib/ssl/src/ssl_server.erl b/lib/ssl/src/ssl_server.erl
deleted file mode 100644
index b66e20a397..0000000000
--- a/lib/ssl/src/ssl_server.erl
+++ /dev/null
@@ -1,1378 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1999-2009. All Rights Reserved.
-%%
-%% The contents of this file are subject to the Erlang Public License,
-%% Version 1.1, (the "License"); you may not use this file except in
-%% compliance with the License. You should have received a copy of the
-%% Erlang Public License along with this software. If not, it can be
-%% retrieved online at http://www.erlang.org/.
-%%
-%% Software distributed under the License is distributed on an "AS IS"
-%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
-%% the License for the specific language governing rights and limitations
-%% under the License.
-%%
-%% %CopyrightEnd%
-%%
-
-%%
-
-%%% Purpose : SSL server
-
-%%
-%% TODO
-%%
-%% XXX The ip option in listen is not general enough. It is assumed
-%% to be a tuple, which is not always the case.
-
--module(ssl_server).
--behaviour(gen_server).
-
-%% External exports
--export([start_link/0]).
-
--export([transport_accept/2, transport_accept/3, ssl_accept/2, ssl_accept/3,
- ciphers/0, connect/5, connect/6,
- connection_info/1, close/1, listen/3, listen/4, peercert/1,
- peername/1, proxy_join/2, seed/1, setnodelay/2, sockname/1,
- version/0]).
-
--export([start_link_prim/0]).
--export([ssl_accept_prim/4, transport_accept_prim/4,
- connect_prim/7, close_prim/2,
- listen_prim/5, proxy_join_prim/3, peername_prim/2, setnodelay_prim/3,
- sockname_prim/2]).
-
--export([dump/0, dump/1]).
--export([enable_debug/0, disable_debug/0, set_debug/1]).
--export([enable_debugmsg/0, disable_debugmsg/0, set_debugmsg/1]).
-
-%% gen_server callbacks
--export([init/1, handle_call/3, handle_cast/2, handle_info/2,
- code_change/3, terminate/2]).
-
--include("ssl_int.hrl").
-
--record(st, {
- port = [], % port() of port program
- progpid = [], % OS pid of port program
- debug = false, % debug printout flag
- cons = [], % All brokers except pending accepts
- paccepts = [], % Pending accept brokers
- proxylsport = [], % proxy listen socket port
- intref = 0, % internal reference counter
- compvsn = "", % ssl compile library version
- libvsn = "", % ssl library version
- ciphers = [] % available ciphers
- }).
-
-
-%% In all functions below IP is a four tuple, e.g. {192, 236, 52, 7}.
-%% Port, Fd and ListenFd are integers; Flags is a string of characters.
-%%
-%% The prefixes F and L mean foreign and local, respectively.
-%% Example: FIP (IP address for foreign end).
-
-%%
-%% start_link() -> {ok, Pid} | {error, Reason}
-%%
-start_link() ->
- gen_server:start_link({local, ssl_server}, ssl_server, [], []).
-
-start_link_prim() ->
- gen_server:start_link({local, ssl_server_prim}, ssl_server, [], []).
-
-%%
-%% transport_accept(ListenFd, Flags) -> {ok, Fd, ProxyLLPort} |
-%% {error, Reason}
-%%
-transport_accept(ListenFd, Flags) ->
- transport_accept(ListenFd, Flags, infinity).
-transport_accept(ListenFd, Flags, Timeout) ->
- transport_accept_prim(ssl_server,ListenFd, Flags, Timeout).
-
-transport_accept_prim(ServerName, ListenFd, Flags, Timeout) ->
- Req = {transport_accept, self(), ListenFd, Flags},
- gen_server:call(ServerName, Req, Timeout).
-
-%%
-%% ssl_accept(ListenFd, Flags) -> {ok, Fd, ProxyLLPort} |
-%% {error, Reason}
-%%
-ssl_accept(ListenFd, Flags) ->
- ssl_accept(ListenFd, Flags, infinity).
-ssl_accept(ListenFd, Flags, Timeout) ->
- ssl_accept_prim(ssl_server, ListenFd, Flags, Timeout).
-
-ssl_accept_prim(ServerName, Fd, Flags, Timeout) ->
- Req = {ssl_accept, Fd, Flags},
- gen_server:call(ServerName, Req, Timeout).
-
-%%
-%% ciphers() -> {ok, Ciphers}
-%%
-ciphers() ->
- gen_server:call(ssl_server, ciphers, infinity).
-
-%%
-%% close(Fd) -> ok
-%%
-close(Fd) ->
- close_prim(ssl_server, Fd).
-close_prim(ServerName, Fd) ->
- gen_server:call(ServerName, {close, self(), Fd}, infinity),
- ok.
-
-%%
-%% connect(LIP, LPort, FIP, FPort, Flags) -> {ok, Fd, ProxyLFPort} |
-%% {error, Reason}
-%%
-connect(LIP, LPort, FIP, FPort, Flags) ->
- connect(LIP, LPort, FIP, FPort, Flags, infinity).
-connect(LIP, LPort, FIP, FPort, Flags, Timeout) ->
- connect_prim(ssl_server, LIP, LPort, FIP, FPort, Flags, Timeout).
-
-connect_prim(ServerName, LIP, LPort, FIP, FPort, Flags, Timeout) ->
- Req = {connect, self(), LIP, LPort, FIP, FPort, Flags},
- gen_server:call(ServerName, Req, Timeout).
-
-%%
-%% connection_info(Fd) -> {ok, {Protocol, Cipher}} | {error, Reason}
-%%
-connection_info(Fd) ->
- Req = {connection_info, self(), Fd},
- gen_server:call(ssl_server, Req, infinity).
-
-%%
-%% listen(IP, LPort, Flags),
-%% listen(IP, LPort, Flags, BackLog) -> {ok, ListenFd, LPort0} |
-%% {error, Reason}
-%%
-listen(IP, LPort, Flags) ->
- listen(IP, LPort, Flags, ?DEF_BACKLOG).
-listen(IP, LPort, Flags, BackLog) ->
- listen_prim(ssl_server, IP, LPort, Flags, BackLog).
-listen_prim(ServerName, IP, LPort, Flags, BackLog) ->
- Req = {listen, self(), IP, LPort, Flags, BackLog},
- gen_server:call(ServerName, Req, infinity).
-
-%%
-%% peercert(Fd) -> {ok, Cert} | {error, Reason}
-%%
-peercert(Fd) ->
- Req = {peercert, self(), Fd},
- gen_server:call(ssl_server, Req, infinity).
-
-%%
-%% peername(Fd) -> {ok, {Address, Port}} | {error, Reason}
-%%
-peername(Fd) ->
- peername_prim(ssl_server, Fd).
-peername_prim(ServerName, Fd) ->
- Req = {peername, self(), Fd},
- gen_server:call(ServerName, Req, infinity).
-
-%%
-%% proxy_join(Fd, LPort) -> ok | {error, Reason}
-%%
-proxy_join(Fd, LPort) ->
- proxy_join_prim(ssl_server, Fd, LPort).
-proxy_join_prim(ServerName, Fd, LPort) ->
- Req = {proxy_join, self(), Fd, LPort},
- gen_server:call(ServerName, Req, infinity).
-
-%%
-%% seed(Data)
-%%
-seed(Data) ->
- Req = {seed, Data},
- gen_server:call(ssl_server, Req, infinity).
-
-%%
-%% set_nodelay(Fd, Boolean)
-%%
-setnodelay(Fd, Boolean) ->
- setnodelay_prim(ssl_server, Fd, Boolean).
-setnodelay_prim(ServerName, Fd, Boolean) ->
- Req = {setnodelay, self(), Fd, Boolean},
- gen_server:call(ServerName, Req, infinity).
-
-%%
-%% sockname(Fd) -> {ok, {Address, Port}} | {error, Reason}
-%%
-sockname(Fd) ->
- sockname_prim(ssl_server, Fd).
-sockname_prim(ServerName, Fd) ->
- Req = {sockname, self(), Fd},
- gen_server:call(ServerName, Req, infinity).
-
-%%
-%% version() -> {ok, {CompVsn, LibVsn}}
-%%
-version() ->
- gen_server:call(ssl_server, version, infinity).
-
-
-enable_debug() ->
- set_debug(true).
-
-disable_debug() ->
- set_debug(false).
-
-set_debug(Bool) ->
- set_debug(Bool, infinity).
-
-set_debug(Bool, Timeout) when is_boolean(Bool) ->
- Req = {set_debug, Bool, self()},
- gen_server:call(ssl_server, Req, Timeout).
-
-enable_debugmsg() ->
- set_debugmsg(true).
-
-disable_debugmsg() ->
- set_debugmsg(false).
-
-set_debugmsg(Bool) ->
- set_debugmsg(Bool, infinity).
-
-set_debugmsg(Bool, Timeout) when is_boolean(Bool) ->
- Req = {set_debugmsg, Bool, self()},
- gen_server:call(ssl_server, Req, Timeout).
-
-dump() ->
- dump(infinity).
-
-dump(Timeout) ->
- Req = {dump, self()},
- gen_server:call(ssl_server, Req, Timeout).
-
-%%
-%% init
-%%
-init([]) ->
- Debug = case application:get_env(ssl, edebug) of
- {ok, true} ->
- true;
- _ ->
- case application:get_env(ssl, debug) of
- {ok, true} ->
- true;
- _ ->
- os:getenv("ERL_SSL_DEBUG") =/= false
- end
- end,
- ProgDir =
- case init:get_argument(ssl_portprogram_dir) of
- {ok, [[D]]} ->
- D;
- _ ->
- find_priv_bin()
- end,
- {Program, Flags} = mk_cmd_line("ssl_esock"),
- Cmd = filename:join(ProgDir, Program) ++ " " ++ Flags,
- debug1(Debug, " start, Cmd = ~s~n", [Cmd]),
- case (catch open_port({spawn, Cmd}, [binary, {packet, 4}])) of
- Port when is_port(Port) ->
- process_flag(trap_exit, true),
- receive
- {Port, {data, Bin}} ->
- {ProxyLLPort, ProgPid, CompVsn, LibVsn, Ciphers} =
- decode_msg(Bin, [int16, int32, string, string,
- string]),
- debug1(Debug, "port program pid = ~w~n",
- [ProgPid]),
- {ok, #st{port = Port,
- proxylsport = ProxyLLPort,
- progpid = ProgPid,
- debug = Debug,
- compvsn = CompVsn,
- libvsn = LibVsn,
- ciphers = Ciphers}};
- {'EXIT', Port, Reason} ->
- {stop, Reason}
- end;
- {'EXIT', Reason} ->
- {stop, Reason}
- end.
-
-%%
-%% transport_accept
-%%
-handle_call({transport_accept, Broker, ListenFd, Flags}, From, St) ->
- debug(St, "transport_accept: broker = ~w, listenfd = ~w~n",
- [Broker, ListenFd]),
- case get_by_fd(ListenFd, St#st.cons) of
- {ok, {ListenFd, _, _}} ->
- send_cmd(St#st.port, ?TRANSPORT_ACCEPT, [int32(ListenFd), Flags, 0]),
- PAccepts = add({ListenFd, Broker, From}, St#st.paccepts),
- %%
- %% We reply when we get TRANSPORT_ACCEPT_REP or ASYNC_ACCEPT_ERR
- %%
- {noreply, St#st{paccepts = PAccepts}};
- _Other ->
- {reply, {error, ebadf}, St}
- end;
-
-%%
-%% ssl_accept
-%%
-handle_call({ssl_accept, Fd, Flags}, From, St) ->
- case replace_from_by_fd(Fd, St#st.cons, From) of
- {ok, _, Cons} = _Rep ->
- send_cmd(St#st.port, ?SSL_ACCEPT, [int32(Fd), Flags, 0]),
- %% We reply when we get SSL_ACCEPT_REP or ASYNC_ACCEPT_ERR
- {noreply, St#st{cons = Cons}};
- _Other ->
- {reply, {error, ebadf}, St}
- end;
-
-%%
-%% version
-%%
-handle_call(ciphers, From, St) ->
- debug(St, "ciphers: from = ~w~n", [From]),
- {reply, {ok, St#st.ciphers}, St};
-
-%%
-%% connect
-%%
-handle_call({connect, Broker, LIP, LPort, FIP, FPort, Flags}, From, St) ->
- debug(St, "connect: broker = ~w, ip = ~w, "
- "sport = ~w~n", [Broker, FIP, FPort]),
- Port = St#st.port,
- LIPStr = ip_to_string(LIP),
- FIPStr = ip_to_string(FIP),
- IntRef = new_intref(St),
- send_cmd(Port, ?CONNECT, [int32(IntRef),
- int16(LPort), LIPStr, 0,
- int16(FPort), FIPStr, 0,
- Flags, 0]),
- Cons = add({{intref, IntRef}, Broker, From}, St#st.cons),
- %% We reply when we have got CONNECT_SYNC_ERR, or CONNECT_WAIT
- %% and CONNECT_REP, or CONNECT_ERR.
- {noreply, St#st{cons = Cons, intref = IntRef}};
-
-%%
-%% connection_info
-%%
-handle_call({connection_info, Broker, Fd}, From, St) ->
- debug(St, "connection_info: broker = ~w, fd = ~w~n",
- [Broker, Fd]),
- case replace_from_by_fd(Fd, St#st.cons, From) of
- {ok, _, Cons} ->
- send_cmd(St#st.port, ?GETCONNINFO, [int32(Fd)]),
- %% We reply when we get GETCONNINFO_REP or GETCONNINFO_ERR.
- {noreply, St#st{cons = Cons}};
- _Other ->
- {reply, {error, ebadf}, St}
- end;
-
-%%
-%% close
-%%
-handle_call({close, Broker, Fd}, _From, St) ->
- debug(St, "close: broker = ~w, fd = ~w~n",
- [Broker, Fd]),
- #st{port = Port, cons = Cons0, paccepts = PAccepts0} = St,
- case delete_by_fd(Fd, Cons0) of
- %% Must match Broker pid; fd may be reused already.
- {ok, {Fd, Broker, _}, Cons} ->
- send_cmd(Port, ?CLOSE, int32(Fd)),
- %% If Fd is a listen socket fd, there might be pending
- %% accepts for that fd.
- case delete_all_by_fd(Fd, PAccepts0) of
- {ok, DelAccepts, RemAccepts} ->
- %% Reply {error, closed} to all pending accepts
- lists:foreach(fun({_, _, AccFrom}) ->
- gen_server:reply(AccFrom,
- {error, closed})
- end, DelAccepts),
- {reply, ok,
- St#st{cons = Cons, paccepts = RemAccepts}};
- _ ->
- {reply, ok, St#st{cons = Cons}}
- end;
- _ ->
- {reply, ok, St}
- end;
-
-%%
-%% listen
-%%
-handle_call({listen, Broker, IP, LPort, Flags, BackLog}, From, St) ->
- debug(St, "listen: broker = ~w, IP = ~w, "
- "sport = ~w~n", [Broker, IP, LPort]),
- Port = St#st.port,
- IPStr = ip_to_string(IP),
- IntRef = new_intref(St),
- send_cmd(Port, ?LISTEN, [int32(IntRef), int16(LPort), IPStr, 0,
- int16(BackLog), Flags, 0]),
- Cons = add({{intref, IntRef}, Broker, From}, St#st.cons),
- %% We reply when we have got LISTEN_REP.
- {noreply, St#st{cons = Cons, intref = IntRef}};
-
-%%
-%% peercert
-%%
-handle_call({peercert, Broker, Fd}, From, St) ->
- debug(St, "peercert: broker = ~w, fd = ~w~n",
- [Broker, Fd]),
- case replace_from_by_fd(Fd, St#st.cons, From) of
- {ok, _, Cons} ->
- send_cmd(St#st.port, ?GETPEERCERT, [int32(Fd)]),
- %% We reply when we get GETPEERCERT_REP or GETPEERCERT_ERR.
- {noreply, St#st{cons = Cons}};
- _Other ->
- {reply, {error, ebadf}, St}
- end;
-
-
-%%
-%% peername
-%%
-handle_call({peername, Broker, Fd}, From, St) ->
- debug(St, "peername: broker = ~w, fd = ~w~n",
- [Broker, Fd]),
- case replace_from_by_fd(Fd, St#st.cons, From) of
- {ok, _, Cons} ->
- send_cmd(St#st.port, ?GETPEERNAME, [int32(Fd)]),
- %% We reply when we get GETPEERNAME_REP or GETPEERNAME_ERR.
- {noreply, St#st{cons = Cons}};
- _Other ->
- {reply, {error, ebadf}, St}
- end;
-
-%%
-%% proxy join
-%%
-handle_call({proxy_join, Broker, Fd, LPort}, From, St) ->
- debug(St, "proxy_join: broker = ~w, fd = ~w, "
- "sport = ~w~n", [Broker, Fd, LPort]),
- case replace_from_by_fd(Fd, St#st.cons, From) of
- {ok, _, Cons} ->
- send_cmd(St#st.port, ?PROXY_JOIN, [int32(Fd),
- int16(LPort)]),
- %% We reply when we get PROXY_JOIN_REP, or PROXY_JOIN_ERR.
- {noreply, St#st{cons = Cons}};
- _Other ->
- {reply, {error, ebadf}, St}
- end;
-
-%%
-%% seed
-%%
-handle_call({seed, Data}, _From, St) when is_binary(Data) ->
- send_cmd(St#st.port, ?SET_SEED, [int32(byte_size(Data)), Data]),
- {reply, ok, St};
-
-handle_call({seed, Data}, From, St) ->
- case catch list_to_binary(Data) of
- {'EXIT', _} ->
- {reply, {error, edata}, St};
- Bin ->
- handle_call({seed, Bin}, From, St)
- end;
-
-%%
-%% setnodelay
-%%
-handle_call({setnodelay, Broker, Fd, Boolean}, From, St) ->
- debug(St, "setnodelay: broker = ~w, fd = ~w, "
- "boolean = ~w~n", [Broker, Fd, Boolean]),
- case replace_from_by_fd(Fd, St#st.cons, From) of
- {ok, _, Cons} ->
- Val = if Boolean == true -> 1; true -> 0 end,
- send_cmd(St#st.port, ?SET_SOCK_OPT,
- [int32(Fd), ?SET_TCP_NODELAY, Val]),
- %% We reply when we get IOCTL_OK or IOCTL_ERR.
- {noreply, St#st{cons = Cons}};
- _Other ->
- {reply, {error, ebadf}, St}
- end;
-
-%%
-%% sockname
-%%
-handle_call({sockname, Broker, Fd}, From, St) ->
- debug(St, "sockname: broker = ~w, fd = ~w~n",
- [Broker, Fd]),
- case replace_from_by_fd(Fd, St#st.cons, From) of
- {ok, _, Cons} ->
- send_cmd(St#st.port, ?GETSOCKNAME, [int32(Fd)]),
- %% We reply when we get GETSOCKNAME_REP or GETSOCKNAME_ERR.
- {noreply, St#st{cons = Cons}};
- _Other ->
- {reply, {error, ebadf}, St}
- end;
-
-%%
-%% version
-%%
-handle_call(version, From, St) ->
- debug(St, "version: from = ~w~n", [From]),
- {reply, {ok, {St#st.compvsn, St#st.libvsn}}, St};
-
-%%
-%% dump
-%%
-handle_call({dump, Broker}, _From, St) ->
- debug(St, "dump: broker = ~w", [Broker]),
- Port = St#st.port,
- send_cmd(Port, ?DUMP_CMD, []),
- {reply, ok, St};
-
-%%
-%% set_debug
-%%
-handle_call({set_debug, Bool, Broker}, _From, St) ->
- debug(St, "set_debug: broker = ~w", [Broker]),
- Value = case Bool of
- true ->
- 1;
- false ->
- 0
- end,
- Port = St#st.port,
- send_cmd(Port, ?DEBUG_CMD, [Value]),
- {reply, ok, St};
-
-%%
-%% set_debugmsg
-%%
-handle_call({set_debugmsg, Bool, Broker}, _From, St) ->
- debug(St, "set_debugmsg: broker = ~w", [Broker]),
- Value = case Bool of
- true ->
- 1;
- false ->
- 0
- end,
- Port = St#st.port,
- send_cmd(Port, ?DEBUGMSG_CMD, [Value]),
- {reply, ok, St};
-
-handle_call(Request, _From, St) ->
- debug(St, "unexpected call: ~w~n", [Request]),
- Reply = {error, {badcall, Request}},
- {reply, Reply, St}.
-
-%%
-%% handle_cast(Msg, St)
-%%
-
-
-handle_cast(Msg, St) ->
- debug(St, "unexpected cast: ~w~n", [Msg]),
- {noreply, St}.
-
-%%
-%% handle_info(Info, St)
-%%
-
-%% Data from port
-%%
-handle_info({Port, {data, Bin}},
- #st{cons = StCons, paccepts = Paccepts,
- port = Port, proxylsport = Proxylsport} = St)
- when is_binary(Bin) ->
- %% io:format("++++ ssl_server got from port: ~w~n", [Bin]),
- <<OpCode:8, _/binary>> = Bin,
- case OpCode of
- %%
- %% transport_accept
- %%
- ?TRANSPORT_ACCEPT_ERR when byte_size(Bin) >= 5 ->
- {ListenFd, Reason} = decode_msg(Bin, [int32, atom]),
- debug(St, "transport_accept_err: listenfd = ~w, "
- "reason = ~w~n", [ListenFd, Reason]),
- case delete_last_by_fd(ListenFd, Paccepts) of
- {ok, {_, _, From}, PAccepts} ->
- gen_server:reply(From, {error, Reason}),
- {noreply, St#st{paccepts = PAccepts}};
- _Other ->
- %% Already closed
- {noreply, St}
- end;
- ?TRANSPORT_ACCEPT_REP when byte_size(Bin) >= 9 ->
- {ListenFd, Fd} = decode_msg(Bin, [int32, int32]),
- debug(St, "transport_accept_rep: listenfd = ~w, "
- "fd = ~w~n", [ListenFd, Fd]),
- case delete_last_by_fd(ListenFd, Paccepts) of
- {ok, {_, Broker, From}, PAccepts} ->
- Reply = {ok, Fd, Proxylsport},
- gen_server:reply(From, Reply),
- debug(St, "transport_accept_rep: From = ~w\n", [From]),
- Cons = add({Fd, Broker, From}, StCons),
- {noreply, St#st{cons = Cons, paccepts = PAccepts}};
- _Other ->
- %% Already closed
- {noreply, St}
- end;
-
- %%
- %% ssl_accept
- %%
- ?SSL_ACCEPT_ERR when byte_size(Bin) >= 5 ->
- {Fd, Reason} = decode_msg(Bin, [int32, atom]),
- debug(St, "ssl_accept_err: listenfd = ~w, "
- "reason = ~w~n", [Fd, Reason]),
- %% JC: remove this?
- case delete_last_by_fd(Fd, StCons) of
- {ok, {_, _, From}, Cons} ->
- gen_server:reply(From, {error, Reason}),
- {noreply, St#st{cons = Cons}};
- _Other ->
- %% Already closed
- {noreply, St}
- end;
- ?SSL_ACCEPT_REP when byte_size(Bin) >= 5 ->
- Fd = decode_msg(Bin, [int32]),
- debug(St, "ssl_accept_rep: Fd = ~w\n", [Fd]),
- case replace_from_by_fd(Fd, StCons, []) of
- {ok, {_, _, From}, Cons} ->
- gen_server:reply(From, ok),
- {noreply, St#st{cons = Cons}};
- _ ->
- {noreply, St}
- end;
-
- %%
- %% connect
- %%
- ?CONNECT_SYNC_ERR when byte_size(Bin) >= 5 ->
- {IntRef, Reason} = decode_msg(Bin, [int32, atom]),
- debug(St, "connect_sync_err: intref = ~w, "
- "reason = ~w~n", [IntRef, Reason]),
- case delete_by_intref(IntRef, StCons) of
- {ok, {_, _, From}, Cons} ->
- gen_server:reply(From, {error, Reason}),
- {noreply, St#st{cons = Cons}};
- _Other ->
- {noreply, St}
- end;
- ?CONNECT_WAIT when byte_size(Bin) >= 9 ->
- {IntRef, Fd} = decode_msg(Bin, [int32, int32]),
- debug(St, "connect_wait: intref = ~w, "
- "fd = ~w~n", [IntRef, Fd]),
- case replace_fd_by_intref(IntRef, StCons, Fd) of
- {ok, _, Cons} ->
- %% We reply when we get CONNECT_REP or CONNECT_ERR
- {noreply, St#st{cons = Cons}};
- _Other ->
- %% We have a new Fd which must be closed
- send_cmd(Port, ?CLOSE, int32(Fd)),
- {noreply, St}
- end;
- ?CONNECT_REP when byte_size(Bin) >= 5 ->
- %% after CONNECT_WAIT
- Fd = decode_msg(Bin, [int32]),
- debug(St, "connect_rep: fd = ~w~n", [Fd]),
- case replace_from_by_fd(Fd, StCons, []) of
- {ok, {_, _, From}, Cons} ->
- gen_server:reply(From, {ok, Fd, Proxylsport}),
- {noreply, St#st{cons = Cons}};
- _Other ->
- {noreply, St}
- end;
- ?CONNECT_ERR when byte_size(Bin) >= 5 ->
- {Fd, Reason} = decode_msg(Bin, [int32, atom]),
- debug(St, "connect_err: fd = ~w, "
- "reason = ~w~n", [Fd, Reason]),
- case delete_by_fd(Fd, StCons) of
- {ok, {_, _, From}, Cons} ->
- %% Fd not yet published - hence close ourselves
- send_cmd(Port, ?CLOSE, int32(Fd)),
- gen_server:reply(From, {error, Reason}),
- {noreply, St#st{cons = Cons}};
- _Other ->
- %% Already closed
- {noreply, St}
- end;
-
- %%
- %% connection_info
- %%
- ?GETCONNINFO_REP when byte_size(Bin) >= 5 ->
- {Fd, Protocol, Cipher} = decode_msg(Bin, [int32, string, string]),
- debug(St, "connection_info_rep: fd = ~w, "
- "protcol = ~p, ip = ~p~n", [Fd, Protocol, Cipher]),
- case replace_from_by_fd(Fd, StCons, []) of
- {ok, {_, _, From}, Cons} ->
- gen_server:reply(From, {ok, {protocol_name(Protocol),
- Cipher}}),
- {noreply, St#st{cons = Cons}};
- _Other ->
- %% Already closed
- {noreply, St}
- end;
- ?GETCONNINFO_ERR when byte_size(Bin) >= 5 ->
- {Fd, Reason} = decode_msg(Bin, [int32, atom]),
- debug(St, "connection_info_err: fd = ~w, "
- "reason = ~w~n", [Fd, Reason]),
- case replace_from_by_fd(Fd, StCons, []) of
- {ok, {_, _, From}, Cons} ->
- gen_server:reply(From, {error, Reason}),
- {noreply, St#st{cons = Cons}};
- _Other ->
- %% Already closed
- {noreply, St}
- end;
-
- %%
- %% listen
- %%
- ?LISTEN_SYNC_ERR when byte_size(Bin) >= 5 ->
- {IntRef, Reason} = decode_msg(Bin, [int32, atom]),
- debug(St, "listen_sync_err: intref = ~w, "
- "reason = ~w~n", [IntRef, Reason]),
- case delete_by_intref(IntRef, StCons) of
- {ok, {_, _, From}, Cons} ->
- gen_server:reply(From, {error, Reason}),
- {noreply, St#st{cons = Cons}};
- _Other ->
- {noreply, St}
- end;
- ?LISTEN_REP when byte_size(Bin) >= 11 ->
- {IntRef, ListenFd, LPort} = decode_msg(Bin, [int32, int32, int16]),
- debug(St, "listen_rep: intref = ~w, "
- "listenfd = ~w, sport = ~w~n", [IntRef, ListenFd, LPort]),
- case replace_fd_from_by_intref(IntRef, StCons, ListenFd, []) of
- {ok, {_, _, From}, Cons} ->
- gen_server:reply(From, {ok, ListenFd, LPort}),
- {noreply, St#st{cons = Cons}};
- _Other ->
- %% ListenFd has to be closed.
- send_cmd(Port, ?CLOSE, int32(ListenFd)),
- {noreply, St}
- end;
-
- %%
- %% proxy join
- %%
- ?PROXY_JOIN_REP when byte_size(Bin) >= 5 ->
- Fd = decode_msg(Bin, [int32]),
- debug(St, "proxy_join_rep: fd = ~w~n",
- [Fd]),
- case get_by_fd(Fd, StCons) of
- {ok, {_, _, From}} ->
- gen_server:reply(From, ok),
- {noreply, St};
- _Other ->
- %% Already closed
- {noreply, St}
- end;
- ?PROXY_JOIN_ERR when byte_size(Bin) >= 5 ->
- {Fd, Reason} = decode_msg(Bin, [int32, atom]),
- debug(St, "proxy_join_rep: fd = ~w, "
- "reason = ~w~n", [Fd, Reason]),
- case delete_by_fd(Fd, StCons) of
- {ok, {_, _, From}, Cons} ->
- case Reason of
- enoproxysocket ->
- send_cmd(Port, ?CLOSE, int32(Fd));
- _ ->
- ok
- %% Must not close Fd since it is published
- end,
- gen_server:reply(From, {error, Reason}),
- {noreply, St#st{cons = Cons}};
- _Other ->
- %% Already closed
- {noreply, St}
- end;
-
- %%
- %% peername
- %%
- ?GETPEERNAME_REP when byte_size(Bin) >= 5 ->
- {Fd, LPort, IPString} = decode_msg(Bin, [int32, int16, string]),
- debug(St, "getpeername_rep: fd = ~w, "
- "sport = ~w, ip = ~p~n", [Fd, LPort, IPString]),
- case replace_from_by_fd(Fd, StCons, []) of
- {ok, {_, _, From}, Cons} ->
- gen_server:reply(From, {ok, {IPString, LPort}}),
- {noreply, St#st{cons = Cons}};
- _Other ->
- %% Already closed
- {noreply, St}
- end;
- ?GETPEERNAME_ERR when byte_size(Bin) >= 5 ->
- {Fd, Reason} = decode_msg(Bin, [int32, atom]),
- debug(St, "getpeername_err: fd = ~w, "
- "reason = ~w~n", [Fd, Reason]),
- case replace_from_by_fd(Fd, StCons, []) of
- {ok, {_, _, From}, Cons} ->
- gen_server:reply(From, {error, Reason}),
- {noreply, St#st{cons = Cons}};
- _Other ->
- %% Already closed
- {noreply, St}
- end;
-
- %%
- %% ioctl
- %%
- ?IOCTL_OK when byte_size(Bin) >= 5 ->
- Fd = decode_msg(Bin, [int32]),
- debug(St, "ioctl_ok: fd = ~w~n",
- [Fd]),
- case replace_from_by_fd(Fd, StCons, []) of
- {ok, {_, _, From}, Cons} ->
- gen_server:reply(From, ok),
- {noreply, St#st{cons = Cons}};
- _Other ->
- %% Already closed
- {noreply, St}
- end;
- ?IOCTL_ERR when byte_size(Bin) >= 5 ->
- {Fd, Reason} = decode_msg(Bin, [int32, atom]),
- debug(St, "ioctl_err: fd = ~w, "
- "reason = ~w~n", [Fd, Reason]),
- case replace_from_by_fd(Fd, StCons, []) of
- {ok, {_, _, From}, Cons} ->
- gen_server:reply(From, {error, Reason}),
- {noreply, St#st{cons = Cons}};
- _Other ->
- %% Already closed
- {noreply, St}
- end;
-
- %%
- %% sockname
- %%
- ?GETSOCKNAME_REP when byte_size(Bin) >= 5 ->
- {Fd, LPort, IPString} = decode_msg(Bin, [int32, int16, string]),
- debug(St, "getsockname_rep: fd = ~w, "
- "sport = ~w, ip = ~p~n", [Fd, LPort, IPString]),
- case replace_from_by_fd(Fd, StCons, []) of
- {ok, {_, _, From}, Cons} ->
- gen_server:reply(From, {ok, {IPString, LPort}}),
- {noreply, St#st{cons = Cons}};
- _Other ->
- %% Already closed
- {noreply, St}
- end;
- ?GETSOCKNAME_ERR when byte_size(Bin) >= 5 ->
- {Fd, Reason} = decode_msg(Bin, [int32, atom]),
- debug(St, "getsockname_err: fd = ~w, "
- "reason = ~w~n", [Fd, Reason]),
- case replace_from_by_fd(Fd, StCons, []) of
- {ok, {_, _, From}, Cons} ->
- gen_server:reply(From, {error, Reason}),
- {noreply, St#st{cons = Cons}};
- _Other ->
- %% Already closed
- {noreply, St}
- end;
-
- %%
- %% peercert
- %%
- ?GETPEERCERT_REP when byte_size(Bin) >= 5 ->
- {Fd, Cert} = decode_msg(Bin, [int32, bin]),
- debug(St, "getpeercert_rep: fd = ~w~n", [Fd]),
- case replace_from_by_fd(Fd, StCons, []) of
- {ok, {_, _, From}, Cons} ->
- gen_server:reply(From, {ok, Cert}),
- {noreply, St#st{cons = Cons}};
- _Other ->
- %% Already closed
- {noreply, St}
- end;
- ?GETPEERCERT_ERR when byte_size(Bin) >= 5 ->
- {Fd, Reason} = decode_msg(Bin, [int32, atom]),
- debug(St, "getpeercert_err: fd = ~w, reason = ~w~n",
- [Fd, Reason]),
- case replace_from_by_fd(Fd, StCons, []) of
- {ok, {_, _, From}, Cons} ->
- gen_server:reply(From, {error, Reason}),
- {noreply, St#st{cons = Cons}};
- _Other ->
- %% Already closed
- {noreply, St}
- end
- end;
-
-%%
-%% EXIT
-%%
-handle_info({'EXIT', Pid, Reason}, St) when is_pid(Pid) ->
- debug(St, "exit pid = ~w, "
- "reason = ~w~n", [Pid, Reason]),
- case delete_by_pid(Pid, St#st.cons) of
- {ok, {{intref, _}, Pid, _}, Cons} ->
- {noreply, St#st{cons = Cons}};
- {ok, {Fd, Pid, _}, Cons} ->
- send_cmd(St#st.port, ?CLOSE, int32(Fd)),
- %% If Fd is a listen socket fd, there might be pending
- %% accepts for that fd.
- case delete_all_by_fd(Fd, St#st.paccepts) of
- {ok, DelAccepts, RemAccepts} ->
- %% Reply {error, closed} to all pending accepts.
- lists:foreach(fun({_, _, From}) ->
- gen_server:reply(From,
- {error, closed})
- end, DelAccepts),
- {noreply,
- St#st{cons = Cons, paccepts = RemAccepts}};
- _ ->
- {noreply, St#st{cons = Cons}}
- end;
- _ ->
- case delete_by_pid(Pid, St#st.paccepts) of
- {ok, {ListenFd, _, _}, PAccepts} ->
- %% decrement ref count in port program
- send_cmd(St#st.port, ?NOACCEPT, int32(ListenFd)),
- {noreply, St#st{paccepts = PAccepts}};
- _ ->
- {noreply, St}
- end
- end;
-
-%%
-%% 'badsig' means bad message to port. Port program is unaffected.
-%%
-handle_info({'EXIT', Port, badsig}, #st{port = Port} = St) ->
- debug(St, "badsig!!!~n", []),
- {noreply, St};
-
-handle_info({'EXIT', Port, Reason}, #st{port = Port} = St) ->
- {stop, Reason, St};
-
-handle_info(Info, St) ->
- debug(St, "unexpected info: ~w~n", [Info]),
- {noreply, St}.
-
-%%
-%% terminate(Reason, St) -> any
-%%
-terminate(_Reason, _St) ->
- ok.
-
-%%
-%% code_change(OldVsn, St, Extra) -> {ok, NSt}
-%%
-code_change(_OldVsn, St, _Extra) ->
- {ok, St}.
-
-%%%----------------------------------------------------------------------
-%%% Internal functions
-%%%----------------------------------------------------------------------
-
-%%
-%% Send binary command to sock
-%%
-send_cmd(Port, Cmd, Args) ->
- Port ! {self(), {command, [Cmd| Args]}}.
-
-%%
-%% add(Descr, Cons) -> NCons
-%%
-add(D, L) ->
- [D| L].
-
-%%
-%% get_by_fd(Fd, Cons) -> {ok, Descr} | not_found
-%%
-get_by_fd(Fd, Cons) ->
- get_by_pos(Fd, 1, Cons).
-
-%%
-%% delete_by_fd(Fd, Cons) -> {ok, OldDesc, NewCons} | not_found.
-%%
-delete_by_fd(Fd, Cons) ->
- delete_by_pos(Fd, 1, Cons).
-
-%%
-%% delete_all_by_fd(Fd, Cons) -> {ok, DelCons, RemCons} | not_found.
-%%
-delete_all_by_fd(Fd, Cons) ->
- delete_all_by_pos(Fd, 1, Cons).
-
-%%
-%% delete_by_intref(IntRef, Cons) -> {ok, OldDesc, NewCons} | not_found.
-%%
-delete_by_intref(IntRef, Cons) ->
- delete_by_pos({intref, IntRef}, 1, Cons).
-
-%%
-%% delete_by_pid(Pid, Cons) -> {ok, OldDesc, NewCons} | not_found.
-%%
-delete_by_pid(Pid, Cons) ->
- delete_by_pos(Pid, 2, Cons).
-
-%%
-%% delete_last_by_fd(Fd, Cons) -> {ok, OldDesc, NCons} | not_found
-%%
-delete_last_by_fd(Fd, Cons) ->
- case dlbf(Fd, Cons) of
- {X, L} ->
- {ok, X, L};
- _Other ->
- not_found
- end.
-
-dlbf(Fd, [H]) ->
- last_elem(Fd, H, []);
-dlbf(Fd, [H|T]) ->
- case dlbf(Fd, T) of
- {X, L} ->
- {X, [H|L]};
- L ->
- last_elem(Fd, H, L)
- end;
-dlbf(_Fd, []) ->
- [].
-
-last_elem(Fd, H, L) when element(1, H) == Fd ->
- {H, L};
-last_elem(_, H, L) ->
- [H|L].
-
-
-%%
-%% replace_from_by_fd(Fd, Cons, From) -> {ok, OldDesc, NewList} | not_found
-%%
-replace_from_by_fd(Fd, Cons, From) ->
- replace_posn_by_pos(Fd, 1, Cons, [{From, 3}]).
-
-%%
-%% replace_fd_by_intref(IntRef, Cons, Fd) -> {ok, OldDesc, NewList} | not_f.
-%%
-replace_fd_by_intref(IntRef, Cons, Fd) ->
- replace_posn_by_pos({intref, IntRef}, 1, Cons, [{Fd, 1}]).
-
-%%
-%% replace_fd_from_by_intref(IntRef, Cons, NFd, From) ->
-%% {ok, OldDesc, NewList} | not_found
-%%
-replace_fd_from_by_intref(IntRef, Cons, NFd, From) ->
- replace_posn_by_pos({intref, IntRef}, 1, Cons, [{NFd, 1}, {From, 3}]).
-
-
-%%
-%% All *_by_pos functions
-%%
-
-get_by_pos(Key, Pos, [H|_]) when element(Pos, H) == Key ->
- {ok, H};
-get_by_pos(Key, Pos, [_|T]) ->
- get_by_pos(Key, Pos, T);
-get_by_pos(_, _, []) ->
- not_found.
-
-delete_by_pos(Key, Pos, Cons) ->
- case delete_by_pos1(Key, Pos, {not_found, Cons}) of
- {not_found, _} ->
- not_found;
- {ODesc, NCons} ->
- {ok, ODesc, NCons}
- end.
-delete_by_pos1(Key, Pos, {_R, [H|T]}) when element(Pos, H) == Key ->
- {H, T};
-delete_by_pos1(Key, Pos, {R, [H|T]}) ->
- {R0, T0} = delete_by_pos1(Key, Pos, {R, T}),
- {R0, [H| T0]};
-delete_by_pos1(_, _, {R, []}) ->
- {R, []}.
-
-delete_all_by_pos(Key, Pos, Cons) ->
- case lists:foldl(fun(H, {Ds, Rs}) when element(Pos, H) == Key ->
- {[H|Ds], Rs};
- (H, {Ds, Rs}) ->
- {Ds, [H|Rs]}
- end, {[], []}, Cons) of
- {[], _} ->
- not_found;
- {DelCons, RemCons} ->
- {ok, DelCons, RemCons}
- end.
-
-replace_posn_by_pos(Key, Pos, Cons, Repls) ->
- replace_posn_by_pos1(Key, Pos, Cons, Repls, []).
-
-replace_posn_by_pos1(Key, Pos, [H0| T], Repls, Acc)
- when element(Pos, H0) =:= Key ->
- H = lists:foldl(fun({Val, VPos}, Tuple) ->
- setelement(VPos, Tuple, Val)
- end, H0, Repls),
- {ok, H0, lists:reverse(Acc, [H| T])};
-replace_posn_by_pos1(Key, Pos, [H|T], Repls, Acc) ->
- replace_posn_by_pos1(Key, Pos, T, Repls, [H| Acc]);
-replace_posn_by_pos1(_, _, [], _, _) ->
- not_found.
-
-%%
-%% Binary/integer conversions
-%%
-int16(I) ->
- %%[(I bsr 8) band 255, I band 255].
- <<I:16>>.
-
-int32(I) ->
- %% [(I bsr 24) band 255,
- %% (I bsr 16) band 255,
- %% (I bsr 8) band 255,
- %% I band 255].
- <<I:32>>.
-
-%% decode_msg(Bin, Format) -> Tuple | integer() | atom() | string() |
-%% list of binaries()
-%%
-%% Decode message from binary
-%% Format = [spec()]
-%% spec() = int16 | int32 | string | atom | bin | bins
-%%
-%% Notice: The first byte (op code) of the binary message is removed.
-%% Notice: bins returns a *list* of binaries.
-%%
-decode_msg(<<_, Bin/binary>>, Format) ->
- Dec = dec(Format, Bin),
- case Dec of
- [Dec1] -> Dec1;
- _ -> list_to_tuple(Dec)
- end.
-
-dec([], _) ->
- [];
-dec([int16| F], <<N:16, Bin/binary>>) ->
- [N| dec(F, Bin)];
-dec([int32| F], <<N:32, Bin/binary>>) ->
- [N| dec(F, Bin)];
-dec([string| F], Bin0) ->
- {Cs, Bin1} = dec_string(Bin0),
- [Cs| dec(F, Bin1)];
-dec([atom|F], Bin0) ->
- {Cs, Bin1} = dec_string(Bin0),
- [list_to_atom(Cs)| dec(F, Bin1)];
-
-dec([bin|F], Bin) ->
- {Bin1, Bin2} = dec_bin(Bin),
- [Bin1| dec(F, Bin2)].
-
-%% NOTE: This clause is not actually used yet.
-%% dec([bins|F], <<N:32, Bin0/binary>>) ->
-%% {Bins, Bin1} = dec_bins(N, Bin0),
-%% [Bins| dec(F, Bin1)].
-
-dec_string(Bin) ->
- dec_string(Bin, []).
-
-dec_string(<<0, Bin/binary>>, RCs) ->
- {lists:reverse(RCs), Bin};
-dec_string(<<C, Bin/binary>>, RCs) ->
- dec_string(Bin, [C| RCs]).
-
-dec_bin(<<L:32, Bin0/binary>>) ->
- <<Bin1:L/binary, Bin2/binary>> = Bin0,
- {Bin1, Bin2}.
-
-%% dec_bins(N, Bin) ->
-%% dec_bins(N, Bin, []).
-
-%% dec_bins(0, Bin, Acc) ->
-%% {lists:reverse(Acc), Bin};
-%% dec_bins(N, Bin0, Acc) when N > 0 ->
-%% {Bin1, Bin2} = dec_bin(Bin0),
-%% dec_bins(N - 1, Bin2, [Bin1| Acc]).
-
-%%
-%% new_intref
-%%
-new_intref(St) ->
- (St#st.intref + 1) band 16#ffffffff.
-
-%%
-%% {Program, Flags} = mk_cmd_line(DefaultProgram)
-%%
-mk_cmd_line(Default) ->
- {port_program(Default),
- lists:flatten([debug_flag(), " ", debug_port_flag(), " ",
- debugdir_flag(), " ",
- msgdebug_flag(), " ", proxylsport_flag(), " ",
- proxybacklog_flag(), " ", ephemeral_rsa_flag(), " ",
- ephemeral_dh_flag(), " ",
- protocol_version_flag(), " "])}.
-
-port_program(Default) ->
- case application:get_env(ssl, port_program) of
- {ok, Program} when is_list(Program) ->
- Program;
- _Other ->
- Default
- end.
-
-%%
-%% As this server may be started by the distribution, it is not safe to assume
-%% a working code server, neither a working file server.
-%% I try to utilize the most primitive interfaces available to determine
-%% the directory of the port_program.
-%%
-find_priv_bin() ->
- PrivDir = case (catch code:priv_dir(ssl)) of
- {'EXIT', _} ->
- %% Code server probably not startet yet
- {ok, P} = erl_prim_loader:get_path(),
- ModuleFile = atom_to_list(?MODULE) ++ extension(),
- Pd = (catch lists:foldl
- (fun(X,Acc) ->
- M = filename:join([X, ModuleFile]),
- %% The file server probably not started
- %% either, has to use raw interface.
- case file:raw_read_file_info(M) of
- {ok,_} ->
- %% Found our own module in the
- %% path, lets bail out with
- %% the priv_dir of this directory
- Y = filename:split(X),
- throw(filename:join
- (lists:sublist
- (Y,length(Y) - 1)
- ++ ["priv"]));
- _ ->
- Acc
- end
- end,
- false,P)),
- case Pd of
- false ->
- exit(ssl_priv_dir_indeterminate);
- _ ->
- Pd
- end;
- Dir ->
- Dir
- end,
- filename:join([PrivDir, "bin"]).
-
-extension() ->
- %% erlang:info(machine) returns machine name as text in all uppercase
- "." ++ string:to_lower(erlang:system_info(machine)).
-
-debug_flag() ->
- case os:getenv("ERL_SSL_DEBUG") of
- false ->
- get_env(debug, "-d");
- _ ->
- "-d"
- end.
-
-debug_port_flag() ->
- case os:getenv("ERL_SSL_DEBUGPORT") of
- false ->
- get_env(debug, "-d");
- _ ->
- "-d"
- end.
-
-msgdebug_flag() ->
- case os:getenv("ERL_SSL_MSGDEBUG") of
- false ->
- get_env(msgdebug, "-dm");
- _ ->
- "-dm"
- end.
-
-proxylsport_flag() ->
- case application:get_env(ssl, proxylsport) of
- {ok, PortNum} ->
- "-pp " ++ integer_to_list(PortNum);
- _Other ->
- ""
- end.
-
-proxybacklog_flag() ->
- case application:get_env(ssl, proxylsbacklog) of
- {ok, Size} ->
- "-pb " ++ integer_to_list(Size);
- _Other ->
- ""
- end.
-
-debugdir_flag() ->
- case os:getenv("ERL_SSL_DEBUG") of
- false ->
- case application:get_env(ssl, debugdir) of
- {ok, Dir} when is_list(Dir) ->
- "-dd " ++ Dir;
- _Other ->
- ""
- end;
- _ ->
- "-dd ./"
- end.
-
-ephemeral_rsa_flag() ->
- case application:get_env(ssl, ephemeral_rsa) of
- {ok, true} ->
- "-ersa ";
- _Other ->
- ""
- end.
-
-ephemeral_dh_flag() ->
- case application:get_env(ssl, ephemeral_dh) of
- {ok, true} ->
- "-edh ";
- _Other ->
- ""
- end.
-
-protocol_version_flag() ->
- case application:get_env(ssl, protocol_version) of
- {ok, []} ->
- "";
- {ok, Vsns} when is_list(Vsns) ->
- case transform_vsns(Vsns) of
- N when (N > 0) ->
- "-pv " ++ integer_to_list(N);
- _ ->
- ""
- end;
- _Other ->
- ""
- end.
-
-transform_vsns(Vsns) ->
- transform_vsns(Vsns, 0).
-
-transform_vsns([sslv2| Vsns], I) ->
- transform_vsns(Vsns, I bor ?SSLv2);
-transform_vsns([sslv3| Vsns], I) ->
- transform_vsns(Vsns, I bor ?SSLv3);
-transform_vsns([tlsv1| Vsns], I) ->
- transform_vsns(Vsns, I bor ?TLSv1);
-transform_vsns([_ | Vsns], I) ->
- transform_vsns(Vsns, I);
-transform_vsns([], I) ->
- I.
-
-protocol_name("SSLv2") -> sslv2;
-protocol_name("SSLv3") -> sslv3;
-protocol_name("TLSv1") -> tlsv1.
-
-get_env(Key, Val) ->
- case application:get_env(ssl, Key) of
- {ok, true} ->
- Val;
- _Other ->
- ""
- end.
-
-ip_to_string({A,B,C,D}) ->
- [integer_to_list(A),$.,integer_to_list(B),$.,
- integer_to_list(C),$.,integer_to_list(D)].
-
-debug(St, Format, Args) ->
- debug1(St#st.debug, Format, Args).
-
-debug1(true, Format0, Args) ->
- {_MS, S, MiS} = erlang:now(),
- Secs = S rem 100,
- MiSecs = MiS div 1000,
- Format = "++++ ~3..0w:~3..0w ssl_server (~w): " ++ Format0,
- io:format(Format, [Secs, MiSecs, self()| Args]);
-debug1(_, _, _) ->
- ok.
diff --git a/lib/ssl/src/ssl_session.erl b/lib/ssl/src/ssl_session.erl
index bf738649f6..df5d7e0146 100644
--- a/lib/ssl/src/ssl_session.erl
+++ b/lib/ssl/src/ssl_session.erl
@@ -103,9 +103,9 @@ select_session([], _, _) ->
select_session(Sessions, #ssl_options{ciphers = Ciphers,
reuse_sessions = ReuseSession}, OwnCert) ->
- IsResumable =
- fun(Session) ->
- ReuseSession andalso (Session#session.is_resumable) andalso
+ IsResumable =
+ fun(Session) ->
+ ReuseSession andalso resumable(Session#session.is_resumable) andalso
lists:member(Session#session.cipher_suite, Ciphers)
andalso (OwnCert == Session#session.own_certificate)
end,
@@ -147,10 +147,10 @@ is_resumable(SuggestedSessionId, Port, ReuseEnabled, ReuseFun, Cache,
#session{cipher_suite = CipherSuite,
own_certificate = SessionOwnCert,
compression_method = Compression,
- is_resumable = Is_resumable,
+ is_resumable = IsResumable,
peer_certificate = PeerCert} = Session ->
ReuseEnabled
- andalso Is_resumable
+ andalso resumable(IsResumable)
andalso (OwnCert == SessionOwnCert)
andalso valid_session(Session, SecondLifeTime)
andalso ReuseFun(SuggestedSessionId, PeerCert,
@@ -158,3 +158,8 @@ is_resumable(SuggestedSessionId, Port, ReuseEnabled, ReuseFun, Cache,
undefined ->
false
end.
+
+resumable(new) ->
+ false;
+resumable(IsResumable) ->
+ IsResumable.
diff --git a/lib/ssl/src/ssl_sup.erl b/lib/ssl/src/ssl_sup.erl
index 316ed8a4e9..cb10b1362a 100644
--- a/lib/ssl/src/ssl_sup.erl
+++ b/lib/ssl/src/ssl_sup.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1998-2010. All Rights Reserved.
+%% Copyright Ericsson AB 1998-2011. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -24,7 +24,7 @@
-behaviour(supervisor).
%% API
--export([start_link/0]).
+-export([start_link/0, manager_opts/0]).
%% Supervisor callback
-export([init/1]).
@@ -51,17 +51,32 @@ init([]) ->
%% Does not start any port programs so it does matter
%% so much if it is not used!
- Child2 = {ssl_broker_sup, {ssl_broker_sup, start_link, []},
- permanent, 2000, supervisor, [ssl_broker_sup]},
+ %% Child2 = {ssl_broker_sup, {ssl_broker_sup, start_link, []},
+ %% permanent, 2000, supervisor, [ssl_broker_sup]},
%% New ssl
SessionCertManager = session_and_cert_manager_child_spec(),
ConnetionManager = connection_manager_child_spec(),
- {ok, {{one_for_all, 10, 3600}, [Child2, SessionCertManager,
- ConnetionManager]}}.
+ {ok, {{one_for_all, 10, 3600}, [SessionCertManager, ConnetionManager]}}.
+
+manager_opts() ->
+ CbOpts = case application:get_env(ssl, session_cb) of
+ {ok, Cb} when is_atom(Cb) ->
+ InitArgs = session_cb_init_args(),
+ [{session_cb, Cb}, {session_cb_init_args, InitArgs}];
+ _ ->
+ []
+ end,
+ case application:get_env(ssl, session_lifetime) of
+ {ok, Time} when is_integer(Time) ->
+ [{session_lifetime, Time}| CbOpts];
+ _ ->
+ CbOpts
+ end.
+
%%--------------------------------------------------------------------
%%% Internal functions
%%--------------------------------------------------------------------
@@ -86,21 +101,6 @@ connection_manager_child_spec() ->
{Name, StartFunc, Restart, Shutdown, Type, Modules}.
-manager_opts() ->
- CbOpts = case application:get_env(ssl, session_cb) of
- {ok, Cb} when is_atom(Cb) ->
- InitArgs = session_cb_init_args(),
- [{session_cb, Cb}, {session_cb_init_args, InitArgs}];
- _ ->
- []
- end,
- case application:get_env(ssl, session_lifetime) of
- {ok, Time} when is_integer(Time) ->
- [{session_lifetime, Time}| CbOpts];
- _ ->
- CbOpts
- end.
-
session_cb_init_args() ->
case application:get_env(ssl, session_cb_init_args) of
{ok, Args} when is_list(Args) ->
diff --git a/lib/ssl/src/ssl_tls_dist_proxy.erl b/lib/ssl/src/ssl_tls_dist_proxy.erl
new file mode 100644
index 0000000000..d63eada571
--- /dev/null
+++ b/lib/ssl/src/ssl_tls_dist_proxy.erl
@@ -0,0 +1,325 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2011-2011. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+-module(ssl_tls_dist_proxy).
+
+
+-export([listen/1, accept/1, connect/2, get_remote_id/2]).
+-export([init/1, start_link/0, handle_call/3, handle_cast/2, handle_info/2,
+ terminate/2, code_change/3, ssl_options/2]).
+
+-include_lib("kernel/include/net_address.hrl").
+
+-record(state,
+ {listen,
+ accept_loop
+ }).
+
+-define(PPRE, 4).
+-define(PPOST, 4).
+
+
+%%====================================================================
+%% Internal application API
+%%====================================================================
+
+listen(Name) ->
+ gen_server:call(?MODULE, {listen, Name}, infinity).
+
+accept(Listen) ->
+ gen_server:call(?MODULE, {accept, Listen}, infinity).
+
+connect(Ip, Port) ->
+ gen_server:call(?MODULE, {connect, Ip, Port}, infinity).
+
+get_remote_id(Socket, Node) ->
+ gen_server:call(?MODULE, {get_remote_id, {Socket,Node}}, infinity).
+
+%%====================================================================
+%% gen_server callbacks
+%%====================================================================
+
+start_link() ->
+ gen_server:start_link({local, ?MODULE}, ?MODULE, [], []).
+
+init([]) ->
+ process_flag(priority, max),
+ {ok, #state{}}.
+
+handle_call({listen, Name}, _From, State) ->
+ case gen_tcp:listen(0, [{active, false}, {packet,?PPRE}]) of
+ {ok, Socket} ->
+ {ok, World} = gen_tcp:listen(0, [{active, false}, binary, {packet,?PPRE}]),
+ TcpAddress = get_tcp_address(Socket),
+ WorldTcpAddress = get_tcp_address(World),
+ {_,Port} = WorldTcpAddress#net_address.address,
+ {ok, Creation} = erl_epmd:register_node(Name, Port),
+ {reply, {ok, {Socket, TcpAddress, Creation}},
+ State#state{listen={Socket, World}}};
+ Error ->
+ {reply, Error, State}
+ end;
+
+handle_call({accept, Listen}, {From, _}, State = #state{listen={_, World}}) ->
+ Self = self(),
+ ErtsPid = spawn_link(fun() -> accept_loop(Self, erts, Listen, From) end),
+ WorldPid = spawn_link(fun() -> accept_loop(Self, world, World, Listen) end),
+ {reply, ErtsPid, State#state{accept_loop={ErtsPid, WorldPid}}};
+
+handle_call({connect, Ip, Port}, {From, _}, State) ->
+ Me = self(),
+ Pid = spawn_link(fun() -> setup_proxy(Ip, Port, Me) end),
+ receive
+ {Pid, go_ahead, LPort} ->
+ Res = {ok, Socket} = try_connect(LPort),
+ ok = gen_tcp:controlling_process(Socket, From),
+ flush_old_controller(From, Socket),
+ {reply, Res, State};
+ {Pid, Error} ->
+ {reply, Error, State}
+ end;
+
+handle_call({get_remote_id, {Socket,_Node}}, _From, State) ->
+ Address = get_tcp_address(Socket),
+ {reply, Address, State};
+
+handle_call(_What, _From, State) ->
+ {reply, ok, State}.
+
+handle_cast(_What, State) ->
+ {noreply, State}.
+
+handle_info(_What, State) ->
+ {noreply, State}.
+
+terminate(_Reason, _St) ->
+ ok.
+
+code_change(_OldVsn, St, _Extra) ->
+ {ok, St}.
+
+%%--------------------------------------------------------------------
+%%% Internal functions
+%%--------------------------------------------------------------------
+get_tcp_address(Socket) ->
+ {ok, Address} = inet:sockname(Socket),
+ {ok, Host} = inet:gethostname(),
+ #net_address{
+ address = Address,
+ host = Host,
+ protocol = proxy,
+ family = inet
+ }.
+
+accept_loop(Proxy, erts = Type, Listen, Extra) ->
+ process_flag(priority, max),
+ case gen_tcp:accept(Listen) of
+ {ok, Socket} ->
+ Extra ! {accept,self(),Socket,inet,proxy},
+ receive
+ {_Kernel, controller, Pid} ->
+ ok = gen_tcp:controlling_process(Socket, Pid),
+ flush_old_controller(Pid, Socket),
+ Pid ! {self(), controller};
+ {_Kernel, unsupported_protocol} ->
+ exit(unsupported_protocol)
+ end;
+ Error ->
+ exit(Error)
+ end,
+ accept_loop(Proxy, Type, Listen, Extra);
+
+accept_loop(Proxy, world = Type, Listen, Extra) ->
+ process_flag(priority, max),
+ case gen_tcp:accept(Listen) of
+ {ok, Socket} ->
+ Opts = get_ssl_options(server),
+ case ssl:ssl_accept(Socket, Opts) of
+ {ok, SslSocket} ->
+ PairHandler =
+ spawn_link(fun() ->
+ setup_connection(SslSocket, Extra)
+ end),
+ ok = ssl:controlling_process(SslSocket, PairHandler),
+ flush_old_controller(PairHandler, SslSocket);
+ _ ->
+ gen_tcp:close(Socket)
+ end;
+ Error ->
+ exit(Error)
+ end,
+ accept_loop(Proxy, Type, Listen, Extra).
+
+try_connect(Port) ->
+ case gen_tcp:connect({127,0,0,1}, Port, [{active, false}, {packet,?PPRE}]) of
+ R = {ok, _S} ->
+ R;
+ {error, _R} ->
+ try_connect(Port)
+ end.
+
+setup_proxy(Ip, Port, Parent) ->
+ process_flag(trap_exit, true),
+ Opts = get_ssl_options(client),
+ case ssl:connect(Ip, Port, [{active, true}, binary, {packet,?PPRE}] ++ Opts) of
+ {ok, World} ->
+ {ok, ErtsL} = gen_tcp:listen(0, [{active, true}, binary, {packet,?PPRE}]),
+ #net_address{address={_,LPort}} = get_tcp_address(ErtsL),
+ Parent ! {self(), go_ahead, LPort},
+ case gen_tcp:accept(ErtsL) of
+ {ok, Erts} ->
+ %% gen_tcp:close(ErtsL),
+ loop_conn_setup(World, Erts);
+ Err ->
+ Parent ! {self(), Err}
+ end;
+ Err ->
+ Parent ! {self(), Err}
+ end.
+
+setup_connection(World, ErtsListen) ->
+ process_flag(trap_exit, true),
+ TcpAddress = get_tcp_address(ErtsListen),
+ {_Addr,Port} = TcpAddress#net_address.address,
+ {ok, Erts} = gen_tcp:connect({127,0,0,1}, Port, [{active, true}, binary, {packet,?PPRE}]),
+ ssl:setopts(World, [{active,true}, {packet,?PPRE}]),
+ loop_conn_setup(World, Erts).
+
+loop_conn_setup(World, Erts) ->
+ receive
+ {ssl, World, Data = <<$a, _/binary>>} ->
+ gen_tcp:send(Erts, Data),
+ ssl:setopts(World, [{packet,?PPOST}]),
+ inet:setopts(Erts, [{packet,?PPOST}]),
+ loop_conn(World, Erts);
+ {tcp, Erts, Data = <<$a, _/binary>>} ->
+ ssl:send(World, Data),
+ ssl:setopts(World, [{packet,?PPOST}]),
+ inet:setopts(Erts, [{packet,?PPOST}]),
+ loop_conn(World, Erts);
+ {ssl, World, Data = <<_, _/binary>>} ->
+ gen_tcp:send(Erts, Data),
+ loop_conn_setup(World, Erts);
+ {tcp, Erts, Data = <<_, _/binary>>} ->
+ ssl:send(World, Data),
+ loop_conn_setup(World, Erts);
+ {ssl, World, Data} ->
+ gen_tcp:send(Erts, Data),
+ loop_conn_setup(World, Erts);
+ {tcp, Erts, Data} ->
+ ssl:send(World, Data),
+ loop_conn_setup(World, Erts)
+ end.
+
+loop_conn(World, Erts) ->
+ receive
+ {ssl, World, Data} ->
+ gen_tcp:send(Erts, Data),
+ loop_conn(World, Erts);
+ {tcp, Erts, Data} ->
+ ssl:send(World, Data),
+ loop_conn(World, Erts);
+ {tcp_closed, Erts} ->
+ ssl:close(World);
+ {ssl_closed, World} ->
+ gen_tcp:close(Erts)
+ end.
+
+get_ssl_options(Type) ->
+ case init:get_argument(ssl_dist_opt) of
+ {ok, Args} ->
+ [{erl_dist, true} | ssl_options(Type, lists:append(Args))];
+ _ ->
+ [{erl_dist, true}]
+ end.
+
+ssl_options(_,[]) ->
+ [];
+ssl_options(server, ["client_" ++ _, _Value |T]) ->
+ ssl_options(server,T);
+ssl_options(client, ["server_" ++ _, _Value|T]) ->
+ ssl_options(client,T);
+ssl_options(server, ["server_certfile", Value|T]) ->
+ [{certfile, Value} | ssl_options(server,T)];
+ssl_options(client, ["client_certfile", Value | T]) ->
+ [{certfile, Value} | ssl_options(client,T)];
+ssl_options(server, ["server_cacertfile", Value|T]) ->
+ [{cacertfile, Value} | ssl_options(server,T)];
+ssl_options(client, ["client_cacertfile", Value|T]) ->
+ [{cacertfile, Value} | ssl_options(client,T)];
+ssl_options(server, ["server_keyfile", Value|T]) ->
+ [{keyfile, Value} | ssl_options(server,T)];
+ssl_options(client, ["client_keyfile", Value|T]) ->
+ [{keyfile, Value} | ssl_options(client,T)];
+ssl_options(server, ["server_password", Value|T]) ->
+ [{password, Value} | ssl_options(server,T)];
+ssl_options(client, ["client_password", Value|T]) ->
+ [{password, Value} | ssl_options(client,T)];
+ssl_options(server, ["server_verify", Value|T]) ->
+ [{verify, atomize(Value)} | ssl_options(server,T)];
+ssl_options(client, ["client_verify", Value|T]) ->
+ [{verify, atomize(Value)} | ssl_options(client,T)];
+ssl_options(server, ["server_reuse_sessions", Value|T]) ->
+ [{reuse_sessions, atomize(Value)} | ssl_options(server,T)];
+ssl_options(client, ["client_reuse_sessions", Value|T]) ->
+ [{reuse_sessions, atomize(Value)} | ssl_options(client,T)];
+ssl_options(server, ["server_secure_renegotiate", Value|T]) ->
+ [{secure_renegotiate, atomize(Value)} | ssl_options(server,T)];
+ssl_options(client, ["client_secure_renegotiate", Value|T]) ->
+ [{secure_renegotiate, atomize(Value)} | ssl_options(client,T)];
+ssl_options(server, ["server_depth", Value|T]) ->
+ [{depth, list_to_integer(Value)} | ssl_options(server,T)];
+ssl_options(client, ["client_depth", Value|T]) ->
+ [{depth, list_to_integer(Value)} | ssl_options(client,T)];
+ssl_options(server, ["server_hibernate_after", Value|T]) ->
+ [{hibernate_after, list_to_integer(Value)} | ssl_options(server,T)];
+ssl_options(client, ["client_hibernate_after", Value|T]) ->
+ [{hibernate_after, list_to_integer(Value)} | ssl_options(client,T)];
+ssl_options(server, ["server_ciphers", Value|T]) ->
+ [{ciphers, Value} | ssl_options(server,T)];
+ssl_options(client, ["client_ciphers", Value|T]) ->
+ [{ciphers, Value} | ssl_options(client,T)];
+ssl_options(server, ["server_dhfile", Value|T]) ->
+ [{dhfile, Value} | ssl_options(server,T)];
+ssl_options(server, ["server_fail_if_no_peer_cert", Value|T]) ->
+ [{fail_if_no_peer_cert, atomize(Value)} | ssl_options(server,T)];
+ssl_options(_,_) ->
+ exit(malformed_ssl_dist_opt).
+
+atomize(List) when is_list(List) ->
+ list_to_atom(List);
+atomize(Atom) when is_atom(Atom) ->
+ Atom.
+
+flush_old_controller(Pid, Socket) ->
+ receive
+ {tcp, Socket, Data} ->
+ Pid ! {tcp, Socket, Data},
+ flush_old_controller(Pid, Socket);
+ {tcp_closed, Socket} ->
+ Pid ! {tcp_closed, Socket},
+ flush_old_controller(Pid, Socket);
+ {ssl, Socket, Data} ->
+ Pid ! {ssl, Socket, Data},
+ flush_old_controller(Pid, Socket);
+ {ssl_closed, Socket} ->
+ Pid ! {ssl_closed, Socket},
+ flush_old_controller(Pid, Socket)
+ after 0 ->
+ ok
+ end.
diff --git a/lib/ssl/test/Makefile b/lib/ssl/test/Makefile
index 922abea41b..6b1da63d08 100644
--- a/lib/ssl/test/Makefile
+++ b/lib/ssl/test/Makefile
@@ -39,32 +39,24 @@ MODULES = \
ssl_basic_SUITE \
ssl_handshake_SUITE \
ssl_packet_SUITE \
+ ssl_cipher_SUITE \
ssl_payload_SUITE \
ssl_to_openssl_SUITE \
ssl_session_cache_SUITE \
- ssl_test_MACHINE \
- old_ssl_active_SUITE \
- old_ssl_active_once_SUITE \
- old_ssl_passive_SUITE \
- old_ssl_verify_SUITE \
- old_ssl_peer_cert_SUITE \
- old_ssl_misc_SUITE \
- old_ssl_protocol_SUITE \
- old_transport_accept_SUITE \
- old_ssl_dist_SUITE \
+ ssl_dist_SUITE \
make_certs\
erl_make_certs
ERL_FILES = $(MODULES:%=%.erl)
-HRL_FILES = ssl_test_MACHINE.hrl
+HRL_FILES =
HRL_FILES_SRC = \
- ssl_int.hrl \
ssl_internal.hrl\
ssl_alert.hrl \
ssl_handshake.hrl \
+ ssl_cipher.hrl \
ssl_record.hrl
HRL_FILES_INC =
diff --git a/lib/ssl/test/old_ssl_active_SUITE.erl b/lib/ssl/test/old_ssl_active_SUITE.erl
deleted file mode 100644
index 52ff0bcc5d..0000000000
--- a/lib/ssl/test/old_ssl_active_SUITE.erl
+++ /dev/null
@@ -1,395 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1999-2011. All Rights Reserved.
-%%
-%% The contents of this file are subject to the Erlang Public License,
-%% Version 1.1, (the "License"); you may not use this file except in
-%% compliance with the License. You should have received a copy of the
-%% Erlang Public License along with this software. If not, it can be
-%% retrieved online at http://www.erlang.org/.
-%%
-%% Software distributed under the License is distributed on an "AS IS"
-%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
-%% the License for the specific language governing rights and limitations
-%% under the License.
-%%
-%% %CopyrightEnd%
-%%
-
-%%
--module(old_ssl_active_SUITE).
-
--export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1,
- init_per_group/2,end_per_group/2,
- init_per_testcase/2,
- end_per_testcase/2,
- cinit_return_chkclose/1,
- sinit_return_chkclose/1,
- cinit_big_return_chkclose/1,
- sinit_big_return_chkclose/1,
- cinit_big_echo_chkclose/1,
- cinit_huge_echo_chkclose/1,
- sinit_big_echo_chkclose/1,
- cinit_few_echo_chkclose/1,
- cinit_many_echo_chkclose/1,
- cinit_cnocert/1
- ]).
-
--import(ssl_test_MACHINE, [mk_ssl_cert_opts/1, test_one_listener/7,
- test_server_only/6]).
-
--include_lib("test_server/include/test_server.hrl").
--include("ssl_test_MACHINE.hrl").
-
--define(MANYCONNS, ssl_test_MACHINE:many_conns()).
-
-init_per_testcase(_Case, Config) ->
- WatchDog = ssl_test_lib:timetrap(?DEFAULT_TIMEOUT),
- [{watchdog, WatchDog}| Config].
-
-end_per_testcase(_Case, Config) ->
- WatchDog = ?config(watchdog, Config),
- test_server:timetrap_cancel(WatchDog).
-
-suite() -> [{ct_hooks,[ts_install_cth]}].
-
-all() ->
- [cinit_return_chkclose, sinit_return_chkclose,
- cinit_big_return_chkclose, sinit_big_return_chkclose,
- cinit_big_echo_chkclose, cinit_huge_echo_chkclose,
- sinit_big_echo_chkclose, cinit_few_echo_chkclose,
- cinit_many_echo_chkclose, cinit_cnocert].
-
-groups() ->
- [].
-
-init_per_group(_GroupName, Config) ->
- Config.
-
-end_per_group(_GroupName, Config) ->
- Config.
-
-
-init_per_suite(doc) ->
- "Want to se what Config contains, and record the number of available "
- "file descriptors";
-init_per_suite(suite) ->
- [];
-init_per_suite(Config) ->
- io:format("Config: ~p~n", [Config]),
- case os:type() of
- {unix, _} ->
- ?line io:format("Max fd value: ~s", [os:cmd("ulimit -n")]);
- _ ->
- ok
- end,
- %% XXX Also record: Erlang/SSL version, version of OpenSSL,
- %% operating system, version of OTP, Erts, kernel and stdlib.
-
- %% Check if SSL exists. If this case fails, all other cases are skipped
- case catch crypto:start() of
- ok ->
- application:start(public_key),
- case ssl:start() of
- ok -> ssl:stop();
- {error, {already_started, _}} -> ssl:stop();
- Error -> ?t:fail({failed_starting_ssl,Error})
- end,
- Config;
- _Else ->
- {skip,"Could not start crypto!"}
- end.
-
-end_per_suite(doc) ->
- "This test case has no mission other than closing the conf case";
-end_per_suite(suite) ->
- [];
-end_per_suite(Config) ->
- crypto:stop(),
- Config.
-
-cinit_return_chkclose(doc) ->
- "Client sends 1000 bytes to server, that receives them, sends them "
- "back, and closes. Client waits for close. Both have certs.";
-cinit_return_chkclose(suite) ->
- [];
-cinit_return_chkclose(Config) when list(Config) ->
- process_flag(trap_exit, true),
- DataSize = 1000, LPort = 3456,
- Timeout = 40000, NConns = 1,
-
- ?line {ok, {CsslOpts, SsslOpts}} = mk_ssl_cert_opts(Config),
- ?line {ok, Host} = inet:gethostname(),
-
- LCmds = [{sockopts, [{backlog, NConns}]},
- {sslopts, SsslOpts},
- {listen, LPort},
- wait_sync,
- lclose],
- ACmds = [{timeout, Timeout},
- accept,
- {recv, DataSize}, {send, DataSize},
- close],
- CCmds = [{timeout, Timeout},
- {sslopts, CsslOpts},
- {connect, {Host, LPort}},
- {send, DataSize}, {recv, DataSize},
- await_close],
- ?line test_one_listener(NConns, LCmds, ACmds, CCmds, Timeout, ?MODULE,
- Config).
-
-sinit_return_chkclose(doc) ->
- "Server sends 1000 bytes to client, that receives them, sends them "
- "back, and closes. Server waits for close. Both have certs.";
-sinit_return_chkclose(suite) ->
- [];
-sinit_return_chkclose(Config) when list(Config) ->
- process_flag(trap_exit, true),
- DataSize = 1000, LPort = 3456,
- Timeout = 40000, NConns = 1,
-
- ?line {ok, {CsslOpts, SsslOpts}} = mk_ssl_cert_opts(Config),
- ?line {ok, Host} = inet:gethostname(),
-
- LCmds = [{sockopts, [{backlog, NConns}]},
- {sslopts, [{ssl_imp, old}|SsslOpts]},
- {listen, LPort},
- wait_sync,
- lclose],
- ACmds = [{timeout, Timeout},
- accept,
- {send, DataSize}, {recv, DataSize},
- await_close],
- CCmds = [{timeout, Timeout},
- {sslopts, [{ssl_imp, old}|CsslOpts]},
- {connect, {Host, LPort}},
- {recv, DataSize}, {send, DataSize},
- close],
-
- ?line test_one_listener(NConns, LCmds, ACmds, CCmds, Timeout, ?MODULE,
- Config).
-
-cinit_big_return_chkclose(doc) ->
- "Client sends 50000 bytes to server, that receives them, sends them "
- "back, and closes. Client waits for close. Both have certs.";
-cinit_big_return_chkclose(suite) ->
- [];
-cinit_big_return_chkclose(Config) when list(Config) ->
- process_flag(trap_exit, true),
- DataSize = 50000, LPort = 3456,
- Timeout = 40000, NConns = 1,
-
- ?line {ok, {CsslOpts, SsslOpts}} = mk_ssl_cert_opts(Config),
- ?line {ok, Host} = inet:gethostname(),
-
- LCmds = [{sockopts, [{backlog, NConns}]},
- {sslopts, SsslOpts},
- {listen, LPort},
- wait_sync,
- lclose],
- ACmds = [{timeout, Timeout},
- accept,
- {recv, DataSize}, {send, DataSize},
- close],
- CCmds = [{timeout, Timeout},
- {sslopts, CsslOpts},
- {connect, {Host, LPort}},
- {send, DataSize}, {recv, DataSize},
- await_close],
- ?line test_one_listener(NConns, LCmds, ACmds, CCmds, Timeout, ?MODULE,
- Config).
-
-sinit_big_return_chkclose(doc) ->
- "Server sends 50000 bytes to client, that receives them, sends them "
- "back, and closes. Server waits for close. Both have certs.";
-sinit_big_return_chkclose(suite) ->
- [];
-sinit_big_return_chkclose(Config) when list(Config) ->
- process_flag(trap_exit, true),
- DataSize = 50000, LPort = 3456,
- Timeout = 40000, NConns = 1,
-
- ?line {ok, {CsslOpts, SsslOpts}} = mk_ssl_cert_opts(Config),
- ?line {ok, Host} = inet:gethostname(),
-
- LCmds = [{sockopts, [{backlog, NConns}]},
- {sslopts, SsslOpts},
- {listen, LPort},
- wait_sync,
- lclose],
- ACmds = [{timeout, Timeout},
- accept,
- {send, DataSize}, {recv, DataSize},
- await_close],
- CCmds = [{timeout, Timeout},
- {sslopts, CsslOpts},
- {connect, {Host, LPort}},
- {recv, DataSize}, {send, DataSize},
- close],
-
- ?line test_one_listener(NConns, LCmds, ACmds, CCmds, Timeout, ?MODULE,
- Config).
-
-cinit_big_echo_chkclose(doc) ->
- "Client sends 50000 bytes to server, that echoes them back "
- "and closes. Client waits for close. Both have certs.";
-cinit_big_echo_chkclose(suite) ->
- [];
-cinit_big_echo_chkclose(Config) when list(Config) ->
- process_flag(trap_exit, true),
- DataSize = 50000, LPort = 3456,
- Timeout = 40000, NConns = 1,
-
- ?line {ok, {CsslOpts, SsslOpts}} = mk_ssl_cert_opts(Config),
- ?line {ok, Host} = inet:gethostname(),
-
- LCmds = [{sockopts, [{backlog, NConns}]},
- {sslopts, SsslOpts},
- {listen, LPort},
- wait_sync,
- lclose],
- ACmds = [{timeout, Timeout},
- accept,
- {echo, DataSize},
- close],
- CCmds = [{timeout, Timeout},
- {sslopts, CsslOpts},
- {connect, {Host, LPort}},
- {send, DataSize}, {recv, DataSize},
- await_close],
- ?line test_one_listener(NConns, LCmds, ACmds, CCmds, Timeout, ?MODULE,
- Config).
-
-cinit_huge_echo_chkclose(doc) ->
- "Client sends 500000 bytes to server, that echoes them back "
- "and closes. Client waits for close. Both have certs.";
-cinit_huge_echo_chkclose(suite) ->
- [];
-cinit_huge_echo_chkclose(Config) when list(Config) ->
- process_flag(trap_exit, true),
- DataSize = 500000, LPort = 3456,
- Timeout = 40000, NConns = 1,
-
- ?line {ok, {CsslOpts, SsslOpts}} = mk_ssl_cert_opts(Config),
- ?line {ok, Host} = inet:gethostname(),
-
- LCmds = [{sockopts, [{backlog, NConns}]},
- {sslopts, SsslOpts},
- {listen, LPort},
- wait_sync,
- lclose],
- ACmds = [{timeout, Timeout},
- accept,
- {echo, DataSize},
- close],
- CCmds = [{timeout, Timeout},
- {sslopts, CsslOpts},
- {connect, {Host, LPort}},
- {send, DataSize}, {recv, DataSize},
- await_close],
- ?line test_one_listener(NConns, LCmds, ACmds, CCmds, Timeout, ?MODULE,
- Config).
-
-sinit_big_echo_chkclose(doc) ->
- "Server sends 50000 bytes to client, that echoes them back "
- "and closes. Server waits for close. Both have certs.";
-sinit_big_echo_chkclose(suite) ->
- [];
-sinit_big_echo_chkclose(Config) when list(Config) ->
- process_flag(trap_exit, true),
- DataSize = 50000, LPort = 3456,
- Timeout = 40000, NConns = 1,
-
- ?line {ok, {CsslOpts, SsslOpts}} = mk_ssl_cert_opts(Config),
- ?line {ok, Host} = inet:gethostname(),
-
- LCmds = [{sockopts, [{backlog, NConns}]},
- {sslopts, SsslOpts},
- {listen, LPort},
- wait_sync,
- lclose],
- ACmds = [{timeout, Timeout},
- accept,
- {send, DataSize}, {recv, DataSize},
- await_close],
- CCmds = [{timeout, Timeout},
- {sslopts, CsslOpts},
- {connect, {Host, LPort}},
- {echo, DataSize},
- close],
-
- ?line test_one_listener(NConns, LCmds, ACmds, CCmds, Timeout, ?MODULE,
- Config).
-
-
-%% This case is repeated several times.
-
-cinit_few_echo_chkclose(X) -> cinit_many_echo_chkclose(X, 7).
-
-cinit_many_echo_chkclose(X) -> cinit_many_echo_chkclose(X, ?MANYCONNS).
-
-cinit_many_echo_chkclose(doc, _NConns) ->
- "N client sends 10000 bytes to server, that echoes them back "
- "and closes. Clients wait for close. All have certs.";
-cinit_many_echo_chkclose(suite, _NConns) ->
- [];
-cinit_many_echo_chkclose(Config, NConns) when list(Config) ->
- process_flag(trap_exit, true),
- DataSize = 10000, LPort = 3456,
- Timeout = 80000,
-
- io:format("~w connections", [NConns]),
-
- ?line {ok, {CsslOpts, SsslOpts}} = mk_ssl_cert_opts(Config),
- ?line {ok, Host} = inet:gethostname(),
-
- LCmds = [{sockopts, [{backlog, NConns}]},
- {sslopts, SsslOpts},
- {listen, LPort},
- wait_sync,
- lclose],
- ACmds = [{timeout, Timeout},
- accept,
- {echo, DataSize},
- close],
- CCmds = [{timeout, Timeout},
- {sslopts, CsslOpts},
- {connect, {Host, LPort}},
- {send, DataSize}, {recv, DataSize},
- await_close],
- ?line test_one_listener(NConns, LCmds, ACmds, CCmds, Timeout, ?MODULE,
- Config).
-
-
-cinit_cnocert(doc) ->
- "Client sends 1000 bytes to server, that receives them, sends them "
- "back, and closes. Client waits for close. Client has no cert, "
- "but server has.";
-cinit_cnocert(suite) ->
- [];
-cinit_cnocert(Config) when list(Config) ->
- process_flag(trap_exit, true),
- DataSize = 1000, LPort = 3457,
- Timeout = 40000, NConns = 1,
-
- ?line {ok, {_CsslOpts, SsslOpts}} = mk_ssl_cert_opts(Config),
- ?line {ok, Host} = inet:gethostname(),
-
- LCmds = [{sockopts, [{backlog, NConns}]},
- {sslopts, SsslOpts},
- {listen, LPort},
- wait_sync,
- lclose],
- ACmds = [{timeout, Timeout},
- accept,
- {recv, DataSize}, {send, DataSize},
- close],
- CCmds = [{timeout, Timeout},
- {connect, {Host, LPort}},
- {send, DataSize}, {recv, DataSize},
- await_close],
- ?line test_one_listener(NConns, LCmds, ACmds, CCmds, Timeout, ?MODULE,
- Config).
-
-
diff --git a/lib/ssl/test/old_ssl_active_once_SUITE.erl b/lib/ssl/test/old_ssl_active_once_SUITE.erl
deleted file mode 100644
index c7beadb301..0000000000
--- a/lib/ssl/test/old_ssl_active_once_SUITE.erl
+++ /dev/null
@@ -1,417 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2002-2011. All Rights Reserved.
-%%
-%% The contents of this file are subject to the Erlang Public License,
-%% Version 1.1, (the "License"); you may not use this file except in
-%% compliance with the License. You should have received a copy of the
-%% Erlang Public License along with this software. If not, it can be
-%% retrieved online at http://www.erlang.org/.
-%%
-%% Software distributed under the License is distributed on an "AS IS"
-%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
-%% the License for the specific language governing rights and limitations
-%% under the License.
-%%
-%% %CopyrightEnd%
-%%
-
-%%
--module(old_ssl_active_once_SUITE).
-
--export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1,
- init_per_group/2,end_per_group/2,
- init_per_testcase/2,
- end_per_testcase/2,
- server_accept_timeout/1,
- cinit_return_chkclose/1,
- sinit_return_chkclose/1,
- cinit_big_return_chkclose/1,
- sinit_big_return_chkclose/1,
- cinit_big_echo_chkclose/1,
- cinit_huge_echo_chkclose/1,
- sinit_big_echo_chkclose/1,
- cinit_few_echo_chkclose/1,
- cinit_many_echo_chkclose/1,
- cinit_cnocert/1
- ]).
-
--import(ssl_test_MACHINE, [mk_ssl_cert_opts/1, test_one_listener/7,
- test_server_only/6]).
--include_lib("test_server/include/test_server.hrl").
--include("ssl_test_MACHINE.hrl").
-
--define(MANYCONNS, ssl_test_MACHINE:many_conns()).
-
-init_per_testcase(_Case, Config) ->
- WatchDog = ssl_test_lib:timetrap(?DEFAULT_TIMEOUT),
- [{watchdog, WatchDog}| Config].
-
-end_per_testcase(_Case, Config) ->
- WatchDog = ?config(watchdog, Config),
- test_server:timetrap_cancel(WatchDog).
-
-suite() -> [{ct_hooks,[ts_install_cth]}].
-
-all() ->
- [server_accept_timeout, cinit_return_chkclose,
- sinit_return_chkclose, cinit_big_return_chkclose,
- sinit_big_return_chkclose, cinit_big_echo_chkclose,
- cinit_huge_echo_chkclose, sinit_big_echo_chkclose,
- cinit_few_echo_chkclose, cinit_many_echo_chkclose,
- cinit_cnocert].
-
-groups() ->
- [].
-
-init_per_group(_GroupName, Config) ->
- Config.
-
-end_per_group(_GroupName, Config) ->
- Config.
-
-
-init_per_suite(doc) ->
- "Want to se what Config contains.";
-init_per_suite(suite) ->
- [];
-init_per_suite(Config) ->
- io:format("Config: ~p~n", [Config]),
-
- %% Check if SSL exists. If this case fails, all other cases are skipped
- case catch crypto:start() of
- ok ->
- application:start(public_key),
- case ssl:start() of
- ok -> ssl:stop();
- {error, {already_started, _}} -> ssl:stop();
- Error -> ?t:fail({failed_starting_ssl,Error})
- end,
- Config;
- _Else ->
- {skip,"Could not start crypto"}
- end.
-
-end_per_suite(doc) ->
- "This test case has no mission other than closing the conf case";
-end_per_suite(suite) ->
- [];
-end_per_suite(Config) ->
- crypto:stop(),
- Config.
-
-server_accept_timeout(doc) ->
- "Server has one pending accept with timeout. Checks that return "
- "value is {error, timeout}.";
-server_accept_timeout(suite) ->
- [];
-server_accept_timeout(Config) when list(Config) ->
- process_flag(trap_exit, true),
- LPort = 3456,
- Timeout = 40000, NConns = 1,
- AccTimeout = 3000,
-
- ?line {ok, {_, SsslOpts}} = mk_ssl_cert_opts(Config),
-
- LCmds = [{sockopts, [{backlog, NConns}, {active, once}]},
- {sslopts, SsslOpts},
- {listen, LPort},
- wait_sync,
- lclose],
- ACmds = [{timeout, AccTimeout},
- accept_timeout],
- ?line test_server_only(NConns, LCmds, ACmds, Timeout, ?MODULE,
- Config).
-
-cinit_return_chkclose(doc) ->
- "Client sends 1000 bytes to server, that receives them, sends them "
- "back, and closes. Client waits for close. Both have certs.";
-cinit_return_chkclose(suite) ->
- [];
-cinit_return_chkclose(Config) when list(Config) ->
- process_flag(trap_exit, true),
- DataSize = 1000, LPort = 3456,
- Timeout = 40000, NConns = 1,
-
- ?line {ok, {CsslOpts, SsslOpts}} = mk_ssl_cert_opts(Config),
- ?line {ok, Host} = inet:gethostname(),
-
- LCmds = [{sockopts, [{backlog, NConns}, {active, once}]},
- {sslopts, SsslOpts},
- {listen, LPort},
- wait_sync,
- lclose],
- ACmds = [{timeout, Timeout},
- accept,
- {recv, DataSize}, {send, DataSize},
- close],
- CCmds = [{timeout, Timeout},
- {sockopts, [{active, once}]},
- {sslopts, CsslOpts},
- {connect, {Host, LPort}},
- {send, DataSize}, {recv, DataSize},
- await_close],
- ?line test_one_listener(NConns, LCmds, ACmds, CCmds, Timeout, ?MODULE,
- Config).
-
-sinit_return_chkclose(doc) ->
- "Server sends 1000 bytes to client, that receives them, sends them "
- "back, and closes. Server waits for close. Both have certs.";
-sinit_return_chkclose(suite) ->
- [];
-sinit_return_chkclose(Config) when list(Config) ->
- process_flag(trap_exit, true),
- DataSize = 1000, LPort = 3456,
- Timeout = 40000, NConns = 1,
-
- ?line {ok, {CsslOpts, SsslOpts}} = mk_ssl_cert_opts(Config),
- ?line {ok, Host} = inet:gethostname(),
-
- LCmds = [{sockopts, [{backlog, NConns}, {active, once}]},
- {sslopts, SsslOpts},
- {listen, LPort},
- wait_sync,
- lclose],
- ACmds = [{timeout, Timeout},
- accept,
- {send, DataSize}, {recv, DataSize},
- await_close],
- CCmds = [{timeout, Timeout},
- {sockopts, [{active, once}]},
- {sslopts, CsslOpts},
- {connect, {Host, LPort}},
- {recv, DataSize}, {send, DataSize},
- close],
-
- ?line test_one_listener(NConns, LCmds, ACmds, CCmds, Timeout, ?MODULE,
- Config).
-
-cinit_big_return_chkclose(doc) ->
- "Client sends 50000 bytes to server, that receives them, sends them "
- "back, and closes. Client waits for close. Both have certs.";
-cinit_big_return_chkclose(suite) ->
- [];
-cinit_big_return_chkclose(Config) when list(Config) ->
- process_flag(trap_exit, true),
- DataSize = 50000, LPort = 3456,
- Timeout = 40000, NConns = 1,
-
- ?line {ok, {CsslOpts, SsslOpts}} = mk_ssl_cert_opts(Config),
- ?line {ok, Host} = inet:gethostname(),
-
- %% Set {active, false} so that accept is passive to begin with.
- LCmds = [{sockopts, [{backlog, NConns}, {active, false}]},
- {sslopts, SsslOpts},
- {listen, LPort},
- wait_sync,
- lclose],
- ACmds = [{timeout, Timeout},
- accept,
- {sockopts, [{active, once}]}, % {active, once} here.
- {recv, DataSize}, {send, DataSize},
- close],
- CCmds = [{timeout, Timeout},
- {sockopts, [{active, once}]},
- {sslopts, CsslOpts},
- {connect, {Host, LPort}},
- {send, DataSize}, {recv, DataSize},
- await_close],
- ?line test_one_listener(NConns, LCmds, ACmds, CCmds, Timeout, ?MODULE,
- Config).
-
-sinit_big_return_chkclose(doc) ->
- "Server sends 50000 bytes to client, that receives them, sends them "
- "back, and closes. Server waits for close. Both have certs.";
-sinit_big_return_chkclose(suite) ->
- [];
-sinit_big_return_chkclose(Config) when list(Config) ->
- process_flag(trap_exit, true),
- DataSize = 50000, LPort = 3456,
- Timeout = 40000, NConns = 1,
-
- ?line {ok, {CsslOpts, SsslOpts}} = mk_ssl_cert_opts(Config),
- ?line {ok, Host} = inet:gethostname(),
-
- LCmds = [{sockopts, [{backlog, NConns}, {active, once}]},
- {sslopts, SsslOpts},
- {listen, LPort},
- wait_sync,
- lclose],
- ACmds = [{timeout, Timeout},
- accept,
- {send, DataSize}, {recv, DataSize},
- await_close],
- CCmds = [{timeout, Timeout},
- {sockopts, [{active, once}]},
- {sslopts, CsslOpts},
- {connect, {Host, LPort}},
- {recv, DataSize}, {send, DataSize},
- close],
-
- ?line test_one_listener(NConns, LCmds, ACmds, CCmds, Timeout, ?MODULE,
- Config).
-
-cinit_big_echo_chkclose(doc) ->
- "Client sends 50000 bytes to server, that echoes them back "
- "and closes. Client waits for close. Both have certs.";
-cinit_big_echo_chkclose(suite) ->
- [];
-cinit_big_echo_chkclose(Config) when list(Config) ->
- process_flag(trap_exit, true),
- DataSize = 50000, LPort = 3456,
- Timeout = 40000, NConns = 1,
-
- ?line {ok, {CsslOpts, SsslOpts}} = mk_ssl_cert_opts(Config),
- ?line {ok, Host} = inet:gethostname(),
-
- LCmds = [{sockopts, [{backlog, NConns}, {active, once}]},
- {sslopts, SsslOpts},
- {listen, LPort},
- wait_sync,
- lclose],
- ACmds = [{timeout, Timeout},
- accept,
- {echo, DataSize},
- close],
- CCmds = [{timeout, Timeout},
- {sockopts, [{active, once}]},
- {sslopts, CsslOpts},
- {connect, {Host, LPort}},
- {send, DataSize}, {recv, DataSize},
- await_close],
- ?line test_one_listener(NConns, LCmds, ACmds, CCmds, Timeout, ?MODULE,
- Config).
-
-cinit_huge_echo_chkclose(doc) ->
- "Client sends 500000 bytes to server, that echoes them back "
- "and closes. Client waits for close. Both have certs.";
-cinit_huge_echo_chkclose(suite) ->
- [];
-cinit_huge_echo_chkclose(Config) when list(Config) ->
- process_flag(trap_exit, true),
- DataSize = 500000, LPort = 3456,
- Timeout = 40000, NConns = 1,
-
- ?line {ok, {CsslOpts, SsslOpts}} = mk_ssl_cert_opts(Config),
- ?line {ok, Host} = inet:gethostname(),
-
- LCmds = [{sockopts, [{backlog, NConns}, {active, once}]},
- {sslopts, SsslOpts},
- {listen, LPort},
- wait_sync,
- lclose],
- ACmds = [{timeout, Timeout},
- accept,
- {echo, DataSize},
- close],
- CCmds = [{timeout, Timeout},
- {sockopts, [{active, once}]},
- {sslopts, CsslOpts},
- {connect, {Host, LPort}},
- {send, DataSize}, {recv, DataSize},
- await_close],
- ?line test_one_listener(NConns, LCmds, ACmds, CCmds, Timeout, ?MODULE,
- Config).
-
-sinit_big_echo_chkclose(doc) ->
- "Server sends 50000 bytes to client, that echoes them back "
- "and closes. Server waits for close. Both have certs.";
-sinit_big_echo_chkclose(suite) ->
- [];
-sinit_big_echo_chkclose(Config) when list(Config) ->
- process_flag(trap_exit, true),
- DataSize = 50000, LPort = 3456,
- Timeout = 40000, NConns = 1,
-
- ?line {ok, {CsslOpts, SsslOpts}} = mk_ssl_cert_opts(Config),
- ?line {ok, Host} = inet:gethostname(),
-
- LCmds = [{sockopts, [{backlog, NConns}, {active, once}]},
- {sslopts, SsslOpts},
- {listen, LPort},
- wait_sync,
- lclose],
- ACmds = [{timeout, Timeout},
- accept,
- {send, DataSize}, {recv, DataSize},
- await_close],
- CCmds = [{timeout, Timeout},
- {sockopts, [{active, once}]},
- {sslopts, CsslOpts},
- {connect, {Host, LPort}},
- {echo, DataSize},
- close],
-
- ?line test_one_listener(NConns, LCmds, ACmds, CCmds, Timeout, ?MODULE,
- Config).
-
-cinit_few_echo_chkclose(X) -> cinit_many_echo_chkclose(X, 7).
-
-cinit_many_echo_chkclose(X) -> cinit_many_echo_chkclose(X, ?MANYCONNS).
-
-cinit_many_echo_chkclose(doc, _NConns) ->
- "client send 10000 bytes to server, that echoes them back "
- "and closes. Clients wait for close. All have certs.";
-cinit_many_echo_chkclose(suite, _NConns) ->
- [];
-cinit_many_echo_chkclose(Config, NConns) when list(Config) ->
- process_flag(trap_exit, true),
- DataSize = 10000, LPort = 3456,
- Timeout = 80000,
-
- io:format("~w connections", [NConns]),
-
- ?line {ok, {CsslOpts, SsslOpts}} = mk_ssl_cert_opts(Config),
- ?line {ok, Host} = inet:gethostname(),
-
- LCmds = [{sockopts, [{backlog, NConns}, {active, once}]},
- {sslopts, SsslOpts},
- {listen, LPort},
- wait_sync,
- lclose],
- ACmds = [{timeout, Timeout},
- accept,
- {echo, DataSize},
- close],
- CCmds = [{timeout, Timeout},
- {sockopts, [{active, once}]},
- {sslopts, CsslOpts},
- {connect, {Host, LPort}},
- {send, DataSize}, {recv, DataSize},
- await_close],
- ?line test_one_listener(NConns, LCmds, ACmds, CCmds, Timeout, ?MODULE,
- Config).
-
-cinit_cnocert(doc) ->
- "Client sends 1000 bytes to server, that receives them, sends them "
- "back, and closes. Client waits for close. Client has no cert, "
- "but server has.";
-cinit_cnocert(suite) ->
- [];
-cinit_cnocert(Config) when list(Config) ->
- process_flag(trap_exit, true),
- DataSize = 1000, LPort = 3457,
- Timeout = 40000, NConns = 1,
-
- ?line {ok, {_CsslOpts, SsslOpts}} = mk_ssl_cert_opts(Config),
- ?line {ok, Host} = inet:gethostname(),
-
- LCmds = [{sockopts, [{backlog, NConns}, {active, once}]},
- {sslopts, SsslOpts},
- {listen, LPort},
- wait_sync,
- lclose],
- ACmds = [{timeout, Timeout},
- accept,
- {recv, DataSize}, {send, DataSize},
- close],
- CCmds = [{timeout, Timeout},
- {sockopts, [{active, once}]},
- {connect, {Host, LPort}},
- {send, DataSize}, {recv, DataSize},
- await_close],
- ?line test_one_listener(NConns, LCmds, ACmds, CCmds, Timeout, ?MODULE,
- Config).
-
-
diff --git a/lib/ssl/test/old_ssl_misc_SUITE.erl b/lib/ssl/test/old_ssl_misc_SUITE.erl
deleted file mode 100644
index ea03e83867..0000000000
--- a/lib/ssl/test/old_ssl_misc_SUITE.erl
+++ /dev/null
@@ -1,117 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2003-2011. All Rights Reserved.
-%%
-%% The contents of this file are subject to the Erlang Public License,
-%% Version 1.1, (the "License"); you may not use this file except in
-%% compliance with the License. You should have received a copy of the
-%% Erlang Public License along with this software. If not, it can be
-%% retrieved online at http://www.erlang.org/.
-%%
-%% Software distributed under the License is distributed on an "AS IS"
-%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
-%% the License for the specific language governing rights and limitations
-%% under the License.
-%%
-%% %CopyrightEnd%
-%%
-
-%%
--module(old_ssl_misc_SUITE).
-
--export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1,
- init_per_group/2,end_per_group/2,
- init_per_testcase/2,
- end_per_testcase/2,
- seed/1,
- app/1
- ]).
-
--import(ssl_test_MACHINE, [mk_ssl_cert_opts/1, test_one_listener/7,
- test_server_only/6]).
--include_lib("test_server/include/test_server.hrl").
--include("ssl_test_MACHINE.hrl").
-
--define(MANYCONNS, 5).
-
-init_per_testcase(_Case, Config) ->
- WatchDog = ssl_test_lib:timetrap(?DEFAULT_TIMEOUT),
- [{watchdog, WatchDog}| Config].
-
-end_per_testcase(_Case, Config) ->
- WatchDog = ?config(watchdog, Config),
- test_server:timetrap_cancel(WatchDog).
-
-suite() -> [{ct_hooks,[ts_install_cth]}].
-
-all() ->
- [seed, app].
-
-groups() ->
- [].
-
-init_per_group(_GroupName, Config) ->
- Config.
-
-end_per_group(_GroupName, Config) ->
- Config.
-
-
-init_per_suite(doc) ->
- "Want to se what Config contains.";
-init_per_suite(suite) ->
- [];
-init_per_suite(Config) ->
- io:format("Config: ~p~n", [Config]),
-
- %% Check if SSL exists. If this case fails, all other cases are skipped
- case catch crypto:start() of
- ok ->
- application:start(public_key),
- case ssl:start() of
- ok -> ssl:stop();
- {error, {already_started, _}} -> ssl:stop();
- Error -> ?t:fail({failed_starting_ssl,Error})
- end,
- Config;
- _Else ->
- {skip,"Could not start crypto!"}
- end.
-
-end_per_suite(doc) ->
- "This test case has no mission other than closing the conf case";
-end_per_suite(suite) ->
- [];
-end_per_suite(Config) ->
- crypto:stop(),
- Config.
-
-seed(doc) ->
- "Test that ssl:seed/1 works.";
-seed(suite) ->
- [];
-seed(Config) when list(Config) ->
- process_flag(trap_exit, true),
- LPort = 3456,
- Timeout = 40000, NConns = 1,
-
- ?line {ok, {_, SsslOpts}} = mk_ssl_cert_opts(Config),
-
- LCmds = [{seed, "tjosan"},
- {sockopts, [{backlog, NConns}, {active, once}]},
- {sslopts, SsslOpts},
- {listen, LPort},
- wait_sync,
- lclose],
- ?line test_server_only(NConns, LCmds, [], Timeout, ?MODULE,
- Config).
-
-app(doc) ->
- "Test that the ssl app file is ok";
-app(suite) ->
- [];
-app(Config) when list(Config) ->
- ?line ok = test_server:app_test(ssl).
-
-
diff --git a/lib/ssl/test/old_ssl_passive_SUITE.erl b/lib/ssl/test/old_ssl_passive_SUITE.erl
deleted file mode 100644
index 7b54fe876a..0000000000
--- a/lib/ssl/test/old_ssl_passive_SUITE.erl
+++ /dev/null
@@ -1,382 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1999-2011. All Rights Reserved.
-%%
-%% The contents of this file are subject to the Erlang Public License,
-%% Version 1.1, (the "License"); you may not use this file except in
-%% compliance with the License. You should have received a copy of the
-%% Erlang Public License along with this software. If not, it can be
-%% retrieved online at http://www.erlang.org/.
-%%
-%% Software distributed under the License is distributed on an "AS IS"
-%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
-%% the License for the specific language governing rights and limitations
-%% under the License.
-%%
-%% %CopyrightEnd%
-%%
-
-%%
--module(old_ssl_passive_SUITE).
-
--export([all/0, suite/0,groups/0,init_per_suite/1,
- end_per_suite/1, init_per_group/2,end_per_group/2,
- init_per_testcase/2,
- end_per_testcase/2,
- server_accept_timeout/1,
- cinit_return_chkclose/1,
- sinit_return_chkclose/1,
- cinit_big_return_chkclose/1,
- sinit_big_return_chkclose/1,
- cinit_big_echo_chkclose/1,
- sinit_big_echo_chkclose/1,
- cinit_few_echo_chkclose/1,
- cinit_many_echo_chkclose/1,
- cinit_cnocert/1
- ]).
-
--import(ssl_test_MACHINE, [mk_ssl_cert_opts/1, test_one_listener/7,
- test_server_only/6]).
-
--include_lib("test_server/include/test_server.hrl").
--include("ssl_test_MACHINE.hrl").
-
--define(MANYCONNS, ssl_test_MACHINE:many_conns()).
-
-init_per_testcase(_Case, Config) ->
- WatchDog = ssl_test_lib:timetrap(?DEFAULT_TIMEOUT),
- [{watchdog, WatchDog}| Config].
-
-end_per_testcase(_Case, Config) ->
- WatchDog = ?config(watchdog, Config),
- test_server:timetrap_cancel(WatchDog).
-
-suite() -> [{ct_hooks,[ts_install_cth]}].
-
-all() ->
- [server_accept_timeout, cinit_return_chkclose,
- sinit_return_chkclose, cinit_big_return_chkclose,
- sinit_big_return_chkclose, cinit_big_echo_chkclose,
- sinit_big_echo_chkclose, cinit_few_echo_chkclose,
- cinit_many_echo_chkclose, cinit_cnocert].
-
-groups() ->
- [].
-
-init_per_group(_GroupName, Config) ->
- Config.
-
-end_per_group(_GroupName, Config) ->
- Config.
-
-
-init_per_suite(doc) ->
- "Want to se what Config contains.";
-init_per_suite(suite) ->
- [];
-init_per_suite(Config) ->
- io:format("Config: ~p~n", [Config]),
-
- %% Check if SSL exists. If this case fails, all other cases are skipped
- case catch crypto:start() of
- ok ->
- application:start(public_key),
- case ssl:start() of
- ok -> ssl:stop();
- {error, {already_started, _}} -> ssl:stop();
- Error -> ?t:fail({failed_starting_ssl,Error})
- end,
- Config;
- _Else ->
- {skip,"Could not start crypto"}
- end.
-
-end_per_suite(doc) ->
- "This test case has no mission other than closing the conf case";
-end_per_suite(suite) ->
- [];
-end_per_suite(Config) ->
- crypto:stop(),
- Config.
-
-server_accept_timeout(doc) ->
- "Server has one pending accept with timeout. Checks that return "
- "value is {error, timeout}.";
-server_accept_timeout(suite) ->
- [];
-server_accept_timeout(Config) when list(Config) ->
- process_flag(trap_exit, true),
- LPort = 3456,
- Timeout = 40000, NConns = 1,
- AccTimeout = 3000,
-
- ?line {ok, {_, SsslOpts}} = mk_ssl_cert_opts(Config),
-
- LCmds = [{sockopts, [{backlog, NConns}, {active, false}]},
- {sslopts, SsslOpts},
- {listen, LPort},
- wait_sync,
- lclose],
- ACmds = [{timeout, AccTimeout},
- accept_timeout],
- ?line test_server_only(NConns, LCmds, ACmds, Timeout, ?MODULE, Config).
-
-cinit_return_chkclose(doc) ->
- "Client sends 1000 bytes to server, that receives them, sends them "
- "back, and closes. Client waits for close. Both have certs.";
-cinit_return_chkclose(suite) ->
- [];
-cinit_return_chkclose(Config) when list(Config) ->
- process_flag(trap_exit, true),
- DataSize = 1000, LPort = 3456,
- Timeout = 40000, NConns = 1,
-
- ?line {ok, {CsslOpts, SsslOpts}} = mk_ssl_cert_opts(Config),
- ?line {ok, Host} = inet:gethostname(),
-
- LCmds = [{sockopts, [{backlog, NConns}, {active, false}]},
- {sslopts, SsslOpts},
- {listen, LPort},
- wait_sync,
- lclose],
- ACmds = [{timeout, Timeout},
- accept,
- {recv, DataSize}, {send, DataSize},
- close],
- CCmds = [{timeout, Timeout},
- {sockopts, [{active, false}]},
- {sslopts, CsslOpts},
- {connect, {Host, LPort}},
- {send, DataSize}, {recv, DataSize},
- await_close],
- ?line test_one_listener(NConns, LCmds, ACmds, CCmds, Timeout, ?MODULE,
- Config).
-
-sinit_return_chkclose(doc) ->
- "Server sends 1000 bytes to client, that receives them, sends them "
- "back, and closes. Server waits for close. Both have certs.";
-sinit_return_chkclose(suite) ->
- [];
-sinit_return_chkclose(Config) when list(Config) ->
- process_flag(trap_exit, true),
- DataSize = 1000, LPort = 3456,
- Timeout = 40000, NConns = 1,
-
- ?line {ok, {CsslOpts, SsslOpts}} = mk_ssl_cert_opts(Config),
- ?line {ok, Host} = inet:gethostname(),
-
- LCmds = [{sockopts, [{backlog, NConns}, {active, false}]},
- {sslopts, SsslOpts},
- {listen, LPort},
- wait_sync,
- lclose],
- ACmds = [{timeout, Timeout},
- accept,
- {send, DataSize}, {recv, DataSize},
- await_close],
- CCmds = [{timeout, Timeout},
- {sockopts, [{active, false}]},
- {sslopts, CsslOpts},
- {connect, {Host, LPort}},
- {recv, DataSize}, {send, DataSize},
- close],
-
- ?line test_one_listener(NConns, LCmds, ACmds, CCmds, Timeout, ?MODULE,
- Config).
-
-cinit_big_return_chkclose(doc) ->
- "Client sends 50000 bytes to server, that receives them, sends them "
- "back, and closes. Client waits for close. Both have certs.";
-cinit_big_return_chkclose(suite) ->
- [];
-cinit_big_return_chkclose(Config) when list(Config) ->
- process_flag(trap_exit, true),
- DataSize = 50000, LPort = 3456,
- Timeout = 40000, NConns = 1,
-
- ?line {ok, {CsslOpts, SsslOpts}} = mk_ssl_cert_opts(Config),
- ?line {ok, Host} = inet:gethostname(),
-
- LCmds = [{sockopts, [{backlog, NConns}, {active, false}]},
- {sslopts, SsslOpts},
- {listen, LPort},
- wait_sync,
- lclose],
- ACmds = [{timeout, Timeout},
- accept,
- {recv, DataSize}, {send, DataSize},
- close],
- CCmds = [{timeout, Timeout},
- {sockopts, [{active, false}]},
- {sslopts, CsslOpts},
- {connect, {Host, LPort}},
- {send, DataSize}, {recv, DataSize},
- await_close],
- ?line test_one_listener(NConns, LCmds, ACmds, CCmds, Timeout, ?MODULE,
- Config).
-
-sinit_big_return_chkclose(doc) ->
- "Server sends 50000 bytes to client, that receives them, sends them "
- "back, and closes. Server waits for close. Both have certs.";
-sinit_big_return_chkclose(suite) ->
- [];
-sinit_big_return_chkclose(Config) when list(Config) ->
- process_flag(trap_exit, true),
- DataSize = 50000, LPort = 3456,
- Timeout = 40000, NConns = 1,
-
- ?line {ok, {CsslOpts, SsslOpts}} = mk_ssl_cert_opts(Config),
- ?line {ok, Host} = inet:gethostname(),
-
- LCmds = [{sockopts, [{backlog, NConns}, {active, false}]},
- {sslopts, SsslOpts},
- {listen, LPort},
- wait_sync,
- lclose],
- ACmds = [{timeout, Timeout},
- accept,
- {send, DataSize}, {recv, DataSize},
- await_close],
- CCmds = [{timeout, Timeout},
- {sockopts, [{active, false}]},
- {sslopts, CsslOpts},
- {connect, {Host, LPort}},
- {recv, DataSize}, {send, DataSize},
- close],
-
- ?line test_one_listener(NConns, LCmds, ACmds, CCmds, Timeout, ?MODULE,
- Config).
-
-cinit_big_echo_chkclose(doc) ->
- "Client sends 50000 bytes to server, that echoes them back "
- "and closes. Client waits for close. Both have certs.";
-cinit_big_echo_chkclose(suite) ->
- [];
-cinit_big_echo_chkclose(Config) when list(Config) ->
- process_flag(trap_exit, true),
- DataSize = 50000, LPort = 3456,
- Timeout = 40000, NConns = 1,
-
- ?line {ok, {CsslOpts, SsslOpts}} = mk_ssl_cert_opts(Config),
- ?line {ok, Host} = inet:gethostname(),
-
- LCmds = [{sockopts, [{backlog, NConns}, {active, false}]},
- {sslopts, SsslOpts},
- {listen, LPort},
- wait_sync,
- lclose],
- ACmds = [{timeout, Timeout},
- accept,
- {echo, DataSize},
- close],
- CCmds = [{timeout, Timeout},
- {sockopts, [{active, false}]},
- {sslopts, CsslOpts},
- {connect, {Host, LPort}},
- {send, DataSize}, {recv, DataSize},
- await_close],
- ?line test_one_listener(NConns, LCmds, ACmds, CCmds, Timeout, ?MODULE,
- Config).
-
-sinit_big_echo_chkclose(doc) ->
- "Server sends 50000 bytes to client, that echoes them back "
- "and closes. Server waits for close. Both have certs.";
-sinit_big_echo_chkclose(suite) ->
- [];
-sinit_big_echo_chkclose(Config) when list(Config) ->
- process_flag(trap_exit, true),
- DataSize = 50000, LPort = 3456,
- Timeout = 40000, NConns = 1,
-
- ?line {ok, {CsslOpts, SsslOpts}} = mk_ssl_cert_opts(Config),
- ?line {ok, Host} = inet:gethostname(),
-
- LCmds = [{sockopts, [{backlog, NConns}, {active, false}]},
- {sslopts, SsslOpts},
- {listen, LPort},
- wait_sync,
- lclose],
- ACmds = [{timeout, Timeout},
- accept,
- {send, DataSize}, {recv, DataSize},
- await_close],
- CCmds = [{timeout, Timeout},
- {sockopts, [{active, false}]},
- {sslopts, CsslOpts},
- {connect, {Host, LPort}},
- {echo, DataSize},
- close],
-
- ?line test_one_listener(NConns, LCmds, ACmds, CCmds, Timeout, ?MODULE,
- Config).
-
-
-cinit_few_echo_chkclose(X) -> cinit_many_echo_chkclose(X, 7).
-
-cinit_many_echo_chkclose(X) -> cinit_many_echo_chkclose(X, ?MANYCONNS).
-
-cinit_many_echo_chkclose(doc, _NConns) ->
- "clients send 10000 bytes to server, that echoes them back "
- "and closes. Clients wait for close. All have certs.";
-cinit_many_echo_chkclose(suite, _NConns) ->
- [];
-cinit_many_echo_chkclose(Config, NConns) when list(Config) ->
- process_flag(trap_exit, true),
- DataSize = 10000, LPort = 3456,
- Timeout = 80000,
-
- io:format("~w connections", [NConns]),
-
- ?line {ok, {CsslOpts, SsslOpts}} = mk_ssl_cert_opts(Config),
- ?line {ok, Host} = inet:gethostname(),
-
- LCmds = [{sockopts, [{backlog, NConns}, {active, false}]},
- {sslopts, SsslOpts},
- {listen, LPort},
- wait_sync,
- lclose],
- ACmds = [{timeout, Timeout},
- accept,
- {echo, DataSize},
- close],
- CCmds = [{timeout, Timeout},
- {sockopts, [{active, false}]},
- {sslopts, CsslOpts},
- {connect, {Host, LPort}},
- {send, DataSize}, {recv, DataSize},
- await_close],
- ?line test_one_listener(NConns, LCmds, ACmds, CCmds, Timeout, ?MODULE,
- Config).
-
-cinit_cnocert(doc) ->
- "Client sends 1000 bytes to server, that receives them, sends them "
- "back, and closes. Client waits for close. Client has no cert, "
- "but server has.";
-cinit_cnocert(suite) ->
- [];
-cinit_cnocert(Config) when list(Config) ->
- process_flag(trap_exit, true),
- DataSize = 1000, LPort = 3457,
- Timeout = 40000, NConns = 1,
-
- ?line {ok, {_CsslOpts, SsslOpts}} = mk_ssl_cert_opts(Config),
- ?line {ok, Host} = inet:gethostname(),
-
- LCmds = [{sockopts, [{backlog, NConns}, {active, false}]},
- {sslopts, SsslOpts},
- {listen, LPort},
- wait_sync,
- lclose],
- ACmds = [{timeout, Timeout},
- accept,
- {recv, DataSize}, {send, DataSize},
- close],
- CCmds = [{timeout, Timeout},
- {sockopts, [{active, false}]},
- {connect, {Host, LPort}},
- {send, DataSize}, {recv, DataSize},
- await_close],
- ?line test_one_listener(NConns, LCmds, ACmds, CCmds, Timeout, ?MODULE,
- Config).
-
diff --git a/lib/ssl/test/old_ssl_peer_cert_SUITE.erl b/lib/ssl/test/old_ssl_peer_cert_SUITE.erl
deleted file mode 100644
index ee19bad175..0000000000
--- a/lib/ssl/test/old_ssl_peer_cert_SUITE.erl
+++ /dev/null
@@ -1,191 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2003-2011. All Rights Reserved.
-%%
-%% The contents of this file are subject to the Erlang Public License,
-%% Version 1.1, (the "License"); you may not use this file except in
-%% compliance with the License. You should have received a copy of the
-%% Erlang Public License along with this software. If not, it can be
-%% retrieved online at http://www.erlang.org/.
-%%
-%% Software distributed under the License is distributed on an "AS IS"
-%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
-%% the License for the specific language governing rights and limitations
-%% under the License.
-%%
-%% %CopyrightEnd%
-%%
-
-%%
--module(old_ssl_peer_cert_SUITE).
-
--export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1,
- init_per_group/2,end_per_group/2,
- init_per_testcase/2,
- end_per_testcase/2,
- cinit_plain/1,
- cinit_both_verify/1,
- cinit_cnocert/1
- ]).
-
--import(ssl_test_MACHINE, [mk_ssl_cert_opts/1, test_one_listener/7,
- test_server_only/6]).
--include_lib("test_server/include/test_server.hrl").
--include("ssl_test_MACHINE.hrl").
-
-
-init_per_testcase(_Case, Config) ->
- WatchDog = ssl_test_lib:timetrap(?DEFAULT_TIMEOUT),
- [{watchdog, WatchDog}| Config].
-
-end_per_testcase(_Case, Config) ->
- WatchDog = ?config(watchdog, Config),
- test_server:timetrap_cancel(WatchDog).
-
-suite() -> [{ct_hooks,[ts_install_cth]}].
-
-all() ->
- [cinit_plain, cinit_both_verify, cinit_cnocert].
-
-groups() ->
- [].
-
-init_per_group(_GroupName, Config) ->
- Config.
-
-end_per_group(_GroupName, Config) ->
- Config.
-
-
-init_per_suite(doc) ->
- "Want to se what Config contains.";
-init_per_suite(suite) ->
- [];
-init_per_suite(Config) ->
- io:format("Config: ~p~n", [Config]),
-
- %% Check if SSL exists. If this case fails, all other cases are skipped
- case catch crypto:start() of
- ok ->
- application:start(public_key),
- case ssl:start() of
- ok -> ssl:stop();
- {error, {already_started, _}} -> ssl:stop();
- Error -> ?t:fail({failed_starting_ssl,Error})
- end,
- Config;
- _Else ->
- {skip,"Could not start crypto"}
- end.
-
-end_per_suite(doc) ->
- "This test case has no mission other than closing the conf case";
-end_per_suite(suite) ->
- [];
-end_per_suite(Config) ->
- crypto:stop(),
- Config.
-
-cinit_plain(doc) ->
- "Server closes after accept, Client waits for close. Both have certs "
- "but both use the defaults for verify and depth, but still tries "
- "to retreive each others certificates.";
-cinit_plain(suite) ->
- [];
-cinit_plain(Config) when list(Config) ->
- process_flag(trap_exit, true),
- DataSize = 1000, LPort = 3456,
- Timeout = 40000, NConns = 1,
-
- ?line {ok, {CsslOpts, SsslOpts}} = mk_ssl_cert_opts(Config),
-
- ?line {ok, Host} = inet:gethostname(),
-
- LCmds = [{sockopts, [{backlog, NConns}]},
- {sslopts, SsslOpts},
- {listen, LPort},
- wait_sync,
- lclose],
- ACmds = [{timeout, Timeout},
- accept,
- nopeercert,
- {recv, DataSize},
- close],
- CCmds = [{timeout, Timeout},
- {sslopts, CsslOpts},
- {connect, {Host, LPort}},
- peercert,
- {send, DataSize},
- await_close],
- ?line test_one_listener(NConns, LCmds, ACmds, CCmds, Timeout,
- ?MODULE, Config).
-
-cinit_both_verify(doc) ->
- "Server closes after accept, Client waits for close. Both have certs "
- "and both verify each other.";
-cinit_both_verify(suite) ->
- [];
-cinit_both_verify(Config) when list(Config) ->
- process_flag(trap_exit, true),
- DataSize = 1000, LPort = 3456,
- Timeout = 40000, NConns = 1,
-
- ?line {ok, {CsslOpts0, SsslOpts0}} = mk_ssl_cert_opts(Config),
- ?line CsslOpts = [{verify, 2}, {depth, 2} | CsslOpts0],
- ?line SsslOpts = [{verify, 2}, {depth, 3} | SsslOpts0],
-
- ?line {ok, Host} = inet:gethostname(),
-
- LCmds = [{sockopts, [{backlog, NConns}]},
- {sslopts, SsslOpts},
- {listen, LPort},
- wait_sync,
- lclose],
- ACmds = [{timeout, Timeout},
- accept,
- peercert,
- {recv, DataSize},
- close],
- CCmds = [{timeout, Timeout},
- {sslopts, CsslOpts},
- {connect, {Host, LPort}},
- peercert,
- {send, DataSize},
- await_close],
- ?line test_one_listener(NConns, LCmds, ACmds, CCmds, Timeout,
- ?MODULE, Config).
-
-cinit_cnocert(doc) ->
- "Client has no cert. Nor the client, nor the server is verifying its "
- "peer. Server closes, client waits for close.";
-cinit_cnocert(suite) ->
- [];
-cinit_cnocert(Config) when list(Config) ->
- process_flag(trap_exit, true),
- DataSize = 1000, LPort = 3457,
- Timeout = 40000, NConns = 1,
-
- ?line {ok, {_, SsslOpts0}} = mk_ssl_cert_opts(Config),
- ?line SsslOpts = [{verify, 0}, {depth, 2} | SsslOpts0],
-
- ?line {ok, Host} = inet:gethostname(),
-
- LCmds = [{sockopts, [{backlog, NConns}]},
- {sslopts, SsslOpts},
- {listen, LPort},
- wait_sync,
- lclose],
- ACmds = [{timeout, Timeout},
- accept,
- {recv, DataSize},
- close],
- CCmds = [{timeout, Timeout},
- {connect, {Host, LPort}},
- peercert,
- {send, DataSize},
- await_close],
- ?line test_one_listener(NConns, LCmds, ACmds, CCmds, Timeout,
- ?MODULE, Config).
-
-
diff --git a/lib/ssl/test/old_ssl_protocol_SUITE.erl b/lib/ssl/test/old_ssl_protocol_SUITE.erl
deleted file mode 100644
index 9b9937c210..0000000000
--- a/lib/ssl/test/old_ssl_protocol_SUITE.erl
+++ /dev/null
@@ -1,185 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2005-2011. All Rights Reserved.
-%%
-%% The contents of this file are subject to the Erlang Public License,
-%% Version 1.1, (the "License"); you may not use this file except in
-%% compliance with the License. You should have received a copy of the
-%% Erlang Public License along with this software. If not, it can be
-%% retrieved online at http://www.erlang.org/.
-%%
-%% Software distributed under the License is distributed on an "AS IS"
-%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
-%% the License for the specific language governing rights and limitations
-%% under the License.
-%%
-%% %CopyrightEnd%
-%%
-
-%%
--module(old_ssl_protocol_SUITE).
-
--export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1,
- init_per_group/2,end_per_group/2,
- init_per_testcase/2, end_per_testcase/2,
- sslv2/1, sslv3/1, tlsv1/1, sslv2_sslv3/1,
- sslv2_tlsv1/1, sslv3_tlsv1/1, sslv2_sslv3_tlsv1/1]).
-
--import(ssl_test_MACHINE, [mk_ssl_cert_opts/1, test_one_listener/7,
- test_server_only/6]).
--include_lib("test_server/include/test_server.hrl").
--include("ssl_test_MACHINE.hrl").
-
-
-init_per_testcase(_Case, Config) ->
- WatchDog = test_server:timetrap(?DEFAULT_TIMEOUT),
- [{watchdog, WatchDog}| Config].
-
-end_per_testcase(_Case, Config) ->
- WatchDog = ?config(watchdog, Config),
- test_server:timetrap_cancel(WatchDog).
-
-suite() -> [{ct_hooks,[ts_install_cth]}].
-
-all() ->
- [sslv2, sslv3, tlsv1, sslv2_sslv3, sslv2_tlsv1,
- sslv3_tlsv1, sslv2_sslv3_tlsv1].
-
-groups() ->
- [].
-
-init_per_group(_GroupName, Config) ->
- Config.
-
-end_per_group(_GroupName, Config) ->
- Config.
-
-
-init_per_suite(doc) ->
- "Want to se what Config contains.";
-init_per_suite(suite) ->
- [];
-init_per_suite(Config) ->
- io:format("Config: ~p~n", [Config]),
-
- %% Check if SSL exists. If this case fails, all other cases are skipped
- case catch crypto:start() of
- ok ->
- application:start(public_key),
- case ssl:start() of
- ok -> ssl:stop();
- {error, {already_started, _}} -> ssl:stop();
- Error -> ?t:fail({failed_starting_ssl,Error})
- end,
- Config;
- _Else ->
- {skip,"Could not start crypto"}
- end.
-
-end_per_suite(doc) ->
- "This test case has no other purpose than closing the conf case.";
-end_per_suite(suite) ->
- [];
-end_per_suite(Config) ->
- crypto:stop(),
- Config.
-
-%%%%%
-
-sslv2(doc) ->
- "Client has no cert. Nor the client, nor the server is verifying its "
- "peer. Server closes, client waits for close. "
- "Client and server choose SSLv2.";
-sslv2(suite) ->
- [];
-sslv2(Config) when list(Config) ->
- do_run_test(Config, [sslv2]).
-
-sslv3(doc) ->
- "Client has no cert. Nor the client, nor the server is verifying its "
- "peer. Server closes, client waits for close. "
- "Client and server choose SSLv3.";
-sslv3(suite) ->
- [];
-sslv3(Config) when list(Config) ->
- do_run_test(Config, [sslv3]).
-
-tlsv1(doc) ->
- "Client has no cert. Nor the client, nor the server is verifying its "
- "peer. Server closes, client waits for close. "
- "Client and server choose TLSv1.";
-tlsv1(suite) ->
- [];
-tlsv1(Config) when list(Config) ->
- do_run_test(Config, [tlsv1]).
-
-sslv2_sslv3(doc) ->
- "Client has no cert. Nor the client, nor the server is verifying its "
- "peer. Server closes, client waits for close. "
- "Client and server choose between SSLv2 and SSLv3.";
-sslv2_sslv3(suite) ->
- [];
-sslv2_sslv3(Config) when list(Config) ->
- do_run_test(Config, [sslv2, sslv3]).
-
-sslv2_tlsv1(doc) ->
- "Client has no cert. Nor the client, nor the server is verifying its "
- "peer. Server closes, client waits for close. "
- "Client and server choose between SSLv2 and TLSv1.";
-sslv2_tlsv1(suite) ->
- [];
-sslv2_tlsv1(Config) when list(Config) ->
- do_run_test(Config, [sslv2, tlsv1]).
-
-sslv3_tlsv1(doc) ->
- "Client has no cert. Nor the client, nor the server is verifying its "
- "peer. Server closes, client waits for close. "
- "Client and server choose between SSLv3 and TLSv1.";
-sslv3_tlsv1(suite) ->
- [];
-sslv3_tlsv1(Config) when list(Config) ->
- do_run_test(Config, [sslv3, tlsv1]).
-
-sslv2_sslv3_tlsv1(doc) ->
- "Client has no cert. Nor the client, nor the server is verifying its "
- "peer. Server closes, client waits for close. "
- "Client and server choose between SSLv2, SSLv3, and TLSv1.";
-sslv2_sslv3_tlsv1(suite) ->
- [];
-sslv2_sslv3_tlsv1(Config) when list(Config) ->
- do_run_test(Config, [sslv2, sslv3, tlsv1]).
-
-%%%%
-
-do_run_test(Config0, Protocols) ->
- process_flag(trap_exit, true),
- LPort = 3456,
- Timeout = 40000, NConns = 1,
- DataSize = 10,
-
- ?line {ok, {_, SsslOpts0}} = mk_ssl_cert_opts(Config0),
- ?line SsslOpts = [{verify, 0}, {depth, 2} | SsslOpts0],
-
- ?line {ok, Host} = inet:gethostname(),
-
- LCmds = [{sockopts, [{backlog, NConns}]},
- {sslopts, SsslOpts},
- {listen, LPort},
- wait_sync,
- lclose],
- ACmds = [{timeout, Timeout},
- accept,
- connection_info,
- {recv, DataSize},
- close],
- CCmds = [{timeout, Timeout},
- {connect, {Host, LPort}},
- connection_info,
- {send, DataSize},
- await_close],
- Config1 = [{env, [{protocol_version, Protocols}]} | Config0],
- ?line test_one_listener(NConns, LCmds, ACmds, CCmds, Timeout,
- ?MODULE, Config1).
-
-
diff --git a/lib/ssl/test/old_ssl_verify_SUITE.erl b/lib/ssl/test/old_ssl_verify_SUITE.erl
deleted file mode 100644
index 4c11ea6850..0000000000
--- a/lib/ssl/test/old_ssl_verify_SUITE.erl
+++ /dev/null
@@ -1,153 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1999-2011. All Rights Reserved.
-%%
-%% The contents of this file are subject to the Erlang Public License,
-%% Version 1.1, (the "License"); you may not use this file except in
-%% compliance with the License. You should have received a copy of the
-%% Erlang Public License along with this software. If not, it can be
-%% retrieved online at http://www.erlang.org/.
-%%
-%% Software distributed under the License is distributed on an "AS IS"
-%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
-%% the License for the specific language governing rights and limitations
-%% under the License.
-%%
-%% %CopyrightEnd%
-%%
-
-%%
--module(old_ssl_verify_SUITE).
-
--export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1,
- init_per_group/2,end_per_group/2,
- init_per_testcase/2,
- end_per_testcase/2,
- cinit_both_verify/1,
- cinit_cnocert/1
- ]).
-
--import(ssl_test_MACHINE, [mk_ssl_cert_opts/1, test_one_listener/7,
- test_server_only/6]).
--include_lib("test_server/include/test_server.hrl").
--include("ssl_test_MACHINE.hrl").
-
-
-init_per_testcase(_Case, Config) ->
- WatchDog = ssl_test_lib:timetrap(?DEFAULT_TIMEOUT),
- [{watchdog, WatchDog}| Config].
-
-end_per_testcase(_Case, Config) ->
- WatchDog = ?config(watchdog, Config),
- test_server:timetrap_cancel(WatchDog).
-
-suite() -> [{ct_hooks,[ts_install_cth]}].
-
-all() ->
- [cinit_both_verify, cinit_cnocert].
-
-groups() ->
- [].
-
-init_per_group(_GroupName, Config) ->
- Config.
-
-end_per_group(_GroupName, Config) ->
- Config.
-
-
-init_per_suite(doc) ->
- "Want to se what Config contains.";
-init_per_suite(suite) ->
- [];
-init_per_suite(Config) ->
- io:format("Config: ~p~n", [Config]),
-
- %% Check if SSL exists. If this case fails, all other cases are skipped
- case catch crypto:start() of
- ok ->
- application:start(public_key),
- case ssl:start() of
- ok -> ssl:stop();
- {error, {already_started, _}} -> ssl:stop();
- Error -> ?t:fail({failed_starting_ssl,Error})
- end,
- Config;
- _Else ->
- {skip,"Could not start crypto"}
- end.
-
-end_per_suite(doc) ->
- "This test case has no mission other than closing the conf case";
-end_per_suite(suite) ->
- [];
-end_per_suite(Config) ->
- crypto:stop(),
- Config.
-
-cinit_both_verify(doc) ->
- "Server closes after accept, Client waits for close. Both have certs "
- "and both verify each other.";
-cinit_both_verify(suite) ->
- [];
-cinit_both_verify(Config) when list(Config) ->
- process_flag(trap_exit, true),
- DataSize = 1000, LPort = 3456,
- Timeout = 40000, NConns = 1,
-
- ?line {ok, {CsslOpts0, SsslOpts0}} = mk_ssl_cert_opts(Config),
- ?line CsslOpts = [{verify, 2}, {depth, 2} | CsslOpts0],
- ?line SsslOpts = [{verify, 2}, {depth, 3} | SsslOpts0],
-
- ?line {ok, Host} = inet:gethostname(),
-
- LCmds = [{sockopts, [{backlog, NConns}]},
- {sslopts, SsslOpts},
- {listen, LPort},
- wait_sync,
- lclose],
- ACmds = [{timeout, Timeout},
- accept,
- {recv, DataSize},
- close],
- CCmds = [{timeout, Timeout},
- {sslopts, CsslOpts},
- {connect, {Host, LPort}},
- {send, DataSize},
- await_close],
- ?line test_one_listener(NConns, LCmds, ACmds, CCmds, Timeout,
- ?MODULE, Config).
-
-cinit_cnocert(doc) ->
- "Client has no cert. Nor the client, nor the server is verifying its "
- "peer. Server closes, client waits for close.";
-cinit_cnocert(suite) ->
- [];
-cinit_cnocert(Config) when list(Config) ->
- process_flag(trap_exit, true),
- DataSize = 1000, LPort = 3457,
- Timeout = 40000, NConns = 1,
-
- ?line {ok, {_, SsslOpts0}} = mk_ssl_cert_opts(Config),
- ?line SsslOpts = [{verify, 0}, {depth, 2} | SsslOpts0],
-
- ?line {ok, Host} = inet:gethostname(),
-
- LCmds = [{sockopts, [{backlog, NConns}]},
- {sslopts, SsslOpts},
- {listen, LPort},
- wait_sync,
- lclose],
- ACmds = [{timeout, Timeout},
- accept,
- {recv, DataSize},
- close],
- CCmds = [{timeout, Timeout},
- {connect, {Host, LPort}},
- {send, DataSize},
- await_close],
- ?line test_one_listener(NConns, LCmds, ACmds, CCmds, Timeout,
- ?MODULE, Config).
-
-
diff --git a/lib/ssl/test/old_transport_accept_SUITE.erl b/lib/ssl/test/old_transport_accept_SUITE.erl
deleted file mode 100644
index 6f0c8e456b..0000000000
--- a/lib/ssl/test/old_transport_accept_SUITE.erl
+++ /dev/null
@@ -1,258 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2007-2011. All Rights Reserved.
-%%
-%% The contents of this file are subject to the Erlang Public License,
-%% Version 1.1, (the "License"); you may not use this file except in
-%% compliance with the License. You should have received a copy of the
-%% Erlang Public License along with this software. If not, it can be
-%% retrieved online at http://www.erlang.org/.
-%%
-%% Software distributed under the License is distributed on an "AS IS"
-%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
-%% the License for the specific language governing rights and limitations
-%% under the License.
-%%
-%% %CopyrightEnd%
-%%
-
-%%
--module(old_transport_accept_SUITE).
--include_lib("common_test/include/ct.hrl").
--include("test_server_line.hrl").
-
-%% Default timetrap timeout (set in init_per_testcase).
--define(default_timeout, ?t:minutes(1)).
--define(application, ssh).
-
--export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1,
- init_per_group/2,end_per_group/2,
- init_per_testcase/2,
- end_per_testcase/2,
- config/1,
- echo_once/1,
- echo_twice/1,
- close_before_ssl_accept/1,
- server/5,
- tolerant_server/5,
- client/5
- ]).
-
-init_per_testcase(_Case, Config) ->
- WatchDog = ssl_test_lib:timetrap(?default_timeout),
- [{watchdog, WatchDog}, {protomod, gen_tcp}, {serialize_accept, true}|
- Config].
-
-end_per_testcase(_Case, Config) ->
- WatchDog = ?config(watchdog, Config),
- test_server:timetrap_cancel(WatchDog).
-
-suite() -> [{ct_hooks,[ts_install_cth]}].
-
-all() ->
- [config, echo_once, echo_twice, close_before_ssl_accept].
-
-groups() ->
- [].
-
-init_per_suite(Config) ->
- try crypto:start() of
- ok ->
- Config
- catch _:_ ->
- {skip, "Crypto did not start"}
- end.
-
-end_per_suite(_Config) ->
- application:stop(crypto),
- ok.
-
-init_per_group(_GroupName, Config) ->
- Config.
-
-end_per_group(_GroupName, Config) ->
- Config.
-
-
-config(doc) ->
- "Want to se what Config contains.";
-config(suite) ->
- [];
-config(Config) ->
- io:format("Config: ~p~n", [Config]),
- ok.
-
-echo_once(doc) ->
- "Client sends 256 bytes to server, that receives them, sends them "
- "back, and closes. Client waits for close. Both have certs.";
-echo_once(suite) ->
- [];
-echo_once(Config) when list(Config) ->
- process_flag(trap_exit, true),
- LPort = 3456,
- {ok, Host} = inet:gethostname(),
- {ok, {COpts, SOpts}} = ssl_test_MACHINE:mk_ssl_cert_opts(Config),
- N = 1,
- Msg = lists:seq(0, 255),
- Self = self(),
- Params = "-pa " ++ filename:dirname(code:which(?MODULE)),
- Node = start_node(server, Params),
- CNode = start_node(client, Params),
- Server = spawn_link(Node, ?MODULE, server, [Self, LPort, SOpts, Msg, N]),
- Client = spawn_link(Node, ?MODULE, client, [Host, LPort, COpts, Msg, N]),
- ok = receive
- {Server, listening} ->
- Client ! {Server, listening},
- ok;
- E ->
- io:format("bad receive (1) ~p\n", [E]),
- E
- end,
- receive
- {Server, done} ->
- ok
- end,
- test_server:stop_node(Node),
- test_server:stop_node(CNode).
-
-close_before_ssl_accept(doc) ->
- "Client sends 256 bytes to server, that receives them, sends them "
- "back, and closes. Client waits for close. Both have certs.";
-close_before_ssl_accept(suite) ->
- [];
-close_before_ssl_accept(Config) when list(Config) ->
- process_flag(trap_exit, true),
- LPort = 3456,
- {ok, Host} = inet:gethostname(),
- {ok, {COpts, SOpts}} = ssl_test_MACHINE:mk_ssl_cert_opts(Config),
- Msg = lists:seq(0, 255),
- Self = self(),
- Params = "-pa " ++ filename:dirname(code:which(?MODULE)),
- Node = start_node(server, Params),
- CNode = start_node(client, Params),
- Server = spawn_link(Node, ?MODULE, tolerant_server,
- [Self, LPort, SOpts, Msg, 2]),
- Client = spawn_link(Node, ?MODULE, client,
- [Host, LPort, COpts, Msg, 1]),
- ok = receive
- {Server, listening} ->
- {ok, S} = gen_tcp:connect(Host, LPort, []),
- gen_tcp:close(S),
- Client ! {Server, listening},
- ok;
- E ->
- io:format("bad receive (1) ~p\n", [E]),
- E
- end,
- receive
- {Server, done} ->
- ok
- end,
- test_server:stop_node(Node),
- test_server:stop_node(CNode).
-
-client(Host, LPort, COpts, Msg, N) ->
- ok = receive
- {_Server, listening} ->
- ok;
- E ->
- io:format("bad receive (2) ~p\n", [E]),
- E
- end,
- Opts = COpts ++ [{packet, raw}, {active, false}],
- app(),
- lists:foreach(fun(_) ->
- {ok, S} = ssl:connect(Host, LPort, Opts),
- ssl:send(S, Msg),
- {ok, Msg} = ssl:recv(S, length(Msg)),
- ssl:close(S)
- end, lists:seq(1, N)).
-
-echo_twice(doc) ->
- "Two clients sends 256 bytes to server, that receives them, sends them "
- "back, and closes. Client waits for close. Both have certs.";
-echo_twice(suite) ->
- [];
-echo_twice(Config) when list(Config) ->
- process_flag(trap_exit, true),
- LPort = 3456,
- {ok, Host} = inet:gethostname(),
- {ok, {COpts, SOpts}} = ssl_test_MACHINE:mk_ssl_cert_opts(Config),
- N = 2,
- Msg = lists:seq(0, 255),
- Self = self(),
- Params = "-pa " ++ filename:dirname(code:which(?MODULE)),
- Node = start_node(server, Params),
- CNode = start_node(client, Params),
- Server = spawn_link(Node, ?MODULE, server,
- [Self, LPort, SOpts, Msg, N]),
- Client = spawn_link(Node, ?MODULE, client,
- [Host, LPort, COpts, Msg, N]),
- ok = receive
- {Server, listening} ->
- Client ! {Server, listening},
- ok;
- E ->
- io:format("bad receive (3) ~p\n", [E]),
- E
- end,
- receive
- {Server, done} ->
- ok
- end,
- test_server:stop_node(Node),
- test_server:stop_node(CNode).
-
-server(Client, Port, SOpts, Msg, N) ->
- app(),
- process_flag(trap_exit, true),
- Opts = SOpts ++ [{packet, raw}, {active, false}],
- {ok, LSock} = ssl:listen(Port, Opts),
- Client ! {self(), listening},
- server_loop(Client, LSock, Msg, N).
-
-server_loop(Client, _, _, 0) ->
- Client ! {self(), done};
-server_loop(Client, LSock, Msg, N) ->
- {ok, S} = ssl:transport_accept(LSock),
- ok = ssl:ssl_accept(S),
- %% P = ssl:controlling_process(S, Proxy),
- {ok, Msg} = ssl:recv(S, length(Msg)),
- ok = ssl:send(S, Msg),
- ok = ssl:close(S),
- server_loop(Client, LSock, Msg, N-1).
-
-tolerant_server(Client, Port, SOpts, Msg, N) ->
- app(),
- process_flag(trap_exit, true),
- Opts = SOpts ++ [{packet, raw}, {active, false}],
- {ok, LSock} = ssl:listen(Port, Opts),
- Client ! {self(), listening},
- tolerant_server_loop(Client, LSock, Msg, N).
-
-tolerant_server_loop(Client, _, _, 0) ->
- Client ! {self(), done};
-tolerant_server_loop(Client, LSock, Msg, N) ->
- {ok, S} = ssl:transport_accept(LSock),
- case ssl:ssl_accept(S) of
- ok ->
- %% P = ssl:controlling_process(S, Proxy),
- {ok, Msg} = ssl:recv(S, length(Msg)),
- ok = ssl:send(S, Msg),
- ok = ssl:close(S);
- E ->
- io:format("ssl_accept error: ~p\n", [E])
- end,
- tolerant_server_loop(Client, LSock, Msg, N-1).
-
-app() ->
- crypto:start(),
- application:start(public_key),
- ssl:start().
-
-start_node(Kind, Params) ->
- S = atom_to_list(?MODULE)++"_" ++ atom_to_list(Kind),
- {ok, Node} = test_server:start_node(list_to_atom(S), slave, [{args, Params}]),
- Node.
-
diff --git a/lib/ssl/test/ssl.cover b/lib/ssl/test/ssl.cover
index 60774cc0f1..6b13e07a37 100644
--- a/lib/ssl/test/ssl.cover
+++ b/lib/ssl/test/ssl.cover
@@ -1,21 +1,4 @@
{incl_app,ssl,details}.
-{excl_mods, ssl, [ssl_pkix_oid,
- 'PKIX1Algorithms88',
- 'PKIX1Explicit88',
- 'PKIX1Implicit88',
- 'PKIXAttributeCertificate',
- 'SSL-PKIX',
- ssl_pem,
- ssl_pkix,
- ssl_base64,
- ssl_broker,
- ssl_broker_int,
- ssl_broker_sup,
- ssl_debug,
- ssl_server,
- ssl_prim,
- inet_ssl_dist,
- 'OTP-PKIX'
- ]}.
+{excl_mods, ssl, [ssl_debug]}.
diff --git a/lib/ssl/test/ssl_basic_SUITE.erl b/lib/ssl/test/ssl_basic_SUITE.erl
index 8da1d947d3..228ec9e294 100644
--- a/lib/ssl/test/ssl_basic_SUITE.erl
+++ b/lib/ssl/test/ssl_basic_SUITE.erl
@@ -28,7 +28,6 @@
-include_lib("public_key/include/public_key.hrl").
-include("ssl_alert.hrl").
--include("ssl_int.hrl").
-include("ssl_internal.hrl").
-include("ssl_record.hrl").
@@ -37,6 +36,7 @@
-define(LONG_TIMEOUT, 600000).
-define(EXPIRE, 10).
-define(SLEEP, 500).
+-define(RENEGOTIATION_DISABLE_TIME, 12000).
%% Test server callback functions
%%--------------------------------------------------------------------
@@ -207,8 +207,8 @@ suite() -> [{ct_hooks,[ts_install_cth]}].
all() ->
[app, alerts, connection_info, protocol_versions,
empty_protocol_versions, controlling_process,
- controller_dies, client_closes_socket, peercert,
- connect_dist, peername, sockname, socket_options,
+ controller_dies, client_closes_socket,
+ connect_dist, peername, peercert, sockname, socket_options,
invalid_inet_get_option, invalid_inet_get_option_not_list,
invalid_inet_get_option_improper_list,
invalid_inet_set_option, invalid_inet_set_option_not_list,
@@ -257,7 +257,9 @@ all() ->
%%different_ca_peer_sign,
no_reuses_session_server_restart_new_cert,
no_reuses_session_server_restart_new_cert_file, reuseaddr,
- hibernate, connect_twice
+ hibernate, connect_twice, renegotiate_dos_mitigate_active,
+ renegotiate_dos_mitigate_passive,
+ tcp_error_propagation_in_active_mode
].
groups() ->
@@ -394,8 +396,8 @@ controlling_process(Config) when is_list(Config) ->
ClientOpts = ?config(client_opts, Config),
ServerOpts = ?config(server_opts, Config),
{ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
- ClientMsg = "Hello server",
- ServerMsg = "Hello client",
+ ClientMsg = "Server hello",
+ ServerMsg = "Client hello",
Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
{from, self()},
@@ -416,11 +418,15 @@ controlling_process(Config) when is_list(Config) ->
[self(), Client, Server]),
receive
+ {ssl, _, "S"} ->
+ receive_s_rizzo_duong_beast();
{ssl, _, ServerMsg} ->
receive
{ssl, _, ClientMsg} ->
ok
end;
+ {ssl, _, "C"} ->
+ receive_c_rizzo_duong_beast();
{ssl, _, ClientMsg} ->
receive
{ssl, _, ServerMsg} ->
@@ -441,6 +447,28 @@ controlling_process_result(Socket, Pid, Msg) ->
ssl:send(Socket, Msg),
no_result_msg.
+receive_s_rizzo_duong_beast() ->
+ receive
+ {ssl, _, "erver hello"} ->
+ receive
+ {ssl, _, "C"} ->
+ receive
+ {ssl, _, "lient hello"} ->
+ ok
+ end
+ end
+ end.
+receive_c_rizzo_duong_beast() ->
+ receive
+ {ssl, _, "lient hello"} ->
+ receive
+ {ssl, _, "S"} ->
+ receive
+ {ssl, _, "erver hello"} ->
+ ok
+ end
+ end
+ end.
%%--------------------------------------------------------------------
controller_dies(doc) ->
["Test that the socket is closed after controlling process dies"];
@@ -584,50 +612,6 @@ client_closes_socket(Config) when is_list(Config) ->
ssl_test_lib:check_result(Server, {error,closed}).
%%--------------------------------------------------------------------
-
-peercert(doc) ->
- [""];
-
-peercert(suite) ->
- [];
-
-peercert(Config) when is_list(Config) ->
- ClientOpts = ?config(client_opts, Config),
- ServerOpts = ?config(server_opts, Config),
- {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
-
- Server = ssl_test_lib:start_server([{node, ClientNode}, {port, 0},
- {from, self()},
- {mfa, {?MODULE, peercert_result, []}},
- {options, ServerOpts}]),
- Port = ssl_test_lib:inet_port(Server),
- Client = ssl_test_lib:start_client([{node, ServerNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {?MODULE, peercert_result, []}},
- {options, ClientOpts}]),
-
- CertFile = proplists:get_value(certfile, ServerOpts),
- [{'Certificate', BinCert, _}]= ssl_test_lib:pem_to_der(CertFile),
- ErlCert = public_key:pkix_decode_cert(BinCert, otp),
-
- ServerMsg = {{error, no_peercert}, {error, no_peercert}},
- ClientMsg = {{ok, BinCert}, {ok, ErlCert}},
-
- test_server:format("Testcase ~p, Client ~p Server ~p ~n",
- [self(), Client, Server]),
-
- ssl_test_lib:check_result(Server, ServerMsg, Client, ClientMsg),
-
- ssl_test_lib:close(Server),
- ssl_test_lib:close(Client).
-
-peercert_result(Socket) ->
- Result1 = ssl:peercert(Socket),
- Result2 = ssl:peercert(Socket, [ssl]),
- {Result1, Result2}.
-
-%%--------------------------------------------------------------------
connect_dist(doc) ->
["Test a simple connect as is used by distribution"];
@@ -708,6 +692,44 @@ peername_result(S) ->
ssl:peername(S).
%%--------------------------------------------------------------------
+peercert(doc) ->
+ [""];
+peercert(suite) ->
+ [];
+peercert(Config) when is_list(Config) ->
+ ClientOpts = ?config(client_opts, Config),
+ ServerOpts = ?config(server_opts, Config),
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+
+ Server = ssl_test_lib:start_server([{node, ClientNode}, {port, 0},
+ {from, self()},
+ {mfa, {?MODULE, peercert_result, []}},
+ {options, ServerOpts}]),
+ Port = ssl_test_lib:inet_port(Server),
+ Client = ssl_test_lib:start_client([{node, ServerNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {?MODULE, peercert_result, []}},
+ {options, ClientOpts}]),
+
+ CertFile = proplists:get_value(certfile, ServerOpts),
+ [{'Certificate', BinCert, _}]= ssl_test_lib:pem_to_der(CertFile),
+
+ ServerMsg = {error, no_peercert},
+ ClientMsg = {ok, BinCert},
+
+ test_server:format("Testcase ~p, Client ~p Server ~p ~n",
+ [self(), Client, Server]),
+
+ ssl_test_lib:check_result(Server, ServerMsg, Client, ClientMsg),
+
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close(Client).
+
+peercert_result(Socket) ->
+ ssl:peercert(Socket).
+
+%%--------------------------------------------------------------------
sockname(doc) ->
["Test API function sockname/1"];
@@ -1238,6 +1260,11 @@ upgrade_result(Socket) ->
%% Make sure binary is inherited from tcp socket and that we do
%% not get the list default!
receive
+ {ssl, _, <<"H">>} ->
+ receive
+ {ssl, _, <<"ello world">>} ->
+ ok
+ end;
{ssl, _, <<"Hello world">>} ->
ok
end.
@@ -1528,7 +1555,6 @@ eoptions(Config) when is_list(Config) ->
end,
TestOpts = [{versions, [sslv2, sslv3]},
- {ssl_imp, cool},
{verify, 4},
{verify_fun, function},
{fail_if_no_peer_cert, 0},
@@ -1540,14 +1566,14 @@ eoptions(Config) when is_list(Config) ->
{cacertfile, ""},
{dhfile,'dh.pem' },
{ciphers, [{foo, bar, sha, ignore}]},
- {reuse_session, foo},
- {reuse_sessions, 0},
+ {reuse_session, foo},
+ {reuse_sessions, 0},
{renegotiate_at, "10"},
- {debug, 1},
+ {debug, 1},
{mode, depech},
- {packet, 8.0},
- {packet_size, "2"},
- {header, a},
+ {packet, 8.0},
+ {packet_size, "2"},
+ {header, a},
{active, trice},
{key, 'key.pem' }],
@@ -2348,7 +2374,7 @@ server_verify_client_once_active(Config) when is_list(Config) ->
Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
{from, self()},
{mfa, {?MODULE, send_recv_result_active, []}},
- {options, [{active, once}, {verify, verify_peer},
+ {options, [{active, true}, {verify, verify_peer},
{verify_client_once, true}
| ServerOpts]}]),
Port = ssl_test_lib:inet_port(Server),
@@ -2600,7 +2626,7 @@ client_renegotiate(Config) when is_list(Config) ->
{options, ServerOpts}]),
Port = ssl_test_lib:inet_port(Server),
- Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
+ Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
{host, Hostname},
{from, self()},
{mfa, {?MODULE,
@@ -2732,17 +2758,28 @@ client_no_wrap_sequence_number(Config) when is_list(Config) ->
{options, ServerOpts}]),
Port = ssl_test_lib:inet_port(Server),
+ Version = ssl_record:highest_protocol_version(ssl_record:supported_protocol_versions()),
+
Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
{host, Hostname},
{from, self()},
{mfa, {ssl_test_lib,
- trigger_renegotiate, [[ErlData, N+2]]}},
+ trigger_renegotiate, [[ErlData, treashold(N, Version)]]}},
{options, [{reuse_sessions, false},
{renegotiate_at, N} | ClientOpts]}]),
ssl_test_lib:check_result(Client, ok),
ssl_test_lib:close(Server),
ssl_test_lib:close(Client).
+
+ %% First two clauses handles 1/n-1 splitting countermeasure Rizzo/Duong-Beast
+treashold(N, {3,0}) ->
+ (N div 2) + 1;
+treashold(N, {3,1}) ->
+ (N div 2) + 1;
+treashold(N, _) ->
+ N + 1.
+
%%--------------------------------------------------------------------
server_no_wrap_sequence_number(doc) ->
["Test that erlang server will renegotiate session when",
@@ -2792,7 +2829,7 @@ extended_key_usage_verify_peer(Config) when is_list(Config) ->
KeyFile = filename:join(PrivDir, "otpCA/private/key.pem"),
[KeyEntry] = ssl_test_lib:pem_to_der(KeyFile),
- Key = public_key:pem_entry_decode(KeyEntry),
+ Key = ssl_test_lib:public_key(public_key:pem_entry_decode(KeyEntry)),
ServerCertFile = proplists:get_value(certfile, ServerOpts),
NewServerCertFile = filename:join(PrivDir, "server/new_cert.pem"),
@@ -2854,7 +2891,7 @@ extended_key_usage_verify_none(Config) when is_list(Config) ->
KeyFile = filename:join(PrivDir, "otpCA/private/key.pem"),
[KeyEntry] = ssl_test_lib:pem_to_der(KeyFile),
- Key = public_key:pem_entry_decode(KeyEntry),
+ Key = ssl_test_lib:public_key(public_key:pem_entry_decode(KeyEntry)),
ServerCertFile = proplists:get_value(certfile, ServerOpts),
NewServerCertFile = filename:join(PrivDir, "server/new_cert.pem"),
@@ -2916,7 +2953,7 @@ no_authority_key_identifier(Config) when is_list(Config) ->
KeyFile = filename:join(PrivDir, "otpCA/private/key.pem"),
[KeyEntry] = ssl_test_lib:pem_to_der(KeyFile),
- Key = public_key:pem_entry_decode(KeyEntry),
+ Key = ssl_test_lib:public_key(public_key:pem_entry_decode(KeyEntry)),
CertFile = proplists:get_value(certfile, ServerOpts),
NewCertFile = filename:join(PrivDir, "server/new_cert.pem"),
@@ -2974,7 +3011,7 @@ invalid_signature_server(Config) when is_list(Config) ->
KeyFile = filename:join(PrivDir, "server/key.pem"),
[KeyEntry] = ssl_test_lib:pem_to_der(KeyFile),
- Key = public_key:pem_entry_decode(KeyEntry),
+ Key = ssl_test_lib:public_key(public_key:pem_entry_decode(KeyEntry)),
ServerCertFile = proplists:get_value(certfile, ServerOpts),
NewServerCertFile = filename:join(PrivDir, "server/invalid_cert.pem"),
@@ -3014,7 +3051,7 @@ invalid_signature_client(Config) when is_list(Config) ->
KeyFile = filename:join(PrivDir, "client/key.pem"),
[KeyEntry] = ssl_test_lib:pem_to_der(KeyFile),
- Key = public_key:pem_entry_decode(KeyEntry),
+ Key = ssl_test_lib:public_key(public_key:pem_entry_decode(KeyEntry)),
ClientCertFile = proplists:get_value(certfile, ClientOpts),
NewClientCertFile = filename:join(PrivDir, "client/invalid_cert.pem"),
@@ -3046,7 +3083,8 @@ tcp_delivery_workaround(Server, ServerMsg, Client, ClientMsg) ->
{Client, ClientMsg} ->
ok;
{Client, {error,closed}} ->
- test_server:format("client got close");
+ test_server:format("client got close"),
+ ok;
Unexpected ->
test_server:fail(Unexpected)
end;
@@ -3091,7 +3129,7 @@ cert_expired(Config) when is_list(Config) ->
KeyFile = filename:join(PrivDir, "otpCA/private/key.pem"),
[KeyEntry] = ssl_test_lib:pem_to_der(KeyFile),
- Key = public_key:pem_entry_decode(KeyEntry),
+ Key = ssl_test_lib:public_key(public_key:pem_entry_decode(KeyEntry)),
ServerCertFile = proplists:get_value(certfile, ServerOpts),
NewServerCertFile = filename:join(PrivDir, "server/expired_cert.pem"),
@@ -3366,14 +3404,14 @@ der_input_opts(Opts) ->
Keyfile = proplists:get_value(keyfile, Opts),
Dhfile = proplists:get_value(dhfile, Opts),
[{_, Cert, _}] = ssl_test_lib:pem_to_der(Certfile),
- [{_, Key, _}] = ssl_test_lib:pem_to_der(Keyfile),
+ [{Asn1Type, Key, _}] = ssl_test_lib:pem_to_der(Keyfile),
[{_, DHParams, _}] = ssl_test_lib:pem_to_der(Dhfile),
CaCerts =
lists:map(fun(Entry) ->
{_, CaCert, _} = Entry,
CaCert
end, ssl_test_lib:pem_to_der(CaCertsfile)),
- {Cert, {rsa, Key}, CaCerts, DHParams}.
+ {Cert, {Asn1Type, Key}, CaCerts, DHParams}.
%%--------------------------------------------------------------------
%% different_ca_peer_sign(doc) ->
@@ -3596,14 +3634,13 @@ hibernate(Config) ->
{from, self()},
{mfa, {?MODULE, send_recv_result_active, []}},
{options, [{hibernate_after, 1000}|ClientOpts]}]),
-
- { current_function, { _M, _F, _A } } =
+ {current_function, _} =
process_info(Pid, current_function),
timer:sleep(1100),
- { current_function, { erlang, hibernate, 3} } =
- process_info(Pid, current_function),
+ {current_function, {erlang, hibernate, 3}} =
+ process_info(Pid, current_function),
ssl_test_lib:close(Server),
ssl_test_lib:close(Client).
@@ -3655,7 +3692,101 @@ connect_twice(Config) when is_list(Config) ->
ssl_test_lib:close(Client),
ssl_test_lib:close(Client1).
+%%--------------------------------------------------------------------
+renegotiate_dos_mitigate_active(doc) ->
+ ["Mitigate DOS computational attack by not allowing client to renegotiate many times in a row",
+ "immediately after each other"];
+
+renegotiate_dos_mitigate_active(suite) ->
+ [];
+
+renegotiate_dos_mitigate_active(Config) when is_list(Config) ->
+ ServerOpts = ?config(server_opts, Config),
+ ClientOpts = ?config(client_opts, Config),
+
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+
+ Server =
+ ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {?MODULE, send_recv_result_active, []}},
+ {options, [ServerOpts]}]),
+ Port = ssl_test_lib:inet_port(Server),
+
+ Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {?MODULE,
+ renegotiate_immediately, []}},
+ {options, ClientOpts}]),
+
+ ssl_test_lib:check_result(Client, ok, Server, ok),
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close(Client).
+
+%%--------------------------------------------------------------------
+renegotiate_dos_mitigate_passive(doc) ->
+ ["Mitigate DOS computational attack by not allowing client to renegotiate many times in a row",
+ "immediately after each other"];
+
+renegotiate_dos_mitigate_passive(suite) ->
+ [];
+
+renegotiate_dos_mitigate_passive(Config) when is_list(Config) ->
+ ServerOpts = ?config(server_opts, Config),
+ ClientOpts = ?config(client_opts, Config),
+
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+
+ Server =
+ ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {?MODULE, send_recv_result, []}},
+ {options, [{active, false} | ServerOpts]}]),
+ Port = ssl_test_lib:inet_port(Server),
+
+ Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {?MODULE,
+ renegotiate_immediately, []}},
+ {options, ClientOpts}]),
+
+ ssl_test_lib:check_result(Client, ok, Server, ok),
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close(Client).
+
+%%--------------------------------------------------------------------
+tcp_error_propagation_in_active_mode(doc) ->
+ ["Test that process recives {ssl_error, Socket, closed} when tcp error ocurres"];
+tcp_error_propagation_in_active_mode(Config) when is_list(Config) ->
+ ClientOpts = ?config(client_opts, Config),
+ ServerOpts = ?config(server_opts, Config),
+
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+
+ Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {ssl_test_lib, no_result, []}},
+ {options, ServerOpts}]),
+ Port = ssl_test_lib:inet_port(Server),
+ {Client, #sslsocket{pid=Pid} = SslSocket} = ssl_test_lib:start_client([return_socket,
+ {node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {?MODULE, receive_msg, []}},
+ {options, ClientOpts}]),
+
+ {status, _, _, StatusInfo} = sys:get_status(Pid),
+ [_, _,_, _, Prop] = StatusInfo,
+ State = ssl_test_lib:state(Prop),
+ Socket = element(10, State),
+
+ %% Fake tcp error
+ Pid ! {tcp_error, Socket, etimedout},
+ ssl_test_lib:check_result(Client, {ssl_closed, SslSocket}).
+
%%--------------------------------------------------------------------
%%% Internal functions
%%--------------------------------------------------------------------
@@ -3667,6 +3798,11 @@ send_recv_result(Socket) ->
send_recv_result_active(Socket) ->
ssl:send(Socket, "Hello world"),
receive
+ {ssl, Socket, "H"} ->
+ receive
+ {ssl, Socket, "ello world"} ->
+ ok
+ end;
{ssl, Socket, "Hello world"} ->
ok
end.
@@ -3674,6 +3810,12 @@ send_recv_result_active(Socket) ->
send_recv_result_active_once(Socket) ->
ssl:send(Socket, "Hello world"),
receive
+ {ssl, Socket, "H"} ->
+ ssl:setopts(Socket, [{active, once}]),
+ receive
+ {ssl, Socket, "ello world"} ->
+ ok
+ end;
{ssl, Socket, "Hello world"} ->
ok
end.
@@ -3698,6 +3840,25 @@ renegotiate_reuse_session(Socket, Data) ->
test_server:sleep(?SLEEP),
renegotiate(Socket, Data).
+renegotiate_immediately(Socket) ->
+ receive
+ {ssl, Socket, "Hello world"} ->
+ ok;
+ %% Handle 1/n-1 splitting countermeasure Rizzo/Duong-Beast
+ {ssl, Socket, "H"} ->
+ receive
+ {ssl, Socket, "ello world"} ->
+ ok
+ end
+ end,
+ ok = ssl:renegotiate(Socket),
+ {error, renegotiation_rejected} = ssl:renegotiate(Socket),
+ test_server:sleep(?RENEGOTIATION_DISABLE_TIME +1),
+ ok = ssl:renegotiate(Socket),
+ test_server:format("Renegotiated again"),
+ ssl:send(Socket, "Hello world"),
+ ok.
+
new_config(PrivDir, ServerOpts0) ->
CaCertFile = proplists:get_value(cacertfile, ServerOpts0),
CertFile = proplists:get_value(certfile, ServerOpts0),
@@ -3871,8 +4032,17 @@ erlang_ssl_receive(Socket, Data) ->
{ssl, Socket, Data} ->
io:format("Received ~p~n",[Data]),
ok;
+ {ssl, Socket, Byte} when length(Byte) == 1 -> %% Handle 1/n-1 splitting countermeasure Rizzo/Duong-Beast
+ io:format("Received ~p~n",[Byte]),
+ erlang_ssl_receive(Socket, tl(Data));
Other ->
test_server:fail({unexpected_message, Other})
after ?SLEEP * 3 ->
test_server:fail({did_not_get, Data})
end.
+
+receive_msg(_) ->
+ receive
+ Msg ->
+ Msg
+ end.
diff --git a/lib/ssl/test/ssl_cipher_SUITE.erl b/lib/ssl/test/ssl_cipher_SUITE.erl
new file mode 100644
index 0000000000..99bc21e820
--- /dev/null
+++ b/lib/ssl/test/ssl_cipher_SUITE.erl
@@ -0,0 +1,163 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2008-2011. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+-module(ssl_cipher_SUITE).
+
+%% Note: This directive should only be used in test suites.
+-compile(export_all).
+
+-include_lib("common_test/include/ct.hrl").
+
+-include("ssl_internal.hrl").
+-include("ssl_record.hrl").
+-include("ssl_cipher.hrl").
+
+-define(TIMEOUT, 600000).
+
+%% Test server callback functions
+%%--------------------------------------------------------------------
+%% Function: init_per_suite(Config) -> Config
+%% Config - [tuple()]
+%% A list of key/value pairs, holding the test case configuration.
+%% Description: Initialization before the whole suite
+%%
+%% Note: This function is free to add any key/value pairs to the Config
+%% variable, but should NOT alter/remove any existing entries.
+%%--------------------------------------------------------------------
+init_per_suite(Config) ->
+ try crypto:start() of
+ ok ->
+ Config
+ catch _:_ ->
+ {skip, "Crypto did not start"}
+ end.
+%%--------------------------------------------------------------------
+%% Function: end_per_suite(Config) -> _
+%% Config - [tuple()]
+%% A list of key/value pairs, holding the test case configuration.
+%% Description: Cleanup after the whole suite
+%%--------------------------------------------------------------------
+end_per_suite(_Config) ->
+ ssl:stop(),
+ application:stop(crypto).
+
+%%--------------------------------------------------------------------
+%% Function: init_per_testcase(TestCase, Config) -> Config
+%% Case - atom()
+%% Name of the test case that is about to be run.
+%% Config - [tuple()]
+%% A list of key/value pairs, holding the test case configuration.
+%%
+%% Description: Initialization before each test case
+%%
+%% Note: This function is free to add any key/value pairs to the Config
+%% variable, but should NOT alter/remove any existing entries.
+%% Description: Initialization before each test case
+%%--------------------------------------------------------------------
+init_per_testcase(_TestCase, Config0) ->
+ Config = lists:keydelete(watchdog, 1, Config0),
+ Dog = ssl_test_lib:timetrap(?TIMEOUT),
+ [{watchdog, Dog} | Config].
+
+%%--------------------------------------------------------------------
+%% Function: end_per_testcase(TestCase, Config) -> _
+%% Case - atom()
+%% Name of the test case that is about to be run.
+%% Config - [tuple()]
+%% A list of key/value pairs, holding the test case configuration.
+%% Description: Cleanup after each test case
+%%--------------------------------------------------------------------
+end_per_testcase(_TestCase, Config) ->
+ Dog = ?config(watchdog, Config),
+ case Dog of
+ undefined ->
+ ok;
+ _ ->
+ test_server:timetrap_cancel(Dog)
+ end.
+
+%%--------------------------------------------------------------------
+%% Function: all(Clause) -> TestCases
+%% Clause - atom() - suite | doc
+%% TestCases - [Case]
+%% Case - atom()
+%% Name of a test case.
+%% Description: Returns a list of all test cases in this test suite
+%%--------------------------------------------------------------------
+suite() -> [{ct_hooks,[ts_install_cth]}].
+
+all() ->
+ [aes_decipher_good, aes_decipher_fail].
+
+groups() ->
+ [].
+
+init_per_group(_GroupName, Config) ->
+ Config.
+
+end_per_group(_GroupName, Config) ->
+ Config.
+
+
+%% Test cases starts here.
+%%--------------------------------------------------------------------
+aes_decipher_good(doc) ->
+ ["Decipher a known cryptotext."];
+
+aes_decipher_good(suite) ->
+ [];
+
+aes_decipher_good(Config) when is_list(Config) ->
+ HashSz = 32,
+ CipherState = #cipher_state{iv = <<59,201,85,117,188,206,224,136,5,109,46,70,104,79,4,9>>,
+ key = <<72,196,247,97,62,213,222,109,210,204,217,186,172,184,197,148>>},
+ Fragment = <<220,193,179,139,171,33,143,245,202,47,123,251,13,232,114,8,
+ 190,162,74,31,186,227,119,155,94,74,119,79,169,193,240,160,
+ 198,181,81,19,98,162,213,228,74,224,253,168,156,59,195,122,
+ 108,101,107,242,20,15,169,150,163,107,101,94,93,104,241,165>>,
+ Version = {3,3},
+ Content = <<183,139,16,132,10,209,67,86,168,100,61,217,145,57,36,56,72,69,76,76,79,10>>,
+ Mac = <<71,136,212,107,223,200,70,232,127,116,148,205,232,35,158,113,237,174,15,217,192,168,35,8,6,107,107,233,25,174,90,111>>,
+ {Content, Mac, _} = ssl_cipher:decipher(?AES, HashSz, CipherState, Fragment, Version),
+ ok.
+
+%%--------------------------------------------------------------------
+
+aes_decipher_fail(doc) ->
+ ["Decipher a known cryptotext."];
+
+aes_decipher_fail(suite) ->
+ [];
+
+%% same as above, last byte of key replaced
+aes_decipher_fail(Config) when is_list(Config) ->
+ HashSz = 32,
+ CipherState = #cipher_state{iv = <<59,201,85,117,188,206,224,136,5,109,46,70,104,79,4,9>>,
+ key = <<72,196,247,97,62,213,222,109,210,204,217,186,172,184,197,254>>},
+ Fragment = <<220,193,179,139,171,33,143,245,202,47,123,251,13,232,114,8,
+ 190,162,74,31,186,227,119,155,94,74,119,79,169,193,240,160,
+ 198,181,81,19,98,162,213,228,74,224,253,168,156,59,195,122,
+ 108,101,107,242,20,15,169,150,163,107,101,94,93,104,241,165>>,
+ Version = {3,3},
+ {Content, Mac, _} = ssl_cipher:decipher(?AES, HashSz, CipherState, Fragment, Version),
+ 32 = byte_size(Content),
+ 32 = byte_size(Mac),
+ ok.
+
+%%--------------------------------------------------------------------
diff --git a/lib/ssl/test/old_ssl_dist_SUITE.erl b/lib/ssl/test/ssl_dist_SUITE.erl
index 4544fb616a..8fe55ee7a4 100644
--- a/lib/ssl/test/old_ssl_dist_SUITE.erl
+++ b/lib/ssl/test/ssl_dist_SUITE.erl
@@ -17,41 +17,32 @@
%% %CopyrightEnd%
%%
-%%
-
-
-%%%-------------------------------------------------------------------
-%%% File : ssl_dist_SUITE.erl
-%%% Author : Rickard Green
-%%% Description : Test that the Erlang distribution works over ssl.
-%%%
-%%% Created : 15 Nov 2007 by Rickard Green
-%%%-------------------------------------------------------------------
--module(old_ssl_dist_SUITE).
+-module(ssl_dist_SUITE).
-include_lib("test_server/include/test_server.hrl").
+%% Note: This directive should only be used in test suites.
+-compile(export_all).
+
-define(DEFAULT_TIMETRAP_SECS, 240).
-define(AWAIT_SLL_NODE_UP_TIMEOUT, 30000).
--export([all/0, suite/0,groups/0,init_per_group/2,end_per_group/2]).
--export([init_per_suite/1,
- end_per_suite/1,
- init_per_testcase/2,
- end_per_testcase/2]).
--export([cnct2tstsrvr/1]).
+-record(node_handle,
+ {connection_handler,
+ socket,
+ name,
+ nodename}
+ ).
--export([basic/1]).
+%% Test server callback functions
+suite() ->
+ [{ct_hooks,[ts_install_cth]}].
--record(node_handle, {connection_handler, socket, name, nodename}).
+all() ->
+ [basic, payload, plain_options, plain_verify_options].
-suite() -> [{ct_hooks,[ts_install_cth]}].
-
-all() ->
- [basic].
-
-groups() ->
+groups() ->
[].
init_per_group(_GroupName, Config) ->
@@ -60,11 +51,17 @@ init_per_group(_GroupName, Config) ->
end_per_group(_GroupName, Config) ->
Config.
-
-init_per_suite(Config) ->
+init_per_suite(Config0) ->
try crypto:start() of
ok ->
- add_ssl_opts_config(Config)
+ case test_server:is_cover() of
+ false ->
+ Config = add_ssl_opts_config(Config0),
+ setup_certs(Config),
+ Config;
+ true ->
+ {skip, "Can not be covered"}
+ end
catch _:_ ->
{skip, "Crypto did not start"}
end.
@@ -73,85 +70,184 @@ end_per_suite(Config) ->
application:stop(crypto),
Config.
-init_per_testcase(Case, Config) when list(Config) ->
+init_per_testcase(plain_verify_options = Case, Config) when is_list(Config) ->
+ SslFlags = setup_dist_opts([{many_verify_opts, true} | Config]),
+ Flags = case os:getenv("ERL_FLAGS") of
+ false ->
+ os:putenv("ERL_FLAGS", SslFlags),
+ "";
+ OldFlags ->
+ os:putenv("ERL_FLAGS", OldFlags ++ "" ++ SslFlags),
+ OldFlags
+ end,
+ common_init(Case, [{old_flags, Flags} | Config]);
+
+init_per_testcase(Case, Config) when is_list(Config) ->
+ common_init(Case, Config).
+
+common_init(Case, Config) ->
Dog = ?t:timetrap(?t:seconds(?DEFAULT_TIMETRAP_SECS)),
[{watchdog, Dog},{testcase, Case}|Config].
-end_per_testcase(_Case, Config) when list(Config) ->
+end_per_testcase(Case, Config) when is_list(Config) ->
+ Flags = proplists:get_value(old_flags, Config),
+ os:putenv("ERL_FLAGS", Flags),
+ common_end(Case, Config).
+
+common_end(_, Config) ->
Dog = ?config(watchdog, Config),
?t:timetrap_cancel(Dog),
ok.
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% %%
-%% Testcases %%
-%% %%
-
+%%--------------------------------------------------------------------
+%% Test cases starts here.
+%%--------------------------------------------------------------------
basic(doc) ->
["Test that two nodes can connect via ssl distribution"];
-basic(suite) ->
- [];
basic(Config) when is_list(Config) ->
- ?line NH1 = start_ssl_node(Config),
- ?line Node1 = NH1#node_handle.nodename,
- ?line NH2 = start_ssl_node(Config),
- ?line Node2 = NH2#node_handle.nodename,
+ NH1 = start_ssl_node(Config),
+ Node1 = NH1#node_handle.nodename,
+ NH2 = start_ssl_node(Config),
+ Node2 = NH2#node_handle.nodename,
- ?line pong = apply_on_ssl_node(NH1, fun () -> net_adm:ping(Node2) end),
+ pong = apply_on_ssl_node(NH1, fun () -> net_adm:ping(Node2) end),
- ?line [Node2] = apply_on_ssl_node(NH1, fun () -> nodes() end),
- ?line [Node1] = apply_on_ssl_node(NH2, fun () -> nodes() end),
+ [Node2] = apply_on_ssl_node(NH1, fun () -> nodes() end),
+ [Node1] = apply_on_ssl_node(NH2, fun () -> nodes() end),
%% The test_server node has the same cookie as the ssl nodes
%% but it should not be able to communicate with the ssl nodes
%% via the erlang distribution.
- ?line pang = net_adm:ping(Node1),
- ?line pang = net_adm:ping(Node2),
-
+ pang = net_adm:ping(Node1),
+ pang = net_adm:ping(Node2),
%%
%% Check that we are able to communicate over the erlang
%% distribution between the ssl nodes.
%%
- ?line Ref = make_ref(),
- ?line spawn(fun () ->
- apply_on_ssl_node(
- NH1,
- fun () ->
- tstsrvr_format("Hi from ~p!~n",
- [node()]),
- send_to_tstcntrl({Ref, self()}),
- receive
- {From, ping} ->
- From ! {self(), pong}
- end
- end)
- end),
- ?line receive
- {Ref, SslPid} ->
- ?line ok = apply_on_ssl_node(
- NH2,
- fun () ->
- tstsrvr_format("Hi from ~p!~n",
- [node()]),
- SslPid ! {self(), ping},
- receive
- {SslPid, pong} ->
- ok
- end
- end)
- end,
-
- ?line stop_ssl_node(NH1),
- ?line stop_ssl_node(NH2),
- ?line success(Config).
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% %%
-%% Internal functions %%
-%% %%
+ Ref = make_ref(),
+ spawn(fun () ->
+ apply_on_ssl_node(
+ NH1,
+ fun () ->
+ tstsrvr_format("Hi from ~p!~n", [node()]),
+ send_to_tstcntrl({Ref, self()}),
+ receive
+ {From, ping} ->
+ tstsrvr_format("Received ping ~p!~n", [node()]),
+ From ! {self(), pong}
+ end
+ end)
+ end),
+ receive
+ {Ref, SslPid} ->
+ ok = apply_on_ssl_node(
+ NH2,
+ fun () ->
+ tstsrvr_format("Hi from ~p!~n", [node()]),
+ SslPid ! {self(), ping},
+ receive
+ {SslPid, pong} ->
+ ok
+ end
+ end)
+ end,
+ stop_ssl_node(NH1),
+ stop_ssl_node(NH2),
+ success(Config).
+
+%%--------------------------------------------------------------------
+payload(doc) ->
+ ["Test that send a lot of data between the ssl distributed noes"];
+payload(Config) when is_list(Config) ->
+ NH1 = start_ssl_node(Config),
+ Node1 = NH1#node_handle.nodename,
+ NH2 = start_ssl_node(Config),
+ Node2 = NH2#node_handle.nodename,
+
+ pong = apply_on_ssl_node(NH1, fun () -> net_adm:ping(Node2) end),
+
+ [Node2] = apply_on_ssl_node(NH1, fun () -> nodes() end),
+ [Node1] = apply_on_ssl_node(NH2, fun () -> nodes() end),
+
+ Ref = make_ref(),
+ spawn(fun () ->
+ apply_on_ssl_node(
+ NH1,
+ fun () ->
+ send_to_tstcntrl({Ref, self()}),
+ receive
+ {From, Msg} ->
+ From ! {self(), Msg}
+ end
+ end)
+ end),
+ receive
+ {Ref, SslPid} ->
+ ok = apply_on_ssl_node(
+ NH2,
+ fun () ->
+ Msg = crypto:rand_bytes(100000),
+ SslPid ! {self(), Msg},
+ receive
+ {SslPid, Msg} ->
+ ok
+ end
+ end)
+ end,
+ stop_ssl_node(NH1),
+ stop_ssl_node(NH2),
+ success(Config).
+%%--------------------------------------------------------------------
+plain_options(doc) ->
+ ["Test specifying additional options"];
+plain_options(Config) when is_list(Config) ->
+ DistOpts = "-ssl_dist_opt server_secure_renegotiate true "
+ "client_secure_renegotiate true "
+ "server_reuse_sessions true client_reuse_sessions true "
+ "client_verify verify_none server_verify verify_none "
+ "server_depth 1 client_depth 1 "
+ "server_hibernate_after 500 client_hibernate_after 500",
+
+ NH1 = start_ssl_node([{additional_dist_opts, DistOpts} | Config]),
+ Node1 = NH1#node_handle.nodename,
+ NH2 = start_ssl_node([{additional_dist_opts, DistOpts} | Config]),
+ Node2 = NH2#node_handle.nodename,
+
+ pong = apply_on_ssl_node(NH1, fun () -> net_adm:ping(Node2) end),
+
+ [Node2] = apply_on_ssl_node(NH1, fun () -> nodes() end),
+ [Node1] = apply_on_ssl_node(NH2, fun () -> nodes() end),
+
+ stop_ssl_node(NH1),
+ stop_ssl_node(NH2),
+ success(Config).
+%%--------------------------------------------------------------------
+plain_verify_options(doc) ->
+ ["Test specifying additional options"];
+plain_verify_options(Config) when is_list(Config) ->
+ DistOpts = "-ssl_dist_opt server_secure_renegotiate true "
+ "client_secure_renegotiate true "
+ "server_reuse_sessions true client_reuse_sessions true "
+ "server_hibernate_after 500 client_hibernate_after 500",
+
+ NH1 = start_ssl_node([{additional_dist_opts, DistOpts} | Config]),
+ Node1 = NH1#node_handle.nodename,
+ NH2 = start_ssl_node([{additional_dist_opts, DistOpts} | Config]),
+ Node2 = NH2#node_handle.nodename,
+
+ pong = apply_on_ssl_node(NH1, fun () -> net_adm:ping(Node2) end),
+
+ [Node2] = apply_on_ssl_node(NH1, fun () -> nodes() end),
+ [Node1] = apply_on_ssl_node(NH2, fun () -> nodes() end),
+
+ stop_ssl_node(NH1),
+ stop_ssl_node(NH2),
+ success(Config).
+
+%%--------------------------------------------------------------------
+%%% Internal functions
+%%--------------------------------------------------------------------
-%%
%% ssl_node side api
%%
@@ -166,7 +262,7 @@ send_to_tstcntrl(Message) ->
%% test_server side api
%%
-apply_on_ssl_node(Node, M, F, A) when atom(M), atom(F), list(A) ->
+apply_on_ssl_node(Node, M, F, A) when is_atom(M), is_atom(F), is_list(A) ->
Ref = make_ref(),
send_to_ssl_node(Node, {apply, self(), Ref, M, F, A}),
receive
@@ -208,7 +304,7 @@ start_ssl_node(Config) ->
start_ssl_node(Config, XArgs) ->
Name = mk_node_name(Config),
SSL = ?config(ssl_opts, Config),
- SSLDistOpts = setup_dist_opts(Name, ?config(priv_dir, Config)),
+ SSLDistOpts = setup_dist_opts(Config),
start_ssl_node_raw(Name, SSL ++ " " ++ SSLDistOpts ++ XArgs).
start_ssl_node_raw(Name, Args) ->
@@ -218,7 +314,7 @@ start_ssl_node_raw(Name, Args) ->
CmdLine = mk_node_cmdline(ListenPort, Name, Args),
?t:format("Attempting to start ssl node ~s: ~s~n", [Name, CmdLine]),
case open_port({spawn, CmdLine}, []) of
- Port when port(Port) ->
+ Port when is_port(Port) ->
unlink(Port),
erlang:port_close(Port),
case await_ssl_node_up(Name, LSock) of
@@ -270,8 +366,8 @@ mk_node_cmdline(ListenPort, Name, Args) ->
Prog ++ " "
++ Static ++ " "
++ NameSw ++ " " ++ Name ++ " "
- ++ "-pa " ++ Pa ++ " "
- ++ "-run application start crypto -run application start public_key "
+ ++ "-pa " ++ Pa ++ " "
+ ++ "-run application start crypto -run application start public_key "
++ "-run " ++ atom_to_list(?MODULE) ++ " cnct2tstsrvr "
++ host_name() ++ " "
++ integer_to_list(ListenPort) ++ " "
@@ -355,6 +451,7 @@ tstsrvr_con_loop(Name, Socket, Parent) ->
{format, FmtStr, ArgList} ->
?t:format(FmtStr, ArgList);
{message, Msg} ->
+ ?t:format("Got message ~p", [Msg]),
Parent ! Msg;
{apply_res, To, Ref, Res} ->
To ! {Ref, Res};
@@ -376,7 +473,7 @@ tstsrvr_con_loop(Name, Socket, Parent) ->
%%
% cnct2tstsrvr() is called via command line arg -run ...
-cnct2tstsrvr([Host, Port]) when list(Host), list(Port) ->
+cnct2tstsrvr([Host, Port]) when is_list(Host), is_list(Port) ->
%% Spawn connection handler on ssl node side
ConnHandler
= spawn(fun () ->
@@ -395,8 +492,10 @@ cnct2tstsrvr([Host, Port]) when list(Host), list(Port) ->
ets:insert(test_server_info,
{test_server_handler, self()}),
ssl_node_con_loop(Socket);
- _Error ->
- halt("Failed to connect to test server")
+ Error ->
+ halt("Failed to connect to test server " ++
+ lists:flatten(io_lib:format("Host:~p ~n Port:~p~n Error:~p~n",
+ [Host, Port, Error])))
end
end),
spawn(fun () ->
@@ -404,9 +503,8 @@ cnct2tstsrvr([Host, Port]) when list(Host), list(Port) ->
receive
{'DOWN', Mon, process, ConnHandler, Reason} ->
receive after 1000 -> ok end,
- halt("test server connection handler terminated: "
- ++
- lists:flatten(io_lib:format("~p", [Reason])))
+ halt("test server connection handler terminated: " ++
+ lists:flatten(io_lib:format("~p", [Reason])))
end
end).
@@ -419,7 +517,7 @@ notify_ssl_node_up(Socket) ->
send_to_tstsrvr(Term) ->
case catch ets:lookup_element(test_server_info, test_server_handler, 2) of
- Hndlr when pid(Hndlr) ->
+ Hndlr when is_pid(Hndlr) ->
Hndlr ! {relay_to_test_server, term_to_binary(Term)}, ok;
_ ->
receive after 200 -> ok end,
@@ -499,9 +597,10 @@ do_append_files([F|Fs], RF) ->
{ok, Data} = file:read_file(F),
ok = file:write(RF, Data),
do_append_files(Fs, RF).
-
-setup_dist_opts(Name, PrivDir) ->
- NodeDir = filename:join([PrivDir, Name]),
+
+setup_certs(Config) ->
+ PrivDir = ?config(priv_dir, Config),
+ NodeDir = filename:join([PrivDir, "Certs"]),
RGenDir = filename:join([NodeDir, "rand_gen"]),
ok = file:make_dir(NodeDir),
ok = file:make_dir(RGenDir),
@@ -516,11 +615,61 @@ setup_dist_opts(Name, PrivDir) ->
CC = filename:join([CDir, "cert.pem"]),
CK = filename:join([CDir, "key.pem"]),
CKC = filename:join([CDir, "keycert.pem"]),
- append_files([CK, CC], CKC),
- "-proto_dist inet_ssl "
- ++ "-ssl_dist_opt server_certfile " ++ SKC ++ " "
- ++ "-ssl_dist_opt client_certfile " ++ CKC ++ " "
-.% ++ "-ssl_dist_opt verify 1 depth 1".
+ append_files([CK, CC], CKC).
+
+setup_dist_opts(Config) ->
+ PrivDir = ?config(priv_dir, Config),
+ DataDir = ?config(data_dir, Config),
+ Dhfile = filename:join([DataDir, "dHParam.pem"]),
+ NodeDir = filename:join([PrivDir, "Certs"]),
+ SDir = filename:join([NodeDir, "server"]),
+ CDir = filename:join([NodeDir, "client"]),
+ SC = filename:join([SDir, "cert.pem"]),
+ SK = filename:join([SDir, "key.pem"]),
+ SKC = filename:join([SDir, "keycert.pem"]),
+ SCA = filename:join([CDir, "cacerts.pem"]),
+ CC = filename:join([CDir, "cert.pem"]),
+ CK = filename:join([CDir, "key.pem"]),
+ CKC = filename:join([CDir, "keycert.pem"]),
+ CCA = filename:join([SDir, "cacerts.pem"]),
+
+ DistOpts = case proplists:get_value(many_verify_opts, Config, false) of
+ false ->
+ "-proto_dist inet_tls "
+ ++ "-ssl_dist_opt server_certfile " ++ SKC ++ " "
+ ++ "-ssl_dist_opt client_certfile " ++ CKC ++ " ";
+ true ->
+ case os:type() of
+ {win32, _} ->
+ "-proto_dist inet_tls "
+ ++ "-ssl_dist_opt server_certfile " ++ SKC ++ " "
+ ++ "-ssl_dist_opt server_cacertfile " ++ SCA ++ " "
+ ++ "-ssl_dist_opt server_verify verify_peer "
+ ++ "-ssl_dist_opt server_fail_if_no_peer_cert true "
+ ++ "-ssl_dist_opt server_ciphers DHE-RSA-AES256-SHA\:DHE-RSA-AES128-SHA "
+ ++ "-ssl_dist_opt server_dhfile " ++ Dhfile ++ " "
+ ++ "-ssl_dist_opt client_certfile " ++ CKC ++ " "
+ ++ "-ssl_dist_opt client_cacertfile " ++ CCA ++ " "
+ ++ "-ssl_dist_opt client_verify verify_peer "
+ ++ "-ssl_dist_opt client_ciphers DHE-RSA-AES256-SHA\:DHE-RSA-AES128-SHA ";
+ _ ->
+ "-proto_dist inet_tls "
+ ++ "-ssl_dist_opt server_certfile " ++ SC ++ " "
+ ++ "-ssl_dist_opt server_keyfile " ++ SK ++ " "
+ ++ "-ssl_dist_opt server_cacertfile " ++ SCA ++ " "
+ ++ "-ssl_dist_opt server_verify verify_peer "
+ ++ "-ssl_dist_opt server_fail_if_no_peer_cert true "
+ ++ "-ssl_dist_opt server_ciphers DHE-RSA-AES256-SHA\:DHE-RSA-AES128-SHA "
+ ++ "-ssl_dist_opt server_dhfile " ++ Dhfile ++ " "
+ ++ "-ssl_dist_opt client_certfile " ++ CC ++ " "
+ ++ "-ssl_dist_opt client_keyfile " ++ CK ++ " "
+ ++ "-ssl_dist_opt client_cacertfile " ++ CCA ++ " "
+ ++ "-ssl_dist_opt client_verify verify_peer "
+ ++ "-ssl_dist_opt client_ciphers DHE-RSA-AES256-SHA\:DHE-RSA-AES128-SHA "
+ end
+ end,
+ MoreOpts = proplists:get_value(additional_dist_opts, Config, []),
+ DistOpts ++ MoreOpts.
%%
%% Start scripts etc...
@@ -544,7 +693,7 @@ add_ssl_opts_config(Config) ->
SSL_VSN = vsn(ssl),
VSN_CRYPTO = vsn(crypto),
VSN_PKEY = vsn(public_key),
-
+
SslDir = filename:join([LibDir, "ssl-" ++ SSL_VSN]),
{ok, _} = file:read_file_info(SslDir),
%% We are using an installed otp system, create the boot script.
diff --git a/lib/ssl/test/ssl_dist_SUITE_data/dHParam.pem b/lib/ssl/test/ssl_dist_SUITE_data/dHParam.pem
new file mode 100644
index 0000000000..feb581da30
--- /dev/null
+++ b/lib/ssl/test/ssl_dist_SUITE_data/dHParam.pem
@@ -0,0 +1,5 @@
+-----BEGIN DH PARAMETERS-----
+MIGHAoGBAMY5VmCZ22ZEy/KO8kjt94PH7ZtSG0Z0zitlMlvd4VsNkDzXsVeu+wkH
+FGDC3h3vgv6iwXGCbmrSOVk/FPZbzLhwZ8aLnkUFOBbOvVvb1JptQwOt8mf+eScG
+M2gGBktheQV5Nf1IrzOctG7VGt+neiqb/Y86uYCcDdL+M8++0qnLAgEC
+-----END DH PARAMETERS-----
diff --git a/lib/ssl/test/ssl_packet_SUITE.erl b/lib/ssl/test/ssl_packet_SUITE.erl
index 9d2599b778..4b74f57a60 100644
--- a/lib/ssl/test/ssl_packet_SUITE.erl
+++ b/lib/ssl/test/ssl_packet_SUITE.erl
@@ -158,14 +158,24 @@ all() ->
packet_asn1_decode, packet_asn1_decode_list,
packet_tpkt_decode, packet_tpkt_decode_list,
packet_sunrm_decode, packet_sunrm_decode_list,
- header_decode_one_byte, header_decode_two_bytes,
- header_decode_two_bytes_one_sent,
- header_decode_two_bytes_two_sent].
+ {group, header}
+ ].
groups() ->
- [].
+ [{header, [], [ header_decode_one_byte,
+ header_decode_two_bytes,
+ header_decode_two_bytes_one_sent,
+ header_decode_two_bytes_two_sent]}].
+
+init_per_group(header, Config) ->
+ case ssl_record:highest_protocol_version(ssl_record:supported_protocol_versions()) of
+ {3, N} when N < 2 ->
+ {skip, ""};
+ _ ->
+ Config
+ end;
-init_per_group(_GroupName, Config) ->
+init_per_group(_, Config) ->
Config.
end_per_group(_GroupName, Config) ->
@@ -2626,6 +2636,13 @@ active_once_raw(_, _, 0, _) ->
ok;
active_once_raw(Socket, Data, N, Acc) ->
receive
+ {ssl, Socket, Byte} when length(Byte) == 1 ->
+ ssl:setopts(Socket, [{active, once}]),
+ receive
+ {ssl, Socket, _} ->
+ ssl:setopts(Socket, [{active, once}]),
+ active_once_raw(Socket, Data, N-1, [])
+ end;
{ssl, Socket, Data} ->
ssl:setopts(Socket, [{active, once}]),
active_once_raw(Socket, Data, N-1, []);
@@ -2648,7 +2665,14 @@ active_once_packet(Socket,_, 0) ->
{other, Other, ssl:session_info(Socket), 0}
end;
active_once_packet(Socket, Data, N) ->
- receive
+ receive
+ {ssl, Socket, Byte} when length(Byte) == 1 ->
+ ssl:setopts(Socket, [{active, once}]),
+ receive
+ {ssl, Socket, _} ->
+ ssl:setopts(Socket, [{active, once}]),
+ active_once_packet(Socket, Data, N-1)
+ end;
{ssl, Socket, Data} ->
ok
end,
@@ -2662,6 +2686,11 @@ active_raw(_Socket, _, 0, _) ->
ok;
active_raw(Socket, Data, N, Acc) ->
receive
+ {ssl, Socket, Byte} when length(Byte) == 1 ->
+ receive
+ {ssl, Socket, _} ->
+ active_raw(Socket, Data, N -1)
+ end;
{ssl, Socket, Data} ->
active_raw(Socket, Data, N-1, []);
{ssl, Socket, Other} ->
@@ -2682,6 +2711,11 @@ active_packet(Socket, _, 0) ->
end;
active_packet(Socket, Data, N) ->
receive
+ {ssl, Socket, Byte} when length(Byte) == 1 ->
+ receive
+ {ssl, Socket, _} ->
+ active_packet(Socket, Data, N -1)
+ end;
{ssl, Socket, Data} ->
active_packet(Socket, Data, N -1);
Other ->
diff --git a/lib/ssl/test/ssl_session_cache_SUITE.erl b/lib/ssl/test/ssl_session_cache_SUITE.erl
index 5ea45018e6..9c4a5ce640 100644
--- a/lib/ssl/test/ssl_session_cache_SUITE.erl
+++ b/lib/ssl/test/ssl_session_cache_SUITE.erl
@@ -210,7 +210,7 @@ session_cleanup(Config)when is_list(Config) ->
{status, _, _, StatusInfo} = sys:get_status(whereis(ssl_manager)),
[_, _,_, _, Prop] = StatusInfo,
- State = state(Prop),
+ State = ssl_test_lib:state(Prop),
Cache = element(2, State),
SessionTimer = element(6, State),
@@ -229,7 +229,7 @@ session_cleanup(Config)when is_list(Config) ->
check_timer(DelayTimer),
- test_server:sleep(?SLEEP), %% Make sure clean has had to run
+ test_server:sleep(?SLEEP), %% Make sure clean has had time to run
undefined = ssl_session_cache:lookup(Cache, {{Hostname, Port}, Id}),
undefined = ssl_session_cache:lookup(Cache, {Port, Id}),
@@ -238,11 +238,6 @@ session_cleanup(Config)when is_list(Config) ->
ssl_test_lib:close(Server),
ssl_test_lib:close(Client).
-state([{data,[{"State", State}]} | _]) ->
- State;
-state([_ | Rest]) ->
- state(Rest).
-
check_timer(Timer) ->
case erlang:read_timer(Timer) of
false ->
@@ -256,7 +251,7 @@ check_timer(Timer) ->
get_delay_timer() ->
{status, _, _, StatusInfo} = sys:get_status(whereis(ssl_manager)),
[_, _,_, _, Prop] = StatusInfo,
- State = state(Prop),
+ State = ssl_test_lib:state(Prop),
case element(7, State) of
undefined ->
test_server:sleep(?SLEEP),
diff --git a/lib/ssl/test/ssl_test_MACHINE.erl b/lib/ssl/test/ssl_test_MACHINE.erl
deleted file mode 100644
index e0ffa15d80..0000000000
--- a/lib/ssl/test/ssl_test_MACHINE.erl
+++ /dev/null
@@ -1,940 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2003-2010. All Rights Reserved.
-%%
-%% The contents of this file are subject to the Erlang Public License,
-%% Version 1.1, (the "License"); you may not use this file except in
-%% compliance with the License. You should have received a copy of the
-%% Erlang Public License along with this software. If not, it can be
-%% retrieved online at http://www.erlang.org/.
-%%
-%% Software distributed under the License is distributed on an "AS IS"
-%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
-%% the License for the specific language governing rights and limitations
-%% under the License.
-%%
-%% %CopyrightEnd%
-%%
-
-%%
--module(ssl_test_MACHINE).
-
--export([many_conns/0, mk_ssl_cert_opts/1, test_one_listener/7,
- test_server_only/6]).
-
--export([process_init/3, do_start/1]).
-
-
--include("test_server.hrl").
--include("ssl_test_MACHINE.hrl").
-
--define(WAIT_TIMEOUT, 10000).
--define(CLOSE_WAIT, 1000).
-
-%%
-%% many_conns() -> ManyConnections
-%%
-%% Choose a suitable number of "many connections" depending on platform
-%% and current limit for file descriptors.
-%%
-many_conns() ->
- case os:type() of
- {unix,_} -> many_conns_1();
- _ -> 10
- end.
-
-many_conns_1() ->
- N0 = os:cmd("ulimit -n"),
- N1 = lists:reverse(N0),
- N2 = lists:dropwhile(fun($\r) -> true;
- ($\n) -> true;
- (_) -> false
- end, N1),
- N = list_to_integer(lists:reverse(N2)),
- lists:min([(N - 10) div 2, 501]).
-
-%%
-%% mk_ssl_cert_opts(Config) -> {ok, {COpts, SOpts}}
-%%
-%%
-mk_ssl_cert_opts(_Config) ->
- Dir = filename:join([code:lib_dir(ssl), "examples", "certs", "etc"]),
- COpts = [{ssl_imp, old},
- {cacertfile, filename:join([Dir, "client", "cacerts.pem"])},
- {certfile, filename:join([Dir, "client", "cert.pem"])},
- {keyfile, filename:join([Dir, "client", "key.pem"])}],
- SOpts = [{ssl_imp, old},
- {cacertfile, filename:join([Dir, "server", "cacerts.pem"])},
- {certfile, filename:join([Dir, "server", "cert.pem"])},
- {keyfile, filename:join([Dir, "server", "key.pem"])}],
- {ok, {COpts, SOpts}}.
-
-%%
-%% Cmds:
-%% {protomod, gen_tcp | ssl} default = ssl
-%% {serialize_accept, true | false} default = false
-%% {timeout, Timeout}
-%% {sockopts, Opts}
-%% {sslopts, Opts}
-%% {protocols, Protocols} [sslv2|sslv3|tlsv1]
-%% {listen, Port}
-%% {lsock, LSock} listen socket for acceptor
-%% peercert
-%% accept
-%% {connect, {Host, Port}}
-%% {recv, N}
-%% {send, N}
-%% {echo, N} async echo back
-%% close close connection socket
-%% {close, Time} wait time and then close socket
-%% lclose close listen socket
-%% await_close wait for close
-%% wait_sync listener's wait for sync from parent
-%% connection_info
-%% {exit, Reason} exit
-%%
-%%
-%% We cannot have more than `backlog' acceptors at the same time.
-%%
-
-
-%%
-%% test_one_listener(NConns, LCmds, ACmds, CCmds, Timeout, Suite, Config)
-%%
-%% Creates one client and one server node, and runs one listener on
-%% the server node (according to LCmds), and creates NConns acceptors
-%% on the server node, and the same number of connectors on the client
-%% node. The acceptors and and connectors execute according to ACmds
-%% and CCmds, respectively.
-%%
-%% It is a good idea to have the backlog size in LCmds set to
-%% be at least as large as NConns.
-%%
-test_one_listener(NConns, LCmds0, ACmds0, CCmds0, Timeout, Suite, Config) ->
- ProtoMod = get_protomod(Config),
- SerializeAccept = get_serialize_accept(Config),
- ?line {ok, {CNode, SNode}} = start_client_server_nodes(Suite),
- case ProtoMod of
- ssl ->
- ?line ok = start_ssl([CNode, SNode], Config);
- gen_tcp ->
- ok
- end,
- LCmds = [{protomod, ProtoMod}| LCmds0],
- ACmds = [{protomod, ProtoMod}, {serialize_accept, SerializeAccept}|
- ACmds0],
- CCmds = [{protomod, ProtoMod}| CCmds0],
-
- ?line {ok, Listener} = start_process(SNode, self(), LCmds, listener),
- ?line {ok, LSock} = wait_lsock(Listener, ?WAIT_TIMEOUT),
- ?line {ok, Accs0} = start_processes(NConns, SNode, self(),
- [{lsock, LSock}| ACmds], acceptor),
- Accs = case ProtoMod of
- gen_tcp ->
- [Acc1| Accs1] = Accs0,
- Acc1 ! {continue_accept, self()},
- Accs1;
- ssl ->
- Accs0
- end,
- ?line {ok, Conns} = start_processes(NConns, CNode, self(),
- CCmds, connector),
- ?line case wait_ack(Accs, Accs0 ++ Conns, Timeout) of
- ok ->
- ?line sync([Listener]),
- ?line wait_ack([], [Listener], ?WAIT_TIMEOUT);
- {error, Reason} ->
- ?line stop_node(SNode),
- ?line stop_node(CNode),
- exit(Reason)
- end,
- ?line stop_node(SNode),
- ?line stop_node(CNode),
- ok.
-
-%%
-%% test_server_only(NConns, LCmds, ACmds, Timeout, Suite, Config)
-%%
-%% Creates only one server node, and runs one listener on
-%% the server node (according to LCmds), and creates NConns acceptors
-%% on the server node. The acceptors execute according to ACmds.
-%% There are no connectors.
-%%
-test_server_only(NConns, LCmds0, ACmds0, Timeout, Suite, Config) ->
- ProtoMod = get_protomod(Config),
- ?line {ok, SNode} = start_server_node(Suite),
- case ProtoMod of
- ssl ->
- ?line ok = start_ssl([SNode], Config);
- gen_tcp ->
- ok
- end,
- LCmds = [{protomod, ProtoMod}| LCmds0],
- ACmds = [{protomod, ProtoMod}| ACmds0],
- ?line {ok, Listener} = start_process(SNode, self(), LCmds, listener),
- ?line {ok, LSock} = wait_lsock(Listener, ?WAIT_TIMEOUT),
- ?line {ok, Accs0} = start_processes(NConns, SNode, self(),
- [{lsock, LSock}| ACmds], acceptor),
- Accs = case ProtoMod of
- gen_tcp ->
- [Acc1| Accs1] = Accs0,
- Acc1 ! {continue_accept, self()},
- Accs1;
- ssl ->
- Accs0
- end,
- ?line case wait_ack(Accs, Accs0, Timeout) of
- ok ->
- ?line sync([Listener]),
- ?line wait_ack([], [Listener], ?WAIT_TIMEOUT);
- {error, Reason} ->
- ?line stop_node(SNode),
- exit(Reason)
- end,
- ?line stop_node(SNode),
- ok.
-
-%%
-%% start_client_server_nodes(Suite) -> {ok, {CNode, SNode}}
-%%
-start_client_server_nodes(Suite) ->
- {ok, CNode} = start_client_node(Suite),
- {ok, SNode} = start_server_node(Suite),
- {ok, {CNode, SNode}}.
-
-start_client_node(Suite) ->
- start_node(lists:concat([Suite, "_client"])).
-
-start_server_node(Suite) ->
- start_node(lists:concat([Suite, "_server"])).
-
-%%
-%% start_ssl(Nodes, Config)
-%%
-start_ssl(Nodes, Config) ->
- Env0 = lists:flatten([Env00 || {env, Env00} <- Config]),
- Env1 = case os:getenv("SSL_DEBUG") of
- false ->
- [];
- _ ->
- Dir = ?config(priv_dir, Config),
- [{debug, true}, {debugdir, Dir}]
- end,
- Env = Env0 ++ Env1,
- lists:foreach(
- fun(Node) -> rpc:call(Node, ?MODULE, do_start, [Env]) end, Nodes),
- ok.
-
-do_start(Env) ->
- application:start(crypto),
- application:start(public_key),
- application:load(ssl),
- lists:foreach(
- fun({Par, Val}) -> application:set_env(ssl, Par, Val) end, Env),
- application:start(ssl).
-
-
-%%
-%% start_node(Name) -> {ok, Node}
-%% start_node(Name, ExtraParams) -> {ok, Node}
-%%
-start_node(Name) ->
- start_node(Name, []).
-start_node(Name, ExtraParams) ->
- Params = "-pa " ++ filename:dirname(code:which(?MODULE)) ++ " " ++
- ExtraParams,
- test_server:start_node(Name, slave, [{args, Params}]).
-
-stop_node(Node) ->
- test_server:stop_node(Node).
-
-%%
-%% start_processes(N, Node, Parent, Cmds, Type) -> {ok, Pids}
-%%
-start_processes(M, Node, Parent, Cmds, Type) ->
- start_processes1(0, M, Node, Parent, Cmds, Type, []).
-start_processes1(M, M, _, _, _, _, Pids) ->
- {ok, lists:reverse(Pids)};
-start_processes1(N, M, Node, Parent, Cmds, Type, Pids) ->
- {ok, Pid} = start_process(Node, Parent, Cmds, {Type, N + 1}),
- start_processes1(N + 1, M, Node, Parent, Cmds, Type, [Pid| Pids]).
-
-%%
-%% start_process(Node, Parent, Cmds, Type) -> {ok, Pid}
-%%
-start_process(Node, Parent, Cmds0, Type) ->
- Cmds = case os:type() of
- {win32, _} ->
- lists:map(fun(close) -> {close, ?CLOSE_WAIT};
- (Term) -> Term end, Cmds0);
- _ ->
- Cmds0
- end,
- Pid = spawn_link(Node, ?MODULE, process_init, [Parent, Cmds, Type]),
- {ok, Pid}.
-
-process_init(Parent, Cmds, Type) ->
- ?debug("#### ~w start~n", [{Type, self()}]),
- pre_main_loop(Cmds, #st{parent = Parent, type = Type}).
-
-%%
-%% pre_main_loop
-%%
-pre_main_loop([], St) ->
- ?debug("#### ~w end~n", [{St#st.type, self()}]),
- main_loop([], St);
-pre_main_loop(Cmds, St) ->
- ?debug("#### ~w -> ~w~n",
- [{St#st.type, self(), St#st.sock, St#st.port,
- St#st.peer, St#st.active}, hd(Cmds)]),
- main_loop(Cmds, St).
-
-%%
-%% main_loop(Cmds, St)
-%%
-main_loop([{protomod, ProtoMod}| Cmds], St) ->
- pre_main_loop(Cmds, St#st{protomod = ProtoMod});
-
-main_loop([{serialize_accept, Bool}| Cmds], St) ->
- pre_main_loop(Cmds, St#st{serialize_accept = Bool});
-
-main_loop([{sockopts, Opts}| Cmds], St) ->
- pre_main_loop(Cmds, St#st{sockopts = Opts});
-
-main_loop([{sslopts, Opts}| Cmds], St) ->
- pre_main_loop(Cmds, St#st{sslopts = Opts});
-
-main_loop([{protocols, Protocols}| Cmds], St) ->
- pre_main_loop(Cmds, St#st{protocols = Protocols});
-
-main_loop([{timeout, T}| Cmds], St) ->
- pre_main_loop(Cmds, St#st{timeout = T});
-
-main_loop([{lsock, LSock}| Cmds], St) ->
- pre_main_loop(Cmds, St#st{lsock = LSock});
-
-main_loop([{seed, Data}| Cmds], St) ->
- case ssl:seed("tjosan") of
- ok ->
- pre_main_loop(Cmds, St);
- {error, Reason} ->
- ?error("#### ~w(~w) in seed: error: ~w~n",
- [St#st.type, self(), Reason]),
- exit(Reason)
- end;
-
-main_loop([{listen, Port}| Cmds], St) ->
- case listen(St, Port) of
- {ok, LSock} ->
- ack_lsock(St#st.parent, LSock),
- NSt = get_active(St#st{port = Port, sock = LSock, lsock = LSock}),
- pre_main_loop(Cmds, St);
- {error, Reason} ->
- ?error("#### ~w(~w) in listen: error: ~w~n",
- [St#st.type, self(), Reason]),
- exit(Reason)
- end;
-
-main_loop([accept| Cmds], St) ->
- case St#st.serialize_accept of
- true ->
- Parent = St#st.parent,
- receive
- {continue_accept, Parent} ->
- ok
- end;
- false ->
- ok
- end,
- case accept(St) of
- {ok, Sock, Port, Peer} ->
- case St#st.serialize_accept of
- true ->
- St#st.parent ! {one_accept_done, self()};
- false ->
- ok
- end,
- NSt = get_active(St#st{sock = Sock, port = Port, peer = Peer}),
- pre_main_loop(Cmds, NSt);
- {error, Reason} ->
- ?error("#### ~w(~w) in accept: error: ~w~n",
- [St#st.type, self(), Reason]),
- exit(Reason)
- end;
-
-main_loop([accept_timeout| Cmds], St) ->
- case accept(St) of
- {error, timeout} ->
- pre_main_loop(Cmds, St);
- {error, Reason} ->
- ?error("#### ~w(~w) in accept_timeout: error: ~w~n",
- [St#st.type, self(), Reason]),
- exit(Reason)
- end;
-
-
-main_loop([{connect, {Host, Port}}| Cmds], St) ->
- case connect(St, Host, Port) of
- {ok, Sock, LPort, Peer} ->
- NSt = get_active(St#st{sock = Sock, port = LPort, peer = Peer}),
- pre_main_loop(Cmds, NSt);
- {error, Reason} ->
- ?error("#### ~w(~w) in connect: error: ~w~n",
- [St#st.type, self(), Reason]),
- exit(Reason)
- end;
-
-main_loop([connection_info| Cmds], St) ->
- case connection_info(St) of
- {ok, ProtoInfo} ->
- io:fwrite("Got connection_info:~n~p~n", [ProtoInfo]),
- pre_main_loop(Cmds, St);
- {error, Reason} ->
- ?error("#### ~w(~w) in connection_info: error: ~w~n",
- [St#st.type, self(), Reason]),
- exit(Reason)
- end;
-
-main_loop([peercert| Cmds], St) ->
- case peercert(St) of
- {ok, Cert} ->
- io:fwrite("Got cert:~n~p~n", [Cert]),
- pre_main_loop(Cmds, St);
- {error, Reason} ->
- ?error("#### ~w(~w) in peercert: error: ~w~n",
- [St#st.type, self(), Reason]),
- exit(Reason)
- end;
-
-main_loop([nopeercert| Cmds], St) ->
- case peercert(St) of
- {error, Reason} ->
- io:fwrite("Got no cert as expected. reason:~n~p~n", [Reason]),
- pre_main_loop(Cmds, St);
- {ok, Cert} ->
- ?error("#### ~w(~w) in peercert: error: got cert: ~p~n",
- [St#st.type, self(), Cert]),
- exit(peercert)
- end;
-
-main_loop([{recv, N}| Cmds], St) ->
- recv_loop([{recv, N}| Cmds], fun recv/1, St); % Returns to main_loop/2.
-
-main_loop([{send, N}| Cmds], St) ->
- Msg = mk_msg(N),
- case send(St, Msg) of
- ok ->
- pre_main_loop(Cmds, St);
- {error, Reason} ->
- ?error("#### ~w(~w) in send: error: ~w~n",
- [St#st.type, self(), Reason]),
- exit(Reason)
- end;
-
-main_loop([{echo, N}| Cmds], St) ->
- recv_loop([{echo, N}| Cmds], fun echo/1, St); % Returns to main_loop/2.
-
-main_loop([{close, WaitTime}| Cmds], St) ->
- wait(WaitTime),
- pre_main_loop([close| Cmds], St);
-
-main_loop([close| Cmds], St) ->
- case close(St) of
- ok ->
- pre_main_loop(Cmds, St#st{sock = nil});
- {error, Reason} ->
- ?error("#### ~w(~w) in close: error: ~w~n",
- [St#st.type, self(), Reason]),
- exit(Reason)
- end;
-
-main_loop([lclose| Cmds], St) ->
- case lclose(St) of
- ok ->
- pre_main_loop(Cmds, St#st{lsock = nil});
- {error, Reason} ->
- ?error("#### ~w(~w) in lclose: error: ~w~n",
- [St#st.type, self(), Reason]),
- exit(Reason)
- end;
-
-main_loop([await_close| Cmds], St) ->
- case await_close(St) of
- ok ->
- pre_main_loop(Cmds, St#st{sock = nil});
- {error, Reason} ->
- ?error("#### ~w(~w) in await_close: error: ~w~n",
- [St#st.type, self(), Reason]),
- exit(Reason)
- end;
-
-main_loop([wait_sync| Cmds], St) ->
- wait_sync(St),
- pre_main_loop(Cmds, St);
-
-main_loop({exit, Reason}, _St) ->
- exit(Reason);
-
-main_loop([], _St) ->
- ok.
-
-%%
-%% recv_loop(Cmds, F, St)
-%%
-%% F = recv/1 | echo/1
-%%
-recv_loop([{_Tag, 0}| Cmds], _, St) ->
- pre_main_loop(Cmds, St);
-recv_loop([{_Tag, N}| _Cmds], _, St) when N < 0 ->
- ?error("#### ~w(~w) in recv_loop: error: too much: ~w~n",
- [St#st.type, self(), N]),
- exit(toomuch); % XXX or {error, Reason}?
-recv_loop([{Tag, N}| Cmds], F, St) ->
- case F(St) of
- {ok, Len} ->
- NSt = St#st{active = new_active(St#st.active)},
- if
- Len == N ->
- pre_main_loop(Cmds, NSt);
- true ->
- ?debug("#### ~w -> ~w~n",
- [{NSt#st.type, self(), NSt#st.sock, NSt#st.port,
- NSt#st.peer, NSt#st.active}, {Tag, N - Len}]),
- recv_loop([{Tag, N - Len}| Cmds], F, NSt)
- end;
- {error, Reason} ->
- ?error("#### ~w(~w) in recv_loop: error: ~w, ~w bytes remain~n",
- [St#st.type, self(), Reason, N]),
- exit(Reason)
- end.
-
-new_active(once) ->
- false;
-new_active(A) ->
- A.
-
-get_active(St) ->
- A = case proplists:get_value(active, St#st.sockopts, undefined) of
- undefined ->
- Mod = case St#st.protomod of
- ssl ->
- ssl;
- gen_tcp ->
- inet
- end,
- {ok, [{active, Ax}]} = Mod:getopts(St#st.sock, [active]),
- Ax;
- Ay ->
- Ay
- end,
- ?debug("#### ~w(~w) get_active: ~p\n", [St#st.type, self(), A]),
- St#st{active = A}.
-
-
-%%
-%% SOCKET FUNCTIONS
-%%
-
-%%
-%% ssl
-%%
-
-%%
-%% listen(St, LPort) -> {ok, LSock} | {error, Reason}
-%%
-listen(St, LPort) ->
- case St#st.protomod of
- ssl ->
- ssl:listen(LPort, [{ssl_imp, old} | St#st.sockopts ++ St#st.sslopts]);
- gen_tcp ->
- gen_tcp:listen(LPort, St#st.sockopts)
- end.
-
-%%
-%% accept(St) -> {ok, Sock} | {error, Reason}
-%%
-accept(St) ->
- case St#st.protomod of
- ssl ->
- case ssl:transport_accept(St#st.lsock, St#st.timeout) of
- {ok, Sock} ->
- case ssl:ssl_accept(Sock, St#st.timeout) of
- ok ->
- {ok, Port} = ssl:sockname(Sock),
- {ok, Peer} = ssl:peername(Sock),
- {ok, Sock, Port, Peer};
- Other ->
- Other
- end;
- Other ->
- Other
- end;
- gen_tcp ->
- case gen_tcp:accept(St#st.lsock, St#st.timeout) of
- {ok, Sock} ->
- {ok, Port} = inet:port(Sock),
- {ok, Peer} = inet:peername(Sock),
- {ok, Sock, Port, Peer};
- Other ->
- Other
- end
- end.
-
-%%
-%% connect(St, Host, Port) -> {ok, Sock} | {error, Reason}
-%%
-connect(St, Host, Port) ->
-
- case St#st.protomod of
- ssl ->
- case ssl:connect(Host, Port,
- [{ssl_imp, old} | St#st.sockopts ++ St#st.sslopts],
- St#st.timeout) of
- {ok, Sock} ->
- {ok, LPort} = ssl:sockname(Sock),
- {ok, Peer} = ssl:peername(Sock),
- {ok, Sock, LPort, Peer};
- Other ->
- Other
- end;
- gen_tcp ->
- case gen_tcp:connect(Host, Port, St#st.sockopts, St#st.timeout) of
- {ok, Sock} ->
- {ok, LPort} = inet:port(Sock),
- {ok, Peer} = inet:peername(Sock),
- {ok, Sock, LPort, Peer};
- Other ->
- Other
- end
- end.
-
-%%
-%% peercert(St) -> {ok, Cert} | {error, Reason}
-%%
-peercert(St) ->
- case St#st.protomod of
- ssl ->
- ssl:peercert(St#st.sock, [ssl]);
- gen_tcp ->
- {ok, <<>>}
- end.
-
-%%
-%% connection_info(St) -> {ok, ProtoInfo} | {error, Reason}
-%%
-connection_info(St) ->
- case St#st.protomod of
- ssl ->
- case ssl:connection_info(St#st.sock) of
- Res = {ok, {Proto, _}} ->
- case St#st.protocols of
- [] ->
- Res;
- Protocols ->
- case lists:member(Proto, Protocols) of
- true ->
- Res;
- false ->
- {error, Proto}
- end
- end;
- Error ->
- Error
- end;
- gen_tcp ->
- {ok, <<>>}
- end.
-
-%%
-%% close(St) -> ok | {error, Reason}
-%%
-
-close(St) ->
- Mod = St#st.protomod,
- case St#st.sock of
- nil ->
- ok;
- _ ->
- Mod:close(St#st.sock)
- end.
-
-%%
-%% lclose(St) -> ok | {error, Reason}
-%%
-lclose(St) ->
- Mod = St#st.protomod,
- case St#st.lsock of
- nil ->
- ok;
- _ ->
- Mod:close(St#st.lsock)
- end.
-
-%%
-%% recv(St) = {ok, Len} | {error, Reason}
-%%
-recv(St) ->
- case do_recv(St) of
- {ok, Msg} ->
- {ok, length(Msg)};
- {error, Reason} ->
- {error, Reason}
- end.
-
-do_recv(St) when St#st.active == false ->
- %% First check that we do *not* have any ssl/gen_tcp messages in the
- %% message queue, then call the receive function.
- Sock = St#st.sock,
- case St#st.protomod of
- ssl ->
- receive
- M = {ssl, Sock, _Msg} ->
- {error, {unexpected_messagex, M}};
- M = {ssl_closed, Sock} ->
- {error, {unexpected_message, M}};
- M = {ssl_error, Sock, _Reason} ->
- {error, {unexpected_message, M}}
- after 0 ->
- ssl:recv(St#st.sock, 0, St#st.timeout)
- end;
- gen_tcp ->
- receive
- M = {tcp, Sock, _Msg} ->
- {error, {unexpected_message, M}};
- M = {tcp_closed, Sock} ->
- {error, {unexpected_message, M}};
- M = {tcp_error, Sock, _Reason} ->
- {error, {unexpected_message, M}}
- after 0 ->
- gen_tcp:recv(St#st.sock, 0, St#st.timeout)
- end
- end;
-do_recv(St) ->
- Sock = St#st.sock,
- Timeout = St#st.timeout,
- case St#st.protomod of
- ssl ->
- receive
- {ssl, Sock, Msg} ->
- {ok, Msg};
- {ssl_closed, Sock} ->
- {error, closed};
- {ssl_error, Sock, Reason} ->
- {error, Reason}
- after Timeout ->
- {error, timeout}
- end;
- gen_tcp ->
- receive
- {tcp, Sock, Msg} ->
- {ok, Msg};
- {tcp_closed, Sock} ->
- {error, closed};
- {tcp_error, Sock, Reason} ->
- {error, Reason}
- after Timeout ->
- {error, timeout}
- end
- end.
-
-%%
-%% echo(St) = {ok, Len} | {error, Reason}
-%%
-echo(St) ->
- Sock = St#st.sock,
- case do_recv(St) of
- {ok, Msg} ->
- Mod = St#st.protomod,
- case Mod:send(Sock, Msg) of
- ok ->
- {ok, length(Msg)};
- {error, Reason} ->
- {error, Reason}
- end;
- {error, Reason} ->
- {error, Reason}
- end.
-
-%%
-%% send(St, Msg) -> ok | {error, Reason}
-%%
-send(St, Msg) ->
- Mod = St#st.protomod,
- Mod:send(St#st.sock, Msg).
-
-%%
-%% await_close(St) -> ok | {error, Reason}
-%%
-await_close(St) when St#st.active == false ->
- %% First check that we do *not* have any ssl/gen_tcp messages in the
- %% message queue, then call the receive function.
- Sock = St#st.sock,
- Res = case St#st.protomod of
- ssl ->
- receive
- M = {ssl, Sock, _Msg0} ->
- {error, {unexpected_message, M}};
- M = {ssl_closed, Sock} ->
- {error, {unexpected_message, M}};
- M = {ssl_error, Sock, _Reason} ->
- {error, {unexpected_message, M}}
- after 0 ->
- ok
- end;
- gen_tcp ->
- receive
- M = {tcp, Sock, _Msg0} ->
- {error, {unexpected_message, M}};
- M = {tcp_closed, Sock} ->
- {error, {unexpected_message, M}};
- M = {tcp_error, Sock, _Reason} ->
- {error, {unexpected_message, M}}
- after 0 ->
- ok
- end
- end,
- case Res of
- ok ->
- Mod = St#st.protomod,
- case Mod:recv(St#st.sock, 0, St#st.timeout) of
- {ok, _Msg} ->
- {error, toomuch};
- {error, _} ->
- ok
- end;
- _ ->
- Res
- end;
-await_close(St) ->
- Sock = St#st.sock,
- Timeout = St#st.timeout,
- case St#st.protomod of
- ssl ->
- receive
- {ssl, Sock, _Msg} ->
- {error, toomuch};
- {ssl_closed, Sock} ->
- ok;
- {ssl_error, Sock, Reason} ->
- {error, Reason}
- after Timeout ->
- {error, timeout}
- end;
- gen_tcp ->
- receive
- {tcp, Sock, _Msg} ->
- {error, toomuch};
- {tcp_closed, Sock} ->
- ok;
- {tcp_error, Sock, Reason} ->
- {error, Reason}
- after Timeout ->
- {error, timeout}
- end
- end.
-
-
-%%
-%% HELP FUNCTIONS
-%%
-
-wait_ack(_, [], _) ->
- ok;
-wait_ack(AccPids0, Pids, Timeout) ->
- ?debug("#### CONTROLLER: waiting for ~w~n", [Pids]),
- receive
- {one_accept_done, Pid} ->
- case lists:delete(Pid, AccPids0) of
- [] ->
- wait_ack([], Pids, Timeout);
- [AccPid| AccPids1] ->
- AccPid ! {continue_accept, self()},
- wait_ack(AccPids1, Pids, Timeout)
- end;
- {'EXIT', Pid, normal} ->
- wait_ack(AccPids0, lists:delete(Pid, Pids), Timeout);
- {'EXIT', Pid, Reason} ->
- ?error("#### CONTROLLER got abnormal exit: ~w, ~w~n",
- [Pid, Reason]),
- {error, Reason}
- after Timeout ->
- ?error("#### CONTROLLER exiting because of timeout = ~w~n",
- [Timeout]),
- {error, Timeout}
- end.
-
-
-%%
-%% ack_lsock(Pid, LSock)
-%%
-ack_lsock(Pid, LSock) ->
- Pid ! {lsock, self(), LSock}.
-
-wait_lsock(Pid, Timeout) ->
- receive
- {lsock, Pid, LSock} ->
- {ok, LSock}
- after Timeout ->
- exit(timeout)
- end.
-
-%%
-%% sync(Pids)
-%%
-sync(Pids) ->
- lists:foreach(fun (Pid) -> Pid ! {self(), sync} end, Pids).
-
-%%
-%% wait_sync(St)
-%%
-wait_sync(St) ->
- Pid = St#st.parent,
- receive
- {Pid, sync} ->
- ok
- end.
-
-%%
-%% wait(Time)
-%%
-wait(Time) ->
- receive
- after Time ->
- ok
- end.
-
-%%
-%% mk_msg(Size)
-%%
-mk_msg(Size) ->
- mk_msg(0, Size, []).
-
-mk_msg(_, 0, Acc) ->
- Acc;
-mk_msg(Pos, Size, Acc) ->
- C = (((Pos + Size) rem 256) - 1) band 255,
- mk_msg(Pos, Size - 1, [C| Acc]).
-
-%%
-%% get_protomod(Config)
-%%
-get_protomod(Config) ->
- case lists:keysearch(protomod, 1, Config) of
- {value, {_, ProtoMod}} ->
- ProtoMod;
- false ->
- ssl
- end.
-
-%%
-%% get_serialize_accept(Config)
-%%
-get_serialize_accept(Config) ->
- case lists:keysearch(serialize_accept, 1, Config) of
- {value, {_, Val}} ->
- Val;
- false ->
- false
- end.
-
diff --git a/lib/ssl/test/ssl_test_lib.erl b/lib/ssl/test/ssl_test_lib.erl
index b7916b96eb..fa8a1826f2 100644
--- a/lib/ssl/test/ssl_test_lib.erl
+++ b/lib/ssl/test/ssl_test_lib.erl
@@ -22,6 +22,7 @@
-include("test_server.hrl").
-include("test_server_line.hrl").
+-include_lib("public_key/include/public_key.hrl").
%% Note: This directive should only be used in test suites.
-compile(export_all).
@@ -661,6 +662,9 @@ cipher_result(Socket, Result) ->
%% to properly test "cipher state" handling
ssl:send(Socket, "Hello\n"),
receive
+ {ssl, Socket, "H"} ->
+ ssl:send(Socket, " world\n"),
+ receive_rizzo_duong_beast();
{ssl, Socket, "Hello\n"} ->
ssl:send(Socket, " world\n"),
receive
@@ -673,3 +677,34 @@ cipher_result(Socket, Result) ->
session_info_result(Socket) ->
ssl:session_info(Socket).
+
+
+public_key(#'PrivateKeyInfo'{privateKeyAlgorithm =
+ #'PrivateKeyInfo_privateKeyAlgorithm'{algorithm = ?rsaEncryption},
+ privateKey = Key}) ->
+ public_key:der_decode('RSAPrivateKey', iolist_to_binary(Key));
+
+public_key(#'PrivateKeyInfo'{privateKeyAlgorithm =
+ #'PrivateKeyInfo_privateKeyAlgorithm'{algorithm = ?'id-dsa'},
+ privateKey = Key}) ->
+ public_key:der_decode('DSAPrivateKey', iolist_to_binary(Key));
+public_key(Key) ->
+ Key.
+receive_rizzo_duong_beast() ->
+ receive
+ {ssl, _, "ello\n"} ->
+ receive
+ {ssl, _, " "} ->
+ receive
+ {ssl, _, "world\n"} ->
+ ok
+ end
+ end
+ end.
+
+state([{data,[{"State", State}]} | _]) ->
+ State;
+state([{data,[{"StateData", State}]} | _]) ->
+ State;
+state([_ | Rest]) ->
+ state(Rest).
diff --git a/lib/ssl/test/ssl_to_openssl_SUITE.erl b/lib/ssl/test/ssl_to_openssl_SUITE.erl
index 64a6a9eaf8..f04ab9af50 100644
--- a/lib/ssl/test/ssl_to_openssl_SUITE.erl
+++ b/lib/ssl/test/ssl_to_openssl_SUITE.erl
@@ -109,6 +109,9 @@ special_init(TestCase, Config)
TestCase == erlang_server_openssl_client_no_wrap_sequence_number ->
check_sane_openssl_renegotaite(Config);
+special_init(ssl2_erlang_server_openssl_client, Config) ->
+ check_sane_openssl_sslv2(Config);
+
special_init(_, Config) ->
Config.
@@ -168,7 +171,8 @@ all() ->
tls1_erlang_server_openssl_client_client_cert,
tls1_erlang_server_erlang_client_client_cert,
ciphers_rsa_signed_certs, ciphers_dsa_signed_certs,
- erlang_client_bad_openssl_server, expired_session,
+ erlang_client_bad_openssl_server,
+ expired_session,
ssl2_erlang_server_openssl_client].
groups() ->
@@ -222,7 +226,6 @@ erlang_client_openssl_server(Config) when is_list(Config) ->
%% Clean close down! Server needs to be closed first !!
close_port(OpensslPort),
-
ssl_test_lib:close(Client),
process_flag(trap_exit, false),
ok.
@@ -256,9 +259,9 @@ erlang_server_openssl_client(Config) when is_list(Config) ->
port_command(OpenSslPort, Data),
ssl_test_lib:check_result(Server, ok),
-
- ssl_test_lib:close(Server),
+ %% Clean close down! Server needs to be closed first !!
+ ssl_test_lib:close(Server),
close_port(OpenSslPort),
process_flag(trap_exit, false),
ok.
@@ -306,7 +309,6 @@ tls1_erlang_client_openssl_server_dsa_cert(Config) when is_list(Config) ->
%% Clean close down! Server needs to be closed first !!
close_port(OpensslPort),
-
ssl_test_lib:close(Client),
process_flag(trap_exit, false),
ok.
@@ -346,8 +348,8 @@ tls1_erlang_server_openssl_client_dsa_cert(Config) when is_list(Config) ->
ssl_test_lib:check_result(Server, ok),
+ %% Clean close down! Server needs to be closed first !!
ssl_test_lib:close(Server),
-
close_port(OpenSslPort),
process_flag(trap_exit, false),
ok.
@@ -395,7 +397,6 @@ ssl3_erlang_client_openssl_server_dsa_cert(Config) when is_list(Config) ->
%% Clean close down! Server needs to be closed first !!
close_port(OpensslPort),
-
ssl_test_lib:close(Client),
process_flag(trap_exit, false),
ok.
@@ -435,8 +436,8 @@ ssl3_erlang_server_openssl_client_dsa_cert(Config) when is_list(Config) ->
ssl_test_lib:check_result(Server, ok),
+ %% Clean close down! Server needs to be closed first !!
ssl_test_lib:close(Server),
-
close_port(OpenSslPort),
process_flag(trap_exit, false),
ok.
@@ -475,8 +476,8 @@ erlang_server_openssl_client_reuse_session(Config) when is_list(Config) ->
ssl_test_lib:check_result(Server, ok),
+ %% Clean close down! Server needs to be closed first !!
ssl_test_lib:close(Server),
-
close_port(OpenSslPort),
process_flag(trap_exit, false),
ok.
@@ -525,7 +526,6 @@ erlang_client_openssl_server_renegotiate(Config) when is_list(Config) ->
%% Clean close down! Server needs to be closed first !!
close_port(OpensslPort),
-
ssl_test_lib:close(Client),
process_flag(trap_exit, false),
ok.
@@ -574,7 +574,6 @@ erlang_client_openssl_server_no_wrap_sequence_number(Config) when is_list(Config
%% Clean close down! Server needs to be closed first !!
close_port(OpensslPort),
-
ssl_test_lib:close(Client),
process_flag(trap_exit, false),
ok.
@@ -615,8 +614,8 @@ erlang_server_openssl_client_no_wrap_sequence_number(Config) when is_list(Config
ssl_test_lib:check_result(Server, ok),
+ %% Clean close down! Server needs to be closed first !!
ssl_test_lib:close(Server),
-
close_port(OpenSslPort),
process_flag(trap_exit, false),
ok.
@@ -663,7 +662,6 @@ erlang_client_openssl_server_no_server_ca_cert(Config) when is_list(Config) ->
%% Clean close down! Server needs to be closed first !!
close_port(OpensslPort),
-
ssl_test_lib:close(Client),
process_flag(trap_exit, false),
ok.
@@ -674,6 +672,7 @@ ssl3_erlang_client_openssl_server(doc) ->
ssl3_erlang_client_openssl_server(suite) ->
[];
ssl3_erlang_client_openssl_server(Config) when is_list(Config) ->
+ process_flag(trap_exit, true),
ServerOpts = ?config(server_opts, Config),
ClientOpts = ?config(client_opts, Config),
@@ -700,11 +699,11 @@ ssl3_erlang_client_openssl_server(Config) when is_list(Config) ->
{options,
[{versions, [sslv3]} | ClientOpts]}]),
ssl_test_lib:check_result(Client, ok),
-
- ssl_test_lib:close(Client),
- %% Clean close down!
+
+ %% Clean close down! Server needs to be closed first !!
close_port(OpensslPort),
- test_server:sleep(?SLEEP),
+ ssl_test_lib:close(Client),
+ process_flag(trap_exit, false),
ok.
%%--------------------------------------------------------------------
@@ -714,6 +713,7 @@ ssl3_erlang_server_openssl_client(doc) ->
ssl3_erlang_server_openssl_client(suite) ->
[];
ssl3_erlang_server_openssl_client(Config) when is_list(Config) ->
+ process_flag(trap_exit, true),
ServerOpts = ?config(server_opts, Config),
{_, ServerNode, _} = ssl_test_lib:run_where(Config),
@@ -734,10 +734,10 @@ ssl3_erlang_server_openssl_client(Config) when is_list(Config) ->
OpenSslPort = open_port({spawn, Cmd}, [stderr_to_stdout]),
ssl_test_lib:check_result(Server, ok),
-
- close_port(OpenSslPort), %% openssl server first
+ %% Clean close down! Server needs to be closed first !!
ssl_test_lib:close(Server),
- test_server:sleep(?SLEEP),
+ close_port(OpenSslPort),
+ process_flag(trap_exit, false),
ok.
%%--------------------------------------------------------------------
@@ -779,7 +779,7 @@ ssl3_erlang_client_openssl_server_client_cert(Config) when is_list(Config) ->
ssl_test_lib:check_result(Client, ok),
- %% Clean close down!
+ %% Clean close down! Server needs to be closed first !!
close_port(OpensslPort),
ssl_test_lib:close(Client),
process_flag(trap_exit, false),
@@ -824,9 +824,9 @@ ssl3_erlang_server_openssl_client_client_cert(Config) when is_list(Config) ->
ssl_test_lib:check_result(Server, ok),
- close_port(OpenSslPort), %% openssl server first
+ %% Clean close down! Server needs to be closed first !!
+ close_port(OpenSslPort),
ssl_test_lib:close(Server),
- %% Clean close down!
process_flag(trap_exit, false),
ok.
@@ -849,7 +849,9 @@ ssl3_erlang_server_erlang_client_client_cert(Config) when is_list(Config) ->
Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
{from, self()},
{mfa, {?MODULE,
- erlang_ssl_receive, [Data]}},
+ erlang_ssl_receive,
+ %% Due to 1/n-1 splitting countermeasure Rizzo/Duong-Beast
+ [Data]}},
{options,
[{verify , verify_peer}
| ServerOpts]}]),
@@ -858,6 +860,7 @@ ssl3_erlang_server_erlang_client_client_cert(Config) when is_list(Config) ->
Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
{host, Hostname},
{from, self()},
+ %% Due to 1/n-1 splitting countermeasure Rizzo/Duong-Beast
{mfa, {ssl, send, [Data]}},
{options,
[{versions, [sslv3]} | ClientOpts]}]),
@@ -869,6 +872,7 @@ ssl3_erlang_server_erlang_client_client_cert(Config) when is_list(Config) ->
process_flag(trap_exit, false),
ok.
+
%%--------------------------------------------------------------------
tls1_erlang_client_openssl_server(doc) ->
@@ -907,10 +911,10 @@ tls1_erlang_client_openssl_server(Config) when is_list(Config) ->
[{versions, [tlsv1]} | ClientOpts]}]),
ssl_test_lib:check_result(Client, ok),
-
- ssl_test_lib:close(Client),
- %% Clean close down!
+
+ %% Clean close down! Server needs to be closed first !!
close_port(OpensslPort),
+ ssl_test_lib:close(Client),
process_flag(trap_exit, false),
ok.
@@ -943,9 +947,9 @@ tls1_erlang_server_openssl_client(Config) when is_list(Config) ->
ssl_test_lib:check_result(Server, ok),
- %% Clean close down!
- close_port(OpenSslPort),
+ %% Clean close down! Server needs to be closed first !!
ssl_test_lib:close(Server),
+ close_port(OpenSslPort),
process_flag(trap_exit, false),
ok.
@@ -989,7 +993,7 @@ tls1_erlang_client_openssl_server_client_cert(Config) when is_list(Config) ->
ssl_test_lib:check_result(Client, ok),
- %% Clean close down!
+ %% Clean close down! Server needs to be closed first !!
close_port(OpensslPort),
ssl_test_lib:close(Client),
process_flag(trap_exit, false),
@@ -1034,9 +1038,9 @@ tls1_erlang_server_openssl_client_client_cert(Config) when is_list(Config) ->
ssl_test_lib:check_result(Server, ok),
- %% Clean close down!
- close_port(OpenSslPort),
+ %% Clean close down! Server needs to be closed first !!
ssl_test_lib:close(Server),
+ close_port(OpenSslPort),
process_flag(trap_exit, false),
ok.
@@ -1071,9 +1075,7 @@ tls1_erlang_server_erlang_client_client_cert(Config) when is_list(Config) ->
[{versions, [tlsv1]} | ClientOpts]}]),
ssl_test_lib:check_result(Server, ok, Client, ok),
-
ssl_test_lib:close(Server),
- %% Clean close down!
process_flag(trap_exit, false),
ok.
%%--------------------------------------------------------------------
@@ -1136,7 +1138,7 @@ cipher(CipherSuite, Version, Config, ClientOpts, ServerOpts) ->
CertFile = proplists:get_value(certfile, ServerOpts),
KeyFile = proplists:get_value(keyfile, ServerOpts),
- Cmd = "openssl s_server -accept " ++ integer_to_list(Port) ++
+ Cmd = "openssl s_server -accept " ++ integer_to_list(Port) ++ version_flag(Version) ++
" -cert " ++ CertFile ++ " -key " ++ KeyFile ++ "",
test_server:format("openssl cmd: ~p~n", [Cmd]),
@@ -1171,8 +1173,8 @@ cipher(CipherSuite, Version, Config, ClientOpts, ServerOpts) ->
Result = ssl_test_lib:wait_for_result(Client, ok),
+ %% Clean close down! Server needs to be closed first !!
close_port(OpenSslPort),
- %% Clean close down!
ssl_test_lib:close(Client),
Return = case Result of
@@ -1184,6 +1186,12 @@ cipher(CipherSuite, Version, Config, ClientOpts, ServerOpts) ->
process_flag(trap_exit, false),
Return.
+
+version_flag(tlsv1) ->
+ " -tls1 ";
+version_flag(sslv3) ->
+ " -ssl3 ".
+
%%--------------------------------------------------------------------
erlang_client_bad_openssl_server(doc) ->
[""];
@@ -1199,26 +1207,26 @@ erlang_client_bad_openssl_server(Config) when is_list(Config) ->
Port = ssl_test_lib:inet_port(node()),
CertFile = proplists:get_value(certfile, ServerOpts),
KeyFile = proplists:get_value(keyfile, ServerOpts),
-
+
Cmd = "openssl s_server -accept " ++ integer_to_list(Port) ++
- " -cert " ++ CertFile ++ " -key " ++ KeyFile ++ "",
-
+ " -cert " ++ CertFile ++ " -key " ++ KeyFile ++ "",
+
test_server:format("openssl cmd: ~p~n", [Cmd]),
OpensslPort = open_port({spawn, Cmd}, [stderr_to_stdout]),
-
+
wait_for_openssl_server(),
Client0 = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {?MODULE, server_sent_garbage, []}},
- {options,
- [{versions, [tlsv1]} | ClientOpts]}]),
+ {host, Hostname},
+ {from, self()},
+ {mfa, {?MODULE, server_sent_garbage, []}},
+ {options,
+ [{versions, [tlsv1]} | ClientOpts]}]),
%% Send garbage
port_command(OpensslPort, ?OPENSSL_GARBAGE),
-
+
test_server:sleep(?SLEEP),
Client0 ! server_sent_garbage,
@@ -1228,17 +1236,16 @@ erlang_client_bad_openssl_server(Config) when is_list(Config) ->
ssl_test_lib:close(Client0),
%% Make sure openssl does not hang and leave zombie process
- Client1 = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
- {host, Hostname},
- {from, self()},
- {mfa, {ssl_test_lib, no_result_msg, []}},
- {options,
- [{versions, [tlsv1]} | ClientOpts]}]),
-
- ssl_test_lib:close(Client1),
-
- %% Clean close down!
+ Client1 = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {ssl_test_lib, no_result_msg, []}},
+ {options,
+ [{versions, [tlsv1]} | ClientOpts]}]),
+
+ %% Clean close down! Server needs to be closed first !!
close_port(OpensslPort),
+ ssl_test_lib:close(Client1),
process_flag(trap_exit, false),
ok.
@@ -1297,6 +1304,7 @@ expired_session(Config) when is_list(Config) ->
{mfa, {ssl_test_lib, no_result, []}},
{from, self()}, {options, ClientOpts}]),
+ %% Clean close down! Server needs to be closed first !!
close_port(OpensslPort),
ssl_test_lib:close(Client2),
process_flag(trap_exit, false).
@@ -1329,8 +1337,8 @@ ssl2_erlang_server_openssl_client(Config) when is_list(Config) ->
ssl_test_lib:check_result(Server, {error,"protocol version"}),
+ %% Clean close down! Server needs to be closed first !!
ssl_test_lib:close(Server),
-
close_port(OpenSslPort),
process_flag(trap_exit, false),
ok.
@@ -1346,6 +1354,8 @@ erlang_ssl_receive(Socket, Data) ->
%% open_ssl server sometimes hangs waiting in blocking read
ssl:send(Socket, "Got it"),
ok;
+ {ssl, Socket, Byte} when length(Byte) == 1 ->
+ erlang_ssl_receive(Socket, tl(Data));
{Port, {data,Debug}} when is_port(Port) ->
io:format("openssl ~s~n",[Debug]),
erlang_ssl_receive(Socket,Data);
@@ -1433,3 +1443,11 @@ check_sane_openssl_renegotaite(Config) ->
_ ->
Config
end.
+
+check_sane_openssl_sslv2(Config) ->
+ case os:cmd("openssl version") of
+ "OpenSSL 1.0.0e" ++ _ ->
+ {skip, "Known option bug"};
+ _ ->
+ Config
+ end.
diff --git a/lib/ssl/vsn.mk b/lib/ssl/vsn.mk
index 8286201df4..2255798f1d 100644
--- a/lib/ssl/vsn.mk
+++ b/lib/ssl/vsn.mk
@@ -1 +1 @@
-SSL_VSN = 4.1.6
+SSL_VSN = 5.0
diff --git a/lib/stdlib/doc/src/Makefile b/lib/stdlib/doc/src/Makefile
index 16e0a86e3b..6c92756ae7 100644
--- a/lib/stdlib/doc/src/Makefile
+++ b/lib/stdlib/doc/src/Makefile
@@ -83,7 +83,6 @@ XML_REF3_FILES = \
queue.xml \
random.xml \
re.xml \
- regexp.xml \
sets.xml \
shell.xml \
shell_default.xml \
diff --git a/lib/stdlib/doc/src/filename.xml b/lib/stdlib/doc/src/filename.xml
index bc3a616d39..9296319b83 100644
--- a/lib/stdlib/doc/src/filename.xml
+++ b/lib/stdlib/doc/src/filename.xml
@@ -295,6 +295,12 @@
<p>Finds the source filename and compiler options for a module.
The result can be fed to <c>compile:file/2</c> in order to
compile the file again.</p>
+
+ <warning><p>We don't recommend using this function. If possible,
+ use <seealso marker="beam_lib">beam_lib(3)</seealso> to extract
+ the abstract code format from the BEAM file and compile that
+ instead.</p></warning>
+
<p>The <c><anno>Beam</anno></c> argument, which can be a string or an atom,
specifies either the module name or the path to the source
code, with or without the <c>".erl"</c> extension. In either
diff --git a/lib/stdlib/doc/src/gen_event.xml b/lib/stdlib/doc/src/gen_event.xml
index 24bcb419fe..79a0c8ad89 100644
--- a/lib/stdlib/doc/src/gen_event.xml
+++ b/lib/stdlib/doc/src/gen_event.xml
@@ -195,12 +195,13 @@ gen_event:stop -----> Module:terminate/2
handlers using the same callback module.</p>
<p><c>Args</c> is an arbitrary term which is passed as the argument
to <c>Module:init/1</c>.</p>
- <p>If <c>Module:init/1</c> returns a correct value, the event
- manager adds the event handler and this function returns
+ <p>If <c>Module:init/1</c> returns a correct value indicating
+ successful completion, the event manager adds the event
+ handler and this function returns
<c>ok</c>. If <c>Module:init/1</c> fails with <c>Reason</c> or
- returns an unexpected value <c>Term</c>, the event handler is
+ returns <c>{error,Reason}</c>, the event handler is
ignored and this function returns <c>{'EXIT',Reason}</c> or
- <c>Term</c>, respectively.</p>
+ <c>{error,Reason}</c>, respectively.</p>
</desc>
</func>
<func>
@@ -448,12 +449,13 @@ gen_event:stop -----> Module:terminate/2
</section>
<funcs>
<func>
- <name>Module:init(InitArgs) -> {ok,State} | {ok,State,hibernate}</name>
+ <name>Module:init(InitArgs) -> {ok,State} | {ok,State,hibernate} | {error,Reason}</name>
<fsummary>Initialize an event handler.</fsummary>
<type>
<v>InitArgs = Args | {Args,Term}</v>
<v>&nbsp;Args = Term = term()</v>
<v>State = term()</v>
+ <v>Reason = term()</v>
</type>
<desc>
<p>Whenever a new event handler is added to an event manager,
@@ -470,8 +472,9 @@ gen_event:stop -----> Module:terminate/2
the argument provided in the function call/return tuple and
<c>Term</c> is the result of terminating the old event handler,
see <c>gen_event:swap_handler/3</c>.</p>
- <p>The function should return <c>{ok,State}</c> or <c>{ok,State, hibernate}</c>
- where <c>State</c> is the initial internal state of the event handler.</p>
+ <p>If successful, the function should return <c>{ok,State}</c>
+ or <c>{ok,State,hibernate}</c> where <c>State</c> is the
+ initial internal state of the event handler.</p>
<p>If <c>{ok,State,hibernate}</c> is returned, the event
manager will go into hibernation (by calling <seealso
marker="proc_lib#hibernate/3">proc_lib:hibernate/3</seealso>),
diff --git a/lib/stdlib/doc/src/gen_server.xml b/lib/stdlib/doc/src/gen_server.xml
index 1045766e01..edeb7dff91 100644
--- a/lib/stdlib/doc/src/gen_server.xml
+++ b/lib/stdlib/doc/src/gen_server.xml
@@ -4,7 +4,7 @@
<erlref>
<header>
<copyright>
- <year>1996</year><year>2010</year>
+ <year>1996</year><year>2011</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -570,13 +570,14 @@ gen_server:abcast -----> Module:handle_cast/2
</desc>
</func>
<func>
- <name>Module:code_change(OldVsn, State, Extra) -> {ok, NewState}</name>
+ <name>Module:code_change(OldVsn, State, Extra) -> {ok, NewState} | {error, Reason}</name>
<fsummary>Update the internal state during upgrade/downgrade.</fsummary>
<type>
<v>OldVsn = Vsn | {down, Vsn}</v>
<v>&nbsp;&nbsp;Vsn = term()</v>
<v>State = NewState = term()</v>
<v>Extra = term()</v>
+ <v>Reason = term()</v>
</type>
<desc>
<p>This function is called by a gen_server when it should
@@ -595,7 +596,10 @@ gen_server:abcast -----> Module:handle_cast/2
<p><c>State</c> is the internal state of the gen_server.</p>
<p><c>Extra</c> is passed as-is from the <c>{advanced,Extra}</c>
part of the update instruction.</p>
- <p>The function should return the updated internal state.</p>
+ <p>If successful, the function shall return the updated
+ internal state.</p>
+ <p>If the function returns <c>{error,Reason}</c>, the ongoing
+ upgrade will fail and roll back to the old release.</p>
</desc>
</func>
<func>
diff --git a/lib/stdlib/doc/src/lists.xml b/lib/stdlib/doc/src/lists.xml
index 6f3ed7af98..7042c84437 100644
--- a/lib/stdlib/doc/src/lists.xml
+++ b/lib/stdlib/doc/src/lists.xml
@@ -240,7 +240,7 @@ flatmap(Fun, List1) ->
<func>
<name name="keydelete" arity="3"/>
<fsummary>Delete an element from a list of tuples</fsummary>
- <type_desc variable="N">1..tuple_size(Tuple)</type_desc>
+ <type_desc variable="N">1..tuple_size(<anno>Tuple</anno>)</type_desc>
<desc>
<p>Returns a copy of <c><anno>TupleList1</anno></c> where the first
occurrence of a tuple whose <c><anno>N</anno></c>th element compares equal to
@@ -266,7 +266,7 @@ flatmap(Fun, List1) ->
<func>
<name name="keymap" arity="3"/>
<fsummary>Map a function over a list of tuples</fsummary>
- <type_desc variable="N">1..tuple_size(Tuple)</type_desc>
+ <type_desc variable="N">1..tuple_size(<anno>Tuple</anno>)</type_desc>
<desc>
<p>Returns a list of tuples where, for each tuple in
<c><anno>TupleList1</anno></c>, the <c><anno>N</anno></c>th element <c><anno>Term1</anno></c> of the tuple
@@ -298,7 +298,7 @@ flatmap(Fun, List1) ->
<func>
<name name="keymerge" arity="3"/>
<fsummary>Merge two key-sorted lists of tuples</fsummary>
- <type_desc variable="N">1..tuple_size(Tuple)</type_desc>
+ <type_desc variable="N">1..tuple_size(<anno>Tuple</anno>)</type_desc>
<desc>
<p>Returns the sorted list formed by merging <c><anno>TupleList1</anno></c>
and <c><anno>TupleList2</anno></c>. The merge is performed on
@@ -312,7 +312,7 @@ flatmap(Fun, List1) ->
<func>
<name name="keyreplace" arity="4"/>
<fsummary>Replace an element in a list of tuples</fsummary>
- <type_desc variable="N">1..tuple_size(Tuple)</type_desc>
+ <type_desc variable="N">1..tuple_size(<anno>Tuple</anno>)</type_desc>
<desc>
<p>Returns a copy of <c><anno>TupleList1</anno></c> where the first
occurrence of a <c>T</c> tuple whose <c><anno>N</anno></c>th element
@@ -342,7 +342,7 @@ flatmap(Fun, List1) ->
<func>
<name name="keysort" arity="2"/>
<fsummary>Sort a list of tuples</fsummary>
- <type_desc variable="N">1..tuple_size(Tuple)</type_desc>
+ <type_desc variable="N">1..tuple_size(<anno>Tuple</anno>)</type_desc>
<desc>
<p>Returns a list containing the sorted elements of the list
<c><anno>TupleList1</anno></c>. Sorting is performed on the <c><anno>N</anno></c>th
@@ -352,7 +352,7 @@ flatmap(Fun, List1) ->
<func>
<name name="keystore" arity="4"/>
<fsummary>Store an element in a list of tuples</fsummary>
- <type_desc variable="N">1..tuple_size(Tuple)</type_desc>
+ <type_desc variable="N">1..tuple_size(<anno>Tuple</anno>)</type_desc>
<desc>
<p>Returns a copy of <c><anno>TupleList1</anno></c> where the first
occurrence of a tuple <c>T</c> whose <c><anno>N</anno></c>th element
@@ -366,7 +366,7 @@ flatmap(Fun, List1) ->
<func>
<name name="keytake" arity="3"/>
<fsummary>Extract an element from a list of tuples</fsummary>
- <type_desc variable="N">1..tuple_size(Tuple)</type_desc>
+ <type_desc variable="N">1..tuple_size(<anno>Tuple</anno>)</type_desc>
<desc>
<p>Searches the list of tuples <c><anno>TupleList1</anno></c> for a tuple
whose <c><anno>N</anno></c>th element compares equal to <c><anno>Key</anno></c>.
@@ -500,7 +500,7 @@ flatmap(Fun, List1) ->
<func>
<name name="nth" arity="2"/>
<fsummary>Return the Nth element of a list</fsummary>
- <type_desc variable="N">1..length(List)</type_desc>
+ <type_desc variable="N">1..length(<anno>List</anno>)</type_desc>
<desc>
<p>Returns the <c><anno>N</anno></c>th element of <c><anno>List</anno></c>. For example:</p>
<pre>
@@ -511,7 +511,7 @@ c</pre>
<func>
<name name="nthtail" arity="2"/>
<fsummary>Return the Nth tail of a list</fsummary>
- <type_desc variable="N">0..length(List)</type_desc>
+ <type_desc variable="N">0..length(<anno>List</anno>)</type_desc>
<desc>
<p>Returns the <c><anno>N</anno></c>th tail of <c><anno>List</anno></c>, that is, the sublist of
<c><anno>List</anno></c> starting at <c><anno>N</anno>+1</c> and continuing up to
@@ -630,7 +630,7 @@ length(lists:seq(From, To, Incr)) == (To-From+Incr) div Incr</code>
<func>
<name name="split" arity="2"/>
<fsummary>Split a list into two lists</fsummary>
- <type_desc variable="N">0..length(List1)</type_desc>
+ <type_desc variable="N">0..length(<anno>List1</anno>)</type_desc>
<desc>
<p>Splits <c><anno>List1</anno></c> into <c><anno>List2</anno></c> and <c><anno>List3</anno></c>.
<c><anno>List2</anno></c> contains the first <c><anno>N</anno></c> elements and
@@ -670,7 +670,7 @@ splitwith(Pred, List) ->
<func>
<name name="sublist" arity="3"/>
<fsummary>Return a sub-list starting at a given position and with a given number of elements</fsummary>
- <type_desc variable="Start">1..(length(List1)+1)</type_desc>
+ <type_desc variable="Start">1..(length(<anno>List1</anno>)+1)</type_desc>
<desc>
<p>Returns the sub-list of <c><anno>List1</anno></c> starting at <c><anno>Start</anno></c>
and with (max) <c><anno>Len</anno></c> elements. It is not an error for
@@ -732,7 +732,7 @@ splitwith(Pred, List) ->
<func>
<name name="ukeymerge" arity="3"/>
<fsummary>Merge two key-sorted lists of tuples, removing duplicates</fsummary>
- <type_desc variable="N">1..tuple_size(Tuple)</type_desc>
+ <type_desc variable="N">1..tuple_size(<anno>Tuple</anno>)</type_desc>
<desc>
<p>Returns the sorted list formed by merging <c><anno>TupleList1</anno></c>
and <c><anno>TupleList2</anno></c>. The merge is performed on the
@@ -746,7 +746,7 @@ splitwith(Pred, List) ->
<func>
<name name="ukeysort" arity="2"/>
<fsummary>Sort a list of tuples, removing duplicates</fsummary>
- <type_desc variable="N">1..tuple_size(Tuple)</type_desc>
+ <type_desc variable="N">1..tuple_size(<anno>Tuple</anno>)</type_desc>
<desc>
<p>Returns a list containing the sorted elements of the list
<c><anno>TupleList1</anno></c> where all but the first tuple of the
diff --git a/lib/stdlib/doc/src/make.dep b/lib/stdlib/doc/src/make.dep
deleted file mode 100644
index 48ee6209ef..0000000000
--- a/lib/stdlib/doc/src/make.dep
+++ /dev/null
@@ -1,40 +0,0 @@
-# ----------------------------------------------------
-# >>>> Do not edit this file <<<<
-# This file was automaticly generated by
-# /home/otp/bin/docdepend
-# ----------------------------------------------------
-
-
-# ----------------------------------------------------
-# TeX files that the DVI file depend on
-# ----------------------------------------------------
-
-book.dvi: array.tex base64.tex beam_lib.tex book.tex \
- c.tex calendar.tex dets.tex dict.tex digraph.tex \
- digraph_utils.tex epp.tex erl_eval.tex erl_expand_records.tex \
- erl_id_trans.tex erl_internal.tex erl_lint.tex \
- erl_parse.tex erl_pp.tex erl_scan.tex erl_tar.tex \
- ets.tex file_sorter.tex filelib.tex filename.tex \
- gb_sets.tex gb_trees.tex gen_event.tex gen_fsm.tex \
- gen_server.tex io.tex io_lib.tex io_protocol.tex \
- lib.tex lists.tex log_mf_h.tex math.tex ms_transform.tex \
- orddict.tex ordsets.tex part.tex pg.tex pool.tex \
- proc_lib.tex proplists.tex qlc.tex queue.tex \
- random.tex re.tex ref_man.tex regexp.tex sets.tex \
- shell.tex shell_default.tex slave.tex sofs.tex \
- stdlib_app.tex string.tex supervisor.tex supervisor_bridge.tex \
- sys.tex timer.tex unicode.tex unicode_usage.tex \
- win32reg.tex zip.tex
-
-# ----------------------------------------------------
-# Source inlined when transforming from source to LaTeX
-# ----------------------------------------------------
-
-book.tex: ref_man.xml
-
-# ----------------------------------------------------
-# Pictures that the DVI file depend on
-# ----------------------------------------------------
-
-book.dvi: ushell1.ps
-
diff --git a/lib/stdlib/doc/src/random.xml b/lib/stdlib/doc/src/random.xml
index 93affc3191..1b8fa44883 100644
--- a/lib/stdlib/doc/src/random.xml
+++ b/lib/stdlib/doc/src/random.xml
@@ -136,6 +136,11 @@
<c>random_seed</c> to remember the current seed.</p>
<p>If a process calls <c>uniform/0</c> or <c>uniform/1</c> without
setting a seed first, <c>seed/0</c> is called automatically.</p>
+ <p>The implementation changed in R15. Upgrading to R15 will break
+ applications that expect a specific output for a given seed. The output
+ is still deterministic number series, but different compared to releases
+ older than R15. The seed <c>{0,0,0}</c> will for example no longer
+ produce a flawed series of only zeros.</p>
</section>
</erlref>
diff --git a/lib/stdlib/doc/src/re.xml b/lib/stdlib/doc/src/re.xml
index 18867cfb68..6d5336796c 100644
--- a/lib/stdlib/doc/src/re.xml
+++ b/lib/stdlib/doc/src/re.xml
@@ -41,8 +41,7 @@
strings and binaries.</p>
<p>The regular expression syntax and semantics resemble that of
- Perl. This library replaces the deprecated pure-Erlang regexp
- library; it has a richer syntax, more options and is faster.</p>
+ Perl.</p>
<p>The library's matching algorithms are currently based on the
PCRE library, but not all of the PCRE library is interfaced and
diff --git a/lib/stdlib/doc/src/ref_man.xml b/lib/stdlib/doc/src/ref_man.xml
index 85aae6151d..6373922c92 100644
--- a/lib/stdlib/doc/src/ref_man.xml
+++ b/lib/stdlib/doc/src/ref_man.xml
@@ -80,7 +80,6 @@
<xi:include href="queue.xml"/>
<xi:include href="random.xml"/>
<xi:include href="re.xml"/>
- <xi:include href="regexp.xml"/>
<xi:include href="sets.xml"/>
<xi:include href="shell.xml"/>
<xi:include href="shell_default.xml"/>
diff --git a/lib/stdlib/doc/src/regexp.xml b/lib/stdlib/doc/src/regexp.xml
deleted file mode 100644
index 35d8e1c3f8..0000000000
--- a/lib/stdlib/doc/src/regexp.xml
+++ /dev/null
@@ -1,381 +0,0 @@
-<?xml version="1.0" encoding="latin1" ?>
-<!DOCTYPE erlref SYSTEM "erlref.dtd">
-
-<erlref>
- <header>
- <copyright>
- <year>1996</year><year>2011</year>
- <holder>Ericsson AB. All Rights Reserved.</holder>
- </copyright>
- <legalnotice>
- The contents of this file are subject to the Erlang Public License,
- Version 1.1, (the "License"); you may not use this file except in
- compliance with the License. You should have received a copy of the
- Erlang Public License along with this software. If not, it can be
- retrieved online at http://www.erlang.org/.
-
- Software distributed under the License is distributed on an "AS IS"
- basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
- the License for the specific language governing rights and limitations
- under the License.
-
- </legalnotice>
-
- <title>regexp</title>
- <prepared>Robert Virding</prepared>
- <responsible>Bjarne Dacker</responsible>
- <docno>1</docno>
- <approved>Bjarne D&auml;cker</approved>
- <checked></checked>
- <date>96-09-28</date>
- <rev>A</rev>
- <file>regexp.sgml</file>
- </header>
- <module>regexp</module>
- <modulesummary>Regular Expression Functions for Strings</modulesummary>
- <description>
- <note><p>This module has been obsoleted by the
- <seealso marker="re">re</seealso> module and will be removed in a future
- release.</p></note>
- <p>This module contains functions for regular expression
- matching and substitution.</p>
- </description>
- <datatypes>
- <datatype>
- <name name="errordesc"></name>
- </datatype>
- <datatype>
- <name name="regexp"></name>
- <desc><p>Internal representation of a regular expression.</p></desc>
- </datatype>
- </datatypes>
- <funcs>
- <func>
- <name name="match" arity="2"/>
- <fsummary>Match a regular expression</fsummary>
- <desc>
- <p>Finds the first, longest match of the regular expression <c><anno>RegExp</anno></c> in <c><anno>String</anno></c>. This function searches for the longest possible match and returns the first one found if there are several expressions of the same length. It returns as follows:</p>
- <taglist>
- <tag><c>{match,<anno>Start</anno>,<anno>Length</anno>}</c></tag>
- <item>
- <p>if the match succeeded. <c><anno>Start</anno></c> is the starting
- position of the match, and <c><anno>Length</anno></c> is the length of
- the matching string.</p>
- </item>
- <tag><c>nomatch</c></tag>
- <item>
- <p>if there were no matching characters.</p>
- </item>
- <tag><c>{error,<anno>Error</anno>}</c></tag>
- <item>
- <p>if there was an error in <c><anno>RegExp</anno></c>.</p>
- </item>
- </taglist>
- </desc>
- </func>
- <func>
- <name name="first_match" arity="2"/>
- <fsummary>Match a regular expression</fsummary>
- <desc>
- <p>Finds the first match of the regular expression <c><anno>RegExp</anno></c> in <c><anno>String</anno></c>. This call is
- usually faster than <c>match</c> and it is also a useful way to ascertain that a match exists. It returns as follows:</p>
- <taglist>
- <tag><c>{match,<anno>Start</anno>,<anno>Length</anno>}</c></tag>
- <item>
- <p>if the match succeeded. <c><anno>Start</anno></c> is the starting
- position of the match and <c><anno>Length</anno></c> is the length of
- the matching string.</p>
- </item>
- <tag><c>nomatch</c></tag>
- <item>
- <p>if there were no matching characters.</p>
- </item>
- <tag><c>{error,<anno>Error</anno>}</c></tag>
- <item>
- <p>if there was an error in <c><anno>RegExp</anno></c>.</p>
- </item>
- </taglist>
- </desc>
- </func>
- <func>
- <name name="matches" arity="2"/>
- <fsummary>Match a regular expression</fsummary>
- <desc>
- <p>Finds all non-overlapping matches of the
- expression <c><anno>RegExp</anno></c> in <c><anno>String</anno></c>.
- It returns as follows:</p>
- <taglist>
- <tag><c>{match, <anno>Matches</anno>}</c></tag>
- <item>
- <p>if the regular expression was correct.
- The list will be empty if there was no match. Each element in the list looks like <c>{<anno>Start</anno>, <anno>Length</anno>}</c>, where <c><anno>Start</anno></c> is the starting position of the match, and <c><anno>Length</anno></c> is the length of the matching string.</p>
- </item>
- <tag><c>{error,<anno>Error</anno>}</c></tag>
- <item>
- <p>if there was an error in <c><anno>RegExp</anno></c>.</p>
- </item>
- </taglist>
- </desc>
- </func>
- <func>
- <name name="sub" arity="3"/>
- <fsummary>Substitute the first occurrence of a regular expression</fsummary>
- <desc>
- <p>Substitutes the first occurrence of a substring matching <c><anno>RegExp</anno></c> in <c><anno>String</anno></c> with the string <c><anno>New</anno></c>. A <c><![CDATA[&]]></c> in the string <c><anno>New</anno></c> is replaced by the matched substring of <c><anno>String</anno></c>. <c><![CDATA[\&]]></c> puts a literal <c><![CDATA[&]]></c> into the replacement string. It returns as follows:</p>
- <taglist>
- <tag><c>{ok,<anno>NewString</anno>,<anno>RepCount</anno>}</c></tag>
- <item>
- <p>if <c><anno>RegExp</anno></c> is correct. <c><anno>RepCount</anno></c> is the number of replacements which have been made
- (this will be either 0 or 1).</p>
- </item>
- <tag><c>{error, <anno>Error</anno>}</c></tag>
- <item>
- <p>if there is an error in <c><anno>RegExp</anno></c>.</p>
- </item>
- </taglist>
- </desc>
- </func>
- <func>
- <name name="gsub" arity="3"/>
- <fsummary>Substitute all occurrences of a regular expression</fsummary>
- <desc>
- <p>The same as <c>sub</c>, except that all non-overlapping
- occurrences of a substring matching
- <c><anno>RegExp</anno></c> in <c><anno>String</anno></c> are replaced by the string <c><anno>New</anno></c>. It returns:</p>
- <taglist>
- <tag><c>{ok,<anno>NewString</anno>,<anno>RepCount</anno>}</c></tag>
- <item>
- <p>if <c><anno>RegExp</anno></c> is correct. <c><anno>RepCount</anno></c> is the number of replacements which have been made.</p>
- </item>
- <tag><c>{error, <anno>Error</anno>}</c></tag>
- <item>
- <p>if there is an error in <c><anno>RegExp</anno></c>.</p>
- </item>
- </taglist>
- </desc>
- </func>
- <func>
- <name name="split" arity="2"/>
- <fsummary>Split a string into fields</fsummary>
- <desc>
- <p><c><anno>String</anno></c> is split into fields (sub-strings) by the
- regular expression <c><anno>RegExp</anno></c>.</p>
- <p>If the separator expression is <c>" "</c> (a single space),
- then the fields are separated by blanks and/or tabs and
- leading and trailing blanks and tabs are discarded. For all
- other values of the separator, leading and trailing blanks
- and tabs are not discarded. It returns:</p>
- <taglist>
- <tag><c>{ok, <anno>FieldList</anno>}</c></tag>
- <item>
- <p>to indicate that the string has been split up into the fields of
- <c><anno>FieldList</anno></c>.</p>
- </item>
- <tag><c>{error, <anno>Error</anno>}</c></tag>
- <item>
- <p>if there is an error in <c><anno>RegExp</anno></c>.</p>
- </item>
- </taglist>
- </desc>
- </func>
- <func>
- <name name="sh_to_awk" arity="1"/>
- <fsummary>Convert an <c>sh</c>regular expression into an <c>AWK</c>one</fsummary>
- <desc>
- <p>Converts the <c>sh</c> type regular expression
- <c><anno>ShRegExp</anno></c> into a full <c>AWK</c> regular
- expression. Returns the converted regular expression
- string. <c>sh</c> expressions are used in the shell for
- matching file names and have the following special
- characters:</p>
- <taglist>
- <tag><c>*</c></tag>
- <item>
- <p>matches any string including the null string.</p>
- </item>
- <tag><c>?</c></tag>
- <item>
- <p>matches any single character.</p>
- </item>
- <tag><c>[...]</c></tag>
- <item>
- <p>matches any of the enclosed characters. Character
- ranges are specified by a pair of characters separated
- by a <c>-</c>. If the first character after <c>[</c> is a
- <c>!</c>, then any character not enclosed is matched.</p>
- </item>
- </taglist>
- <p>It may sometimes be more practical to use <c>sh</c> type
- expansions as they are simpler and easier to use, even though they are not as powerful.</p>
- </desc>
- </func>
- <func>
- <name name="parse" arity="1"/>
- <fsummary>Parse a regular expression</fsummary>
- <desc>
- <p>Parses the regular expression <c><anno>RegExp</anno></c> and builds the
- internal representation used in the other regular expression
- functions. Such representations can be used in all of the
- other functions instead of a regular expression string. This
- is more efficient when the same regular expression is used
- in many strings. It returns:</p>
- <taglist>
- <tag><c>{ok, <anno>RE</anno>}</c></tag>
- <item>
- <p>if <c>RegExp</c> is correct and <c><anno>RE</anno></c> is the internal representation.</p>
- </item>
- <tag><c>{error, <anno>Error</anno>}</c></tag>
- <item>
- <p>if there is an error in <c><anno>RegExp</anno></c>.</p>
- </item>
- </taglist>
- </desc>
- </func>
- <func>
- <name name="format_error" arity="1"/>
- <fsummary>Format an error descriptor</fsummary>
- <desc>
- <p>Returns a string which describes the error <c><anno>ErrorDescriptor</anno></c>
- returned when there is an error in a regular expression.</p>
- </desc>
- </func>
- </funcs>
-
- <section>
- <title>Regular Expressions</title>
- <p>The regular expressions allowed here is a subset of the set found
- in <c>egrep</c> and in the <c>AWK</c> programming language, as
- defined in the book, <c>The AWK Programming Language, by A. V. Aho, B. W. Kernighan, P. J. Weinberger</c>. They are
- composed of the following characters:</p>
- <taglist>
- <tag>c</tag>
- <item>
- <p>matches the non-metacharacter <c>c</c>.</p>
- </item>
- <tag>\c</tag>
- <item>
- <p>matches the escape sequence or literal character <c>c</c>.</p>
- </item>
- <tag>.</tag>
- <item>
- <p>matches any character.</p>
- </item>
- <tag>^</tag>
- <item>
- <p>matches the beginning of a string.</p>
- </item>
- <tag>$</tag>
- <item>
- <p>matches the end of a string.</p>
- </item>
- <tag>[abc...]</tag>
- <item>
- <p>character class, which matches any of the characters
- <c>abc...</c> Character ranges are specified by a pair of
- characters separated by a <c>-</c>.</p>
- </item>
- <tag>[^abc...]</tag>
- <item>
- <p>negated character class, which matches any character except
- <c>abc...</c>.</p>
- </item>
- <tag>r1 | r2</tag>
- <item>
- <p>alternation. It matches either <c>r1</c> or <c>r2</c>.</p>
- </item>
- <tag>r1r2</tag>
- <item>
- <p>concatenation. It matches <c>r1</c> and then <c>r2</c>.</p>
- </item>
- <tag>r+</tag>
- <item>
- <p>matches one or more <c>r</c>s.</p>
- </item>
- <tag>r*</tag>
- <item>
- <p>matches zero or more <c>r</c>s.</p>
- </item>
- <tag>r?</tag>
- <item>
- <p>matches zero or one <c>r</c>s.</p>
- </item>
- <tag>(r)</tag>
- <item>
- <p>grouping. It matches <c>r</c>.</p>
- </item>
- </taglist>
- <p>The escape sequences allowed are the same as for Erlang
- strings:</p>
- <taglist>
- <tag><c>\b</c></tag>
- <item>
- <p>backspace</p>
- </item>
- <tag><c>\f</c></tag>
- <item>
- <p>form feed </p>
- </item>
- <tag><c>\n</c></tag>
- <item>
- <p>newline (line feed) </p>
- </item>
- <tag><c>\r</c></tag>
- <item>
- <p>carriage return </p>
- </item>
- <tag><c>\t</c></tag>
- <item>
- <p>tab </p>
- </item>
- <tag><c>\e</c></tag>
- <item>
- <p>escape </p>
- </item>
- <tag><c>\v</c></tag>
- <item>
- <p>vertical tab </p>
- </item>
- <tag><c>\s</c></tag>
- <item>
- <p>space </p>
- </item>
- <tag><c>\d</c></tag>
- <item>
- <p>delete </p>
- </item>
- <tag><c>\ddd</c></tag>
- <item>
- <p>the octal value ddd </p>
- </item>
- <tag><c>\xhh</c></tag>
- <item>
- <p>The hexadecimal value <c>hh</c>.</p>
- </item>
- <tag><c>\x{h...}</c></tag>
- <item>
- <p>The hexadecimal value <c>h...</c>.</p>
- </item>
- <tag><c>\c</c></tag>
- <item>
- <p>any other character literally, for example <c>\\</c> for backslash,
- <c>\"</c> for ")</p>
- </item>
- </taglist>
- <p>To make these functions easier to use, in combination with the
- function <c>io:get_line</c> which terminates the input line with
- a new line, the <c>$</c> characters also matches a string ending
- with <c>"...\n"</c>. The following examples
- define Erlang data types:</p>
- <pre>
-Atoms [a-z][0-9a-zA-Z_]*
-
-Variables [A-Z_][0-9a-zA-Z_]*
-
-Floats (\+|-)?[0-9]+\.[0-9]+((E|e)(\+|-)?[0-9]+)?</pre>
- <p>Regular expressions are written as Erlang strings when used with the functions in this module. This means that any <c>\</c> or <c>"</c> characters in a regular expression
- string must be written with <c>\</c> as they are also escape characters for the string. For example, the regular expression string for Erlang floats is:
- <c>"(\\+|-)?[0-9]+\\.[0-9]+((E|e)(\\+|-)?[0-9]+)?"</c>.</p>
- <p>It is not really necessary to have the escape sequences as part of the regular expression syntax as they can always be generated directly in the string. They are included for completeness and can they can also be useful when generating regular expressions, or when they are entered other than with Erlang strings.</p>
- </section>
-</erlref>
-
diff --git a/lib/stdlib/doc/src/specs.xml b/lib/stdlib/doc/src/specs.xml
index 98338b5ec2..49c60529d2 100644
--- a/lib/stdlib/doc/src/specs.xml
+++ b/lib/stdlib/doc/src/specs.xml
@@ -46,7 +46,6 @@
<xi:include href="../specs/specs_queue.xml"/>
<xi:include href="../specs/specs_random.xml"/>
<xi:include href="../specs/specs_re.xml"/>
- <xi:include href="../specs/specs_regexp.xml"/>
<xi:include href="../specs/specs_sets.xml"/>
<xi:include href="../specs/specs_shell.xml"/>
<xi:include href="../specs/specs_shell_default.xml"/>
diff --git a/lib/stdlib/doc/src/supervisor.xml b/lib/stdlib/doc/src/supervisor.xml
index ec607d6e4c..cddb55e5c5 100644
--- a/lib/stdlib/doc/src/supervisor.xml
+++ b/lib/stdlib/doc/src/supervisor.xml
@@ -93,6 +93,10 @@
instead the child specification identifier is used,
<c>terminate_child/2</c> will return
<c>{error,simple_one_for_one}</c>.</p>
+ <p>Because a <c>simple_one_for_one</c> supervisor could have many
+ children, it shuts them all down at same time. So, order in which they
+ are stopped is not defined. For the same reason, it could have an
+ overhead with regards to the <c>Shutdown</c> strategy.</p>
</item>
</list>
<p>To prevent a supervisor from getting into an infinite loop of
@@ -154,7 +158,7 @@ child_spec() = {Id,StartFunc,Restart,Shutdown,Type,Modules}
death causes the temporary process to be terminated) and a
<c>transient</c> child process should be restarted only if
it terminates abnormally, i.e. with another exit reason
- than <c>normal</c>.</p>
+ than <c>normal</c>, <c>shutdown</c> or <c>{shutdown,Term}</c>.</p>
</item>
<item>
<p><c>Shutdown</c> defines how a child process should be
@@ -169,7 +173,15 @@ child_spec() = {Id,StartFunc,Restart,Shutdown,Type,Modules}
<c>exit(Child,kill)</c>.</p>
<p>If the child process is another supervisor, <c>Shutdown</c>
should be set to <c>infinity</c> to give the subtree ample
- time to shutdown.</p>
+ time to shutdown. It is also allowed to set it to <c>infinity</c>,
+ if the child process is a worker.</p>
+ <warning>
+ <p>Be careful by setting the <c>Shutdown</c> strategy to
+ <c>infinity</c> when the child process is a worker. Because, in this
+ situation, the termination of the supervision tree depends on the
+ child process, it must be implemented in a safe way and its cleanup
+ procedure must always return.</p>
+ </warning>
<p><em>Important note on simple-one-for-one supervisors:</em>
The dynamically created child processes of a
simple-one-for-one supervisor are not explicitly killed,
@@ -343,14 +355,23 @@ child_spec() = {Id,StartFunc,Restart,Shutdown,Type,Modules}
<desc>
<p>Tells the supervisor <c><anno>SupRef</anno></c> to terminate the given
child.</p>
+
<p>If the supervisor is not <c>simple_one_for_one</c>,
- <c><anno>Id</anno></c> must be the child specification identifier. The
- process, if there is one, is terminated but the child
- specification is kept by the supervisor. The child process
- may later be restarted by the supervisor. The child process
- can also be restarted explicitly by calling
+ <c><anno>Id</anno></c> must be the child specification
+ identifier. The process, if there is one, is terminated and,
+ unless it is a temporary child, the child specification is
+ kept by the supervisor. The child process may later be
+ restarted by the supervisor. The child process can also be
+ restarted explicitly by calling
<c>restart_child/2</c>. Use <c>delete_child/2</c> to remove
the child specification.</p>
+
+ <p>If the child is temporary, the child specification is deleted as
+ soon as the process terminates. This means
+ that <c>delete_child/2</c> has no meaning
+ and <c>restart_child/2</c> can not be used for these
+ children.</p>
+
<p>If the supervisor is <c>simple_one_for_one</c>, <c><anno>Id</anno></c>
must be the child process' <c>pid()</c>. I the specified
process is alive, but is not a child of the given
@@ -387,26 +408,34 @@ child_spec() = {Id,StartFunc,Restart,Shutdown,Type,Modules}
<name name="restart_child" arity="2"/>
<fsummary>Restart a terminated child process belonging to a supervisor.</fsummary>
<desc>
- <p>Tells the supervisor <c><anno>SupRef</anno></c> to restart a child process
- corresponding to the child specification identified by
- <c><anno>Id</anno></c>. The child specification must exist and
- the corresponding child process must not be running.</p>
- <p>See <seealso marker="#SupRef"><c>start_child/2</c></seealso> for a description of
- <c>SupRef</c>.</p>
- <p>If the child specification identified by <c><anno>Id</anno></c> does not
- exist, the function returns <c>{error,not_found}</c>. If
- the child specification exists but the corresponding process
- is already running, the function returns
+ <p>Tells the supervisor <c><anno>SupRef</anno></c> to restart
+ a child process corresponding to the child specification
+ identified by <c><anno>Id</anno></c>. The child
+ specification must exist and the corresponding child process
+ must not be running.</p>
+ <p>Note that for temporary children, the child specification
+ is automatically deleted when the child terminates, and thus
+ it is not possible to restart such children.</p>
+ <p>See <seealso marker="#SupRef"><c>start_child/2</c></seealso>
+ for a description of <c>SupRef</c>.</p>
+ <p>If the child specification identified
+ by <c><anno>Id</anno></c> does not exist, the function
+ returns <c>{error,not_found}</c>. If the child specification
+ exists but the corresponding process is already running, the
+ function returns
<c>{error,running}</c>.</p>
- <p>If the child process start function returns <c>{ok,<anno>Child</anno>}</c>
- or <c>{ok,<anno>Child</anno>,<anno>Info</anno>}</c>, the pid is added to the supervisor
- and the function returns the same value.</p>
+ <p>If the child process start function
+ returns <c>{ok,<anno>Child</anno>}</c>
+ or <c>{ok,<anno>Child</anno>,<anno>Info</anno>}</c>, the pid
+ is added to the supervisor and the function returns the same
+ value.</p>
<p>If the child process start function returns <c>ignore</c>,
the pid remains set to <c>undefined</c> and the function
returns <c>{ok,undefined}</c>.</p>
- <p>If the child process start function returns an error tuple or
- an erroneous value, or if it fails, the function returns
- <c>{error,<anno>Error</anno>}</c> where <c><anno>Error</anno></c> is a term containing
+ <p>If the child process start function returns an error tuple
+ or an erroneous value, or if it fails, the function returns
+ <c>{error,<anno>Error</anno>}</c>
+ where <c><anno>Error</anno></c> is a term containing
information about the error.</p>
</desc>
</func>
diff --git a/lib/stdlib/doc/src/unicode.xml b/lib/stdlib/doc/src/unicode.xml
index d02763f75c..1001ebbae4 100644
--- a/lib/stdlib/doc/src/unicode.xml
+++ b/lib/stdlib/doc/src/unicode.xml
@@ -203,8 +203,7 @@
<item>greater than <c>16#10FFFF</c>
(the maximum unicode character),</item>
<item>in the range <c>16#D800</c> to <c>16#DFFF</c>
- (invalid unicode range)</item>
- <item>or equal to 16#FFFE or 16#FFFF (non characters)</item>
+ (invalid range reserved for UTF-16 surrogate pairs)</item>
</list>
is found.
</item>
diff --git a/lib/stdlib/doc/src/unicode_usage.xml b/lib/stdlib/doc/src/unicode_usage.xml
index 0fa7de0a5c..a7e010a05f 100644
--- a/lib/stdlib/doc/src/unicode_usage.xml
+++ b/lib/stdlib/doc/src/unicode_usage.xml
@@ -59,7 +59,7 @@
<title>Standard Unicode representation in Erlang</title>
<p>In Erlang, strings are actually lists of integers. A string is defined to be encoded in the ISO-latin-1 (ISO8859-1) character set, which is, codepoint by codepoint, a sub-range of the Unicode character set.</p>
<p>The standard list encoding for strings is therefore easily extendible to cope with the whole Unicode range: A Unicode string in Erlang is simply a list containing integers, each integer being a valid Unicode codepoint and representing one character in the Unicode character set.</p>
-<p>Regular Erlang strings in ISO-latin-1 are a subset of there Unicode strings.</p>
+<p>Regular Erlang strings in ISO-latin-1 are a subset of their Unicode strings.</p>
<p>Binaries on the other hand are more troublesome. For performance reasons, programs often store textual data in binaries instead of lists, mainly because they are more compact (one byte per character instead of two words per character, as is the case with lists). Using erlang:list_to_binary/1, an regular Erlang string can be converted into a binary, effectively using the ISO-latin-1 encoding in the binary - one byte per character. This is very convenient for those regular Erlang strings, but cannot be done for Unicode lists.</p>
<p>As the UTF-8 encoding is widely spread and provides the most compact storage, it is selected as the standard encoding of Unicode characters in binaries for Erlang.</p>
diff --git a/lib/stdlib/examples/erl_id_trans.erl b/lib/stdlib/examples/erl_id_trans.erl
index b63acdd40a..72e41d6473 100644
--- a/lib/stdlib/examples/erl_id_trans.erl
+++ b/lib/stdlib/examples/erl_id_trans.erl
@@ -419,7 +419,14 @@ expr({'fun',Line,Body}) ->
{'fun',Line,{clauses,Cs1}};
{function,F,A} ->
{'fun',Line,{function,F,A}};
- {function,M,F,A} -> %R10B-6: fun M:F/A.
+ {function,M,F,A} when is_atom(M), is_atom(F), is_integer(A) ->
+ %% R10B-6: fun M:F/A. (Backward compatibility)
+ {'fun',Line,{function,M,F,A}};
+ {function,M0,F0,A0} ->
+ %% R15: fun M:F/A with variables.
+ M = expr(M0),
+ F = expr(F0),
+ A = expr(A0),
{'fun',Line,{function,M,F,A}}
end;
expr({call,Line,F0,As0}) ->
diff --git a/lib/stdlib/src/Makefile b/lib/stdlib/src/Makefile
index 600303d7e1..9ce1f6f5c8 100644
--- a/lib/stdlib/src/Makefile
+++ b/lib/stdlib/src/Makefile
@@ -105,7 +105,6 @@ MODULES= \
qlc_pt \
queue \
random \
- regexp \
sets \
shell \
shell_default \
diff --git a/lib/stdlib/src/beam_lib.erl b/lib/stdlib/src/beam_lib.erl
index fdfbb2e998..e9a5e6831e 100644
--- a/lib/stdlib/src/beam_lib.erl
+++ b/lib/stdlib/src/beam_lib.erl
@@ -224,7 +224,7 @@ version(File) ->
MD5 :: binary().
md5(File) ->
- case catch read_significant_chunks(File) of
+ case catch read_significant_chunks(File, md5_chunks()) of
{ok, {Module, Chunks0}} ->
Chunks = filter_funtab(Chunks0),
{ok, {Module, erlang:md5([C || {_Id, C} <- Chunks])}};
@@ -395,7 +395,7 @@ strip_fils(Files) ->
%% -> {ok, {Mod, FileName}} | {ok, {Mod, binary()}} | throw(Error)
strip_file(File) ->
- {ok, {Mod, Chunks}} = read_significant_chunks(File),
+ {ok, {Mod, Chunks}} = read_significant_chunks(File, significant_chunks()),
{ok, Stripped0} = build_module(Chunks),
Stripped = compress(Stripped0),
case File of
@@ -453,8 +453,8 @@ is_useless_chunk("CInf") -> true;
is_useless_chunk(_) -> false.
%% -> {ok, {Module, Chunks}} | throw(Error)
-read_significant_chunks(File) ->
- case read_chunk_data(File, significant_chunks(), [allow_missing_chunks]) of
+read_significant_chunks(File, ChunkList) ->
+ case read_chunk_data(File, ChunkList, [allow_missing_chunks]) of
{ok, {Module, Chunks0}} ->
Mandatory = mandatory_chunks(),
Chunks = filter_significant_chunks(Chunks0, Mandatory, File, Module),
@@ -835,12 +835,15 @@ file_error(FileName, {error, Reason}) ->
error(Reason) ->
throw({error, ?MODULE, Reason}).
-
-%% The following chunks are significant when calculating the MD5 for a module,
-%% and also the modules that must be retained when stripping a file.
-%% They are listed in the order that they should be MD5:ed.
+%% The following chunks must be kept when stripping a BEAM file.
significant_chunks() ->
+ ["Line" | md5_chunks()].
+
+%% The following chunks are significant when calculating the MD5
+%% for a module. They are listed in the order that they should be MD5:ed.
+
+md5_chunks() ->
["Atom", "Code", "StrT", "ImpT", "ExpT", "FunT", "LitT"].
%% The following chunks are mandatory in every Beam file.
diff --git a/lib/stdlib/src/c.erl b/lib/stdlib/src/c.erl
index febfdd6285..a920921a5e 100644
--- a/lib/stdlib/src/c.erl
+++ b/lib/stdlib/src/c.erl
@@ -797,7 +797,7 @@ appcall(App, M, F, Args) ->
catch
error:undef ->
case erlang:get_stacktrace() of
- [{M,F,Args}|_] ->
+ [{M,F,Args,_}|_] ->
Arity = length(Args),
io:format("Call to ~w:~w/~w in application ~w failed.\n",
[M,F,Arity,App]);
diff --git a/lib/stdlib/src/dets.erl b/lib/stdlib/src/dets.erl
index fa0641ffd9..c0f9ce34b0 100644
--- a/lib/stdlib/src/dets.erl
+++ b/lib/stdlib/src/dets.erl
@@ -1754,17 +1754,6 @@ system_code_change(State, _Module, _OldVsn, _Extra) ->
%%% Internal functions
%%%----------------------------------------------------------------------
-constants(FH, FileName) ->
- Version = FH#fileheader.version,
- if
- Version =< 8 ->
- dets_v8:constants();
- Version =:= 9 ->
- dets_v9:constants();
- true ->
- throw({error, {not_a_dets_file, FileName}})
- end.
-
%% -> {ok, Fd, fileheader()} | throw(Error)
read_file_header(FileName, Access, RamFile) ->
BF = if
@@ -1842,7 +1831,11 @@ do_bchunk_init(Head, Tab) ->
{H2, {error, old_version}};
Parms ->
L = dets_utils:all_allocated(H2),
- C0 = #dets_cont{no_objs = default, bin = <<>>, alloc = L},
+ Bin = if
+ L =:= <<>> -> eof;
+ true -> <<>>
+ end,
+ C0 = #dets_cont{no_objs = default, bin = Bin, alloc = L},
BinParms = term_to_binary(Parms),
{H2, {C0#dets_cont{tab = Tab, proc = self(),what = bchunk},
[BinParms]}}
@@ -2475,10 +2468,23 @@ fopen2(Fname, Tab) ->
%% Fd is not always closed upon error, but exit is soon called.
{ok, Fd, FH} = read_file_header(Fname, Acc, Ram),
Mod = FH#fileheader.mod,
- case Mod:check_file_header(FH, Fd) of
- {error, not_closed} ->
- io:format(user,"dets: file ~p not properly closed, "
- "repairing ...~n", [Fname]),
+ Do = case Mod:check_file_header(FH, Fd) of
+ {ok, Head1, ExtraInfo} ->
+ Head2 = Head1#head{filename = Fname},
+ try {ok, Mod:init_freelist(Head2, ExtraInfo)}
+ catch
+ throw:_ ->
+ {repair, " has bad free lists, repairing ..."}
+ end;
+ {error, not_closed} ->
+ M = " not properly closed, repairing ...",
+ {repair, M};
+ Else ->
+ Else
+ end,
+ case Do of
+ {repair, Mess} ->
+ io:format(user, "dets: file ~p~s~n", [Fname, Mess]),
Version = default,
case fsck(Fd, Tab, Fname, FH, default, default, Version) of
ok ->
@@ -2486,9 +2492,9 @@ fopen2(Fname, Tab) ->
Error ->
throw(Error)
end;
- {ok, Head, ExtraInfo} ->
+ {ok, Head} ->
open_final(Head, Fname, Acc, Ram, ?DEFAULT_CACHE,
- Tab, ExtraInfo, false);
+ Tab, false);
{error, Reason} ->
throw({error, {Reason, Fname}})
end;
@@ -2520,12 +2526,13 @@ fopen_existing_file(Tab, OpenArgs) ->
V9 = (Version =:= 9) or (Version =:= default),
MinF = (MinSlots =:= default) or (MinSlots =:= FH#fileheader.min_no_slots),
MaxF = (MaxSlots =:= default) or (MaxSlots =:= FH#fileheader.max_no_slots),
- Do = case (FH#fileheader.mod):check_file_header(FH, Fd) of
+ Mod = (FH#fileheader.mod),
+ Wh = case Mod:check_file_header(FH, Fd) of
{ok, Head, true} when Rep =:= force, Acc =:= read_write,
FH#fileheader.version =:= 9,
FH#fileheader.no_colls =/= undefined,
MinF, MaxF, V9 ->
- {compact, Head};
+ {compact, Head, true};
{ok, _Head, _Extra} when Rep =:= force, Acc =:= read ->
throw({error, {access_mode, Fname}});
{ok, Head, need_compacting} when Acc =:= read ->
@@ -2555,6 +2562,17 @@ fopen_existing_file(Tab, OpenArgs) ->
{error, Reason} ->
throw({error, {Reason, Fname}})
end,
+ Do = case Wh of
+ {Tag, Hd, Extra} when Tag =:= final; Tag =:= compact ->
+ Hd1 = Hd#head{filename = Fname},
+ try {Tag, Mod:init_freelist(Hd1, Extra)}
+ catch
+ throw:_ ->
+ {repair, " has bad free lists, repairing ..."}
+ end;
+ Else ->
+ Else
+ end,
case Do of
_ when FH#fileheader.type =/= Type ->
throw({error, {type_mismatch, Fname}});
@@ -2563,8 +2581,7 @@ fopen_existing_file(Tab, OpenArgs) ->
{compact, SourceHead} ->
io:format(user, "dets: file ~p is now compacted ...~n", [Fname]),
{ok, NewSourceHead} = open_final(SourceHead, Fname, read, false,
- ?DEFAULT_CACHE, Tab, true,
- Debug),
+ ?DEFAULT_CACHE, Tab, Debug),
case catch compact(NewSourceHead) of
ok ->
erlang:garbage_collect(),
@@ -2584,9 +2601,9 @@ fopen_existing_file(Tab, OpenArgs) ->
Version, OpenArgs);
_ when FH#fileheader.version =/= Version, Version =/= default ->
throw({error, {version_mismatch, Fname}});
- {final, H, EI} ->
+ {final, H} ->
H1 = H#head{auto_save = Auto},
- open_final(H1, Fname, Acc, Ram, CacheSz, Tab, EI, Debug)
+ open_final(H1, Fname, Acc, Ram, CacheSz, Tab, Debug)
end.
do_repair(Fd, Tab, Fname, FH, MinSlots, MaxSlots, Version, OpenArgs) ->
@@ -2600,19 +2617,16 @@ do_repair(Fd, Tab, Fname, FH, MinSlots, MaxSlots, Version, OpenArgs) ->
end.
%% -> {ok, head()} | throw(Error)
-open_final(Head, Fname, Acc, Ram, CacheSz, Tab, ExtraInfo, Debug) ->
+open_final(Head, Fname, Acc, Ram, CacheSz, Tab, Debug) ->
Head1 = Head#head{access = Acc,
ram_file = Ram,
filename = Fname,
name = Tab,
cache = dets_utils:new_cache(CacheSz)},
init_disk_map(Head1#head.version, Tab, Debug),
- Mod = Head#head.mod,
- Mod:cache_segps(Head1#head.fptr, Fname, Head1#head.next),
- Ftab = Mod:init_freelist(Head1, ExtraInfo),
+ (Head1#head.mod):cache_segps(Head1#head.fptr, Fname, Head1#head.next),
check_growth(Head1),
- NewHead = Head1#head{freelists = Ftab},
- {ok, NewHead}.
+ {ok, Head1}.
%% -> {ok, head()} | throw(Error)
fopen_init_file(Tab, OpenArgs) ->
@@ -3139,8 +3153,12 @@ init_scan(Head, NoObjs) ->
check_safe_fixtable(Head),
FreeLists = dets_utils:get_freelists(Head),
Base = Head#head.base,
- {From, To} = dets_utils:find_next_allocated(FreeLists, Base, Base),
- #dets_cont{no_objs = NoObjs, bin = <<>>, alloc = {From, To, <<>>}}.
+ case dets_utils:find_next_allocated(FreeLists, Base, Base) of
+ {From, To} ->
+ #dets_cont{no_objs = NoObjs, bin = <<>>, alloc = {From,To,<<>>}};
+ none ->
+ #dets_cont{no_objs = NoObjs, bin = eof, alloc = <<>>}
+ end.
check_safe_fixtable(Head) ->
case (Head#head.fixed =:= false) andalso
@@ -3241,18 +3259,20 @@ view(FileName) ->
case catch read_file_header(FileName, read, false) of
{ok, Fd, FH} ->
Mod = FH#fileheader.mod,
- case Mod:check_file_header(FH, Fd) of
- {ok, H0, ExtraInfo} ->
- Ftab = Mod:init_freelist(H0, ExtraInfo),
- {_Bump, Base} = constants(FH, FileName),
- H = H0#head{freelists=Ftab, base = Base},
- v_free_list(H),
- Mod:v_segments(H),
- file:close(Fd);
- X ->
- file:close(Fd),
- X
- end;
+ try Mod:check_file_header(FH, Fd) of
+ {ok, H0, ExtraInfo} ->
+ Mod = FH#fileheader.mod,
+ case Mod:check_file_header(FH, Fd) of
+ {ok, H0, ExtraInfo} ->
+ H = Mod:init_freelist(H0, ExtraInfo),
+ v_free_list(H),
+ Mod:v_segments(H),
+ ok;
+ X ->
+ X
+ end
+ after file:close(Fd)
+ end;
X ->
X
end.
diff --git a/lib/stdlib/src/dets.hrl b/lib/stdlib/src/dets.hrl
index fbffc9d008..a3f99357a2 100644
--- a/lib/stdlib/src/dets.hrl
+++ b/lib/stdlib/src/dets.hrl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2001-2010. All Rights Reserved.
+%% Copyright Ericsson AB 2001-2011. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -92,6 +92,7 @@
%% Info extracted from the file header.
-record(fileheader, {
freelist,
+ fl_base,
cookie,
closed_properly,
type,
diff --git a/lib/stdlib/src/dets_v8.erl b/lib/stdlib/src/dets_v8.erl
index cdd38d5604..3e962a1c8b 100644
--- a/lib/stdlib/src/dets_v8.erl
+++ b/lib/stdlib/src/dets_v8.erl
@@ -21,7 +21,7 @@
%% Dets files, implementation part. This module handles versions up to
%% and including 8(c). To be called from dets.erl only.
--export([constants/0, mark_dirty/1, read_file_header/2,
+-export([mark_dirty/1, read_file_header/2,
check_file_header/2, do_perform_save/1, initiate_file/11,
init_freelist/2, fsck_input/4,
bulk_input/3, output_objs/4, write_cache/1, may_grow/3,
@@ -196,10 +196,6 @@
%%-define(DEBUGF(X,Y), io:format(X, Y)).
-define(DEBUGF(X,Y), void).
-%% {Bump}
-constants() ->
- {?BUMP, ?BASE}.
-
%% -> ok | throw({NewHead,Error})
mark_dirty(Head) ->
Dirty = [{?CLOSED_PROPERLY_POS, <<?NOT_PROPERLY_CLOSED:32>>}],
@@ -308,8 +304,9 @@ init_freelist(Head, {convert_freelist,_Version}) ->
Pos = Head#head.freelists_p,
case catch prterm(Head, Pos, ?OHDSZ) of
{0, _Sz, Term} ->
- FreeList = lists:reverse(Term),
- dets_utils:init_slots_from_old_file(FreeList, Ftab);
+ FreeList1 = lists:reverse(Term),
+ FreeList = dets_utils:init_slots_from_old_file(FreeList1, Ftab),
+ Head#head{freelists = FreeList, base = ?BASE};
_ ->
throw({error, {bad_freelists, Head#head.filename}})
end;
@@ -318,7 +315,7 @@ init_freelist(Head, _) ->
Pos = Head#head.freelists_p,
case catch prterm(Head, Pos, ?OHDSZ) of
{0, _Sz, Term} ->
- Term;
+ Head#head{freelists = Term, base = ?BASE};
_ ->
throw({error, {bad_freelists, Head#head.filename}})
end.
@@ -331,6 +328,7 @@ read_file_header(Fd, FileName) ->
{ok, EOF} = dets_utils:position_close(Fd, FileName, eof),
{ok, <<FileSize:32>>} = dets_utils:pread_close(Fd, FileName, EOF-4, 4),
FH = #fileheader{freelist = Freelist,
+ fl_base = ?BASE,
cookie = Cookie,
closed_properly = CP,
type = dets_utils:code_to_type(Type2),
@@ -413,7 +411,7 @@ check_file_header(FH, Fd) ->
version = ?FILE_FORMAT_VERSION,
mod = ?MODULE,
bump = ?BUMP,
- base = ?BASE},
+ base = FH#fileheader.fl_base},
{ok, H, ExtraInfo};
Error ->
Error
diff --git a/lib/stdlib/src/dets_v9.erl b/lib/stdlib/src/dets_v9.erl
index 132af01f79..f577b4410f 100644
--- a/lib/stdlib/src/dets_v9.erl
+++ b/lib/stdlib/src/dets_v9.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2001-2010. All Rights Reserved.
+%% Copyright Ericsson AB 2001-2011. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -21,7 +21,7 @@
%% Dets files, implementation part. This module handles version 9.
%% To be called from dets.erl only.
--export([constants/0, mark_dirty/1, read_file_header/2,
+-export([mark_dirty/1, read_file_header/2,
check_file_header/2, do_perform_save/1, initiate_file/11,
prep_table_copy/9, init_freelist/2, fsck_input/4,
bulk_input/3, output_objs/4, bchunk_init/2,
@@ -70,6 +70,17 @@
%% 16 MD5-sum for the 44 plus 112 bytes before the MD5-sum.
%% (FreelistsPointer, Cookie and ClosedProperly are not digested.)
%% 128 Reserved for future versions. Initially zeros.
+%% Version 9(d), introduced in R15A, has instead:
+%% 112 28 counters for the buddy system sizes (as for 9(b)).
+%% 16 MD5-sum for the 44 plus 112 bytes before the MD5-sum.
+%% (FreelistsPointer, Cookie and ClosedProperly are not digested.)
+%% 4 Base of the buddy system.
+%% 0 (zero) if the base is equal to ?BASE. Compatible with R14B.
+%% File size at the end of the file is RealFileSize - Base.
+%% The reason for modifying file size is that when a file created
+%% by R15 is read by R14 a repair takes place immediately, which
+%% is acceptable when downgrading.
+%% 124 Reserved for future versions. Initially zeros.
%% ---
%% ------------------ end of file header
%% 4*256 SegmentArray Pointers.
@@ -86,7 +97,7 @@
%% -----------------------------
%% ??? Free lists
%% -----------------------------
-%% 4 File size, in bytes.
+%% 4 File size, in bytes. See 9(d) obove.
%% Before we can find an object we must find the slot where the
%% object resides. Each slot is a (possibly empty) list (or chain) of
@@ -177,14 +188,14 @@
%%% File header
%%%
--define(RESERVED, 128). % Reserved for future use.
+-define(RESERVED, 124). % Reserved for future use.
-define(COLL_CNTRS, (28*4)). % Counters for the buddy system.
-define(MD5SZ, 16).
+-define(FL_BASE, 4).
--define(HEADSZ,
- 56+?COLL_CNTRS+?MD5SZ). % The size of the file header, in bytes,
- % not including the reserved part.
+-define(HEADSZ, 56+?COLL_CNTRS % The size of the file header, in bytes,
+ +?MD5SZ+?FL_BASE). % not including the reserved part.
-define(HEADEND, (?HEADSZ+?RESERVED)).
% End of header and reserved area.
-define(SEGSZ, 512). % Size of a segment, in words. SZOBJP*SEGSZP.
@@ -270,10 +281,6 @@
%%-define(DEBUGF(X,Y), io:format(X, Y)).
-define(DEBUGF(X,Y), void).
-%% {Bump}
-constants() ->
- {?BUMP, ?BASE}.
-
%% -> ok | throw({NewHead,Error})
mark_dirty(Head) ->
Dirty = [{?CLOSED_PROPERLY_POS, <<?NOT_PROPERLY_CLOSED:32>>}],
@@ -356,7 +363,7 @@ init_file(Fd, Tab, Fname, Type, Kp, MinSlots, MaxSlots, Ram, CacheSz,
cache = dets_utils:new_cache(CacheSz),
version = ?FILE_FORMAT_VERSION,
bump = ?BUMP,
- base = ?BASE,
+ base = ?BASE, % to be overwritten
mod = ?MODULE
},
@@ -378,13 +385,20 @@ init_file(Fd, Tab, Fname, Type, Kp, MinSlots, MaxSlots, Ram, CacheSz,
{Head1, Ws1} = init_parts(Head0, 0, no_parts(Next), Zero, []),
NoSegs = no_segs(Next),
- {Head, WsI, WsP} = init_segments(Head1, 0, NoSegs, Zero, [], []),
+ {Head2, WsI, WsP} = init_segments(Head1, 0, NoSegs, Zero, [], []),
Ws2 = if
DoInitSegments -> WsP ++ WsI;
true -> WsP
end,
dets_utils:pwrite(Fd, Fname, [W0 | lists:append(Ws1) ++ Ws2]),
- true = hash_invars(Head),
+ true = hash_invars(Head2),
+ %% The allocations that have been made so far (parts, segments)
+ %% are permanent; the table will never shrink. Therefore the base
+ %% of the Buddy system can be set to the first free object.
+ %% This is used in allocate_all(), see below.
+ {_, Where, _} = dets_utils:alloc(Head2, ?BUMP),
+ NewFtab = dets_utils:init_alloc(Where),
+ Head = Head2#head{freelists = NewFtab, base = Where},
{ok, Head}.
%% Returns a power of two not less than 256.
@@ -451,8 +465,9 @@ read_file_header(Fd, FileName) ->
Version:32, M:32, Next:32, Kp:32,
NoObjects:32, NoKeys:32, MinNoSlots:32, MaxNoSlots:32,
HashMethod:32, N:32, NoCollsB:?COLL_CNTRS/binary,
- MD5:?MD5SZ/binary>> = Bin,
- <<_:12/binary,MD5DigestedPart:(?HEADSZ-?MD5SZ-12)/binary,_/binary>> = Bin,
+ MD5:?MD5SZ/binary, FlBase:32>> = Bin,
+ <<_:12/binary,MD5DigestedPart:(?HEADSZ-?MD5SZ-?FL_BASE-12)/binary,
+ _/binary>> = Bin,
{ok, EOF} = dets_utils:position_close(Fd, FileName, eof),
{ok, <<FileSize:32>>} = dets_utils:pread_close(Fd, FileName, EOF-4, 4),
{CL, <<>>} = lists:foldl(fun(LSz, {Acc,<<NN:32,R/binary>>}) ->
@@ -468,8 +483,12 @@ read_file_header(Fd, FileName) ->
true ->
lists:reverse(CL)
end,
-
+ Base = case FlBase of
+ 0 -> ?BASE;
+ _ -> FlBase
+ end,
FH = #fileheader{freelist = FreeList,
+ fl_base = Base,
cookie = Cookie,
closed_properly = CP,
type = dets_utils:code_to_type(Type2),
@@ -486,7 +505,7 @@ read_file_header(Fd, FileName) ->
read_md5 = MD5,
has_md5 = <<0:?MD5SZ/unit:8>> =/= MD5,
md5 = erlang:md5(MD5DigestedPart),
- trailer = FileSize,
+ trailer = FileSize + FlBase,
eof = EOF,
n = N,
mod = ?MODULE},
@@ -544,7 +563,7 @@ check_file_header(FH, Fd) ->
version = ?FILE_FORMAT_VERSION,
mod = ?MODULE,
bump = ?BUMP,
- base = ?BASE},
+ base = FH#fileheader.fl_base},
{ok, H, ExtraInfo};
Error ->
Error
@@ -1185,41 +1204,25 @@ write_loop(Head, BytesToWrite, Bin) ->
write_loop(Head, BytesToWrite, SmallBin).
%% By allocating bigger objects before smaller ones, holes in the
-%% buddy system memory map are avoided. Unfortunately, the segments
-%% are always allocated first, so if there are objects bigger than a
-%% segment, there is a hole to handle. (Haven't considered placing the
-%% segments among other objects of the same size.)
+%% buddy system memory map are avoided.
allocate_all_objects(Head, SizeT) ->
DTL = lists:reverse(lists:keysort(1, ets:tab2list(SizeT))),
MaxSz = element(1, hd(DTL)),
- SegSize = ?ACTUAL_SEG_SIZE,
- {Head1, HSz, HN, HA} = alloc_hole(MaxSz, Head, SegSize),
- {Head2, NL} = allocate_all(Head1, DTL, []),
+ {Head1, NL} = allocate_all(Head, DTL, []),
%% Find the position that will be the end of the file by allocating
%% a minimal object.
- {_Head, EndOfFile, _} = dets_utils:alloc(Head2, ?BUMP),
- Head3 = free_hole(Head2, HSz, HN, HA),
- NewHead = Head3#head{maxobjsize = max_objsize(Head3#head.no_collections)},
+ {_Head, EndOfFile, _} = dets_utils:alloc(Head1, ?BUMP),
+ NewHead = Head1#head{maxobjsize = max_objsize(Head1#head.no_collections)},
{NewHead, NL, MaxSz, EndOfFile}.
-alloc_hole(LSize, Head, SegSz) when ?POW(LSize-1) > SegSz ->
- Size = ?POW(LSize-1),
- {_, SegAddr, _} = dets_utils:alloc(Head, adjsz(SegSz)),
- {_, Addr, _} = dets_utils:alloc(Head, adjsz(Size)),
- N = (Addr - SegAddr) div SegSz,
- Head1 = dets_utils:alloc_many(Head, SegSz, N, SegAddr),
- {Head1, SegSz, N, SegAddr};
-alloc_hole(_MaxSz, Head, _SegSz) ->
- {Head, 0, 0, 0}.
-
-free_hole(Head, _Size, 0, _Addr) ->
- Head;
-free_hole(Head, Size, N, Addr) ->
- {Head1, _} = dets_utils:free(Head, Addr, adjsz(Size)),
- free_hole(Head1, Size, N-1, Addr+Size).
-
%% One (temporary) file for each buddy size, write all objects of that
%% size to the file.
+%%
+%% Before R15 a "hole" was needed before the first bucket if the size
+%% of the biggest bucket was greater than the size of a segment. The
+%% hole proved to be a problem with almost full tables with huge
+%% buckets. Since R15 the hole is no longer needed due to the fact
+%% that the base of the Buddy system is flexible.
allocate_all(Head, [{?FSCK_SEGMENT,_,Data,_}], L) ->
%% And one file for the segments...
%% Note that space for the array parts and the segments has
@@ -1593,23 +1596,28 @@ do_perform_save(H) ->
H1 = H#head{freelists_p = FreeListsPointer},
{FLW, FLSize} = free_lists_to_file(H1),
FileSize = FreeListsPointer + FLSize + 4,
- ok = dets_utils:write(H1, [FLW | <<FileSize:32>>]),
+ AdjustedFileSize = case H#head.base of
+ ?BASE -> FileSize;
+ Base -> FileSize - Base
+ end,
+ ok = dets_utils:write(H1, [FLW | <<AdjustedFileSize:32>>]),
FileHeader = file_header(H1, FreeListsPointer, ?CLOSED_PROPERLY),
case dets_utils:debug_mode() of
true ->
- TmpHead = H1#head{freelists = init_freelist(H1, true),
- fixed = false},
+ TmpHead0 = init_freelist(H1#head{fixed = false}, true),
+ TmpHead = TmpHead0#head{base = H1#head.base},
case
catch dets_utils:all_allocated_as_list(TmpHead)
=:= dets_utils:all_allocated_as_list(H1)
- of
+ of
true ->
dets_utils:pwrite(H1, [{0, FileHeader}]);
_ ->
+ throw(
dets_utils:corrupt_reason(H1, {failed_to_save_free_lists,
FreeListsPointer,
TmpHead#head.freelists,
- H1#head.freelists})
+ H1#head.freelists}))
end;
false ->
dets_utils:pwrite(H1, [{0, FileHeader}])
@@ -1648,7 +1656,11 @@ file_header(Head, FreeListsPointer, ClosedProperly, NoColls) ->
true -> erlang:md5(DigH);
false -> <<0:?MD5SZ/unit:8>>
end,
- [H1, DigH, MD5 | <<0:?RESERVED/unit:8>>].
+ Base = case Head#head.base of
+ ?BASE -> <<0:32>>;
+ FlBase -> <<FlBase:32>>
+ end,
+ [H1, DigH, MD5, Base | <<0:?RESERVED/unit:8>>].
%% Going through some trouble to avoid creating one single binary for
%% the free lists. If the free lists are huge, binary_to_term and
@@ -1695,8 +1707,8 @@ free_lists_from_file(H, Pos) ->
case catch bin_to_tree([], H, start, FL, -1, []) of
{'EXIT', _} ->
throw({error, {bad_freelists, H#head.filename}});
- Reply ->
- Reply
+ Ftab ->
+ H#head{freelists = Ftab, base = ?BASE}
end.
bin_to_tree(Bin, H, LastPos, Ftab, A0, L) ->
diff --git a/lib/stdlib/src/epp.erl b/lib/stdlib/src/epp.erl
index d804c1dee5..ccc14610d7 100644
--- a/lib/stdlib/src/epp.erl
+++ b/lib/stdlib/src/epp.erl
@@ -267,8 +267,10 @@ init_server(Pid, Name, File, AtLocation, Path, Pdm, Pre) ->
case user_predef(Pdm, Ms0) of
{ok,Ms1} ->
epp_reply(Pid, {ok,self()}),
+ %% ensure directory of current source file is first in path
+ Path1 = [filename:dirname(Name) | Path],
St = #epp{file=File, location=AtLocation, delta=0, name=Name,
- name2=Name, path=Path, macs=Ms1, pre_opened = Pre},
+ name2=Name, path=Path1, macs=Ms1, pre_opened = Pre},
From = wait_request(St),
enter_file_reply(From, Name, AtLocation, AtLocation),
wait_req_scan(St);
@@ -360,18 +362,18 @@ wait_req_skip(St, Sis) ->
From = wait_request(St),
skip_toks(From, St, Sis).
-%% enter_file(Path, FileName, IncludeToken, From, EppState)
+%% enter_file(FileName, IncludeToken, From, EppState)
%% leave_file(From, EppState)
%% Handle entering and leaving included files. Notify caller when the
%% current file is changed. Note it is an error to exit a file if we are
%% in a conditional. These functions never return.
-enter_file(_Path, _NewName, Inc, From, St)
+enter_file(_NewName, Inc, From, St)
when length(St#epp.sstk) >= 8 ->
epp_reply(From, {error,{abs_loc(Inc),epp,{depth,"include"}}}),
wait_req_scan(St);
-enter_file(Path, NewName, Inc, From, St) ->
- case file:path_open(Path, NewName, [read]) of
+enter_file(NewName, Inc, From, St) ->
+ case file:path_open(St#epp.path, NewName, [read]) of
{ok,NewF,Pname} ->
Loc = start_loc(St#epp.location),
wait_req_scan(enter_file2(NewF, Pname, From, St, Loc));
@@ -384,13 +386,16 @@ enter_file(Path, NewName, Inc, From, St) ->
%% Set epp to use this file and "enter" it.
enter_file2(NewF, Pname, From, St, AtLocation) ->
- enter_file2(NewF, Pname, From, St, AtLocation, []).
-
-enter_file2(NewF, Pname, From, St, AtLocation, ExtraPath) ->
Loc = start_loc(AtLocation),
enter_file_reply(From, Pname, Loc, AtLocation),
Ms = dict:store({atom,'FILE'}, {none,[{string,Loc,Pname}]}, St#epp.macs),
- Path = St#epp.path ++ ExtraPath,
+ %% update the head of the include path to be the directory of the new
+ %% source file, so that an included file can always include other files
+ %% relative to its current location (this is also how C does it); note
+ %% that the directory of the parent source file (the previous head of
+ %% the path) must be dropped, otherwise the path used within the current
+ %% file will depend on the order of file inclusions in the parent files
+ Path = [filename:dirname(Pname) | tl(St#epp.path)],
#epp{file=NewF,location=Loc,name=Pname,delta=0,
sstk=[St|St#epp.sstk],path=Path,macs=Ms}.
@@ -655,7 +660,7 @@ scan_undef(_Toks, Undef, From, St) ->
scan_include([{'(',_Llp},{string,_Lf,NewName0},{')',_Lrp},{dot,_Ld}], Inc,
From, St) ->
NewName = expand_var(NewName0),
- enter_file(St#epp.path, NewName, Inc, From, St);
+ enter_file(NewName, Inc, From, St);
scan_include(_Toks, Inc, From, St) ->
epp_reply(From, {error,{abs_loc(Inc),epp,{bad,include}}}),
wait_req_scan(St).
@@ -684,12 +689,11 @@ scan_include_lib([{'(',_Llp},{string,_Lf,NewName0},{')',_Lrp},{dot,_Ld}],
{error,_E1} ->
case catch find_lib_dir(NewName) of
{LibDir, Rest} when is_list(LibDir) ->
- LibName = filename:join([LibDir | Rest]),
+ LibName = fname_join([LibDir | Rest]),
case file:open(LibName, [read]) of
{ok,NewF} ->
- ExtraPath = [filename:dirname(LibName)],
wait_req_scan(enter_file2(NewF, LibName, From,
- St, Loc, ExtraPath));
+ St, Loc));
{error,_E2} ->
epp_reply(From,
{error,{abs_loc(Inc),epp,
@@ -1154,7 +1158,12 @@ expand_var1(NewName) ->
[[$$ | Var] | Rest] = filename:split(NewName),
Value = os:getenv(Var),
true = Value =/= false,
- {ok, filename:join([Value | Rest])}.
+ {ok, fname_join([Value | Rest])}.
+
+fname_join(["." | [_|_]=Rest]) ->
+ fname_join(Rest);
+fname_join(Components) ->
+ filename:join(Components).
%% The line only. (Other tokens may have the column and text as well...)
loc_attr(Line) when is_integer(Line) ->
diff --git a/lib/stdlib/src/erl_eval.erl b/lib/stdlib/src/erl_eval.erl
index 515ea2ebb7..bf3c7b3504 100644
--- a/lib/stdlib/src/erl_eval.erl
+++ b/lib/stdlib/src/erl_eval.erl
@@ -256,7 +256,8 @@ expr({'receive',_,Cs}, Bs, Lf, Ef, RBs) ->
expr({'receive',_, Cs, E, TB}, Bs0, Lf, Ef, RBs) ->
{value,T,Bs} = expr(E, Bs0, Lf, Ef, none),
receive_clauses(T, Cs, {TB,Bs}, Bs0, Lf, Ef, [], RBs);
-expr({'fun',_Line,{function,Mod,Name,Arity}}, Bs, _Lf, _Ef, RBs) ->
+expr({'fun',_Line,{function,Mod0,Name0,Arity0}}, Bs0, Lf, Ef, RBs) ->
+ {[Mod,Name,Arity],Bs} = expr_list([Mod0,Name0,Arity0], Bs0, Lf, Ef),
F = erlang:make_fun(Mod, Name, Arity),
ret_expr(F, Bs, RBs);
expr({'fun',_Line,{function,Name,Arity}}, _Bs0, _Lf, _Ef, _RBs) -> % R8
@@ -340,7 +341,7 @@ expr({call,_,{remote,_,Mod,Func},As0}, Bs0, Lf, Ef, RBs) ->
true ->
bif(F, As, Bs3, Ef, RBs);
false ->
- do_apply({M,F}, As, Bs3, Ef, RBs)
+ do_apply(M, F, As, Bs3, Ef, RBs)
end;
expr({call,_,{atom,_,Func},As0}, Bs0, Lf, Ef, RBs) ->
case erl_internal:bif(Func, length(As0)) of
@@ -498,11 +499,11 @@ local_func2({eval,F,As,Bs}, RBs) -> % This reply is not documented.
bif(apply, [erlang,apply,As], Bs, Ef, RBs) ->
bif(apply, As, Bs, Ef, RBs);
bif(apply, [M,F,As], Bs, Ef, RBs) ->
- do_apply({M,F}, As, Bs, Ef, RBs);
+ do_apply(M, F, As, Bs, Ef, RBs);
bif(apply, [F,As], Bs, Ef, RBs) ->
do_apply(F, As, Bs, Ef, RBs);
bif(Name, As, Bs, Ef, RBs) ->
- do_apply({erlang,Name}, As, Bs, Ef, RBs).
+ do_apply(erlang, Name, As, Bs, Ef, RBs).
%% do_apply(MF, Arguments, Bindings, ExternalFuncHandler, RBs) ->
%% {value,Value,Bindings} | Value when
@@ -562,6 +563,19 @@ do_apply(Func, As, Bs0, Ef, RBs) ->
ret_expr(F(Func, As), Bs0, RBs)
end.
+do_apply(Mod, Func, As, Bs0, Ef, RBs) ->
+ case Ef of
+ none when RBs =:= value ->
+ %% Make tail recursive calls when possible.
+ apply(Mod, Func, As);
+ none ->
+ ret_expr(apply(Mod, Func, As), Bs0, RBs);
+ {value,F} when RBs =:= value ->
+ F({Mod,Func}, As);
+ {value,F} ->
+ ret_expr(F({Mod,Func}, As), Bs0, RBs)
+ end.
+
%% eval_lc(Expr, [Qualifier], Bindings, LocalFunctionHandler,
%% ExternalFuncHandler, RetBindings) ->
%% {value,Value,Bindings} | Value
@@ -621,7 +635,7 @@ eval_generate(Term, _P, _Bs0, _Lf, _Ef, _CompFun, _Acc) ->
erlang:raise(error, {bad_generator,Term}, stacktrace()).
eval_b_generate(<<_/bitstring>>=Bin, P, Bs0, Lf, Ef, CompFun, Acc) ->
- Mfun = fun(L, R, Bs) -> match1(L, R, Bs, Bs0) end,
+ Mfun = match_fun(Bs0),
Efun = fun(Exp, Bs) -> expr(Exp, Bs, Lf, Ef, none) end,
case eval_bits:bin_gen(P, Bin, new_bindings(), Bs0, Mfun, Efun) of
{match, Rest, Bs1} ->
@@ -730,10 +744,10 @@ expr_list([], Vs, _, Bs, _Lf, _Ef) ->
{reverse(Vs),Bs}.
eval_op(Op, Arg1, Arg2, Bs, Ef, RBs) ->
- do_apply({erlang,Op}, [Arg1,Arg2], Bs, Ef, RBs).
+ do_apply(erlang, Op, [Arg1,Arg2], Bs, Ef, RBs).
eval_op(Op, Arg, Bs, Ef, RBs) ->
- do_apply({erlang,Op}, [Arg], Bs, Ef, RBs).
+ do_apply(erlang, Op, [Arg], Bs, Ef, RBs).
%% if_clauses(Clauses, Bindings, LocalFuncHandler, ExtFuncHandler, RBs)
@@ -919,8 +933,9 @@ guard0([], _Bs, _Lf, _Ef) -> true.
guard_test({call,L,{atom,Ln,F},As0}, Bs0, Lf, Ef) ->
TT = type_test(F),
- guard_test({call,L,{tuple,Ln,[{atom,Ln,erlang},{atom,Ln,TT}]},As0},
- Bs0, Lf, Ef);
+ G = {call,L,{atom,Ln,TT},As0},
+ try {value,true,_} = expr(G, Bs0, Lf, Ef, none)
+ catch error:_ -> {value,false,Bs0} end;
guard_test({call,L,{remote,_Lr,{atom,_Lm,erlang},{atom,_Lf,_F}=T},As0},
Bs0, Lf, Ef) ->
guard_test({call,L,T,As0}, Bs0, Lf, Ef);
@@ -1024,7 +1039,7 @@ match1({tuple,_,_}, _, _Bs, _BBs) ->
throw(nomatch);
match1({bin, _, Fs}, <<_/bitstring>>=B, Bs0, BBs) ->
eval_bits:match_bits(Fs, B, Bs0, BBs,
- fun(L, R, Bs) -> match1(L, R, Bs, BBs) end,
+ match_fun(BBs),
fun(E, Bs) -> expr(E, Bs, none, none, none) end);
match1({bin,_,_}, _, _Bs, _BBs) ->
throw(nomatch);
@@ -1053,6 +1068,12 @@ match1({op,Line,Op,L,R}, Term, Bs, BBs) ->
match1(_, _, _Bs, _BBs) ->
throw(invalid).
+match_fun(BBs) ->
+ fun(match, {L,R,Bs}) -> match1(L, R, Bs, BBs);
+ (binding, {Name,Bs}) -> binding(Name, Bs);
+ (add_binding, {Name,Val,Bs}) -> add_binding(Name, Val, Bs)
+ end.
+
match_tuple([E|Es], Tuple, I, Bs0, BBs) ->
{match,Bs} = match1(E, element(I, Tuple), Bs0, BBs),
match_tuple(Es, Tuple, I+1, Bs, BBs);
diff --git a/lib/stdlib/src/erl_internal.erl b/lib/stdlib/src/erl_internal.erl
index 3073fc0fb5..cd3b531d10 100644
--- a/lib/stdlib/src/erl_internal.erl
+++ b/lib/stdlib/src/erl_internal.erl
@@ -264,7 +264,6 @@ bif(bitstring_to_list, 1) -> true;
bif(byte_size, 1) -> true;
bif(check_old_code, 1) -> true;
bif(check_process_code, 2) -> true;
-bif(concat_binary, 1) -> true;
bif(date, 0) -> true;
bif(delete_module, 1) -> true;
bif(demonitor, 1) -> true;
@@ -406,7 +405,6 @@ old_bif(bit_size, 1) -> true;
old_bif(bitstring_to_list, 1) -> true;
old_bif(byte_size, 1) -> true;
old_bif(check_process_code, 2) -> true;
-old_bif(concat_binary, 1) -> true;
old_bif(date, 0) -> true;
old_bif(delete_module, 1) -> true;
old_bif(disconnect_node, 1) -> true;
diff --git a/lib/stdlib/src/erl_lint.erl b/lib/stdlib/src/erl_lint.erl
index dd0b9bc2ab..e5adb84932 100644
--- a/lib/stdlib/src/erl_lint.erl
+++ b/lib/stdlib/src/erl_lint.erl
@@ -123,6 +123,7 @@ value_option(Flag, Default, On, OnVal, Off, OffVal, Opts) ->
called= [] :: [{fa(),line()}], %Called functions
usage = #usage{} :: #usage{},
specs = dict:new() :: dict(), %Type specifications
+ callbacks = dict:new() :: dict(), %Callback types
types = dict:new() :: dict(), %Type definitions
exp_types=gb_sets:empty():: gb_set() %Exported types
}).
@@ -310,8 +311,6 @@ format_error({conflicting_behaviours,{Name,Arity},B,FirstL,FirstB}) ->
format_error({undefined_behaviour_func, {Func,Arity}, Behaviour}) ->
io_lib:format("undefined callback function ~w/~w (behaviour '~w')",
[Func,Arity,Behaviour]);
-format_error({undefined_behaviour_func, {Func,Arity,_Spec}, Behaviour}) ->
- format_error({undefined_behaviour_func, {Func,Arity}, Behaviour});
format_error({undefined_behaviour,Behaviour}) ->
io_lib:format("behaviour ~w undefined", [Behaviour]);
format_error({undefined_behaviour_callbacks,Behaviour}) ->
@@ -320,6 +319,9 @@ format_error({undefined_behaviour_callbacks,Behaviour}) ->
format_error({ill_defined_behaviour_callbacks,Behaviour}) ->
io_lib:format("behaviour ~w callback functions erroneously defined",
[Behaviour]);
+format_error({behaviour_info, {_M,F,A}}) ->
+ io_lib:format("cannot define callback attibute for ~w/~w when "
+ "behaviour_info is defined",[F,A]);
%% --- types and specs ---
format_error({singleton_typevar, Name}) ->
io_lib:format("type variable ~w is only used once (is unbound)", [Name]);
@@ -348,12 +350,16 @@ format_error({type_syntax, Constr}) ->
io_lib:format("bad ~w type", [Constr]);
format_error({redefine_spec, {M, F, A}}) ->
io_lib:format("spec for ~w:~w/~w already defined", [M, F, A]);
+format_error({redefine_callback, {M, F, A}}) ->
+ io_lib:format("callback ~w:~w/~w already defined", [M, F, A]);
format_error({spec_fun_undefined, {M, F, A}}) ->
io_lib:format("spec for undefined function ~w:~w/~w", [M, F, A]);
format_error({missing_spec, {F,A}}) ->
io_lib:format("missing specification for function ~w/~w", [F, A]);
format_error(spec_wrong_arity) ->
"spec has the wrong arity";
+format_error(callback_wrong_arity) ->
+ "callback has the wrong arity";
format_error({imported_predefined_type, Name}) ->
io_lib:format("referring to built-in type ~w as a remote type; "
"please take out the module name", [Name]);
@@ -747,6 +753,8 @@ attribute_state({attribute,L,opaque,{TypeName,TypeDef,Args}}, St) ->
type_def(opaque, L, TypeName, TypeDef, Args, St);
attribute_state({attribute,L,spec,{Fun,Types}}, St) ->
spec_decl(L, Fun, Types, St);
+attribute_state({attribute,L,callback,{Fun,Types}}, St) ->
+ callback_decl(L, Fun, Types, St);
attribute_state({attribute,L,on_load,Val}, St) ->
on_load(L, Val, St);
attribute_state({attribute,_L,_Other,_Val}, St) -> % Ignore others
@@ -840,7 +848,8 @@ post_traversal_check(Forms, St0) ->
StB = check_unused_types(Forms, StA),
StC = check_untyped_records(Forms, StB),
StD = check_on_load(StC),
- check_unused_records(Forms, StD).
+ StE = check_unused_records(Forms, StD),
+ check_callback_information(StE).
%% check_behaviour(State0) -> State
%% Check that the behaviour attribute is valid.
@@ -1139,6 +1148,23 @@ check_unused_records(Forms, St0) ->
St0
end.
+check_callback_information(#lint{callbacks = Callbacks,
+ defined = Defined} = State) ->
+ case gb_sets:is_member({behaviour_info,1}, Defined) of
+ false -> State;
+ true ->
+ case dict:size(Callbacks) of
+ 0 -> State;
+ _ ->
+ CallbacksList = dict:to_list(Callbacks),
+ FoldL =
+ fun({Fa,Line},St) ->
+ add_error(Line, {behaviour_info, Fa}, St)
+ end,
+ lists:foldl(FoldL, State, CallbacksList)
+ end
+ end.
+
%% For storing the import list we use the orddict module.
%% We know an empty set is [].
@@ -2101,8 +2127,13 @@ expr({'fun',Line,Body}, Vt, St) ->
true -> {[],St};
false -> {[],call_function(Line, F, A, St)}
end;
- {function,_M,_F,_A} ->
- {[],St}
+ {function,M,F,A} when is_atom(M), is_atom(F), is_integer(A) ->
+ %% Compatibility with pre-R15 abstract format.
+ {[],St};
+ {function,M,F,A} ->
+ %% New in R15.
+ {Bvt, St1} = expr_list([M,F,A], Vt, St),
+ {vtupdate(Bvt, Vt),St1}
end;
expr({call,_Line,{atom,_Lr,is_record},[E,{atom,Ln,Name}]}, Vt, St0) ->
{Rvt,St1} = expr(E, Vt, St0),
@@ -2736,12 +2767,6 @@ default_types() ->
{var, 1}],
dict:from_list([{T, -1} || T <- DefTypes]).
-%% R12B-5
-is_newly_introduced_builtin_type({module, 0}) -> true;
-is_newly_introduced_builtin_type({node, 0}) -> true;
-is_newly_introduced_builtin_type({nonempty_string, 0}) -> true;
-is_newly_introduced_builtin_type({term, 0}) -> true;
-is_newly_introduced_builtin_type({timeout, 0}) -> true;
%% R13
is_newly_introduced_builtin_type({arity, 0}) -> true;
is_newly_introduced_builtin_type({array, 0}) -> true; % opaque
@@ -2770,6 +2795,20 @@ spec_decl(Line, MFA0, TypeSpecs, St0 = #lint{specs = Specs, module = Mod}) ->
false -> check_specs(TypeSpecs, Arity, St1)
end.
+%% callback_decl(Line, Fun, Types, State) -> State.
+
+callback_decl(Line, MFA0, TypeSpecs,
+ St0 = #lint{callbacks = Callbacks, module = Mod}) ->
+ MFA = case MFA0 of
+ {F, Arity} -> {Mod, F, Arity};
+ {_M, _F, Arity} -> MFA0
+ end,
+ St1 = St0#lint{callbacks = dict:store(MFA, Line, Callbacks)},
+ case dict:is_key(MFA, Callbacks) of
+ true -> add_error(Line, {redefine_callback, MFA}, St1);
+ false -> check_specs(TypeSpecs, Arity, St1)
+ end.
+
check_specs([FunType|Left], Arity, St0) ->
{FunType1, CTypes} =
case FunType of
@@ -3275,6 +3314,8 @@ modify_line1({attribute,L,record,{Name,Fields}}, Mf) ->
{attribute,Mf(L),record,{Name,modify_line1(Fields, Mf)}};
modify_line1({attribute,L,spec,{Fun,Types}}, Mf) ->
{attribute,Mf(L),spec,{Fun,modify_line1(Types, Mf)}};
+modify_line1({attribute,L,callback,{Fun,Types}}, Mf) ->
+ {attribute,Mf(L),callback,{Fun,modify_line1(Types, Mf)}};
modify_line1({attribute,L,type,{TypeName,TypeDef,Args}}, Mf) ->
{attribute,Mf(L),type,{TypeName,modify_line1(TypeDef, Mf),
modify_line1(Args, Mf)}};
diff --git a/lib/stdlib/src/erl_parse.yrl b/lib/stdlib/src/erl_parse.yrl
index bd5d65a1e1..928c10f7f2 100644
--- a/lib/stdlib/src/erl_parse.yrl
+++ b/lib/stdlib/src/erl_parse.yrl
@@ -35,7 +35,7 @@ tuple
%struct
record_expr record_tuple record_field record_fields
if_expr if_clause if_clauses case_expr cr_clause cr_clauses receive_expr
-fun_expr fun_clause fun_clauses
+fun_expr fun_clause fun_clauses atom_or_var integer_or_var
try_expr try_catch try_clause try_clauses query_expr
function_call argument_list
exprs guard
@@ -62,7 +62,7 @@ char integer float atom string var
'==' '/=' '=<' '<' '>=' '>' '=:=' '=/=' '<='
'<<' '>>'
'!' '=' '::' '..' '...'
-'spec' % helper
+'spec' 'callback' % helper
dot.
Expect 2.
@@ -77,6 +77,7 @@ attribute -> '-' atom attr_val : build_attribute('$2', '$3').
attribute -> '-' atom typed_attr_val : build_typed_attribute('$2','$3').
attribute -> '-' atom '(' typed_attr_val ')' : build_typed_attribute('$2','$4').
attribute -> '-' 'spec' type_spec : build_type_spec('$2', '$3').
+attribute -> '-' 'callback' type_spec : build_type_spec('$2', '$3').
type_spec -> spec_fun type_sigs : {'$1', '$2'}.
type_spec -> '(' spec_fun type_sigs ')' : {'$2', '$3'}.
@@ -394,11 +395,17 @@ receive_expr -> 'receive' cr_clauses 'after' expr clause_body 'end' :
fun_expr -> 'fun' atom '/' integer :
{'fun',?line('$1'),{function,element(3, '$2'),element(3, '$4')}}.
-fun_expr -> 'fun' atom ':' atom '/' integer :
- {'fun',?line('$1'),{function,element(3, '$2'),element(3, '$4'),element(3,'$6')}}.
+fun_expr -> 'fun' atom_or_var ':' atom_or_var '/' integer_or_var :
+ {'fun',?line('$1'),{function,'$2','$4','$6'}}.
fun_expr -> 'fun' fun_clauses 'end' :
build_fun(?line('$1'), '$2').
+atom_or_var -> atom : '$1'.
+atom_or_var -> var : '$1'.
+
+integer_or_var -> integer : '$1'.
+integer_or_var -> var : '$1'.
+
fun_clauses -> fun_clause : ['$1'].
fun_clauses -> fun_clause ';' fun_clauses : ['$1' | '$3'].
@@ -549,6 +556,8 @@ Erlang code.
ErrorInfo :: error_info().
parse_form([{'-',L1},{atom,L2,spec}|Tokens]) ->
parse([{'-',L1},{'spec',L2}|Tokens]);
+parse_form([{'-',L1},{atom,L2,callback}|Tokens]) ->
+ parse([{'-',L1},{'callback',L2}|Tokens]);
parse_form(Tokens) ->
parse(Tokens).
@@ -603,7 +612,8 @@ build_typed_attribute({atom,La,Attr},_) ->
_ -> ret_err(La, "bad attribute")
end.
-build_type_spec({spec,La}, {SpecFun, TypeSpecs}) ->
+build_type_spec({Kind,La}, {SpecFun, TypeSpecs})
+ when (Kind =:= spec) or (Kind =:= callback) ->
NewSpecFun =
case SpecFun of
{atom, _, Fun} ->
@@ -617,7 +627,7 @@ build_type_spec({spec,La}, {SpecFun, TypeSpecs}) ->
%% Old style spec. Allow this for now.
{Mod,Fun,Arity}
end,
- {attribute,La,spec,{NewSpecFun, TypeSpecs}}.
+ {attribute,La,Kind,{NewSpecFun, TypeSpecs}}.
find_arity_from_specs([Spec|_]) ->
%% Use the first spec to find the arity. If all are not the same,
diff --git a/lib/stdlib/src/erl_pp.erl b/lib/stdlib/src/erl_pp.erl
index 7dc19f2e9b..6b5aa951cf 100644
--- a/lib/stdlib/src/erl_pp.erl
+++ b/lib/stdlib/src/erl_pp.erl
@@ -457,8 +457,16 @@ lexpr({'fun',_,{function,F,A}}, _Prec, _Hook) ->
leaf(format("fun ~w/~w", [F,A]));
lexpr({'fun',_,{function,F,A},Extra}, _Prec, _Hook) ->
{force_nl,fun_info(Extra),leaf(format("fun ~w/~w", [F,A]))};
-lexpr({'fun',_,{function,M,F,A}}, _Prec, _Hook) ->
+lexpr({'fun',_,{function,M,F,A}}, _Prec, _Hook)
+ when is_atom(M), is_atom(F), is_integer(A) ->
+ %% For backward compatibility with pre-R15 abstract format.
leaf(format("fun ~w:~w/~w", [M,F,A]));
+lexpr({'fun',_,{function,M,F,A}}, _Prec, Hook) ->
+ %% New format in R15.
+ NameItem = lexpr(M, Hook),
+ CallItem = lexpr(F, Hook),
+ ArityItem = lexpr(A, Hook),
+ ["fun ",NameItem,$:,CallItem,$/,ArityItem];
lexpr({'fun',_,{clauses,Cs}}, _Prec, Hook) ->
{list,[{first,'fun',fun_clauses(Cs, Hook)},'end']};
lexpr({'fun',_,{clauses,Cs},Extra}, _Prec, Hook) ->
diff --git a/lib/stdlib/src/error_logger_tty_h.erl b/lib/stdlib/src/error_logger_tty_h.erl
index 435e57aa0e..fa13fbb2bd 100644
--- a/lib/stdlib/src/error_logger_tty_h.erl
+++ b/lib/stdlib/src/error_logger_tty_h.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2009. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2011. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -34,10 +34,12 @@
handle_event/2, handle_call/2, handle_info/2,
terminate/2, code_change/3]).
+-export([write_event/2]).
+
%% This one is used when we takeover from the simple error_logger.
init({[], {error_logger, Buf}}) ->
User = set_group_leader(),
- write_events(Buf),
+ write_events(Buf,io),
{ok, {User, error_logger}};
%% This one is used if someone took over from us, and now wants to
%% go back.
@@ -52,7 +54,7 @@ init([]) ->
handle_event({_Type, GL, _Msg}, State) when node(GL) =/= node() ->
{ok, State};
handle_event(Event, State) ->
- write_event(tag_event(Event)),
+ write_event(tag_event(Event),io),
{ok, State}.
handle_info({'EXIT', User, _Reason}, {User, PrevHandler}) ->
@@ -64,10 +66,10 @@ handle_info({'EXIT', User, _Reason}, {User, PrevHandler}) ->
PrevHandler, go_back}
end;
handle_info({emulator, GL, Chars}, State) when node(GL) == node() ->
- write_event(tag_event({emulator, GL, Chars})),
+ write_event(tag_event({emulator, GL, Chars}),io),
{ok, State};
handle_info({emulator, noproc, Chars}, State) ->
- write_event(tag_event({emulator, noproc, Chars})),
+ write_event(tag_event({emulator, noproc, Chars}),io),
{ok, State};
handle_info(_, State) ->
{ok, State}.
@@ -97,65 +99,65 @@ set_group_leader() ->
tag_event(Event) ->
{erlang:localtime(), Event}.
-write_events(Events) -> write_events1(lists:reverse(Events)).
+write_events(Events,IOMod) -> write_events1(lists:reverse(Events),IOMod).
-write_events1([Event|Es]) ->
- write_event(Event),
- write_events1(Es);
-write_events1([]) ->
+write_events1([Event|Es],IOMod) ->
+ write_event(Event,IOMod),
+ write_events1(Es,IOMod);
+write_events1([],_IOMod) ->
ok.
-write_event({Time, {error, _GL, {Pid, Format, Args}}}) ->
+write_event({Time, {error, _GL, {Pid, Format, Args}}},IOMod) ->
T = write_time(maybe_utc(Time)),
case catch io_lib:format(add_node(Format,Pid), Args) of
S when is_list(S) ->
- format(T ++ S);
+ format(IOMod, T ++ S);
_ ->
F = add_node("ERROR: ~p - ~p~n", Pid),
- format(T ++ F, [Format,Args])
+ format(IOMod, T ++ F, [Format,Args])
end;
-write_event({Time, {emulator, _GL, Chars}}) ->
+write_event({Time, {emulator, _GL, Chars}},IOMod) ->
T = write_time(maybe_utc(Time)),
case catch io_lib:format(Chars, []) of
S when is_list(S) ->
- format(T ++ S);
+ format(IOMod, T ++ S);
_ ->
- format(T ++ "ERROR: ~p ~n", [Chars])
+ format(IOMod, T ++ "ERROR: ~p ~n", [Chars])
end;
-write_event({Time, {info, _GL, {Pid, Info, _}}}) ->
+write_event({Time, {info, _GL, {Pid, Info, _}}},IOMod) ->
T = write_time(maybe_utc(Time)),
- format(T ++ add_node("~p~n",Pid),[Info]);
-write_event({Time, {error_report, _GL, {Pid, std_error, Rep}}}) ->
+ format(IOMod, T ++ add_node("~p~n",Pid),[Info]);
+write_event({Time, {error_report, _GL, {Pid, std_error, Rep}}},IOMod) ->
T = write_time(maybe_utc(Time)),
S = format_report(Rep),
- format(T ++ S ++ add_node("", Pid));
-write_event({Time, {info_report, _GL, {Pid, std_info, Rep}}}) ->
+ format(IOMod, T ++ S ++ add_node("", Pid));
+write_event({Time, {info_report, _GL, {Pid, std_info, Rep}}},IOMod) ->
T = write_time(maybe_utc(Time), "INFO REPORT"),
S = format_report(Rep),
- format(T ++ S ++ add_node("", Pid));
-write_event({Time, {info_msg, _GL, {Pid, Format, Args}}}) ->
+ format(IOMod, T ++ S ++ add_node("", Pid));
+write_event({Time, {info_msg, _GL, {Pid, Format, Args}}},IOMod) ->
T = write_time(maybe_utc(Time), "INFO REPORT"),
case catch io_lib:format(add_node(Format,Pid), Args) of
S when is_list(S) ->
- format(T ++ S);
+ format(IOMod, T ++ S);
_ ->
F = add_node("ERROR: ~p - ~p~n", Pid),
- format(T ++ F, [Format,Args])
+ format(IOMod, T ++ F, [Format,Args])
end;
-write_event({Time, {warning_report, _GL, {Pid, std_warning, Rep}}}) ->
+write_event({Time, {warning_report, _GL, {Pid, std_warning, Rep}}},IOMod) ->
T = write_time(maybe_utc(Time), "WARNING REPORT"),
S = format_report(Rep),
- format(T ++ S ++ add_node("", Pid));
-write_event({Time, {warning_msg, _GL, {Pid, Format, Args}}}) ->
+ format(IOMod, T ++ S ++ add_node("", Pid));
+write_event({Time, {warning_msg, _GL, {Pid, Format, Args}}},IOMod) ->
T = write_time(maybe_utc(Time), "WARNING REPORT"),
case catch io_lib:format(add_node(Format,Pid), Args) of
S when is_list(S) ->
- format(T ++ S);
+ format(IOMod, T ++ S);
_ ->
F = add_node("ERROR: ~p - ~p~n", Pid),
- format(T ++ F, [Format,Args])
+ format(IOMod, T ++ F, [Format,Args])
end;
-write_event({_Time, _Error}) ->
+write_event({_Time, _Error},_IOMod) ->
ok.
maybe_utc(Time) ->
@@ -178,8 +180,9 @@ maybe_utc(Time) ->
Time
end.
-format(String) -> io:format(user, String, []).
-format(String, Args) -> io:format(user, String, Args).
+format(IOMod, String) -> format(IOMod, String, []).
+format(io_lib, String, Args) -> io_lib:format(String, Args);
+format(io, String, Args) -> io:format(user, String, Args).
format_report(Rep) when is_list(Rep) ->
case string_p(Rep) of
diff --git a/lib/stdlib/src/escript.erl b/lib/stdlib/src/escript.erl
index cd1bacd2f5..ad49d89908 100644
--- a/lib/stdlib/src/escript.erl
+++ b/lib/stdlib/src/escript.erl
@@ -866,7 +866,7 @@ hidden_apply(App, M, F, Args) ->
catch
error:undef ->
case erlang:get_stacktrace() of
- [{M,F,Args} | _] ->
+ [{M,F,Args,_} | _] ->
Arity = length(Args),
Text = io_lib:format("Call to ~w:~w/~w in application ~w failed.\n",
[M, F, Arity, App]),
diff --git a/lib/stdlib/src/eval_bits.erl b/lib/stdlib/src/eval_bits.erl
index 1ffa6ea328..f40904df1c 100644
--- a/lib/stdlib/src/eval_bits.erl
+++ b/lib/stdlib/src/eval_bits.erl
@@ -31,8 +31,9 @@
%% @type evalfun(). A closure which evaluates an expression given an
%% environment
%%
-%% @type matchfun(). A closure which performs a match given a value, a
-%% pattern and an environment
+%% @type matchfun(). A closure which depending on its first argument
+%% can perform a match (given a value, a pattern and an environment),
+%% lookup a variable in the bindings, or add a new binding
%%
%% @type field(). Represents a field in a "bin".
@@ -144,7 +145,8 @@ eval_exp_field(Val, Size, Unit, binary, _, _) ->
bin_gen({bin,_,Fs}, Bin, Bs0, BBs0, Mfun, Efun) ->
bin_gen(Fs, Bin, Bs0, BBs0, Mfun, Efun, true).
-bin_gen([F|Fs], Bin, Bs0, BBs0, Mfun, Efun, Flag) ->
+bin_gen([F|Fs], Bin, Bs0, BBs0, Mfun, Efun, Flag)
+ when is_function(Mfun, 2), is_function(Efun, 2) ->
case bin_gen_field(F, Bin, Bs0, BBs0, Mfun, Efun) of
{match,Bs,BBs,Rest} ->
bin_gen(Fs, Rest, Bs, BBs, Mfun, Efun, Flag);
@@ -175,14 +177,14 @@ bin_gen_field({bin_element,Line,VE,Size0,Options0},
{Size1, [Type,{unit,Unit},Sign,Endian]} =
make_bit_type(Line, Size0, Options0),
V = erl_eval:partial_eval(VE),
- match_check_size(Size1, BBs0),
+ match_check_size(Mfun, Size1, BBs0),
{value, Size, _BBs} = Efun(Size1, BBs0),
case catch get_value(Bin, Type, Size, Unit, Sign, Endian) of
{Val,<<_/bitstring>>=Rest} ->
NewV = coerce_to_float(V, Type),
- case catch Mfun(NewV, Val, Bs0) of
+ case catch Mfun(match, {NewV,Val,Bs0}) of
{match,Bs} ->
- BBs = add_bin_binding(NewV, Bs, BBs0),
+ BBs = add_bin_binding(Mfun, NewV, Bs, BBs0),
{match,Bs,BBs,Rest};
_ ->
{nomatch,Rest}
@@ -205,7 +207,8 @@ bin_gen_field({bin_element,Line,VE,Size0,Options0},
match_bits(Fs, Bin, Bs0, BBs, Mfun, Efun, _) ->
match_bits(Fs, Bin, Bs0, BBs, Mfun, Efun).
-match_bits(Fs, Bin, Bs0, BBs, Mfun, Efun) ->
+match_bits(Fs, Bin, Bs0, BBs, Mfun, Efun)
+ when is_function(Mfun, 2), is_function(Efun, 2) ->
case catch match_bits_1(Fs, Bin, Bs0, BBs, Mfun, Efun) of
{match,Bs} -> {match,Bs};
invalid -> throw(invalid);
@@ -230,12 +233,12 @@ match_field_1({bin_element,Line,VE,Size0,Options0},
make_bit_type(Line, Size0, Options0),
V = erl_eval:partial_eval(VE),
Size2 = erl_eval:partial_eval(Size1),
- match_check_size(Size2, BBs0),
+ match_check_size(Mfun, Size2, BBs0),
{value, Size, _BBs} = Efun(Size2, BBs0),
{Val,Rest} = get_value(Bin, Type, Size, Unit, Sign, Endian),
NewV = coerce_to_float(V, Type),
- {match,Bs} = Mfun(NewV, Val, Bs0),
- BBs = add_bin_binding(NewV, Bs, BBs0),
+ {match,Bs} = Mfun(match, {NewV,Val,Bs0}),
+ BBs = add_bin_binding(Mfun, NewV, Bs, BBs0),
{Bs,BBs,Rest}.
%% Almost identical to the one in sys_pre_expand.
@@ -249,12 +252,12 @@ coerce_to_float({integer,L,I}=E, float) ->
coerce_to_float(E, _Type) ->
E.
-add_bin_binding({var,_,'_'}, _Bs, BBs) ->
+add_bin_binding(_, {var,_,'_'}, _Bs, BBs) ->
BBs;
-add_bin_binding({var,_,Name}, Bs, BBs) ->
- {value,Value} = erl_eval:binding(Name, Bs),
- erl_eval:add_binding(Name, Value, BBs);
-add_bin_binding(_, _Bs, BBs) ->
+add_bin_binding(Mfun, {var,_,Name}, Bs, BBs) ->
+ {value,Value} = Mfun(binding, {Name,Bs}),
+ Mfun(add_binding, {Name,Value,BBs});
+add_bin_binding(_, _, _Bs, BBs) ->
BBs.
get_value(Bin, integer, Size, Unit, Sign, Endian) ->
@@ -327,20 +330,20 @@ make_bit_type(_Line, Size, Type0) -> %Size evaluates to an integer or 'all'
{error,Reason} -> error(Reason)
end.
-match_check_size({var,_,V}, Bs) ->
- case erl_eval:binding(V, Bs) of
+match_check_size(Mfun, {var,_,V}, Bs) ->
+ case Mfun(binding, {V,Bs}) of
{value,_} -> ok;
unbound -> throw(invalid) % or, rather, error({unbound,V})
end;
-match_check_size({atom,_,all}, _Bs) ->
+match_check_size(_, {atom,_,all}, _Bs) ->
ok;
-match_check_size({atom,_,undefined}, _Bs) ->
+match_check_size(_, {atom,_,undefined}, _Bs) ->
ok;
-match_check_size({integer,_,_}, _Bs) ->
+match_check_size(_, {integer,_,_}, _Bs) ->
ok;
-match_check_size({value,_,_}, _Bs) ->
+match_check_size(_, {value,_,_}, _Bs) ->
ok; %From the debugger.
-match_check_size(_, _Bs) ->
+match_check_size(_, _, _Bs) ->
throw(invalid).
%% error(Reason) -> exception thrown
diff --git a/lib/stdlib/src/filename.erl b/lib/stdlib/src/filename.erl
index 1cb9e4a25e..dbfcbea4f7 100644
--- a/lib/stdlib/src/filename.erl
+++ b/lib/stdlib/src/filename.erl
@@ -147,9 +147,10 @@ basename(Name) when is_binary(Name) ->
end;
basename(Name0) ->
- Name = flatten(Name0),
+ Name1 = flatten(Name0),
{DirSep2, DrvSep} = separators(),
- basename1(skip_prefix(Name, DrvSep), [], DirSep2).
+ Name = skip_prefix(Name1, DrvSep),
+ basename1(Name, Name, DirSep2).
win_basenameb(<<Letter,$:,Rest/binary>>) when ?IS_DRIVELETTER(Letter) ->
basenameb(Rest,[<<"/">>,<<"\\">>]);
@@ -167,16 +168,18 @@ basenameb(Bin,Sep) ->
-basename1([$/|[]], Tail, DirSep2) ->
- basename1([], Tail, DirSep2);
+basename1([$/], Tail0, _DirSep2) ->
+ %% End of filename -- must get rid of trailing directory separator.
+ [_|Tail] = lists:reverse(Tail0),
+ lists:reverse(Tail);
basename1([$/|Rest], _Tail, DirSep2) ->
- basename1(Rest, [], DirSep2);
+ basename1(Rest, Rest, DirSep2);
basename1([DirSep2|Rest], Tail, DirSep2) when is_integer(DirSep2) ->
basename1([$/|Rest], Tail, DirSep2);
basename1([Char|Rest], Tail, DirSep2) when is_integer(Char) ->
- basename1(Rest, [Char|Tail], DirSep2);
+ basename1(Rest, Tail, DirSep2);
basename1([], Tail, _DirSep2) ->
- lists:reverse(Tail).
+ Tail.
skip_prefix(Name, false) ->
Name;
@@ -369,8 +372,8 @@ extension(Name0) ->
Name = flatten(Name0),
extension(Name, [], major_os_type()).
-extension([$.|Rest], _Result, OsType) ->
- extension(Rest, [$.], OsType);
+extension([$.|Rest]=Result, _Result, OsType) ->
+ extension(Rest, Result, OsType);
extension([Char|Rest], [], OsType) when is_integer(Char) ->
extension(Rest, [], OsType);
extension([$/|Rest], _Result, OsType) ->
@@ -378,9 +381,9 @@ extension([$/|Rest], _Result, OsType) ->
extension([$\\|Rest], _Result, win32) ->
extension(Rest, [], win32);
extension([Char|Rest], Result, OsType) when is_integer(Char) ->
- extension(Rest, [Char|Result], OsType);
+ extension(Rest, Result, OsType);
extension([], Result, _OsType) ->
- lists:reverse(Result).
+ Result.
%% Joins a list of filenames with directory separators.
@@ -833,16 +836,18 @@ try_file(undefined, ObjFilename, Mod, Rules) ->
Error -> Error
end;
try_file(Src, _ObjFilename, Mod, _Rules) ->
- List = Mod:module_info(compile),
- {options, Options} = lists:keyfind(options, 1, List),
+ List = case Mod:module_info(compile) of
+ none -> [];
+ List0 -> List0
+ end,
+ Options = proplists:get_value(options, List, []),
{ok, Cwd} = file:get_cwd(),
AbsPath = make_abs_path(Cwd, Src),
{AbsPath, filter_options(dirname(AbsPath), Options, [])}.
%% Filters the options.
%%
-%% 1) Remove options that have no effect on the generated code,
-%% such as report and verbose.
+%% 1) Only keep options that have any effect on code generation.
%%
%% 2) The paths found in {i, Path} and {outdir, Path} are converted
%% to absolute paths. When doing this, it is assumed that relatives
@@ -854,14 +859,10 @@ filter_options(Base, [{outdir, Path}|Rest], Result) ->
filter_options(Base, Rest, [{outdir, make_abs_path(Base, Path)}|Result]);
filter_options(Base, [{i, Path}|Rest], Result) ->
filter_options(Base, Rest, [{i, make_abs_path(Base, Path)}|Result]);
-filter_options(Base, [Option|Rest], Result) when Option =:= trace ->
- filter_options(Base, Rest, [Option|Result]);
filter_options(Base, [Option|Rest], Result) when Option =:= export_all ->
filter_options(Base, Rest, [Option|Result]);
filter_options(Base, [Option|Rest], Result) when Option =:= binary ->
filter_options(Base, Rest, [Option|Result]);
-filter_options(Base, [Option|Rest], Result) when Option =:= fast ->
- filter_options(Base, Rest, [Option|Result]);
filter_options(Base, [Tuple|Rest], Result) when element(1, Tuple) =:= d ->
filter_options(Base, Rest, [Tuple|Result]);
filter_options(Base, [Tuple|Rest], Result)
@@ -875,12 +876,7 @@ filter_options(_Base, [], Result) ->
%% Gets the source file given path of object code and module name.
get_source_file(Obj, Mod, Rules) ->
- case catch Mod:module_info(source_file) of
- {'EXIT', _Reason} ->
- source_by_rules(dirname(Obj), packages:last(Mod), Rules);
- File ->
- {ok, File}
- end.
+ source_by_rules(dirname(Obj), packages:last(Mod), Rules).
source_by_rules(Dir, Base, [{From, To}|Rest]) ->
case try_rule(Dir, Base, From, To) of
diff --git a/lib/stdlib/src/gen.erl b/lib/stdlib/src/gen.erl
index 574146b1cd..5d803091b6 100644
--- a/lib/stdlib/src/gen.erl
+++ b/lib/stdlib/src/gen.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2010. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2011. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -273,7 +273,7 @@ reply({To, Tag}, Reply) ->
%%%-----------------------------------------------------------------
%%% Misc. functions.
%%%-----------------------------------------------------------------
-where({global, Name}) -> global:safe_whereis_name(Name);
+where({global, Name}) -> global:whereis_name(Name);
where({local, Name}) -> whereis(Name).
name_register({local, Name} = LN) ->
diff --git a/lib/stdlib/src/gen_event.erl b/lib/stdlib/src/gen_event.erl
index 1c4a73680b..3317b30e5c 100644
--- a/lib/stdlib/src/gen_event.erl
+++ b/lib/stdlib/src/gen_event.erl
@@ -36,8 +36,6 @@
add_handler/3, add_sup_handler/3, delete_handler/3, swap_handler/3,
swap_sup_handler/3, which_handlers/1, call/3, call/4, wake_hib/4]).
--export([behaviour_info/1]).
-
-export([init_it/6,
system_continue/3,
system_terminate/4,
@@ -60,14 +58,6 @@
%%% API
%%%=========================================================================
--spec behaviour_info(atom()) -> 'undefined' | [{atom(), arity()}].
-
-behaviour_info(callbacks) ->
- [{init,1},{handle_event,2},{handle_call,2},{handle_info,2},
- {terminate,2},{code_change,3}];
-behaviour_info(_Other) ->
- undefined.
-
%% gen_event:start(Handler) -> {ok, Pid} | {error, What}
%% gen_event:add_handler(Handler, Mod, Args) -> ok | Other
%% gen_event:notify(Handler, Event) -> ok
@@ -78,41 +68,37 @@ behaviour_info(_Other) ->
%% gen_event:which_handler(Handler) -> [Mod]
%% gen_event:stop(Handler) -> ok
-
-%% handlers must export
-%% Mod:init(Args) -> {ok, State} | Other
-%% Mod:handle_event(Event, State) ->
-%% {ok, State'} | remove_handler | {swap_handler,Args1,State1,Mod2,Args2}
-%% Mod:handle_info(Info, State) ->
-%% {ok, State'} | remove_handler | {swap_handler,Args1,State1,Mod2,Args2}
-%% Mod:handle_call(Query, State) ->
-%% {ok, Reply, State'} | {remove_handler, Reply} |
-%% {swap_handler, Reply, Args1,State1,Mod2,Args2}
-%% Mod:terminate(Args, State) -> Val
-
-
-%% add_handler(H, Mod, Args) -> ok | Other
-%% Mod:init(Args) -> {ok, State} | Other
-
-%% delete_handler(H, Mod, Args) -> Val
-%% Mod:terminate(Args, State) -> Val
-
-%% notify(H, Event)
-%% Mod:handle_event(Event, State) ->
-%% {ok, State1}
-%% remove_handler
-%% Mod:terminate(remove_handler, State) is called
-%% the return value is ignored
-%% {swap_handler, Args1, State1, Mod2, Args2}
-%% State2 = Mod:terminate(Args1, State1) is called
-%% the return value is chained into the new module and
-%% Mod2:init({Args2, State2}) is called
-%% Other
-%% Mod:terminate({error, Other}, State) is called
-%% The return value is ignored
-%% call(H, Mod, Query) -> Val
-%% call(H, Mod, Query, Timeout) -> Val
-%% Mod:handle_call(Query, State) -> as above
+-callback init(InitArgs :: term()) ->
+ {ok, State :: term()} |
+ {ok, State :: term(), hibernate} |
+ {error, Reason :: term()}.
+-callback handle_event(Event :: term(), State :: term()) ->
+ {ok, NewState :: term()} |
+ {ok, NewState :: term(), hibernate} |
+ {swap_handler, Args1 :: term(), NewState :: term(),
+ Handler2 :: (atom() | {atom(), Id :: term()}), Args2 :: term()} |
+ remove_handler.
+-callback handle_call(Request :: term(), State :: term()) ->
+ {ok, Reply :: term(), NewState :: term()} |
+ {ok, Reply :: term(), NewState :: term(), hibernate} |
+ {swap_handler, Reply :: term(), Args1 :: term(), NewState :: term(),
+ Handler2 :: (atom() | {atom(), Id :: term()}), Args2 :: term()} |
+ {remove_handler, Reply :: term()}.
+-callback handle_info(Info :: term(), State :: term()) ->
+ {ok, NewState :: term()} |
+ {ok, NewState :: term(), hibernate} |
+ {swap_handler, Args1 :: term(), NewState :: term(),
+ Handler2 :: (atom() | {atom(), Id :: term()}), Args2 :: term()} |
+ remove_handler.
+-callback terminate(Args :: (term() | {stop, Reason :: term()} |
+ stop | remove_handler |
+ {error, {'EXIT', Reason :: term()}} |
+ {error, term()}),
+ State :: term()) ->
+ term().
+-callback code_change(OldVsn :: (term() | {down, term()}),
+ State :: term(), Extra :: term()) ->
+ {ok, NewState :: term()}.
%%---------------------------------------------------------------------------
@@ -667,16 +653,16 @@ report_error(_Handler, {swapped,_,_}, _, _, _) -> ok;
report_error(Handler, Reason, State, LastIn, SName) ->
Reason1 =
case Reason of
- {'EXIT',{undef,[{M,F,A}|MFAs]}} ->
+ {'EXIT',{undef,[{M,F,A,L}|MFAs]}} ->
case code:is_loaded(M) of
false ->
- {'module could not be loaded',[{M,F,A}|MFAs]};
+ {'module could not be loaded',[{M,F,A,L}|MFAs]};
_ ->
case erlang:function_exported(M, F, length(A)) of
true ->
- {undef,[{M,F,A}|MFAs]};
+ {undef,[{M,F,A,L}|MFAs]};
false ->
- {'function not exported',[{M,F,A}|MFAs]}
+ {'function not exported',[{M,F,A,L}|MFAs]}
end
end;
{'EXIT',Why} ->
diff --git a/lib/stdlib/src/gen_fsm.erl b/lib/stdlib/src/gen_fsm.erl
index f2f1365d3d..57734a075c 100644
--- a/lib/stdlib/src/gen_fsm.erl
+++ b/lib/stdlib/src/gen_fsm.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2010. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2011. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -113,8 +113,6 @@
start_timer/2,send_event_after/2,cancel_timer/1,
enter_loop/4, enter_loop/5, enter_loop/6, wake_hib/6]).
--export([behaviour_info/1]).
-
%% Internal exports
-export([init_it/6,
system_continue/3,
@@ -128,13 +126,38 @@
%%% Interface functions.
%%% ---------------------------------------------------
--spec behaviour_info(atom()) -> 'undefined' | [{atom(), arity()}].
-
-behaviour_info(callbacks) ->
- [{init,1},{handle_event,3},{handle_sync_event,4},{handle_info,3},
- {terminate,3},{code_change,4}];
-behaviour_info(_Other) ->
- undefined.
+-callback init(Args :: term()) ->
+ {ok, StateName :: atom(), StateData :: term()} |
+ {ok, StateName :: atom(), StateData :: term(), timeout() | hibernate} |
+ {stop, Reason :: term()} | ignore.
+-callback handle_event(Event :: term(), StateName :: atom(),
+ StateData :: term()) ->
+ {next_state, NextStateName :: atom(), NewStateData :: term()} |
+ {next_state, NextStateName :: atom(), NewStateData :: term(),
+ timeout() | hibernate} |
+ {stop, Reason :: term(), NewStateData :: term()}.
+-callback handle_sync_event(Event :: term(), From :: {pid(), Tag :: term()},
+ StateName :: atom(), StateData :: term()) ->
+ {reply, Reply :: term(), NextStateName :: atom(), NewStateData :: term()} |
+ {reply, Reply :: term(), NextStateName :: atom(), NewStateData :: term(),
+ timeout() | hibernate} |
+ {next_state, NextStateName :: atom(), NewStateData :: term()} |
+ {next_state, NextStateName :: atom(), NewStateData :: term(),
+ timeout() | hibernate} |
+ {stop, Reason :: term(), Reply :: term(), NewStateData :: term()} |
+ {stop, Reason :: term(), NewStateData :: term()}.
+-callback handle_info(Info :: term(), StateName :: atom(),
+ StateData :: term()) ->
+ {next_state, NextStateName :: atom(), NewStateData :: term()} |
+ {next_state, NextStateName :: atom(), NewStateData :: term(),
+ timeout() | hibernate} |
+ {stop, Reason :: normal | term(), NewStateData :: term()}.
+-callback terminate(Reason :: normal | shutdown | {shutdown, term()}
+ | term(), StateName :: atom(), StateData :: term()) ->
+ term().
+-callback code_change(OldVsn :: term() | {down, term()}, StateName :: atom(),
+ StateData :: term(), Extra :: term()) ->
+ {ok, NextStateName :: atom(), NewStateData :: term()}.
%%% ---------------------------------------------------
%%% Starts a generic state machine.
@@ -273,7 +296,7 @@ get_proc_name({local, Name}) ->
exit(process_not_registered)
end;
get_proc_name({global, Name}) ->
- case global:safe_whereis_name(Name) of
+ case global:whereis_name(Name) of
undefined ->
exit(process_not_registered_globally);
Pid when Pid =:= self() ->
@@ -295,7 +318,7 @@ get_parent() ->
name_to_pid(Name) ->
case whereis(Name) of
undefined ->
- case global:safe_whereis_name(Name) of
+ case global:whereis_name(Name) of
undefined ->
exit(could_not_find_registerd_name);
Pid ->
@@ -325,12 +348,15 @@ init_it(Starter, Parent, Name0, Mod, Args, Options) ->
proc_lib:init_ack(Starter, {ok, self()}),
loop(Parent, Name, StateName, StateData, Mod, Timeout, Debug);
{stop, Reason} ->
+ unregister_name(Name0),
proc_lib:init_ack(Starter, {error, Reason}),
exit(Reason);
ignore ->
+ unregister_name(Name0),
proc_lib:init_ack(Starter, ignore),
exit(normal);
{'EXIT', Reason} ->
+ unregister_name(Name0),
proc_lib:init_ack(Starter, {error, Reason}),
exit(Reason);
Else ->
@@ -343,6 +369,13 @@ name({local,Name}) -> Name;
name({global,Name}) -> Name;
name(Pid) when is_pid(Pid) -> Pid.
+unregister_name({local,Name}) ->
+ _ = (catch unregister(Name));
+unregister_name({global,Name}) ->
+ _ = global:unregister_name(Name);
+unregister_name(Pid) when is_pid(Pid) ->
+ Pid.
+
%%-----------------------------------------------------------------
%% The MAIN loop
%%-----------------------------------------------------------------
@@ -561,16 +594,16 @@ terminate(Reason, Name, Msg, Mod, StateName, StateData, Debug) ->
error_info(Reason, Name, Msg, StateName, StateData, Debug) ->
Reason1 =
case Reason of
- {undef,[{M,F,A}|MFAs]} ->
+ {undef,[{M,F,A,L}|MFAs]} ->
case code:is_loaded(M) of
false ->
- {'module could not be loaded',[{M,F,A}|MFAs]};
+ {'module could not be loaded',[{M,F,A,L}|MFAs]};
_ ->
case erlang:function_exported(M, F, length(A)) of
true ->
Reason;
false ->
- {'function not exported',[{M,F,A}|MFAs]}
+ {'function not exported',[{M,F,A,L}|MFAs]}
end
end;
_ ->
diff --git a/lib/stdlib/src/gen_server.erl b/lib/stdlib/src/gen_server.erl
index 09d94a9c40..af07bc988a 100644
--- a/lib/stdlib/src/gen_server.erl
+++ b/lib/stdlib/src/gen_server.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2010. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2011. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -94,8 +94,6 @@
multi_call/2, multi_call/3, multi_call/4,
enter_loop/3, enter_loop/4, enter_loop/5, wake_hib/5]).
--export([behaviour_info/1]).
-
%% System exports
-export([system_continue/3,
system_terminate/4,
@@ -111,13 +109,32 @@
%%% API
%%%=========================================================================
--spec behaviour_info(atom()) -> 'undefined' | [{atom(), arity()}].
-
-behaviour_info(callbacks) ->
- [{init,1},{handle_call,3},{handle_cast,2},{handle_info,2},
- {terminate,2},{code_change,3}];
-behaviour_info(_Other) ->
- undefined.
+-callback init(Args :: term()) ->
+ {ok, State :: term()} | {ok, State :: term(), timeout() | hibernate} |
+ {stop, Reason :: term()} | ignore.
+-callback handle_call(Request :: term(), From :: {pid(), Tag :: term()},
+ State :: term()) ->
+ {reply, Reply :: term(), NewState :: term()} |
+ {reply, Reply :: term(), NewState :: term(), timeout() | hibernate} |
+ {noreply, NewState :: term()} |
+ {noreply, NewState :: term(), timeout() | hibernate} |
+ {stop, Reason :: term(), Reply :: term(), NewState :: term()} |
+ {stop, Reason :: term(), NewState :: term()}.
+-callback handle_cast(Request :: term(), State :: term()) ->
+ {noreply, NewState :: term()} |
+ {noreply, NewState :: term(), timeout() | hibernate} |
+ {stop, Reason :: term(), NewState :: term()}.
+-callback handle_info(Info :: timeout() | term(), State :: term()) ->
+ {noreply, NewState :: term()} |
+ {noreply, NewState :: term(), timeout() | hibernate} |
+ {stop, Reason :: term(), NewState :: term()}.
+-callback terminate(Reason :: (normal | shutdown | {shutdown, term()} |
+ term()),
+ State :: term()) ->
+ term().
+-callback code_change(OldVsn :: (term() | {down, term()}), State :: term(),
+ Extra :: term()) ->
+ {ok, NewState :: term()} | {error, Reason :: term()}.
%%% -----------------------------------------------------------------
%%% Starts a generic server.
@@ -729,16 +746,16 @@ error_info(_Reason, application_controller, _Msg, _State, _Debug) ->
error_info(Reason, Name, Msg, State, Debug) ->
Reason1 =
case Reason of
- {undef,[{M,F,A}|MFAs]} ->
+ {undef,[{M,F,A,L}|MFAs]} ->
case code:is_loaded(M) of
false ->
- {'module could not be loaded',[{M,F,A}|MFAs]};
+ {'module could not be loaded',[{M,F,A,L}|MFAs]};
_ ->
case erlang:function_exported(M, F, length(A)) of
true ->
Reason;
false ->
- {'function not exported',[{M,F,A}|MFAs]}
+ {'function not exported',[{M,F,A,L}|MFAs]}
end
end;
_ ->
@@ -803,7 +820,7 @@ get_proc_name({local, Name}) ->
exit(process_not_registered)
end;
get_proc_name({global, Name}) ->
- case global:safe_whereis_name(Name) of
+ case global:whereis_name(Name) of
undefined ->
exit(process_not_registered_globally);
Pid when Pid =:= self() ->
@@ -825,7 +842,7 @@ get_parent() ->
name_to_pid(Name) ->
case whereis(Name) of
undefined ->
- case global:safe_whereis_name(Name) of
+ case global:whereis_name(Name) of
undefined ->
exit(could_not_find_registerd_name);
Pid ->
diff --git a/lib/stdlib/src/lib.erl b/lib/stdlib/src/lib.erl
index c303ae60b5..314fd60903 100644
--- a/lib/stdlib/src/lib.erl
+++ b/lib/stdlib/src/lib.erl
@@ -173,12 +173,12 @@ format_fun(Fun) when is_function(Fun) ->
analyze_exception(error, Term, Stack) ->
case {is_stacktrace(Stack), Stack, Term} of
- {true, [{_M,_F,As}=MFA|MFAs], function_clause} when is_list(As) ->
- {Term,[MFA],MFAs};
- {true, [{shell,F,A}], function_clause} when is_integer(A) ->
+ {true, [{_,_,As,_}=MFAL|MFAs], function_clause} when is_list(As) ->
+ {Term,[MFAL],MFAs};
+ {true, [{shell,F,A,_}], function_clause} when is_integer(A) ->
{Term, [{F,A}], []};
- {true, [{_M,_F,_AorAs}=MFA|MFAs], undef} ->
- {Term,[MFA],MFAs};
+ {true, [{_,_,_,_}=MFAL|MFAs], undef} ->
+ {Term,[MFAL],MFAs};
{true, _, _} ->
{Term,[],Stack};
{false, _, _} ->
@@ -194,9 +194,11 @@ analyze_exception(_Class, Term, Stack) ->
is_stacktrace([]) ->
true;
-is_stacktrace([{M,F,A}|Fs]) when is_atom(M), is_atom(F), is_integer(A) ->
+is_stacktrace([{M,F,A,I}|Fs])
+ when is_atom(M), is_atom(F), is_integer(A), is_list(I) ->
is_stacktrace(Fs);
-is_stacktrace([{M,F,As}|Fs]) when is_atom(M), is_atom(F), length(As) >= 0 ->
+is_stacktrace([{M,F,As,I}|Fs])
+ when is_atom(M), is_atom(F), length(As) >= 0, is_list(I) ->
is_stacktrace(Fs);
is_stacktrace(_) ->
false.
@@ -225,9 +227,9 @@ explain_reason(function_clause, error, [{F,A}], _PF, _S) ->
%% Shell commands
FAs = io_lib:fwrite(<<"~w/~w">>, [F, A]),
[<<"no function clause matching call to ">> | FAs];
-explain_reason(function_clause, error=Cl, [{M,F,As}], PF, S) ->
+explain_reason(function_clause, error=Cl, [{M,F,As,Loc}], PF, S) ->
Str = <<"no function clause matching ">>,
- format_errstr_call(Str, Cl, {M,F}, As, PF, S);
+ [format_errstr_call(Str, Cl, {M,F}, As, PF, S),$\s|location(Loc)];
explain_reason(if_clause, error, [], _PF, _S) ->
<<"no true branch found when evaluating an if expression">>;
explain_reason(noproc, error, [], _PF, _S) ->
@@ -242,11 +244,11 @@ explain_reason({try_clause,V}, error=Cl, [], PF, S) ->
%% "there is no try clause with a true guard sequence and a
%% pattern matching..."
format_value(V, <<"no try clause matching ">>, Cl, PF, S);
-explain_reason(undef, error, [{M,F,A}], _PF, _S) ->
+explain_reason(undef, error, [{M,F,A,_}], _PF, _S) ->
%% Only the arity is displayed, not the arguments, if there are any.
io_lib:fwrite(<<"undefined function ~s">>,
[mfa_to_string(M, F, n_args(A))]);
-explain_reason({shell_undef,F,A}, error, [], _PF, _S) ->
+explain_reason({shell_undef,F,A,_}, error, [], _PF, _S) ->
%% Give nicer reports for undefined shell functions
%% (but not when the user actively calls shell_default:F(...)).
io_lib:fwrite(<<"undefined shell command ~s/~w">>, [F, n_args(A)]);
@@ -292,17 +294,19 @@ argss(I) ->
io_lib:fwrite(<<"~w arguments">>, [I]).
format_stacktrace1(S0, Stack0, PF, SF) ->
- Stack1 = lists:dropwhile(fun({M,F,A}) -> SF(M, F, A)
+ Stack1 = lists:dropwhile(fun({M,F,A,_}) -> SF(M, F, A)
end, lists:reverse(Stack0)),
S = [" " | S0],
Stack = lists:reverse(Stack1),
format_stacktrace2(S, Stack, 1, PF).
-format_stacktrace2(S, [{M,F,A}|Fs], N, PF) when is_integer(A) ->
- [io_lib:fwrite(<<"~s~s ~s">>,
- [sep(N, S), origin(N, M, F, A), mfa_to_string(M, F, A)])
+format_stacktrace2(S, [{M,F,A,L}|Fs], N, PF) when is_integer(A) ->
+ [io_lib:fwrite(<<"~s~s ~s ~s">>,
+ [sep(N, S), origin(N, M, F, A),
+ mfa_to_string(M, F, A),
+ location(L)])
| format_stacktrace2(S, Fs, N + 1, PF)];
-format_stacktrace2(S, [{M,F,As}|Fs], N, PF) when is_list(As) ->
+format_stacktrace2(S, [{M,F,As,_}|Fs], N, PF) when is_list(As) ->
A = length(As),
CalledAs = [S,<<" called as ">>],
C = format_call("", CalledAs, {M,F}, As, PF),
@@ -313,6 +317,16 @@ format_stacktrace2(S, [{M,F,As}|Fs], N, PF) when is_list(As) ->
format_stacktrace2(_S, [], _N, _PF) ->
"".
+location(L) ->
+ File = proplists:get_value(file, L),
+ Line = proplists:get_value(line, L),
+ if
+ File =/= undefined, Line =/= undefined ->
+ io_lib:format("(~s, line ~w)", [File, Line]);
+ true ->
+ ""
+ end.
+
sep(1, S) -> S;
sep(_, S) -> [$\n | S].
diff --git a/lib/stdlib/src/lists.erl b/lib/stdlib/src/lists.erl
index bba46e4cb6..e73c087753 100644
--- a/lib/stdlib/src/lists.erl
+++ b/lib/stdlib/src/lists.erl
@@ -628,9 +628,10 @@ keydelete3(_, _, []) -> [].
-spec keyreplace(Key, N, TupleList1, NewTuple) -> TupleList2 when
Key :: term(),
N :: pos_integer(),
- TupleList1 :: [tuple()],
- TupleList2 :: [tuple()],
- NewTuple :: tuple().
+ TupleList1 :: [Tuple],
+ TupleList2 :: [Tuple],
+ NewTuple :: Tuple,
+ Tuple :: tuple().
keyreplace(K, N, L, New) when is_integer(N), N > 0, is_tuple(New) ->
keyreplace3(K, N, L, New).
@@ -660,9 +661,10 @@ keytake(_K, _N, [], _L) -> false.
-spec keystore(Key, N, TupleList1, NewTuple) -> TupleList2 when
Key :: term(),
N :: pos_integer(),
- TupleList1 :: [tuple()],
- TupleList2 :: [tuple(), ...],
- NewTuple :: tuple().
+ TupleList1 :: [Tuple],
+ TupleList2 :: [Tuple, ...],
+ NewTuple :: Tuple,
+ Tuple :: tuple().
keystore(K, N, L, New) when is_integer(N), N > 0, is_tuple(New) ->
keystore2(K, N, L, New).
@@ -740,8 +742,9 @@ keysort_1(_I, X, _EX, [], R) ->
TupleList1 :: [T1],
TupleList2 :: [T2],
TupleList3 :: [(T1 | T2)],
- T1 :: tuple(),
- T2 :: tuple().
+ T1 :: Tuple,
+ T2 :: Tuple,
+ Tuple :: tuple().
keymerge(Index, T1, L2) when is_integer(Index), Index > 0 ->
case L2 of
@@ -842,8 +845,9 @@ ukeysort_1(_I, X, _EX, []) ->
TupleList1 :: [T1],
TupleList2 :: [T2],
TupleList3 :: [(T1 | T2)],
- T1 :: tuple(),
- T2 :: tuple().
+ T1 :: Tuple,
+ T2 :: Tuple,
+ Tuple :: tuple().
ukeymerge(Index, L1, T2) when is_integer(Index), Index > 0 ->
case L1 of
@@ -873,8 +877,9 @@ rukeymerge(Index, T1, L2) when is_integer(Index), Index > 0 ->
-spec keymap(Fun, N, TupleList1) -> TupleList2 when
Fun :: fun((Term1 :: term()) -> Term2 :: term()),
N :: pos_integer(),
- TupleList1 :: [tuple()],
- TupleList2 :: [tuple()].
+ TupleList1 :: [Tuple],
+ TupleList2 :: [Tuple],
+ Tuple :: tuple().
keymap(Fun, Index, [Tup|Tail]) ->
[setelement(Index, Tup, Fun(element(Index, Tup)))|keymap(Fun, Index, Tail)];
diff --git a/lib/stdlib/src/ms_transform.erl b/lib/stdlib/src/ms_transform.erl
index 48e22e53fa..63b397f3a5 100644
--- a/lib/stdlib/src/ms_transform.erl
+++ b/lib/stdlib/src/ms_transform.erl
@@ -333,17 +333,18 @@ form({function,Line,Name0,Arity0,Clauses0}) ->
form(AnyOther) ->
AnyOther.
function(Name, Arity, Clauses0) ->
- {Clauses1,_} = clauses(Clauses0,gb_sets:new()),
+ Clauses1 = clauses(Clauses0),
{Name,Arity,Clauses1}.
-clauses([C0|Cs],Bound) ->
- {C1,Bound1} = clause(C0,Bound),
- {C2,Bound2} = clauses(Cs,Bound1),
- {[C1|C2],Bound2};
-clauses([],Bound) -> {[],Bound}.
+clauses([C0|Cs]) ->
+ C1 = clause(C0,gb_sets:new()),
+ C2 = clauses(Cs),
+ [C1|C2];
+clauses([]) -> [].
+
clause({clause,Line,H0,G0,B0},Bound) ->
{H1,Bound1} = copy(H0,Bound),
- {B1,Bound2} = copy(B0,Bound1),
- {{clause,Line,H1,G0,B1},Bound2}.
+ {B1,_Bound2} = copy(B0,Bound1),
+ {clause,Line,H1,G0,B1}.
copy({call,Line,{remote,_Line2,{atom,_Line3,ets},{atom,_Line4,fun2ms}},
As0},Bound) ->
diff --git a/lib/stdlib/src/otp_internal.erl b/lib/stdlib/src/otp_internal.erl
index 5129ba5074..ade79e710a 100644
--- a/lib/stdlib/src/otp_internal.erl
+++ b/lib/stdlib/src/otp_internal.erl
@@ -41,37 +41,12 @@ obsolete(Module, Name, Arity) ->
no
end.
-obsolete_1(init, get_flag, 1) ->
- {removed, {init, get_argument, 1}, "R12B"};
-obsolete_1(init, get_flags, 0) ->
- {removed, {init, get_arguments, 0}, "R12B"};
-obsolete_1(init, get_args, 0) ->
- {removed, {init, get_plain_arguments, 0}, "R12B"};
-obsolete_1(unix, cmd, 1) ->
- {removed, {os,cmd,1}, "R9B"};
-
obsolete_1(net, _, _) ->
{deprecated, "module 'net' obsolete; use 'net_adm'"};
obsolete_1(erl_internal, builtins, 0) ->
{deprecated, {erl_internal, bif, 2}};
-obsolete_1(string, re_sh_to_awk, 1) ->
- {removed, {regexp, sh_to_awk, 1}, "R12B"};
-obsolete_1(string, re_parse, 1) ->
- {removed, {regexp, parse, 1}, "R12B"};
-obsolete_1(string, re_match, 2) ->
- {removed, {regexp, match, 2}, "R12B"};
-obsolete_1(string, re_sub, 3) ->
- {removed, {regexp, sub, 3}, "R12B"};
-obsolete_1(string, re_gsub, 3) ->
- {removed, {regexp, gsub, 3}, "R12B"};
-obsolete_1(string, re_split, 2) ->
- {removed, {regexp, split, 2}, "R12B"};
-
-obsolete_1(string, index, 2) ->
- {removed, {string, str, 2}, "R12B"};
-
obsolete_1(erl_eval, seq, 2) ->
{deprecated, {erl_eval, exprs, 2}};
obsolete_1(erl_eval, seq, 3) ->
@@ -81,99 +56,9 @@ obsolete_1(erl_eval, arg_list, 2) ->
obsolete_1(erl_eval, arg_list, 3) ->
{deprecated, {erl_eval, expr_list, 3}};
-obsolete_1(erl_pp, seq, 1) ->
- {removed, {erl_pp, exprs, 1}, "R12B"};
-obsolete_1(erl_pp, seq, 2) ->
- {removed, {erl_pp, exprs, 2}, "R12B"};
-
-obsolete_1(io, scan_erl_seq, 1) ->
- {removed, {io, scan_erl_exprs, 1}, "R12B"};
-obsolete_1(io, scan_erl_seq, 2) ->
- {removed, {io, scan_erl_exprs, 2}, "R12B"};
-obsolete_1(io, scan_erl_seq, 3) ->
- {removed, {io, scan_erl_exprs, 3}, "R12B"};
-obsolete_1(io, parse_erl_seq, 1) ->
- {removed, {io, parse_erl_exprs, 1}, "R12B"};
-obsolete_1(io, parse_erl_seq, 2) ->
- {removed, {io, parse_erl_exprs, 2}, "R12B"};
-obsolete_1(io, parse_erl_seq, 3) ->
- {removed, {io, parse_erl_exprs, 3}, "R12B"};
-obsolete_1(io, parse_exprs, 2) ->
- {removed, {io, parse_erl_exprs, 2}, "R12B"};
-
-obsolete_1(io_lib, scan, 1) ->
- {removed, {erl_scan, string, 1}, "R12B"};
-obsolete_1(io_lib, scan, 2) ->
- {removed, {erl_scan, string, 2}, "R12B"};
-obsolete_1(io_lib, scan, 3) ->
- {removed, {erl_scan, tokens, 3}, "R12B"};
-obsolete_1(io_lib, reserved_word, 1) ->
- {removed, {erl_scan, reserved_word, 1}, "R12B"};
-
-obsolete_1(lists, keymap, 4) ->
- {removed, {lists, keymap, 3}, "R12B"};
-obsolete_1(lists, all, 3) ->
- {removed, {lists, all, 2}, "R12B"};
-obsolete_1(lists, any, 3) ->
- {removed, {lists, any, 2}, "R12B"};
-obsolete_1(lists, map, 3) ->
- {removed, {lists, map, 2}, "R12B"};
-obsolete_1(lists, flatmap, 3) ->
- {removed, {lists, flatmap, 2}, "R12B"};
-obsolete_1(lists, foldl, 4) ->
- {removed, {lists, foldl, 3}, "R12B"};
-obsolete_1(lists, foldr, 4) ->
- {removed, {lists, foldr, 3}, "R12B"};
-obsolete_1(lists, mapfoldl, 4) ->
- {removed, {lists, mapfoldl, 3}, "R12B"};
-obsolete_1(lists, mapfoldr, 4) ->
- {removed, {lists, mapfoldr, 3}, "R12B"};
-obsolete_1(lists, filter, 3) ->
- {removed, {lists, filter, 2}, "R12B"};
-obsolete_1(lists, foreach, 3) ->
- {removed, {lists, foreach, 2}, "R12B"};
-obsolete_1(lists, zf, 3) ->
- {removed, {lists, zf, 2}, "R12B"};
-
-obsolete_1(ets, fixtable, 2) ->
- {removed, {ets, safe_fixtable, 2}, "R12B"};
-
-obsolete_1(erlang, old_binary_to_term, 1) ->
- {removed, {erlang, binary_to_term, 1}, "R12B"};
-obsolete_1(erlang, info, 1) ->
- {removed, {erlang, system_info, 1}, "R12B"};
obsolete_1(erlang, hash, 2) ->
{deprecated, {erlang, phash2, 2}};
-obsolete_1(file, file_info, 1) ->
- {removed, {file, read_file_info, 1}, "R12B"};
-
-obsolete_1(dict, dict_to_list, 1) ->
- {removed, {dict,to_list,1}, "R12B"};
-obsolete_1(dict, list_to_dict, 1) ->
- {removed, {dict,from_list,1}, "R12B"};
-obsolete_1(orddict, dict_to_list, 1) ->
- {removed, {orddict,to_list,1}, "R12B"};
-obsolete_1(orddict, list_to_dict, 1) ->
- {removed, {orddict,from_list,1}, "R12B"};
-
-obsolete_1(sets, new_set, 0) ->
- {removed, {sets, new, 0}, "R12B"};
-obsolete_1(sets, set_to_list, 1) ->
- {removed, {sets, to_list, 1}, "R12B"};
-obsolete_1(sets, list_to_set, 1) ->
- {removed, {sets, from_list, 1}, "R12B"};
-obsolete_1(sets, subset, 2) ->
- {removed, {sets, is_subset, 2}, "R12B"};
-obsolete_1(ordsets, new_set, 0) ->
- {removed, {ordsets, new, 0}, "R12B"};
-obsolete_1(ordsets, set_to_list, 1) ->
- {removed, {ordsets, to_list, 1}, "R12B"};
-obsolete_1(ordsets, list_to_set, 1) ->
- {removed, {ordsets, from_list, 1}, "R12B"};
-obsolete_1(ordsets, subset, 2) ->
- {removed, {ordsets, is_subset, 2}, "R12B"};
-
obsolete_1(calendar, local_time_to_universal_time, 1) ->
{deprecated, {calendar, local_time_to_universal_time_dst, 1}};
@@ -302,17 +187,6 @@ obsolete_1(auth, node_cookie, 1) ->
obsolete_1(auth, node_cookie, 2) ->
{deprecated, "Deprecated; use erlang:set_cookie/2 and net_adm:ping/1 instead"};
-%% Added in R11B-5.
-obsolete_1(http_base_64, _, _) ->
- {removed, "The http_base_64 module was removed in R12B; use the base64 module instead"};
-obsolete_1(httpd_util, encode_base64, 1) ->
- {removed, "Removed in R12B; use one of the encode functions in the base64 module instead"};
-obsolete_1(httpd_util, decode_base64, 1) ->
- {removed, "Removed in R12B; use one of the decode functions in the base64 module instead"};
-obsolete_1(httpd_util, to_upper, 1) ->
- {removed, {string, to_upper, 1}, "R12B"};
-obsolete_1(httpd_util, to_lower, 1) ->
- {removed, {string, to_lower, 1}, "R12B"};
obsolete_1(erlang, is_constant, 1) ->
{removed, "Removed in R13B"};
@@ -330,22 +204,22 @@ obsolete_1(erlang, fault, 2) ->
obsolete_1(file, rawopen, 2) ->
{removed, "deprecated (will be removed in R13B); use file:open/2 with the raw option"};
-obsolete_1(http, request, 1) -> {deprecated,{httpc,request,1},"R15B"};
-obsolete_1(http, request, 2) -> {deprecated,{httpc,request,2},"R15B"};
-obsolete_1(http, request, 4) -> {deprecated,{httpc,request,4},"R15B"};
-obsolete_1(http, request, 5) -> {deprecated,{httpc,request,5},"R15B"};
-obsolete_1(http, cancel_request, 1) -> {deprecated,{httpc,cancel_request,1},"R15B"};
-obsolete_1(http, cancel_request, 2) -> {deprecated,{httpc,cancel_request,2},"R15B"};
-obsolete_1(http, set_option, 2) -> {deprecated,{httpc,set_option,2},"R15B"};
-obsolete_1(http, set_option, 3) -> {deprecated,{httpc,set_option,3},"R15B"};
-obsolete_1(http, set_options, 1) -> {deprecated,{httpc,set_options,1},"R15B"};
-obsolete_1(http, set_options, 2) -> {deprecated,{httpc,set_options,2},"R15B"};
-obsolete_1(http, verify_cookies, 2) -> {deprecated,{httpc,verify_cookies,2},"R15B"};
-obsolete_1(http, verify_cookies, 3) -> {deprecated,{httpc,verify_cookies,3},"R15B"};
-obsolete_1(http, cookie_header, 1) -> {deprecated,{httpc,cookie_header,1},"R15B"};
-obsolete_1(http, cookie_header, 2) -> {deprecated,{httpc,cookie_header,2},"R15B"};
-obsolete_1(http, stream_next, 1) -> {deprecated,{httpc,stream_next,1},"R15B"};
-obsolete_1(http, default_profile, 0) -> {deprecated,{httpc,default_profile,0},"R15B"};
+obsolete_1(http, request, 1) -> {removed,{httpc,request,1},"R15B"};
+obsolete_1(http, request, 2) -> {removed,{httpc,request,2},"R15B"};
+obsolete_1(http, request, 4) -> {removed,{httpc,request,4},"R15B"};
+obsolete_1(http, request, 5) -> {removed,{httpc,request,5},"R15B"};
+obsolete_1(http, cancel_request, 1) -> {removed,{httpc,cancel_request,1},"R15B"};
+obsolete_1(http, cancel_request, 2) -> {removed,{httpc,cancel_request,2},"R15B"};
+obsolete_1(http, set_option, 2) -> {removed,{httpc,set_option,2},"R15B"};
+obsolete_1(http, set_option, 3) -> {removed,{httpc,set_option,3},"R15B"};
+obsolete_1(http, set_options, 1) -> {removed,{httpc,set_options,1},"R15B"};
+obsolete_1(http, set_options, 2) -> {removed,{httpc,set_options,2},"R15B"};
+obsolete_1(http, verify_cookies, 2) -> {removed,{httpc,store_cookies,2},"R15B"};
+obsolete_1(http, verify_cookies, 3) -> {removed,{httpc,store_cookies,3},"R15B"};
+obsolete_1(http, cookie_header, 1) -> {removed,{httpc,cookie_header,1},"R15B"};
+obsolete_1(http, cookie_header, 2) -> {removed,{httpc,cookie_header,2},"R15B"};
+obsolete_1(http, stream_next, 1) -> {removed,{httpc,stream_next,1},"R15B"};
+obsolete_1(http, default_profile, 0) -> {removed,{httpc,default_profile,0},"R15B"};
obsolete_1(httpd, start, 0) -> {removed,{inets,start,[2,3]},"R14B"};
obsolete_1(httpd, start, 1) -> {removed,{inets,start,[2,3]},"R14B"};
@@ -431,7 +305,7 @@ obsolete_1(ssh_sshd, stop, 1) ->
%% Added in R13A.
obsolete_1(regexp, _, _) ->
- {deprecated, "the regexp module is deprecated (will be removed in R15A); use the re module instead"};
+ {removed, "removed in R15; use the re module instead"};
obsolete_1(lists, flat_length, 1) ->
{removed,{lists,flatlength,1},"R14"};
@@ -449,7 +323,7 @@ obsolete_1(ssl_pkix, decode_cert, A) when A =:= 1; A =:= 2 ->
%% Added in R13B04.
obsolete_1(erlang, concat_binary, 1) ->
- {deprecated,{erlang,list_to_binary,1},"R15B"};
+ {removed,{erlang,list_to_binary,1},"R15B"};
%% Added in R14A.
obsolete_1(ssl, peercert, 2) ->
@@ -469,6 +343,12 @@ obsolete_1(docb_transform, _, _) ->
obsolete_1(docb_xml_check, _, _) ->
{deprecated,"the DocBuilder application is deprecated (will be removed in R15B)"};
+%% Added in R15B
+obsolete_1(asn1rt, F, _) when F == load_driver; F == unload_driver ->
+ {deprecated,"deprecated (will be removed in R16A); has no effect as drivers are no longer used."};
+obsolete_1(ssl, pid, 1) ->
+ {deprecated,"deprecated (will be removed in R17); is no longer needed"};
+
obsolete_1(_, _, _) ->
no.
diff --git a/lib/stdlib/src/qlc.erl b/lib/stdlib/src/qlc.erl
index 5ca04ff023..2b691e6abf 100644
--- a/lib/stdlib/src/qlc.erl
+++ b/lib/stdlib/src/qlc.erl
@@ -123,7 +123,7 @@
-record(setup, {parent}).
--define(THROWN_ERROR, {?MODULE, throw_error, _}).
+-define(THROWN_ERROR, {?MODULE, throw_error, _, _}).
-export_type([query_handle/0]).
@@ -1272,7 +1272,10 @@ abstr_term(Fun, Line) when is_function(Fun) ->
case erlang:fun_info(Fun, type) of
{type, external} ->
{module, Module} = erlang:fun_info(Fun, module),
- {'fun', Line, {function,Module,Name,Arity}};
+ {'fun', Line, {function,
+ {atom,Line,Module},
+ {atom,Line,Name},
+ {integer,Line,Arity}}};
{type, local} ->
{'fun', Line, {function,Name,Arity}}
end
@@ -3701,7 +3704,8 @@ lookup_join(F1, C1, LuF, C2, Rev) ->
maybe_error_logger(allowed, _) ->
ok;
maybe_error_logger(Name, Why) ->
- [_, _, {?MODULE,maybe_error_logger,_} | Stacktrace] = expand_stacktrace(),
+ [_, _, {?MODULE,maybe_error_logger,_,_} | Stacktrace] =
+ expand_stacktrace(),
Trimmer = fun(M, _F, _A) -> M =:= erl_eval end,
Formater = fun(Term, I) -> io_lib:print(Term, I, 80, -1) end,
X = lib:format_stacktrace(1, Stacktrace, Trimmer, Formater),
@@ -3720,7 +3724,7 @@ expand_stacktrace() ->
expand_stacktrace(D) ->
_ = erlang:system_flag(backtrace_depth, D),
{'EXIT', {foo, Stacktrace}} = (catch erlang:error(foo)),
- L = lists:takewhile(fun({M,_,_}) -> M =/= ?MODULE
+ L = lists:takewhile(fun({M,_,_,_}) -> M =/= ?MODULE
end, lists:reverse(Stacktrace)),
if
length(L) < 3 andalso length(Stacktrace) =:= D ->
diff --git a/lib/stdlib/src/random.erl b/lib/stdlib/src/random.erl
index dbb524cc74..d7b51a151c 100644
--- a/lib/stdlib/src/random.erl
+++ b/lib/stdlib/src/random.erl
@@ -26,6 +26,10 @@
-export([seed/0, seed/1, seed/3, uniform/0, uniform/1,
uniform_s/1, uniform_s/2, seed0/0]).
+-define(PRIME1, 30269).
+-define(PRIME2, 30307).
+-define(PRIME3, 30323).
+
%%-----------------------------------------------------------------------
%% The type of the state
@@ -44,7 +48,11 @@ seed0() ->
-spec seed() -> ran().
seed() ->
- reseed(seed0()).
+ case seed_put(seed0()) of
+ undefined -> seed0();
+ {_,_,_} = Tuple -> Tuple
+ end.
+
%% seed({A1, A2, A3})
%% Seed random number generation
@@ -66,17 +74,15 @@ seed({A1, A2, A3}) ->
A3 :: integer().
seed(A1, A2, A3) ->
- put(random_seed,
- {abs(A1) rem 30269, abs(A2) rem 30307, abs(A3) rem 30323}).
+ seed_put({(abs(A1) rem (?PRIME1-1)) + 1, % Avoid seed numbers that are
+ (abs(A2) rem (?PRIME2-1)) + 1, % even divisors of the
+ (abs(A3) rem (?PRIME3-1)) + 1}). % corresponding primes.
--spec reseed(ran()) -> ran().
-
-reseed({A1, A2, A3}) ->
- case seed(A1, A2, A3) of
- undefined -> seed0();
- {_,_,_} = Tuple -> Tuple
- end.
+-spec seed_put(ran()) -> 'undefined' | ran().
+
+seed_put(Seed) ->
+ put(random_seed, Seed).
%% uniform()
%% Returns a random float between 0 and 1.
@@ -88,11 +94,11 @@ uniform() ->
undefined -> seed0();
Tuple -> Tuple
end,
- B1 = (A1*171) rem 30269,
- B2 = (A2*172) rem 30307,
- B3 = (A3*170) rem 30323,
+ B1 = (A1*171) rem ?PRIME1,
+ B2 = (A2*172) rem ?PRIME2,
+ B3 = (A3*170) rem ?PRIME3,
put(random_seed, {B1,B2,B3}),
- R = A1/30269 + A2/30307 + A3/30323,
+ R = B1/?PRIME1 + B2/?PRIME2 + B3/?PRIME3,
R - trunc(R).
%% uniform(N) -> I
@@ -116,10 +122,10 @@ uniform(N) when is_integer(N), N >= 1 ->
State1 :: ran().
uniform_s({A1, A2, A3}) ->
- B1 = (A1*171) rem 30269,
- B2 = (A2*172) rem 30307,
- B3 = (A3*170) rem 30323,
- R = A1/30269 + A2/30307 + A3/30323,
+ B1 = (A1*171) rem ?PRIME1,
+ B2 = (A2*172) rem ?PRIME2,
+ B3 = (A3*170) rem ?PRIME3,
+ R = B1/?PRIME1 + B2/?PRIME2 + B3/?PRIME3,
{R - trunc(R), {B1,B2,B3}}.
%% uniform_s(N, State) -> {I, NewState}
diff --git a/lib/stdlib/src/re.erl b/lib/stdlib/src/re.erl
index e08258a535..246d535943 100644
--- a/lib/stdlib/src/re.erl
+++ b/lib/stdlib/src/re.erl
@@ -48,7 +48,7 @@ split(Subject,RE) ->
Subject :: iodata() | unicode:charlist(),
RE :: mp() | iodata() | unicode:charlist(),
Options :: [ Option ],
- Option :: anchored | global | notbol | noteol | notempty
+ Option :: anchored | notbol | noteol | notempty
| {offset, non_neg_integer()} | {newline, nl_spec()}
| bsr_anycrlf | bsr_unicode | {return, ReturnType}
| {parts, NumParts} | group | trim | CompileOpt,
@@ -573,10 +573,10 @@ ucompile(RE,Options) ->
re:compile(unicode:characters_to_binary(RE,unicode),Options)
catch
error:AnyError ->
- {'EXIT',{new_stacktrace,[{Mod,_,L}|Rest]}} =
+ {'EXIT',{new_stacktrace,[{Mod,_,L,Loc}|Rest]}} =
(catch erlang:error(new_stacktrace,
[RE,Options])),
- erlang:raise(error,AnyError,[{Mod,compile,L}|Rest])
+ erlang:raise(error,AnyError,[{Mod,compile,L,Loc}|Rest])
end.
@@ -585,10 +585,10 @@ urun(Subject,RE,Options) ->
urun2(Subject,RE,Options)
catch
error:AnyError ->
- {'EXIT',{new_stacktrace,[{Mod,_,L}|Rest]}} =
+ {'EXIT',{new_stacktrace,[{Mod,_,L,Loc}|Rest]}} =
(catch erlang:error(new_stacktrace,
[Subject,RE,Options])),
- erlang:raise(error,AnyError,[{Mod,run,L}|Rest])
+ erlang:raise(error,AnyError,[{Mod,run,L,Loc}|Rest])
end.
urun2(Subject0,RE0,Options0) ->
@@ -625,20 +625,20 @@ grun(Subject,RE,{Options,NeedClean}) ->
grun2(Subject,RE,{Options,NeedClean})
catch
error:AnyError ->
- {'EXIT',{new_stacktrace,[{Mod,_,L}|Rest]}} =
+ {'EXIT',{new_stacktrace,[{Mod,_,L,Loc}|Rest]}} =
(catch erlang:error(new_stacktrace,
[Subject,RE,Options])),
- erlang:raise(error,AnyError,[{Mod,run,L}|Rest])
+ erlang:raise(error,AnyError,[{Mod,run,L,Loc}|Rest])
end;
grun(Subject,RE,{Options,NeedClean,OrigRE}) ->
try
grun2(Subject,RE,{Options,NeedClean})
catch
error:AnyError ->
- {'EXIT',{new_stacktrace,[{Mod,_,L}|Rest]}} =
+ {'EXIT',{new_stacktrace,[{Mod,_,L,Loc}|Rest]}} =
(catch erlang:error(new_stacktrace,
[Subject,OrigRE,Options])),
- erlang:raise(error,AnyError,[{Mod,run,L}|Rest])
+ erlang:raise(error,AnyError,[{Mod,run,L,Loc}|Rest])
end.
grun2(Subject,RE,{Options,NeedClean}) ->
diff --git a/lib/stdlib/src/regexp.erl b/lib/stdlib/src/regexp.erl
deleted file mode 100644
index 65f9ca247d..0000000000
--- a/lib/stdlib/src/regexp.erl
+++ /dev/null
@@ -1,557 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 1996-2011. All Rights Reserved.
-%%
-%% The contents of this file are subject to the Erlang Public License,
-%% Version 1.1, (the "License"); you may not use this file except in
-%% compliance with the License. You should have received a copy of the
-%% Erlang Public License along with this software. If not, it can be
-%% retrieved online at http://www.erlang.org/.
-%%
-%% Software distributed under the License is distributed on an "AS IS"
-%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
-%% the License for the specific language governing rights and limitations
-%% under the License.
-%%
-%% %CopyrightEnd%
-%%
--module(regexp).
-
-%% This entire module is deprecated and will be removed in a future
-%% release. Use the 're' module instead.
-%%
-%% This module provides a basic set of regular expression functions
-%% for strings. The functions provided are taken from AWK.
-%%
-%% Note that we interpret the syntax tree of a regular expression
-%% directly instead of converting it to an NFA and then interpreting
-%% that. This method seems to go significantly faster.
-
--export([sh_to_awk/1,parse/1,format_error/1,match/2,first_match/2,matches/2]).
--export([sub/3,gsub/3,split/2]).
-
--deprecated([sh_to_awk/1,parse/1,format_error/1,match/2,first_match/2,matches/2]).
--deprecated([sub/3,gsub/3,split/2]).
-
--import(string, [substr/2,substr/3]).
--import(lists, [reverse/1]).
-
--type errordesc() :: term().
--opaque regexp() :: term().
-
-%% -type matchres() = {match,Start,Length} | nomatch | {error,E}.
-%% -type subres() = {ok,RepString,RepCount} | {error,E}.
-%% -type splitres() = {ok,[SubString]} | {error,E}.
-
-%%-compile([export_all]).
-
-%% This is the regular expression grammar used. It is equivalent to the
-%% one used in AWK, except that we allow ^ $ to be used anywhere and fail
-%% in the matching.
-%%
-%% reg -> reg1 : '$1'.
-%% reg1 -> reg1 "|" reg2 : {'or','$1','$2'}.
-%% reg1 -> reg2 : '$1'.
-%% reg2 -> reg2 reg3 : {concat,'$1','$2'}.
-%% reg2 -> reg3 : '$1'.
-%% reg3 -> reg3 "*" : {kclosure,'$1'}.
-%% reg3 -> reg3 "+" : {pclosure,'$1'}.
-%% reg3 -> reg3 "?" : {optional,'$1'}.
-%% reg3 -> reg4 : '$1'.
-%% reg4 -> "(" reg ")" : '$2'.
-%% reg4 -> "\\" char : '$2'.
-%% reg4 -> "^" : bos.
-%% reg4 -> "$" : eos.
-%% reg4 -> "." : char.
-%% reg4 -> "[" class "]" : {char_class,char_class('$2')}
-%% reg4 -> "[" "^" class "]" : {comp_class,char_class('$3')}
-%% reg4 -> "\"" chars "\"" : char_string('$2')
-%% reg4 -> char : '$1'.
-%% reg4 -> empty : epsilon.
-%% The grammar of the current regular expressions. The actual parser
-%% is a recursive descent implementation of the grammar.
-
-reg(S) -> reg1(S).
-
-%% reg1 -> reg2 reg1'
-%% reg1' -> "|" reg2
-%% reg1' -> empty
-
-reg1(S0) ->
- {L,S1} = reg2(S0),
- reg1p(S1, L).
-
-reg1p([$||S0], L) ->
- {R,S1} = reg2(S0),
- reg1p(S1, {'or',L,R});
-reg1p(S, L) -> {L,S}.
-
-%% reg2 -> reg3 reg2'
-%% reg2' -> reg3
-%% reg2' -> empty
-
-reg2(S0) ->
- {L,S1} = reg3(S0),
- reg2p(S1, L).
-
-reg2p([C|S0], L) when C =/= $|, C =/= $) ->
- {R,S1} = reg3([C|S0]),
- reg2p(S1, {concat,L,R});
-reg2p(S, L) -> {L,S}.
-
-%% reg3 -> reg4 reg3'
-%% reg3' -> "*" reg3'
-%% reg3' -> "+" reg3'
-%% reg3' -> "?" reg3'
-%% reg3' -> empty
-
-reg3(S0) ->
- {L,S1} = reg4(S0),
- reg3p(S1, L).
-
-reg3p([$*|S], L) -> reg3p(S, {kclosure,L});
-reg3p([$+|S], L) -> reg3p(S, {pclosure,L});
-reg3p([$?|S], L) -> reg3p(S, {optional,L});
-reg3p(S, L) -> {L,S}.
-
--define(HEX(C), C >= $0 andalso C =< $9 orelse
- C >= $A andalso C =< $F orelse
- C >= $a andalso C =< $f).
-
-reg4([$(|S0]) ->
- case reg(S0) of
- {R,[$)|S1]} -> {R,S1};
- {_R,_S} -> throw({error,{unterminated,"("}})
- end;
-reg4([$\\,O1,O2,O3|S]) when
- O1 >= $0, O1 =< $7, O2 >= $0, O2 =< $7, O3 >= $0, O3 =< $7 ->
- {(O1*8 + O2)*8 + O3 - 73*$0,S};
-reg4([$\\,$x,H1,H2|S]) when ?HEX(H1), ?HEX(H2) ->
- {erlang:list_to_integer([H1,H2], 16),S};
-reg4([$\\,$x,${|S]) ->
- hex(S, []);
-reg4([$\\,$x|_]) ->
- throw({error,{illegal,[$x]}});
-reg4([$\\,C|S]) -> {escape_char(C),S};
-reg4([$\\]) -> throw({error,{unterminated,"\\"}});
-reg4([$^|S]) -> {bos,S};
-reg4([$$|S]) -> {eos,S};
-reg4([$.|S]) -> {{comp_class,"\n"},S};
-reg4("[^" ++ S0) ->
- case char_class(S0) of
- {Cc,[$]|S1]} -> {{comp_class,Cc},S1};
- {_Cc,_S} -> throw({error,{unterminated,"["}})
- end;
-reg4([$[|S0]) ->
- case char_class(S0) of
- {Cc,[$]|S1]} -> {{char_class,Cc},S1};
- {_Cc,_S1} -> throw({error,{unterminated,"["}})
- end;
-%reg4([$"|S0]) ->
-% case char_string(S0) of
-% {St,[$"|S1]} -> {St,S1};
-% {St,S1} -> throw({error,{unterminated,"\""}})
-% end;
-reg4([C|S]) when C =/= $*, C =/= $+, C =/= $?, C =/= $] -> {C,S};
-reg4([C|_S]) -> throw({error,{illegal,[C]}});
-reg4([]) -> {epsilon,[]}.
-
-hex([C|Cs], L) when ?HEX(C) ->
- hex(Cs, [C|L]);
-hex([$}|S], L) ->
- case catch erlang:list_to_integer(lists:reverse(L), 16) of
- V when V =< 16#FF ->
- {V,S};
- _ ->
- throw({error,{illegal,[$}]}})
- end;
-hex(_S, _) ->
- throw({error,{unterminated,"\\x{"}}).
-
-escape_char($n) -> $\n; %\n = LF
-escape_char($r) -> $\r; %\r = CR
-escape_char($t) -> $\t; %\t = TAB
-escape_char($v) -> $\v; %\v = VT
-escape_char($b) -> $\b; %\b = BS
-escape_char($f) -> $\f; %\f = FF
-escape_char($e) -> $\e; %\e = ESC
-escape_char($s) -> $\s; %\s = SPACE
-escape_char($d) -> $\d; %\d = DEL
-escape_char(C) -> C.
-
-char_class([$]|S]) -> char_class(S, [$]]);
-char_class(S) -> char_class(S, []).
-
-char($\\, [O1,O2,O3|S]) when
- O1 >= $0, O1 =< $7, O2 >= $0, O2 =< $7, O3 >= $0, O3 =< $7 ->
- {(O1*8 + O2)*8 + O3 - 73*$0,S};
-char($\\, [$x,H1,H2|S]) when ?HEX(H1), ?HEX(H2) ->
- {erlang:list_to_integer([H1,H2], 16),S};
-char($\\,[$x,${|S]) ->
- hex(S, []);
-char($\\,[$x|_]) ->
- throw({error,{illegal,[$x]}});
-char($\\, [C|S]) -> {escape_char(C),S};
-char(C, S) -> {C,S}.
-
-char_class([C1|S0], Cc) when C1 =/= $] ->
- case char(C1, S0) of
- {Cf,[$-,C2|S1]} when C2 =/= $] ->
- case char(C2, S1) of
- {Cl,S2} when Cf < Cl -> char_class(S2, [{Cf,Cl}|Cc]);
- {Cl,_S2} -> throw({error,{char_class,[Cf,$-,Cl]}})
- end;
- {C,S1} -> char_class(S1, [C|Cc])
- end;
-char_class(S, Cc) -> {Cc,S}.
-
-%char_string([C|S]) when C =/= $" -> char_string(S, C);
-%char_string(S) -> {epsilon,S}.
-
-%char_string([C|S0], L) when C =/= $" ->
-% char_string(S0, {concat,L,C});
-%char_string(S, L) -> {L,S}.
-
-%% -deftype re_app_res() = {match,RestPos,Rest} | nomatch.
-
-%% re_apply(String, StartPos, RegExp) -> re_app_res().
-%%
-%% Apply the (parse of the) regular expression RegExp to String. If
-%% there is a match return the position of the remaining string and
-%% the string if else return 'nomatch'. BestMatch specifies if we want
-%% the longest match, or just a match.
-%%
-%% StartPos should be the real start position as it is used to decide
-%% if we ae at the beginning of the string.
-%%
-%% Pass two functions to re_apply_or so it can decide, on the basis
-%% of BestMatch, whether to just any take any match or try both to
-%% find the longest. This is slower but saves duplicatng code.
-
-re_apply(S, St, RE) -> re_apply(RE, [], S, St).
-
-re_apply(epsilon, More, S, P) -> %This always matches
- re_apply_more(More, S, P);
-re_apply({'or',RE1,RE2}, More, S, P) ->
- re_apply_or(re_apply(RE1, More, S, P),
- re_apply(RE2, More, S, P));
-re_apply({concat,RE1,RE2}, More, S0, P) ->
- re_apply(RE1, [RE2|More], S0, P);
-re_apply({kclosure,CE}, More, S, P) ->
- %% Be careful with the recursion, explicitly do one call before
- %% looping.
- re_apply_or(re_apply_more(More, S, P),
- re_apply(CE, [{kclosure,CE}|More], S, P));
-re_apply({pclosure,CE}, More, S, P) ->
- re_apply(CE, [{kclosure,CE}|More], S, P);
-re_apply({optional,CE}, More, S, P) ->
- re_apply_or(re_apply_more(More, S, P),
- re_apply(CE, More, S, P));
-re_apply(bos, More, S, 1) -> re_apply_more(More, S, 1);
-re_apply(eos, More, [$\n|S], P) -> re_apply_more(More, S, P);
-re_apply(eos, More, [], P) -> re_apply_more(More, [], P);
-re_apply({char_class,Cc}, More, [C|S], P) ->
- case in_char_class(C, Cc) of
- true -> re_apply_more(More, S, P+1);
- false -> nomatch
- end;
-re_apply({comp_class,Cc}, More, [C|S], P) ->
- case in_char_class(C, Cc) of
- true -> nomatch;
- false -> re_apply_more(More, S, P+1)
- end;
-re_apply(C, More, [C|S], P) when is_integer(C) ->
- re_apply_more(More, S, P+1);
-re_apply(_RE, _More, _S, _P) -> nomatch.
-
-%% re_apply_more([RegExp], String, Length) -> re_app_res().
-
-re_apply_more([RE|More], S, P) -> re_apply(RE, More, S, P);
-re_apply_more([], S, P) -> {match,P,S}.
-
-%% in_char_class(Char, Class) -> bool().
-
-in_char_class(C, [{C1,C2}|_Cc]) when C >= C1, C =< C2 -> true;
-in_char_class(C, [C|_Cc]) -> true;
-in_char_class(C, [_|Cc]) -> in_char_class(C, Cc);
-in_char_class(_C, []) -> false.
-
-%% re_apply_or(Match1, Match2) -> re_app_res().
-%% If we want the best match then choose the longest match, else just
-%% choose one by trying sequentially.
-
-re_apply_or({match,P1,S1}, {match,P2,_S2}) when P1 >= P2 -> {match,P1,S1};
-re_apply_or({match,_P1,_S1}, {match,P2,S2}) -> {match,P2,S2};
-re_apply_or(nomatch, R2) -> R2;
-re_apply_or(R1, nomatch) -> R1.
-
-%% sh_to_awk(ShellRegExp)
-%% Convert a sh style regexp into a full AWK one. The main difficulty is
-%% getting character sets right as the conventions are different.
-
--spec sh_to_awk(ShRegExp) -> AwkRegExp when
- ShRegExp :: string(),
- AwkRegExp :: string().
-
-sh_to_awk(Sh) -> "^(" ++ sh_to_awk_1(Sh). %Fix the beginning
-
-sh_to_awk_1([$*|Sh]) -> %This matches any string
- ".*" ++ sh_to_awk_1(Sh);
-sh_to_awk_1([$?|Sh]) -> %This matches any character
- [$.|sh_to_awk_1(Sh)];
-sh_to_awk_1([$[,$^,$]|Sh]) -> %This takes careful handling
- "\\^" ++ sh_to_awk_1(Sh);
-sh_to_awk_1("[^" ++ Sh) -> [$[|sh_to_awk_2(Sh, true)];
-sh_to_awk_1("[!" ++ Sh) -> "[^" ++ sh_to_awk_2(Sh, false);
-sh_to_awk_1([$[|Sh]) -> [$[|sh_to_awk_2(Sh, false)];
-sh_to_awk_1([C|Sh]) ->
- %% Unspecialise everything else which is not an escape character.
- case special_char(C) of
- true -> [$\\,C|sh_to_awk_1(Sh)];
- false -> [C|sh_to_awk_1(Sh)]
- end;
-sh_to_awk_1([]) -> ")$". %Fix the end
-
-sh_to_awk_2([$]|Sh], UpArrow) -> [$]|sh_to_awk_3(Sh, UpArrow)];
-sh_to_awk_2(Sh, UpArrow) -> sh_to_awk_3(Sh, UpArrow).
-
-sh_to_awk_3([$]|Sh], true) -> "^]" ++ sh_to_awk_1(Sh);
-sh_to_awk_3([$]|Sh], false) -> [$]|sh_to_awk_1(Sh)];
-sh_to_awk_3([C|Sh], UpArrow) -> [C|sh_to_awk_3(Sh, UpArrow)];
-sh_to_awk_3([], true) -> [$^|sh_to_awk_1([])];
-sh_to_awk_3([], false) -> sh_to_awk_1([]).
-
-%% -type special_char(char()) -> bool().
-%% Test if a character is a special character.
-
-special_char($|) -> true;
-special_char($*) -> true;
-special_char($+) -> true;
-special_char($?) -> true;
-special_char($() -> true;
-special_char($)) -> true;
-special_char($\\) -> true;
-special_char($^) -> true;
-special_char($$) -> true;
-special_char($.) -> true;
-special_char($[) -> true;
-special_char($]) -> true;
-special_char($") -> true;
-special_char(_C) -> false.
-
-%% parse(RegExp) -> {ok,RE} | {error,E}.
-%% Parse the regexp described in the string RegExp.
-
--spec parse(RegExp) -> ParseRes when
- RegExp :: string(),
- ParseRes :: {ok, RE} | {error, Error},
- RE :: regexp(),
- Error :: errordesc().
-
-parse(S) ->
- case catch reg(S) of
- {R,[]} -> {ok,R};
- {_R,[C|_]} -> {error,{illegal,[C]}};
- {error,E} -> {error,E}
- end.
-
-%% format_error(Error) -> String.
-
--spec format_error(ErrorDescriptor) -> Chars when
- ErrorDescriptor :: errordesc(),
- Chars :: io_lib:chars().
-
-format_error({illegal,What}) -> ["illegal character `",What,"'"];
-format_error({unterminated,What}) -> ["unterminated `",What,"'"];
-format_error({char_class,What}) ->
- ["illegal character class ",io_lib:write_string(What)].
-
-%% -type match(String, RegExp) -> matchres().
-%% Find the longest match of RegExp in String.
-
--spec match(String, RegExp) -> MatchRes when
- String :: string(),
- RegExp :: string() | regexp(),
- MatchRes :: {match, Start, Length} | nomatch | {error, Error},
- Start :: pos_integer(),
- Length :: pos_integer(),
- Error :: errordesc().
-
-match(S, RegExp) when is_list(RegExp) ->
- case parse(RegExp) of
- {ok,RE} -> match(S, RE);
- {error,E} -> {error,E}
- end;
-match(S, RE) ->
- case match(RE, S, 1, 0, -1) of
- {Start,Len} when Len >= 0 ->
- {match,Start,Len};
- {_Start,_Len} -> nomatch
- end.
-
-match(RE, S, St, Pos, L) ->
- case first_match(RE, S, St) of
- {St1,L1} ->
- Nst = St1 + 1,
- if L1 > L -> match(RE, lists:nthtail(Nst-St, S), Nst, St1, L1);
- true -> match(RE, lists:nthtail(Nst-St, S), Nst, Pos, L)
- end;
- nomatch -> {Pos,L}
- end.
-
-%% -type first_match(String, RegExp) -> matchres().
-%% Find the first match of RegExp in String.
-
--spec first_match(String, RegExp) -> MatchRes when
- String :: string(),
- RegExp :: string() | regexp(),
- MatchRes :: {match, Start, Length} | nomatch | {error, Error},
- Start :: pos_integer(),
- Length :: pos_integer(),
- Error :: errordesc().
-
-first_match(S, RegExp) when is_list(RegExp) ->
- case parse(RegExp) of
- {ok,RE} -> first_match(S, RE);
- {error,E} -> {error,E}
- end;
-first_match(S, RE) ->
- case first_match(RE, S, 1) of
- {Start,Len} when Len >= 0 ->
- {match,Start,Len};
- nomatch -> nomatch
- end.
-
-first_match(RE, S, St) when S =/= [] ->
- case re_apply(S, St, RE) of
- {match,P,_Rest} -> {St,P-St};
- nomatch -> first_match(RE, tl(S), St+1)
- end;
-first_match(_RE, [], _St) -> nomatch.
-
-%% -type matches(String, RegExp) -> {match,[{Start,Length}]} | {error,E}.
-%% Return the all the non-overlapping matches of RegExp in String.
-
--spec matches(String, RegExp) -> MatchRes when
- String :: string(),
- RegExp :: string() | regexp(),
- MatchRes :: {match, Matches} | {error, Error},
- Matches :: [{Start, Length}],
- Start :: pos_integer(),
- Length :: pos_integer(),
- Error :: errordesc().
-
-matches(S, RegExp) when is_list(RegExp) ->
- case parse(RegExp) of
- {ok,RE} -> matches(S, RE);
- {error,E} -> {error,E}
- end;
-matches(S, RE) ->
- {match,matches(S, RE, 1)}.
-
-matches(S, RE, St) ->
- case first_match(RE, S, St) of
- {St1,0} -> [{St1,0}|matches(substr(S, St1+2-St), RE, St1+1)];
- {St1,L1} -> [{St1,L1}|matches(substr(S, St1+L1+1-St), RE, St1+L1)];
- nomatch -> []
- end.
-
-%% -type sub(String, RegExp, Replace) -> subsres().
-%% Substitute the first match of the regular expression RegExp with
-%% the string Replace in String. Accept pre-parsed regular
-%% expressions.
-
--spec sub(String, RegExp, New) -> SubRes when
- String :: string(),
- RegExp :: string() | regexp(),
- New :: string(),
- NewString :: string(),
- SubRes :: {ok, NewString, RepCount} | {error, Error},
- RepCount :: 0 | 1,
- Error :: errordesc().
-
-sub(String, RegExp, Rep) when is_list(RegExp) ->
- case parse(RegExp) of
- {ok,RE} -> sub(String, RE, Rep);
- {error,E} -> {error,E}
- end;
-sub(String, RE, Rep) ->
- Ss = sub_match(String, RE, 1),
- {ok,sub_repl(Ss, Rep, String, 1),length(Ss)}.
-
-sub_match(S, RE, St) ->
- case first_match(RE, S, St) of
- {St1,L1} -> [{St1,L1}];
- nomatch -> []
- end.
-
-sub_repl([{St,L}|Ss], Rep, S, Pos) ->
- Rs = sub_repl(Ss, Rep, S, St+L),
- substr(S, Pos, St-Pos) ++ sub_repl(Rep, substr(S, St, L), Rs);
-sub_repl([], _Rep, S, Pos) -> substr(S, Pos).
-
-sub_repl([$&|Rep], M, Rest) -> M ++ sub_repl(Rep, M, Rest);
-sub_repl("\\&" ++ Rep, M, Rest) -> [$&|sub_repl(Rep, M, Rest)];
-sub_repl([C|Rep], M, Rest) -> [C|sub_repl(Rep, M, Rest)];
-sub_repl([], _M, Rest) -> Rest.
-
-%% -type gsub(String, RegExp, Replace) -> subres().
-%% Substitute every match of the regular expression RegExp with the
-%% string New in String. Accept pre-parsed regular expressions.
-
--spec gsub(String, RegExp, New) -> SubRes when
- String :: string(),
- RegExp :: string() | regexp(),
- New :: string(),
- NewString :: string(),
- SubRes :: {ok, NewString, RepCount} | {error, Error},
- RepCount :: non_neg_integer(),
- Error :: errordesc().
-
-gsub(String, RegExp, Rep) when is_list(RegExp) ->
- case parse(RegExp) of
- {ok,RE} -> gsub(String, RE, Rep);
- {error,E} -> {error,E}
- end;
-gsub(String, RE, Rep) ->
- Ss = matches(String, RE, 1),
- {ok,sub_repl(Ss, Rep, String, 1),length(Ss)}.
-
-%% -type split(String, RegExp) -> splitres().
-%% Split a string into substrings where the RegExp describes the
-%% field seperator. The RegExp " " is specially treated.
-
--spec split(String, RegExp) -> SplitRes when
- String :: string(),
- RegExp :: string() | regexp(),
- SplitRes :: {ok, FieldList} | {error, Error},
- FieldList :: [string()],
- Error :: errordesc().
-
-split(String, " ") -> %This is really special
- {ok,RE} = parse("[ \t]+"),
- case split_apply(String, RE, true) of
- [[]|Ss] -> {ok,Ss};
- Ss -> {ok,Ss}
- end;
-split(String, RegExp) when is_list(RegExp) ->
- case parse(RegExp) of
- {ok,RE} -> {ok,split_apply(String, RE, false)};
- {error,E} -> {error,E}
- end;
-split(String, RE) -> {ok,split_apply(String, RE, false)}.
-
-split_apply(S, RE, Trim) -> split_apply(S, 1, RE, Trim, []).
-
-split_apply([], _P, _RE, true, []) -> [];
-split_apply([], _P, _RE, _T, Sub) -> [reverse(Sub)];
-split_apply(S, P, RE, T, Sub) ->
- case re_apply(S, P, RE) of
- {match,P,_Rest} ->
- split_apply(tl(S), P+1, RE, T, [hd(S)|Sub]);
- {match,P1,Rest} ->
- [reverse(Sub)|split_apply(Rest, P1, RE, T, [])];
- nomatch ->
- split_apply(tl(S), P+1, RE, T, [hd(S)|Sub])
- end.
diff --git a/lib/stdlib/src/shell.erl b/lib/stdlib/src/shell.erl
index e3e23e09bc..dc450f0ee6 100644
--- a/lib/stdlib/src/shell.erl
+++ b/lib/stdlib/src/shell.erl
@@ -1065,9 +1065,10 @@ local_func(F, As0, Bs0, _Shell, _RT, Lf, Ef) when is_atom(F) ->
non_builtin_local_func(F,As,Bs).
non_builtin_local_func(F,As,Bs) ->
- case erlang:function_exported(user_default, F, length(As)) of
+ Arity = length(As),
+ case erlang:function_exported(user_default, F, Arity) of
true ->
- {eval,{user_default,F},As,Bs};
+ {eval,erlang:make_fun(user_default, F, Arity),As,Bs};
false ->
shell_default(F,As,Bs)
end.
@@ -1079,7 +1080,7 @@ shell_default(F,As,Bs) ->
{module, _} ->
case erlang:function_exported(M,F,A) of
true ->
- {eval,{M,F},As,Bs};
+ {eval,erlang:make_fun(M, F, A),As,Bs};
false ->
shell_undef(F,A)
end;
@@ -1088,7 +1089,7 @@ shell_default(F,As,Bs) ->
end.
shell_undef(F,A) ->
- erlang:error({shell_undef,F,A}).
+ erlang:error({shell_undef,F,A,[]}).
local_func_handler(Shell, RT, Ef) ->
H = fun(Lf) ->
diff --git a/lib/stdlib/src/stdlib.app.src b/lib/stdlib/src/stdlib.app.src
index 9d15f01683..da65db4b9d 100644
--- a/lib/stdlib/src/stdlib.app.src
+++ b/lib/stdlib/src/stdlib.app.src
@@ -85,7 +85,6 @@
queue,
random,
re,
- regexp,
sets,
shell,
shell_default,
diff --git a/lib/stdlib/src/stdlib.appup.src b/lib/stdlib/src/stdlib.appup.src
index 54a63833e6..94e81188b5 100644
--- a/lib/stdlib/src/stdlib.appup.src
+++ b/lib/stdlib/src/stdlib.appup.src
@@ -1 +1,27 @@
-{"%VSN%",[],[]}.
+%% -*- erlang -*-
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 1999-2011. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+{"%VSN%",
+ %% Up from - max two major revisions back
+ [{<<"1\\.18(\\.[0-9]+)*">>,[restart_new_emulator]}, %% R15
+ {<<"1\\.17(\\.[0-9]+)*">>,[restart_new_emulator]}, %% R14
+ {<<"1\\.16(\\.[0-9]+)*">>,[restart_new_emulator]}],%% R13
+ %% Down to - max two major revisions back
+ [{<<"1\\.18(\\.[0-9]+)*">>,[restart_new_emulator]}, %% R15
+ {<<"1\\.17(\\.[0-9]+)*">>,[restart_new_emulator]}, %% R14
+ {<<"1\\.16(\\.[0-9]+)*">>,[restart_new_emulator]}] %% R13
+}.
diff --git a/lib/stdlib/src/supervisor.erl b/lib/stdlib/src/supervisor.erl
index dc31647eb5..42ea42f42e 100644
--- a/lib/stdlib/src/supervisor.erl
+++ b/lib/stdlib/src/supervisor.erl
@@ -27,8 +27,6 @@
which_children/1, count_children/1,
check_childspecs/1]).
--export([behaviour_info/1]).
-
%% Internal exports
-export([init/1, handle_call/3, handle_info/2, terminate/2, code_change/3]).
-export([handle_cast/2]).
@@ -39,7 +37,7 @@
%%--------------------------------------------------------------------------
--type child() :: pid() | 'undefined'.
+-type child() :: 'undefined' | pid() | [pid()].
-type child_id() :: term().
-type mfargs() :: {M :: module(), F :: atom(), A :: [term()] | undefined}.
-type modules() :: [module()] | 'dynamic'.
@@ -90,14 +88,12 @@
-define(is_simple(State), State#state.strategy =:= simple_one_for_one).
-%%--------------------------------------------------------------------------
-
--spec behaviour_info(atom()) -> 'undefined' | [{atom(), arity()}].
-
-behaviour_info(callbacks) ->
- [{init,1}];
-behaviour_info(_Other) ->
- undefined.
+-callback init(Args :: term()) ->
+ {ok, {{RestartStrategy :: strategy(),
+ MaxR :: non_neg_integer(),
+ MaxT :: non_neg_integer()},
+ [ChildSpec :: child_spec()]}}
+ | ignore.
%%% ---------------------------------------------------
%%% This is a general process supervisor built upon gen_server.erl.
@@ -519,9 +515,12 @@ handle_info(Msg, State) ->
%%
-spec terminate(term(), state()) -> 'ok'.
+terminate(_Reason, #state{children=[Child]} = State) when ?is_simple(State) ->
+ terminate_dynamic_children(Child, dynamics_db(Child#child.restart_type,
+ State#state.dynamics),
+ State#state.name);
terminate(_Reason, State) ->
- terminate_children(State#state.children, State#state.name),
- ok.
+ terminate_children(State#state.children, State#state.name).
%%
%% Change code for the supervisor.
@@ -661,6 +660,9 @@ do_restart(_, normal, Child, State) ->
do_restart(_, shutdown, Child, State) ->
NState = state_del_child(Child, State),
{ok, NState};
+do_restart(_, {shutdown, _Term}, Child, State) ->
+ NState = state_del_child(Child, State),
+ {ok, NState};
do_restart(transient, Reason, Child, State) ->
report_error(child_terminated, Reason, Child, State#state.name),
restart(Child, State);
@@ -831,8 +833,109 @@ monitor_child(Pid) ->
%% that will be handled in shutdown/2.
ok
end.
-
-
+
+
+%%-----------------------------------------------------------------
+%% Func: terminate_dynamic_children/3
+%% Args: Child = child_rec()
+%% Dynamics = ?DICT() | ?SET()
+%% SupName = {local, atom()} | {global, atom()} | {pid(),Mod}
+%% Returns: ok
+%%
+%%
+%% Shutdown all dynamic children. This happens when the supervisor is
+%% stopped. Because the supervisor can have millions of dynamic children, we
+%% can have an significative overhead here.
+%%-----------------------------------------------------------------
+terminate_dynamic_children(Child, Dynamics, SupName) ->
+ {Pids, EStack0} = monitor_dynamic_children(Child, Dynamics),
+ Sz = ?SETS:size(Pids),
+ EStack = case Child#child.shutdown of
+ brutal_kill ->
+ ?SETS:fold(fun(P, _) -> exit(P, kill) end, ok, Pids),
+ wait_dynamic_children(Child, Pids, Sz, undefined, EStack0);
+ infinity ->
+ ?SETS:fold(fun(P, _) -> exit(P, shutdown) end, ok, Pids),
+ wait_dynamic_children(Child, Pids, Sz, undefined, EStack0);
+ Time ->
+ ?SETS:fold(fun(P, _) -> exit(P, shutdown) end, ok, Pids),
+ TRef = erlang:start_timer(Time, self(), kill),
+ wait_dynamic_children(Child, Pids, Sz, TRef, EStack0)
+ end,
+ %% Unrool stacked errors and report them
+ ?DICT:fold(fun(Reason, Ls, _) ->
+ report_error(shutdown_error, Reason,
+ Child#child{pid=Ls}, SupName)
+ end, ok, EStack).
+
+
+monitor_dynamic_children(#child{restart_type=temporary}, Dynamics) ->
+ ?SETS:fold(fun(P, {Pids, EStack}) ->
+ case monitor_child(P) of
+ ok ->
+ {?SETS:add_element(P, Pids), EStack};
+ {error, normal} ->
+ {Pids, EStack};
+ {error, Reason} ->
+ {Pids, ?DICT:append(Reason, P, EStack)}
+ end
+ end, {?SETS:new(), ?DICT:new()}, Dynamics);
+monitor_dynamic_children(#child{restart_type=RType}, Dynamics) ->
+ ?DICT:fold(fun(P, _, {Pids, EStack}) ->
+ case monitor_child(P) of
+ ok ->
+ {?SETS:add_element(P, Pids), EStack};
+ {error, normal} when RType =/= permanent ->
+ {Pids, EStack};
+ {error, Reason} ->
+ {Pids, ?DICT:append(Reason, P, EStack)}
+ end
+ end, {?SETS:new(), ?DICT:new()}, Dynamics).
+
+
+wait_dynamic_children(_Child, _Pids, 0, undefined, EStack) ->
+ EStack;
+wait_dynamic_children(_Child, _Pids, 0, TRef, EStack) ->
+ %% If the timer has expired before its cancellation, we must empty the
+ %% mail-box of the 'timeout'-message.
+ erlang:cancel_timer(TRef),
+ receive
+ {timeout, TRef, kill} ->
+ EStack
+ after 0 ->
+ EStack
+ end;
+wait_dynamic_children(#child{shutdown=brutal_kill} = Child, Pids, Sz,
+ TRef, EStack) ->
+ receive
+ {'DOWN', _MRef, process, Pid, killed} ->
+ wait_dynamic_children(Child, ?SETS:del_element(Pid, Pids), Sz-1,
+ TRef, EStack);
+
+ {'DOWN', _MRef, process, Pid, Reason} ->
+ wait_dynamic_children(Child, ?SETS:del_element(Pid, Pids), Sz-1,
+ TRef, ?DICT:append(Reason, Pid, EStack))
+ end;
+wait_dynamic_children(#child{restart_type=RType} = Child, Pids, Sz,
+ TRef, EStack) ->
+ receive
+ {'DOWN', _MRef, process, Pid, shutdown} ->
+ wait_dynamic_children(Child, ?SETS:del_element(Pid, Pids), Sz-1,
+ TRef, EStack);
+
+ {'DOWN', _MRef, process, Pid, normal} when RType =/= permanent ->
+ wait_dynamic_children(Child, ?SETS:del_element(Pid, Pids), Sz-1,
+ TRef, EStack);
+
+ {'DOWN', _MRef, process, Pid, Reason} ->
+ wait_dynamic_children(Child, ?SETS:del_element(Pid, Pids), Sz-1,
+ TRef, ?DICT:append(Reason, Pid, EStack));
+
+ {timeout, TRef, kill} ->
+ ?SETS:fold(fun(P, _) -> exit(P, kill) end, ok, Pids),
+ wait_dynamic_children(Child, Pids, Sz-1, undefined, EStack)
+ end.
+
%%-----------------------------------------------------------------
%% Child/State manipulating functions.
%%-----------------------------------------------------------------
@@ -1054,7 +1157,7 @@ validRestartType(RestartType) -> throw({invalid_restart_type, RestartType}).
validShutdown(Shutdown, _)
when is_integer(Shutdown), Shutdown > 0 -> true;
-validShutdown(infinity, supervisor) -> true;
+validShutdown(infinity, _) -> true;
validShutdown(brutal_kill, _) -> true;
validShutdown(Shutdown, _) -> throw({invalid_shutdown, Shutdown}).
@@ -1135,6 +1238,13 @@ report_error(Error, Reason, Child, SupName) ->
error_logger:error_report(supervisor_report, ErrorMsg).
+extract_child(Child) when is_list(Child#child.pid) ->
+ [{nb_children, length(Child#child.pid)},
+ {name, Child#child.name},
+ {mfargs, Child#child.mfargs},
+ {restart_type, Child#child.restart_type},
+ {shutdown, Child#child.shutdown},
+ {child_type, Child#child.child_type}];
extract_child(Child) ->
[{pid, Child#child.pid},
{name, Child#child.name},
diff --git a/lib/stdlib/src/supervisor_bridge.erl b/lib/stdlib/src/supervisor_bridge.erl
index 555cb5a66f..e8405ab9a4 100644
--- a/lib/stdlib/src/supervisor_bridge.erl
+++ b/lib/stdlib/src/supervisor_bridge.erl
@@ -22,15 +22,14 @@
%% External exports
-export([start_link/2, start_link/3]).
--export([behaviour_info/1]).
%% Internal exports
-export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2]).
-export([code_change/3]).
-behaviour_info(callbacks) ->
- [{init,1},{terminate,2}];
-behaviour_info(_Other) ->
- undefined.
+-callback init(Args :: term()) ->
+ {ok, Pid :: pid(), State :: term()} | ignore | {error, Error :: term()}.
+-callback terminate(Reason :: (shutdown | term()), State :: term()) ->
+ Ignored :: term().
%%%-----------------------------------------------------------------
%%% This is a rewrite of supervisor_bridge from BS.3.
diff --git a/lib/stdlib/src/unicode.erl b/lib/stdlib/src/unicode.erl
index a5d9965ca2..e9b90befe6 100644
--- a/lib/stdlib/src/unicode.erl
+++ b/lib/stdlib/src/unicode.erl
@@ -73,7 +73,7 @@ characters_to_list_int(ML, Encoding) ->
_ ->
badarg
end,
- {'EXIT',{new_stacktrace,[{Mod,_,L}|Rest]}} =
+ {'EXIT',{new_stacktrace,[{Mod,_,L,_}|Rest]}} =
(catch erlang:error(new_stacktrace,
[ML,Encoding])),
erlang:raise(error,TheError,[{Mod,characters_to_list,L}|Rest])
@@ -109,7 +109,7 @@ characters_to_binary(ML) ->
_ ->
badarg
end,
- {'EXIT',{new_stacktrace,[{Mod,_,L}|Rest]}} =
+ {'EXIT',{new_stacktrace,[{Mod,_,L,_}|Rest]}} =
(catch erlang:error(new_stacktrace,
[ML])),
erlang:raise(error,TheError,[{Mod,characters_to_binary,L}|Rest])
@@ -127,7 +127,7 @@ characters_to_binary_int(ML,InEncoding) ->
_ ->
badarg
end,
- {'EXIT',{new_stacktrace,[{Mod,_,L}|Rest]}} =
+ {'EXIT',{new_stacktrace,[{Mod,_,L,_}|Rest]}} =
(catch erlang:error(new_stacktrace,
[ML,InEncoding])),
erlang:raise(error,TheError,[{Mod,characters_to_binary,L}|Rest])
@@ -159,7 +159,7 @@ characters_to_binary(ML, latin1, Uni) when is_binary(ML) and ((Uni =:= utf8) or
_ ->
badarg
end,
- {'EXIT',{new_stacktrace,[{Mod,_,L}|Rest]}} =
+ {'EXIT',{new_stacktrace,[{Mod,_,L,_}|Rest]}} =
(catch erlang:error(new_stacktrace,
[ML,latin1,Uni])),
erlang:raise(error,TheError,
@@ -181,7 +181,7 @@ characters_to_binary(ML,Uni,latin1) when is_binary(ML) and ((Uni =:= utf8) or
_ ->
badarg
end,
- {'EXIT',{new_stacktrace,[{Mod,_,L}|Rest]}} =
+ {'EXIT',{new_stacktrace,[{Mod,_,L,_}|Rest]}} =
(catch erlang:error(new_stacktrace,
[ML,Uni,latin1])),
erlang:raise(error,TheError,
@@ -200,7 +200,7 @@ characters_to_binary(ML, InEncoding, OutEncoding) ->
_ ->
badarg
end,
- {'EXIT',{new_stacktrace,[{Mod,_,L}|Rest]}} =
+ {'EXIT',{new_stacktrace,[{Mod,_,L,_}|Rest]}} =
(catch erlang:error(new_stacktrace,
[ML,InEncoding,OutEncoding])),
erlang:raise(error,TheError,[{Mod,characters_to_binary,L}|Rest])
diff --git a/lib/stdlib/test/Makefile b/lib/stdlib/test/Makefile
index 5502c69fa5..aa6a660c34 100644
--- a/lib/stdlib/test/Makefile
+++ b/lib/stdlib/test/Makefile
@@ -65,6 +65,7 @@ MODULES= \
stdlib_SUITE \
string_SUITE \
supervisor_1 \
+ supervisor_2 \
naughty_child \
shell_SUITE \
supervisor_SUITE \
diff --git a/lib/stdlib/test/beam_lib_SUITE.erl b/lib/stdlib/test/beam_lib_SUITE.erl
index 27520a5c88..5df19ca7f1 100644
--- a/lib/stdlib/test/beam_lib_SUITE.erl
+++ b/lib/stdlib/test/beam_lib_SUITE.erl
@@ -181,7 +181,8 @@ error(Conf) when is_list(Conf) ->
?line verify(not_a_beam_file, beam_lib:info(<<"short">>)),
?line {Binary1, _} = split_binary(Binary, byte_size(Binary)-10),
- ?line verify(chunk_too_big, beam_lib:chunks(Binary1, ["Abst"])),
+ LastChunk = last_chunk(Binary),
+ ?line verify(chunk_too_big, beam_lib:chunks(Binary1, [LastChunk])),
?line Chunks = chunk_info(Binary),
?line {value, {_, AbstractStart, _}} = lists:keysearch("Abst", 1, Chunks),
?line {Binary2, _} = split_binary(Binary, AbstractStart),
@@ -205,6 +206,12 @@ error(Conf) when is_list(Conf) ->
?line file:delete(ACopy),
ok.
+last_chunk(Bin) ->
+ L = beam_lib:info(Bin),
+ {chunks,Chunks} = lists:keyfind(chunks, 1, L),
+ {Last,_,_} = lists:last(Chunks),
+ Last.
+
do_error(BeamFile, ACopy) ->
% evil tests
?line Chunks = chunk_info(BeamFile),
@@ -330,6 +337,7 @@ strip(Conf) when is_list(Conf) ->
?line {Source2D1, BeamFile2D1} = make_beam(PrivDir, simple2, concat),
?line {Source3D1, BeamFile3D1} = make_beam(PrivDir, make_fun, make_fun),
?line {Source4D1, BeamFile4D1} = make_beam(PrivDir, constant, constant),
+ ?line {Source5D1, BeamFile5D1} = make_beam(PrivDir, lines, lines),
?line NoOfTables = length(ets:all()),
?line P0 = pps(),
@@ -360,13 +368,25 @@ strip(Conf) when is_list(Conf) ->
?line {module, make_fun} = code:load_abs(filename:rootname(BeamFile3D1)),
?line {module, constant} = code:load_abs(filename:rootname(BeamFile4D1)),
+ %% check that line number information is still present after stripping
+ ?line {module, lines} = code:load_abs(filename:rootname(BeamFile5D1)),
+ ?line {'EXIT',{badarith,[{lines,t,1,Info}|_]}} =
+ (catch lines:t(atom)),
+ ?line true = code:delete(lines),
+ ?line false = code:purge(lines),
+ ?line {ok, {lines,BeamFile5D1}} = beam_lib:strip(BeamFile5D1),
+ ?line {module, lines} = code:load_abs(filename:rootname(BeamFile5D1)),
+ ?line {'EXIT',{badarith,[{lines,t,1,Info}|_]}} =
+ (catch lines:t(atom)),
+
?line true = (P0 == pps()),
?line NoOfTables = length(ets:all()),
?line delete_files([SourceD1, BeamFileD1,
Source2D1, BeamFile2D1,
Source3D1, BeamFile3D1,
- Source4D1, BeamFile4D1]),
+ Source4D1, BeamFile4D1,
+ Source5D1, BeamFile5D1]),
ok.
@@ -783,6 +803,12 @@ simple_file(File, Module, constant2) ->
"t(A) -> "
" {a,b,[2,3],x,y}. "]),
ok = file:write_file(File, B);
+simple_file(File, Module, lines) ->
+ B = list_to_binary(["-module(", atom_to_list(Module), ").\n"
+ "-export([t/1]).\n"
+ "t(A) ->\n"
+ " A+1.\n"]),
+ ok = file:write_file(File, B);
simple_file(File, Module, F) ->
B = list_to_binary(["-module(", atom_to_list(Module), "). "
"-export([t/0]). "
diff --git a/lib/stdlib/test/binary_module_SUITE.erl b/lib/stdlib/test/binary_module_SUITE.erl
index 8fb63f33bd..bac59a3107 100644
--- a/lib/stdlib/test/binary_module_SUITE.erl
+++ b/lib/stdlib/test/binary_module_SUITE.erl
@@ -20,7 +20,7 @@
-export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1,
init_per_group/2,end_per_group/2,
- interesting/1,random_ref_comp/1,random_ref_sr_comp/1,
+ interesting/1,scope_return/1,random_ref_comp/1,random_ref_sr_comp/1,
random_ref_fla_comp/1,parts/1, bin_to_list/1, list_to_bin/1,
copy/1, referenced/1,guard/1,encode_decode/1,badargs/1,longest_common_trap/1]).
@@ -67,7 +67,7 @@ end_per_testcase(_Case, Config) ->
suite() -> [{ct_hooks,[ts_install_cth]}].
all() ->
- [interesting, random_ref_fla_comp, random_ref_sr_comp,
+ [scope_return,interesting, random_ref_fla_comp, random_ref_sr_comp,
random_ref_comp, parts, bin_to_list, list_to_bin, copy,
referenced, guard, encode_decode, badargs,
longest_common_trap].
@@ -379,6 +379,20 @@ subj() ->
Subject.
+scope_return(doc) ->
+ ["Test correct return values for scopes (OTP-9701)."];
+scope_return(Config) when is_list(Config) ->
+ N=10000,
+ Bin=binary:copy(<<"a">>,N),
+ scope_loop(Bin,0,N).
+
+scope_loop(_,N,N) ->
+ ok;
+scope_loop(Bin,N,M) ->
+ ?line {N,1} = binary:match(Bin,<<"a">>,[{scope,{N,1}}]),
+ ?line {N,1} = binary:match(Bin,[<<"a">>,<<"b">>],[{scope,{N,1}}]),
+ scope_loop(Bin,N+1,M).
+
interesting(doc) ->
["Try some interesting patterns"];
interesting(Config) when is_list(Config) ->
diff --git a/lib/stdlib/test/dets_SUITE.erl b/lib/stdlib/test/dets_SUITE.erl
index 22a9d4a7ff..6f77cff2b9 100644
--- a/lib/stdlib/test/dets_SUITE.erl
+++ b/lib/stdlib/test/dets_SUITE.erl
@@ -34,6 +34,8 @@
-define(datadir(Conf), ?config(data_dir, Conf)).
-endif.
+-compile(r13). % OTP-9607
+
-export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1,
init_per_group/2,end_per_group/2,
not_run/1, newly_started/1, basic_v8/1, basic_v9/1,
@@ -53,7 +55,7 @@
simultaneous_open/1, insert_new/1, repair_continuation/1,
otp_5487/1, otp_6206/1, otp_6359/1, otp_4738/1, otp_7146/1,
otp_8070/1, otp_8856/1, otp_8898/1, otp_8899/1, otp_8903/1,
- otp_8923/1, otp_9282/1]).
+ otp_8923/1, otp_9282/1, otp_9607/1]).
-export([dets_dirty_loop/0]).
@@ -112,7 +114,7 @@ all() ->
many_clients, otp_4906, otp_5402, simultaneous_open,
insert_new, repair_continuation, otp_5487, otp_6206,
otp_6359, otp_4738, otp_7146, otp_8070, otp_8856, otp_8898,
- otp_8899, otp_8903, otp_8923, otp_9282]
+ otp_8899, otp_8903, otp_8923, otp_9282, otp_9607]
end.
groups() ->
@@ -554,7 +556,11 @@ dets_dirty_loop() ->
{From, [write, Name, Value]} ->
Ret = dets:insert(Name, Value),
From ! {self(), Ret},
- dets_dirty_loop()
+ dets_dirty_loop();
+ {From, [close, Name]} ->
+ Ret = dets:close(Name),
+ From ! {self(), Ret},
+ dets_dirty_loop()
end.
@@ -1568,8 +1574,10 @@ repair(Config, V) ->
?line FileSize = dets:info(TabRef, memory),
?line ok = dets:close(TabRef),
crash(Fname, FileSize+20),
- ?line {error, {bad_freelists, Fname}} =
+ %% Used to return bad_freelists, but that changed in OTP-9622
+ ?line {ok, TabRef} =
dets:open_file(TabRef, [{file,Fname},{version,V}]),
+ ?line ok = dets:close(TabRef),
?line file:delete(Fname),
%% File not closed, opening with read and read_write access tried.
@@ -1857,10 +1865,10 @@ fixtable(Config, Version) when is_list(Config) ->
?line {ok, _} = dets:open_file(T, Args),
%% badarg
- ?line {'EXIT', {badarg, [{dets,safe_fixtable,[no_table,true]}|_]}} =
- (catch dets:safe_fixtable(no_table,true)),
- ?line {'EXIT', {badarg, [{dets,safe_fixtable,[T,undefined]}|_]}} =
- (catch dets:safe_fixtable(T,undefined)),
+ ?line check_badarg(catch dets:safe_fixtable(no_table,true),
+ dets, safe_fixtable, [no_table,true]),
+ ?line check_badarg(catch dets:safe_fixtable(T,undefined),
+ dets, safe_fixtable, [T,undefined]),
%% The table is not allowed to grow while the elements are inserted:
@@ -1940,22 +1948,22 @@ match(Config, Version) ->
%% match, badarg
MSpec = [{'_',[],['$_']}],
- ?line {'EXIT', {badarg, [{dets,safe_fixtable,[no_table,true]}|_]}} =
- (catch dets:match(no_table, '_')),
- ?line {'EXIT', {badarg, [{dets,match,[T,'_',not_a_number]}|_]}} =
- (catch dets:match(T, '_', not_a_number)),
+ ?line check_badarg(catch dets:match(no_table, '_'),
+ dets, safe_fixtable, [no_table,true]),
+ ?line check_badarg(catch dets:match(T, '_', not_a_number),
+ dets, match, [T,'_',not_a_number]),
?line {EC1, _} = dets:select(T, MSpec, 1),
- ?line {'EXIT', {badarg, [{dets,match,[EC1]}|_]}} =
- (catch dets:match(EC1)),
+ ?line check_badarg(catch dets:match(EC1),
+ dets, match, [EC1]),
%% match_object, badarg
- ?line {'EXIT', {badarg, [{dets,safe_fixtable,[no_table,true]}|_]}} =
- (catch dets:match_object(no_table, '_')),
- ?line {'EXIT', {badarg, [{dets,match_object,[T,'_',not_a_number]}|_]}} =
- (catch dets:match_object(T, '_', not_a_number)),
+ ?line check_badarg(catch dets:match_object(no_table, '_'),
+ dets, safe_fixtable, [no_table,true]),
+ ?line check_badarg(catch dets:match_object(T, '_', not_a_number),
+ dets, match_object, [T,'_',not_a_number]),
?line {EC2, _} = dets:select(T, MSpec, 1),
- ?line {'EXIT', {badarg, [{dets,match_object,[EC2]}|_]}} =
- (catch dets:match_object(EC2)),
+ ?line check_badarg(catch dets:match_object(EC2),
+ dets, match_object, [EC2]),
dets:safe_fixtable(T, true),
?line {[_, _], C1} = dets:match_object(T, '_', 2),
@@ -2118,17 +2126,17 @@ select(Config, Version) ->
%% badarg
MSpec = [{'_',[],['$_']}],
- ?line {'EXIT', {badarg, [{dets,safe_fixtable,[no_table,true]}|_]}} =
- (catch dets:select(no_table, MSpec)),
- ?line {'EXIT', {badarg, [{dets,select,[T,<<17>>]}|_]}} =
- (catch dets:select(T, <<17>>)),
- ?line {'EXIT', {badarg, [{dets,select,[T,[]]}|_]}} =
- (catch dets:select(T, [])),
- ?line {'EXIT', {badarg, [{dets,select,[T,MSpec,not_a_number]}|_]}} =
- (catch dets:select(T, MSpec, not_a_number)),
+ ?line check_badarg(catch dets:select(no_table, MSpec),
+ dets, safe_fixtable, [no_table,true]),
+ ?line check_badarg(catch dets:select(T, <<17>>),
+ dets, select, [T,<<17>>]),
+ ?line check_badarg(catch dets:select(T, []),
+ dets, select, [T,[]]),
+ ?line check_badarg(catch dets:select(T, MSpec, not_a_number),
+ dets, select, [T,MSpec,not_a_number]),
?line {EC, _} = dets:match(T, '_', 1),
- ?line {'EXIT', {badarg, [{dets,select,[EC]}|_]}} =
- (catch dets:select(EC)),
+ ?line check_badarg(catch dets:select(EC),
+ dets, select, [EC]),
AllSpec = [{'_',[],['$_']}],
@@ -2210,8 +2218,8 @@ update_counter(Config) when is_list(Config) ->
?line file:delete(Fname),
P0 = pps(),
- ?line {'EXIT', {badarg, [{dets,update_counter,[no_table,1,1]}|_]}} =
- (catch dets:update_counter(no_table, 1, 1)),
+ ?line check_badarg(catch dets:update_counter(no_table, 1, 1),
+ dets, update_counter, [no_table,1,1]),
Args = [{file,Fname},{keypos,2}],
?line {ok, _} = dets:open_file(T, [{type,set} | Args]),
@@ -2254,66 +2262,66 @@ badarg(Config) when is_list(Config) ->
%% badargs are tested in match, select and fixtable too.
%% open
- ?line {'EXIT', {badarg, [{dets,open_file,[{a,tuple},[]]}|_]}} =
- (catch dets:open_file({a,tuple},[])),
- ?line {'EXIT', {badarg, [{dets,open_file,[{a,tuple}]}|_]}} =
- (catch dets:open_file({a,tuple})),
- ?line {'EXIT', {badarg, [{dets,open_file,[file,[foo]]}|_]}} =
- (catch dets:open_file(file,[foo])),
- ?line {'EXIT', {badarg,[{dets,open_file,[{hej,san},[{type,set}|3]]}|_]}} =
- (catch dets:open_file({hej,san},[{type,set}|3])),
+ ?line check_badarg(catch dets:open_file({a,tuple},[]),
+ dets, open_file, [{a,tuple},[]]),
+ ?line check_badarg(catch dets:open_file({a,tuple}),
+ dets, open_file,[{a,tuple}]),
+ ?line check_badarg(catch dets:open_file(file,[foo]),
+ dets, open_file, [file,[foo]]),
+ ?line check_badarg(catch dets:open_file({hej,san},[{type,set}|3]),
+ dets, open_file, [{hej,san},[{type,set}|3]]),
%% insert
- ?line {'EXIT', {badarg, [{dets,insert,[no_table,{1,2}]}|_]}} =
- (catch dets:insert(no_table, {1,2})),
- ?line {'EXIT', {badarg, [{dets,insert,[no_table,[{1,2}]]}|_]}} =
- (catch dets:insert(no_table, [{1,2}])),
- ?line {'EXIT', {badarg, [{dets,insert,[T,{1,2}]}|_]}} =
- (catch dets:insert(T, {1,2})),
- ?line {'EXIT', {badarg, [{dets,insert,[T,[{1,2}]]}|_]}} =
- (catch dets:insert(T, [{1,2}])),
- ?line {'EXIT', {badarg, [{dets,insert,[T,[{1,2,3}|3]]}|_]}} =
- (catch dets:insert(T, [{1,2,3} | 3])),
+ ?line check_badarg(catch dets:insert(no_table, {1,2}),
+ dets, insert, [no_table,{1,2}]),
+ ?line check_badarg(catch dets:insert(no_table, [{1,2}]),
+ dets, insert, [no_table,[{1,2}]]),
+ ?line check_badarg(catch dets:insert(T, {1,2}),
+ dets, insert, [T,{1,2}]),
+ ?line check_badarg(catch dets:insert(T, [{1,2}]),
+ dets, insert, [T,[{1,2}]]),
+ ?line check_badarg(catch dets:insert(T, [{1,2,3} | 3]),
+ dets, insert, [T,[{1,2,3}|3]]),
%% lookup{_keys}
- ?line {'EXIT', {badarg, [{dets,lookup_keys,[badarg,[]]}|_]}} =
- (catch dets:lookup_keys(T, [])),
- ?line {'EXIT', {badarg, [{dets,lookup,[no_table,1]}|_]}} =
- (catch dets:lookup(no_table, 1)),
- ?line {'EXIT', {badarg, [{dets,lookup_keys,[T,[1|2]]}|_]}} =
- (catch dets:lookup_keys(T, [1 | 2])),
+ ?line check_badarg(catch dets:lookup_keys(T, []),
+ dets, lookup_keys, [badarg,[]]),
+ ?line check_badarg(catch dets:lookup(no_table, 1),
+ dets, lookup, [no_table,1]),
+ ?line check_badarg(catch dets:lookup_keys(T, [1 | 2]),
+ dets, lookup_keys, [T,[1|2]]),
%% member
- ?line {'EXIT', {badarg, [{dets,member,[no_table,1]}|_]}} =
- (catch dets:member(no_table, 1)),
+ ?line check_badarg(catch dets:member(no_table, 1),
+ dets, member, [no_table,1]),
%% sync
- ?line {'EXIT', {badarg, [{dets,sync,[no_table]}|_]}} =
- (catch dets:sync(no_table)),
+ ?line check_badarg(catch dets:sync(no_table),
+ dets, sync, [no_table]),
%% delete{_keys}
- ?line {'EXIT', {badarg, [{dets,delete,[no_table,1]}|_]}} =
- (catch dets:delete(no_table, 1)),
+ ?line check_badarg(catch dets:delete(no_table, 1),
+ dets, delete, [no_table,1]),
%% delete_object
- ?line {'EXIT', {badarg, [{dets,delete_object,[no_table,{1,2,3}]}|_]}} =
- (catch dets:delete_object(no_table, {1,2,3})),
- ?line {'EXIT', {badarg, [{dets,delete_object,[T,{1,2}]}|_]}} =
- (catch dets:delete_object(T, {1,2})),
- ?line {'EXIT', {badarg, [{dets,delete_object,[no_table,[{1,2,3}]]}|_]}} =
- (catch dets:delete_object(no_table, [{1,2,3}])),
- ?line {'EXIT', {badarg, [{dets,delete_object,[T,[{1,2}]]}|_]}} =
- (catch dets:delete_object(T, [{1,2}])),
- ?line {'EXIT', {badarg, [{dets,delete_object,[T,[{1,2,3}|3]]}|_]}} =
- (catch dets:delete_object(T, [{1,2,3} | 3])),
+ ?line check_badarg(catch dets:delete_object(no_table, {1,2,3}),
+ dets, delete_object, [no_table,{1,2,3}]),
+ ?line check_badarg(catch dets:delete_object(T, {1,2}),
+ dets, delete_object, [T,{1,2}]),
+ ?line check_badarg(catch dets:delete_object(no_table, [{1,2,3}]),
+ dets, delete_object, [no_table,[{1,2,3}]]),
+ ?line check_badarg(catch dets:delete_object(T, [{1,2}]),
+ dets, delete_object, [T,[{1,2}]]),
+ ?line check_badarg(catch dets:delete_object(T, [{1,2,3} | 3]),
+ dets, delete_object, [T,[{1,2,3}|3]]),
%% first,next,slot
- ?line {'EXIT', {badarg, [{dets,first,[no_table]}|_]}} =
- (catch dets:first(no_table)),
- ?line {'EXIT', {badarg, [{dets,next,[no_table,1]}|_]}} =
- (catch dets:next(no_table, 1)),
- ?line {'EXIT', {badarg, [{dets,slot,[no_table,0]}|_]}} =
- (catch dets:slot(no_table, 0)),
+ ?line check_badarg(catch dets:first(no_table),
+ dets, first, [no_table]),
+ ?line check_badarg(catch dets:next(no_table, 1),
+ dets, next, [no_table,1]),
+ ?line check_badarg(catch dets:slot(no_table, 0),
+ dets, slot, [no_table,0]),
%% info
?line undefined = dets:info(no_table),
@@ -2321,27 +2329,27 @@ badarg(Config) when is_list(Config) ->
?line undefined = dets:info(T, foo),
%% match_delete
- ?line {'EXIT', {badarg, [{dets,safe_fixtable,[no_table,true]}|_]}} =
- (catch dets:match_delete(no_table, '_')),
+ ?line check_badarg(catch dets:match_delete(no_table, '_'),
+ dets, safe_fixtable, [no_table,true]),
%% delete_all_objects
- ?line {'EXIT', {badarg, [{dets,delete_all_objects,[no_table]}|_]}} =
- (catch dets:delete_all_objects(no_table)),
+ ?line check_badarg(catch dets:delete_all_objects(no_table),
+ dets, delete_all_objects, [no_table]),
%% select_delete
MSpec = [{'_',[],['$_']}],
- ?line {'EXIT', {badarg, [{dets,safe_fixtable,[no_table,true]}|_]}} =
- (catch dets:select_delete(no_table, MSpec)),
- ?line {'EXIT', {badarg, [{dets,select_delete,[T, <<17>>]}|_]}} =
- (catch dets:select_delete(T, <<17>>)),
+ ?line check_badarg(catch dets:select_delete(no_table, MSpec),
+ dets, safe_fixtable, [no_table,true]),
+ ?line check_badarg(catch dets:select_delete(T, <<17>>),
+ dets, select_delete, [T, <<17>>]),
%% traverse, fold
- ?line {'EXIT', {badarg, [{dets,safe_fixtable,[no_table,true]}|_]}} =
- (catch dets:traverse(no_table, fun(_) -> continue end)),
- ?line {'EXIT', {badarg, [{dets,safe_fixtable,[no_table,true]}|_]}} =
- (catch dets:foldl(fun(_, A) -> A end, [], no_table)),
- ?line {'EXIT', {badarg, [{dets,safe_fixtable,[no_table,true]}|_]}} =
- (catch dets:foldr(fun(_, A) -> A end, [], no_table)),
+ ?line check_badarg(catch dets:traverse(no_table, fun(_) -> continue end),
+ dets, safe_fixtable, [no_table,true]),
+ ?line check_badarg(catch dets:foldl(fun(_, A) -> A end, [], no_table),
+ dets, safe_fixtable, [no_table,true]),
+ ?line check_badarg(catch dets:foldr(fun(_, A) -> A end, [], no_table),
+ dets, safe_fixtable, [no_table,true]),
%% close
?line ok = dets:close(T),
@@ -2349,15 +2357,16 @@ badarg(Config) when is_list(Config) ->
?line {error, not_owner} = dets:close(T),
%% init_table
- ?line {'EXIT', {badarg,[{dets,init_table,[no_table,_,[]]}|_]}} =
- (catch dets:init_table(no_table, fun(X) -> X end)),
- ?line {'EXIT', {badarg,[{dets,init_table,[no_table,_,[]]}|_]}} =
- (catch dets:init_table(no_table, fun(X) -> X end, [])),
+ IF = fun(X) -> X end,
+ ?line check_badarg(catch dets:init_table(no_table, IF),
+ dets, init_table, [no_table,IF,[]]),
+ ?line check_badarg(catch dets:init_table(no_table, IF, []),
+ dets, init_table, [no_table,IF,[]]),
%% from_ets
Ets = ets:new(ets,[]),
- ?line {'EXIT', {badarg,[{dets,from_ets,[no_table,_]}|_]}} =
- (catch dets:from_ets(no_table, Ets)),
+ ?line check_badarg(catch dets:from_ets(no_table, Ets),
+ dets, from_ets, [no_table,Ets]),
ets:delete(Ets),
?line {ok, T} = dets:open_file(T, Args),
@@ -3879,10 +3888,91 @@ some_calls(Tab, Config) ->
?line ok = dets:close(T),
file:delete(File).
+otp_9607(doc) ->
+ ["OTP-9607. Test downgrading the slightly changed format."];
+otp_9607(suite) ->
+ [];
+otp_9607(Config) when is_list(Config) ->
+ %% Note: the bug is about almost full tables. The fix of that
+ %% problem is *not* tested here.
+ Version = r13b,
+ case ?t:is_release_available(atom_to_list(Version)) of
+ true ->
+ T = otp_9607,
+ File = filename(T, Config),
+ Key = a,
+ Value = 1,
+ Args = [{file,File}],
+ ?line {ok, T} = dets:open_file(T, Args),
+ ?line ok = dets:insert(T, {Key, Value}),
+ ?line ok = dets:close(T),
+
+ ?line Call = fun(P, A) ->
+ P ! {self(), A},
+ receive
+ {P, Ans} ->
+ Ans
+ after 5000 ->
+ exit(other_process_dead)
+ end
+ end,
+ %% Create a file on the modified format, read the file
+ %% with an emulator that doesn't know about the modified
+ %% format.
+ ?line {ok, Node} = start_node_rel(Version, Version, slave),
+ ?line Pid = rpc:call(Node, erlang, spawn,
+ [?MODULE, dets_dirty_loop, []]),
+ ?line {error,{needs_repair, File}} =
+ Call(Pid, [open, T, Args++[{repair,false}]]),
+ io:format("Expect repair:~n"),
+ ?line {ok, T} = Call(Pid, [open, T, Args]),
+ ?line [{Key,Value}] = Call(Pid, [read, T, Key]),
+ ?line ok = Call(Pid, [close, T]),
+ file:delete(File),
+
+ %% Create a file on the unmodified format. Modify the file
+ %% using an emulator that must not turn the file into the
+ %% modified format. Read the file and make sure it is not
+ %% repaired.
+ ?line {ok, T} = Call(Pid, [open, T, Args]),
+ ?line ok = Call(Pid, [write, T, {Key,Value}]),
+ ?line [{Key,Value}] = Call(Pid, [read, T, Key]),
+ ?line ok = Call(Pid, [close, T]),
+
+ Key2 = b,
+ Value2 = 2,
+
+ ?line {ok, T} = dets:open_file(T, Args),
+ ?line [{Key,Value}] = dets:lookup(T, Key),
+ ?line ok = dets:insert(T, {Key2,Value2}),
+ ?line ok = dets:close(T),
+
+ ?line {ok, T} = Call(Pid, [open, T, Args++[{repair,false}]]),
+ ?line [{Key2,Value2}] = Call(Pid, [read, T, Key2]),
+ ?line ok = Call(Pid, [close, T]),
+
+ ?t:stop_node(Node),
+ file:delete(File),
+ ok;
+ false ->
+ {skipped, "No support for old node"}
+ end.
+
+
+
%%
%% Parts common to several test cases
%%
+start_node_rel(Name, Rel, How) ->
+ Release = [{release, atom_to_list(Rel)}],
+ ?line Pa = filename:dirname(code:which(?MODULE)),
+ ?line test_server:start_node(Name, How,
+ [{args,
+ " -kernel net_setuptime 100 "
+ " -pa " ++ Pa},
+ {erl, Release}]).
+
crash(File, Where) ->
crash(File, Where, 10).
@@ -4268,6 +4358,11 @@ bad_object({error,{{bad_object,_}, FileName}}, FileName) ->
bad_object({error,{{{bad_object,_,_},_,_,_}, FileName}}, FileName) ->
ok. % Debug.
+check_badarg({'EXIT', {badarg, [{M,F,Args,_} | _]}}, M, F, Args) ->
+ true;
+check_badarg({'EXIT', {badarg, [{M,F,A,_} | _]}}, M, F, Args) ->
+ true = test_server:is_native(M) andalso length(Args) =:= A.
+
check_pps(P0) ->
case pps() of
P0 ->
diff --git a/lib/stdlib/test/epp_SUITE.erl b/lib/stdlib/test/epp_SUITE.erl
index 57f3f4eddb..f79414db49 100644
--- a/lib/stdlib/test/epp_SUITE.erl
+++ b/lib/stdlib/test/epp_SUITE.erl
@@ -20,7 +20,7 @@
-export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1,
init_per_group/2,end_per_group/2]).
--export([rec_1/1, predef_mac/1,
+-export([rec_1/1, include_local/1, predef_mac/1,
upcase_mac_1/1, upcase_mac_2/1,
variable_1/1, otp_4870/1, otp_4871/1, otp_5362/1,
pmod/1, not_circular/1, skip_header/1, otp_6277/1, otp_7702/1,
@@ -63,7 +63,7 @@ end_per_testcase(_, Config) ->
suite() -> [{ct_hooks,[ts_install_cth]}].
all() ->
- [rec_1, {group, upcase_mac}, predef_mac,
+ [rec_1, {group, upcase_mac}, include_local, predef_mac,
{group, variable}, otp_4870, otp_4871, otp_5362, pmod,
not_circular, skip_header, otp_6277, otp_7702, otp_8130,
overload_mac, otp_8388, otp_8470, otp_8503, otp_8562,
@@ -97,6 +97,22 @@ rec_1(Config) when is_list(Config) ->
?line check_errors(List),
ok.
+include_local(doc) ->
+ [];
+include_local(suite) ->
+ [];
+include_local(Config) when is_list(Config) ->
+ ?line DataDir = ?config(data_dir, Config),
+ ?line File = filename:join(DataDir, "include_local.erl"),
+ %% include_local.erl includes include/foo.hrl which
+ %% includes bar.hrl (also in include/) without requiring
+ %% any additional include path, and overriding any file
+ %% of the same name that the path points to
+ ?line {ok, List} = epp:parse_file(File, [DataDir], []),
+ ?line {value, {attribute,_,a,{true,true}}} =
+ lists:keysearch(a,3,List),
+ ok.
+
%%% Here is a little reimplementation of epp:parse_file, which times out
%%% after 4 seconds if the epp server doesn't respond. If we use the
%%% regular epp:parse_file, the test case will time out, and then epp
@@ -234,16 +250,23 @@ otp_4871(Config) when is_list(Config) ->
%% so there are some sanity checks before killing.
?line {ok,Epp} = epp:open(File, []),
timer:sleep(1),
- ?line {current_function,{epp,_,_}} = process_info(Epp, current_function),
+ ?line true = current_module(Epp, epp),
?line {monitored_by,[Io]} = process_info(Epp, monitored_by),
- ?line {current_function,{file_io_server,_,_}} =
- process_info(Io, current_function),
+ ?line true = current_module(Io, file_io_server),
?line exit(Io, emulate_crash),
timer:sleep(1),
?line {error,{_Line,epp,cannot_parse}} = otp_4871_parse_file(Epp),
?line epp:close(Epp),
ok.
+current_module(Pid, Mod) ->
+ case process_info(Pid, current_function) of
+ {current_function, undefined} ->
+ true = test_server:is_native(Mod);
+ {current_function, {Mod, _, _}} ->
+ true
+ end.
+
otp_4871_parse_file(Epp) ->
case epp:parse_erl_form(Epp) of
{ok,_} -> otp_4871_parse_file(Epp);
diff --git a/lib/stdlib/test/epp_SUITE_data/bar.hrl b/lib/stdlib/test/epp_SUITE_data/bar.hrl
new file mode 100644
index 0000000000..01c527d549
--- /dev/null
+++ b/lib/stdlib/test/epp_SUITE_data/bar.hrl
@@ -0,0 +1,4 @@
+%% should not be included from include/foo.hrl even though the
+%% include path points here - include/bar.hrl overrides it
+
+-define(BAR_HRL, false).
diff --git a/lib/stdlib/test/epp_SUITE_data/include/bar.hrl b/lib/stdlib/test/epp_SUITE_data/include/bar.hrl
new file mode 100644
index 0000000000..038d3c900e
--- /dev/null
+++ b/lib/stdlib/test/epp_SUITE_data/include/bar.hrl
@@ -0,0 +1,3 @@
+%% included from foo.hrl in same directory
+
+-define(BAR_HRL, true).
diff --git a/lib/stdlib/test/epp_SUITE_data/include/foo.hrl b/lib/stdlib/test/epp_SUITE_data/include/foo.hrl
new file mode 100644
index 0000000000..a6dfa3d18a
--- /dev/null
+++ b/lib/stdlib/test/epp_SUITE_data/include/foo.hrl
@@ -0,0 +1,4 @@
+%% includes bar.hrl in same directory
+
+-define(FOO_HRL, true).
+-include("bar.hrl").
diff --git a/lib/stdlib/test/epp_SUITE_data/include_local.erl b/lib/stdlib/test/epp_SUITE_data/include_local.erl
new file mode 100644
index 0000000000..c8e155a064
--- /dev/null
+++ b/lib/stdlib/test/epp_SUITE_data/include_local.erl
@@ -0,0 +1,6 @@
+
+-module(include_local).
+
+-include("include/foo.hrl").
+
+-a({?FOO_HRL, ?BAR_HRL}).
diff --git a/lib/stdlib/test/erl_eval_SUITE.erl b/lib/stdlib/test/erl_eval_SUITE.erl
index 784c7cb86e..369d8b224e 100644
--- a/lib/stdlib/test/erl_eval_SUITE.erl
+++ b/lib/stdlib/test/erl_eval_SUITE.erl
@@ -1036,6 +1036,12 @@ funs(Config) when is_list(Config) ->
lists:usort([run_many_args(SAs) || SAs <- many_args(MaxArgs)]),
?line {'EXIT',{{argument_limit,_},_}} =
(catch run_many_args(many_args1(MaxArgs+1))),
+
+ ?line check(fun() -> M = lists, F = fun M:reverse/1,
+ [1,2] = F([2,1]), ok end,
+ "begin M = lists, F = fun M:reverse/1,"
+ " [1,2] = F([2,1]), ok end.",
+ ok),
ok.
run_many_args({S, As}) ->
diff --git a/lib/stdlib/test/erl_pp_SUITE.erl b/lib/stdlib/test/erl_pp_SUITE.erl
index 280c95b1aa..64853ca078 100644
--- a/lib/stdlib/test/erl_pp_SUITE.erl
+++ b/lib/stdlib/test/erl_pp_SUITE.erl
@@ -116,7 +116,6 @@ func(Config) when is_list(Config) ->
{func_3,
<<"t() -> fun t/0.">>},
{func_4,
- %% Has already been expanded away in sys_pre_expand.
<<"t() -> fun modul:foo/3.">>},
{func_5, % 'when' is moved down one line
<<"tkjlksjflksdjflsdjlk()
@@ -127,7 +126,9 @@ func(Config) when is_list(Config) ->
<<"t() ->
(fun() ->
true
- end)().">>}
+ end)().">>},
+ {func_7,
+ <<"t(M, F, A) -> fun M:F/A.">>}
],
?line compile(Config, Ts),
ok.
diff --git a/lib/stdlib/test/ets_SUITE.erl b/lib/stdlib/test/ets_SUITE.erl
index e2f22cfbc9..0e8849b5b3 100644
--- a/lib/stdlib/test/ets_SUITE.erl
+++ b/lib/stdlib/test/ets_SUITE.erl
@@ -794,21 +794,26 @@ t_ets_dets(Config, Opts) ->
?line true = ets:from_dets(ETab,DTab),
?line 3000 = ets:info(ETab,size),
?line ets:delete(ETab),
- ?line {'EXIT',{badarg,[{ets,to_dets,[ETab,DTab]}|_]}} =
- (catch ets:to_dets(ETab,DTab)),
- ?line {'EXIT',{badarg,[{ets,from_dets,[ETab,DTab]}|_]}} =
- (catch ets:from_dets(ETab,DTab)),
+ ?line check_badarg(catch ets:to_dets(ETab,DTab),
+ ets, to_dets, [ETab,DTab]),
+ ?line check_badarg(catch ets:from_dets(ETab,DTab),
+ ets, from_dets, [ETab,DTab]),
?line ETab2 = ets_new(x,Opts),
?line filltabint(ETab2,3000),
?line dets:close(DTab),
- ?line {'EXIT',{badarg,[{ets,to_dets,[ETab2,DTab]}|_]}} =
- (catch ets:to_dets(ETab2,DTab)),
- ?line {'EXIT',{badarg,[{ets,from_dets,[ETab2,DTab]}|_]}} =
- (catch ets:from_dets(ETab2,DTab)),
+ ?line check_badarg(catch ets:to_dets(ETab2,DTab),
+ ets, to_dets, [ETab2,DTab]),
+ ?line check_badarg(catch ets:from_dets(ETab2,DTab),
+ ets, from_dets, [ETab2,DTab]),
?line ets:delete(ETab2),
?line (catch file:delete(Fname)),
ok.
+check_badarg({'EXIT', {badarg, [{M,F,Args,_} | _]}}, M, F, Args) ->
+ true;
+check_badarg({'EXIT', {badarg, [{M,F,A,_} | _]}}, M, F, Args) ->
+ true = test_server:is_native(M) andalso length(Args) =:= A.
+
t_delete_all_objects(doc) ->
["Test ets:delete_all_objects/1"];
t_delete_all_objects(suite) ->
@@ -2649,7 +2654,7 @@ maybe_sort(L) when is_list(L) ->
%maybe_sort({'EXIT',{Reason, [{Module, Function, _}|_]}}) ->
% {'EXIT',{Reason, [{Module, Function, '_'}]}};
maybe_sort({'EXIT',{Reason, List}}) when is_list(List) ->
- {'EXIT',{Reason, lists:map(fun({Module, Function, _}) ->
+ {'EXIT',{Reason, lists:map(fun({Module, Function, _, _}) ->
{Module, Function, '_'}
end,
List)}};
diff --git a/lib/stdlib/test/filelib_SUITE.erl b/lib/stdlib/test/filelib_SUITE.erl
index 3010f5e760..1de639a166 100644
--- a/lib/stdlib/test/filelib_SUITE.erl
+++ b/lib/stdlib/test/filelib_SUITE.erl
@@ -97,11 +97,12 @@ wildcard_errors(Config) when is_list(Config) ->
wcc(Wc, Error) ->
{'EXIT',{{badpattern,Error},
- [{filelib,compile_wildcard,1}|_]}} = (catch filelib:compile_wildcard(Wc)),
+ [{filelib,compile_wildcard,1,_}|_]}} =
+ (catch filelib:compile_wildcard(Wc)),
{'EXIT',{{badpattern,Error},
- [{filelib,wildcard,1}|_]}} = (catch filelib:wildcard(Wc)),
+ [{filelib,wildcard,1,_}|_]}} = (catch filelib:wildcard(Wc)),
{'EXIT',{{badpattern,Error},
- [{filelib,wildcard,2}|_]}} = (catch filelib:wildcard(Wc, ".")).
+ [{filelib,wildcard,2,_}|_]}} = (catch filelib:wildcard(Wc, ".")).
do_wildcard_1(Dir, Wcf0) ->
do_wildcard_2(Dir, Wcf0),
diff --git a/lib/stdlib/test/filename_SUITE.erl b/lib/stdlib/test/filename_SUITE.erl
index 70b0d413dc..4cfa589660 100644
--- a/lib/stdlib/test/filename_SUITE.erl
+++ b/lib/stdlib/test/filename_SUITE.erl
@@ -483,6 +483,22 @@ find_src(Config) when is_list(Config) ->
%% Try to find the source for a preloaded module.
?line {error,{preloaded,init}} = filename:find_src(init),
+
+ %% Make sure that find_src works for a slim BEAM file.
+ OldPath = code:get_path(),
+ try
+ PrivDir = ?config(priv_dir, Config),
+ code:add_patha(PrivDir),
+ Src = "simple",
+ SrcPath = filename:join(PrivDir, Src) ++ ".erl",
+ SrcContents = "-module(simple).\n",
+ ok = file:write_file(SrcPath, SrcContents),
+ {ok,simple} = compile:file(SrcPath, [slim,{outdir,PrivDir}]),
+ BeamPath = filename:join(PrivDir, Src),
+ {BeamPath,[]} = filename:find_src(simple)
+ after
+ code:set_path(OldPath)
+ end,
ok.
%%
diff --git a/lib/stdlib/test/gen_server_SUITE.erl b/lib/stdlib/test/gen_server_SUITE.erl
index a614d6595d..7fb8d54f2d 100644
--- a/lib/stdlib/test/gen_server_SUITE.erl
+++ b/lib/stdlib/test/gen_server_SUITE.erl
@@ -694,7 +694,7 @@ multicall_down(Config) when is_list(Config) ->
%% We use 'global' as a gen_server to call.
?line {Good, Bad} = gen_server:multi_call([Name, node()],
global_name_server,
- {whereis, gurkburk},
+ info,
3000),
io:format("good = ~p, bad = ~p~n", [Good, Bad]),
?line [Name] = Bad,
diff --git a/lib/stdlib/test/ms_transform_SUITE.erl b/lib/stdlib/test/ms_transform_SUITE.erl
index 4e5df12798..c9688354b1 100644
--- a/lib/stdlib/test/ms_transform_SUITE.erl
+++ b/lib/stdlib/test/ms_transform_SUITE.erl
@@ -39,6 +39,7 @@
-export([float_1_function/1]).
-export([action_function/1]).
-export([warnings/1]).
+-export([no_warnings/1]).
-export([init_per_testcase/2, end_per_testcase/2]).
init_per_testcase(_Func, Config) ->
@@ -55,7 +56,7 @@ all() ->
[from_shell, basic_ets, basic_dbg, records,
record_index, multipass, bitsyntax, record_defaults,
andalso_orelse, float_1_function, action_function,
- warnings, top_match, old_guards, autoimported,
+ warnings, no_warnings, top_match, old_guards, autoimported,
semicolon].
groups() ->
@@ -155,6 +156,34 @@ warnings(Config) when is_list(Config) ->
compile_ww(Prog7),
ok.
+no_warnings(suite) ->
+ [];
+no_warnings(doc) ->
+ ["Check that variables bound in other function clauses don't generate "
+ "warning"];
+no_warnings(Config) when is_list(Config) ->
+ ?line setup(Config),
+ Prog = <<"tmp(X) when X > 100 ->\n",
+ " Y=X,\n"
+ " Y;\n"
+ "tmp(X) ->\n"
+ " ets:fun2ms(fun(Y) ->\n"
+ " {X, 3*Y}\n"
+ " end)">>,
+ ?line [] = compile_no_ww(Prog),
+
+ Prog2 = <<"tmp(X) when X > 100 ->\n",
+ " Y=X,\n"
+ " Y;\n"
+ "tmp(X) when X < 200 ->\n"
+ " ok;\n"
+ "tmp(X) ->\n"
+ " ets:fun2ms(fun(Y) ->\n"
+ " {X, 3*Y}\n"
+ " end)">>,
+ ?line [] = compile_no_ww(Prog2),
+ ok.
+
andalso_orelse(suite) ->
[];
andalso_orelse(doc) ->
@@ -842,6 +871,20 @@ compile_ww(Records,Expr) ->
nowarn_unused_record]),
Wlist.
+compile_no_ww(Expr) ->
+ Prog = <<
+ "-module(tmp).\n",
+ "-include_lib(\"stdlib/include/ms_transform.hrl\").\n",
+ "-export([tmp/1]).\n\n",
+ Expr/binary,".\n">>,
+ FN=temp_name(),
+ file:write_file(FN,Prog),
+ {ok,Forms} = epp:parse_file(FN,"",""),
+ {ok,tmp,_Bin,Wlist} = compile:forms(Forms,[return_warnings,
+ nowarn_unused_vars,
+ nowarn_unused_record]),
+ Wlist.
+
do_eval(String) ->
{done,{ok,T,_},[]} = erl_scan:tokens(
[],
diff --git a/lib/stdlib/test/proc_lib_SUITE.erl b/lib/stdlib/test/proc_lib_SUITE.erl
index 1565aa9bba..c95089117c 100644
--- a/lib/stdlib/test/proc_lib_SUITE.erl
+++ b/lib/stdlib/test/proc_lib_SUITE.erl
@@ -328,7 +328,7 @@ otp_6345(doc) ->
["'monitor' spawn_opt option"];
otp_6345(Config) when is_list(Config) ->
Opts = [link,monitor],
- {'EXIT', {badarg,[{proc_lib,check_for_monitor,_}|_Stack]}} =
+ {'EXIT', {badarg,[{proc_lib,check_for_monitor,_,_}|_Stack]}} =
(catch proc_lib:start(?MODULE, otp_6345_init, [self()],
1000, Opts)),
ok.
diff --git a/lib/stdlib/test/qlc_SUITE.erl b/lib/stdlib/test/qlc_SUITE.erl
index 98eeaee118..50a76cdfb5 100644
--- a/lib/stdlib/test/qlc_SUITE.erl
+++ b/lib/stdlib/test/qlc_SUITE.erl
@@ -20,7 +20,6 @@
%%% Purpose:Test Suite for the 'qlc' module.
%%%-----------------------------------------------------------------
-module(qlc_SUITE).
--compile(r12).
-define(QLC, qlc).
-define(QLCs, "qlc").
@@ -6118,6 +6117,7 @@ otp_6964(Config) when is_list(Config) ->
qlc:e(Q, [{max_list_size,64*1024},{tmpdir_usage,Use}])
end,
D = erlang:system_flag(backtrace_depth, 0),
+ try
20000 = length(F(allowed)),
ErrReply = F(not_allowed),
{error, qlc, {tmpdir_usage,joining}} = ErrReply,
@@ -6129,8 +6129,10 @@ otp_6964(Config) when is_list(Config) ->
20000 = length(F(info_msg)),
{info, joining} = qlc_SUITE:read_error_logger(),
20000 = length(F(error_msg)),
- {error, joining} = qlc_SUITE:read_error_logger(),
- _ = erlang:system_flag(backtrace_depth, D),
+ {error, joining} = qlc_SUITE:read_error_logger()
+ after
+ _ = erlang:system_flag(backtrace_depth, D)
+ end,
qlc_SUITE:uninstall_error_logger()">>],
?line run(Config, T1),
@@ -6632,7 +6634,7 @@ otp_7232(Config) when is_list(Config) ->
{call,_,
{remote,_,{atom,_,qlc},{atom,_,sort}},
[{cons,_,
- {'fun',_,{function,math,sqrt,_}},
+ {'fun',_,{function,{atom,_,math},{atom,_,sqrt},_}},
{cons,_,
{string,_,\"<0.4.1>\"}, % could use list_to_pid..
{cons,_,{string,_,\"#Ref<\"++_},{nil,_}}}},
@@ -7399,70 +7401,37 @@ backward(doc) ->
"OTP-6674. Join info and extra constants.";
backward(suite) -> [];
backward(Config) when is_list(Config) ->
- case try_old_join_info(Config) of
- ok ->
- ok;
- Reply ->
- Reply
- end.
-
--ifdef(debug).
-try_old_join_info(_Config) ->
+ try_old_join_info(Config),
ok.
--else.
+
try_old_join_info(Config) ->
- case ?t:is_release_available("r12b") of
- true ->
- %% Check join info for handlers of extra constants. Start R12B-0.
- ?line {ok, R12} = start_node_rel(r12, r12b, slave),
- File = filename("handle.erl", Config),
- ?line file:write_file(File,
- <<"-module(handle).\n"
- "-export([create_handle/0, lookup_handle/0]).\n"
- "-include_lib(\"stdlib/include/qlc.hrl\").\n"
- "create_handle() ->\n"
- " H1 = qlc:sort([{192.0,1,a},{192.0,2,b},{192.0,3,c}]),\n"
- " qlc:q([{X, Y} || {B,X,_} <- H1,\n"
- " B =:= 192.0,\n"
- " {Y} <- [{0},{1},{2}],\n"
- " X == Y]).\n",
- "\n",
- "lookup_handle() ->\n"
- " E = qlc_SUITE:table([{1,a},{2,b},{3,c}], 1, [1]),\n"
- " qlc:q([{X, Y} || {X,_} <- E,\n"
- " {Y} <- [{0},{1},{2}],\n"
- " X =:= Y]).\n">>),
- ?line {ok, handle} = rpc:call(R12, compile, file,
- [File, [{outdir,?privdir}]]),
- ?line {module, handle} = rpc:call(R12, code, load_abs,
- [filename:rootname(File)]),
- ?line H = rpc:call(R12, handle, create_handle, []),
- ?line {module, handle} = code:load_abs(filename:rootname(File)),
- ?line {block,0,
- [{match,_,_,
- {call,_,_,
- [{lc,_,_,
- [_,
- {op,_,'=:=',
- {float,_,192.0},
- {call,_,{atom,_,element},[{integer,_,1},_]}}]}]}},
- _,_,
- {call,_,_,
- [{lc,_,_,
- [_,
- {op,_,'=:=',{var,_,'B'},{float,_,192.0}},
- {op,_,'==',{var,_,'X'},{var,_,'Y'}}]}]}]}
- = qlc:info(H,{format,abstract_code}),
- ?line [{1,1},{2,2}] = qlc:e(H),
- ?line H2 = rpc:call(R12, handle, lookup_handle, []),
- ?line {qlc,_,[{generate,_,{qlc,_,_,[{join,lookup}]}},_],[]} =
- qlc:info(H2, {format,debug}),
- ?line [{1,1},{2,2}] = qlc:e(H2),
- stop_node(R12);
- false ->
- ?line {skipped, "No support for old node"}
- end.
--endif.
+ %% Check join info for handlers of extra constants.
+ File = filename:join(?datadir, "join_info_compat.erl"),
+ M = join_info_compat,
+ {ok, M} = compile:file(File, [{outdir, ?datadir}]),
+ {module, M} = code:load_abs(filename:rootname(File)),
+ H = M:create_handle(),
+ {block,0,
+ [{match,_,_,
+ {call,_,_,
+ [{lc,_,_,
+ [_,
+ {op,_,'=:=',
+ {float,_,192.0},
+ {call,_,{atom,_,element},[{integer,_,1},_]}}]}]}},
+ _,_,
+ {call,_,_,
+ [{lc,_,_,
+ [_,
+ {op,_,'=:=',{var,_,'B'},{float,_,192.0}},
+ {op,_,'==',{var,_,'X'},{var,_,'Y'}}]}]}]}
+ = qlc:info(H,{format,abstract_code}),
+ [{1,1},{2,2}] = qlc:e(H),
+
+ H2 = M:lookup_handle(),
+ {qlc,_,[{generate,_,{qlc,_,_,[{join,lookup}]}},_],[]} =
+ qlc:info(H2, {format,debug}),
+ [{1,1},{2,2}] = qlc:e(H2).
forward(doc) ->
"";
@@ -8127,27 +8096,6 @@ fail(Source) ->
%% Copied from global_SUITE.erl.
-start_node_rel(Name, Rel, How) ->
- {Release, Compat} = case Rel of
- this ->
- {[this], "+R8"};
- Rel when is_atom(Rel) ->
- {[{release, atom_to_list(Rel)}], ""};
- RelList ->
- {RelList, ""}
- end,
- ?line Pa = filename:dirname(code:which(?MODULE)),
- ?line Res = test_server:start_node(Name, How,
- [{args,
- Compat ++
- " -kernel net_setuptime 100 "
- " -pa " ++ Pa},
- {erl, Release}]),
- Res.
-
-stop_node(Node) ->
- ?line ?t:stop_node(Node).
-
install_error_logger() ->
error_logger:add_report_handler(?MODULE, self()).
diff --git a/lib/stdlib/test/qlc_SUITE_data/join_info_compat.erl b/lib/stdlib/test/qlc_SUITE_data/join_info_compat.erl
new file mode 100644
index 0000000000..e0db132c47
--- /dev/null
+++ b/lib/stdlib/test/qlc_SUITE_data/join_info_compat.erl
@@ -0,0 +1,1771 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2008-2011. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+-module(join_info_compat).
+
+-compile(export_all).
+
+create_handle() ->
+ H1 = qlc:sort([{192.0,1,a},{192.0,2,b},{192.0,3,c}]),
+ qlc:q({qlc_lc,
+ % fun-info: {23,109048965,'-create_handle/0-fun-23-'}
+ fun() ->
+ {qlc_v1,
+ % fun-info: {2,105724313,'-create_handle/0-fun-2-'}
+ fun(S01_0_1, RL01_0_1, Go01_0_1) ->
+ Fun1_0_1 =
+ % fun-info: {1,131900588,'-create_handle/0-fun-1-'}
+ fun(0, RL1_0_1, _, _, _, _, _, _, _)
+ when is_list(RL1_0_1) ->
+ lists:reverse(RL1_0_1);
+ (0, _, _, _, _, _, _, _, _) ->
+ [];
+ (1,
+ RL1_0_1,
+ Fun1_0_1,
+ Go1_0_1,
+ C1_3_1,
+ Y1,
+ C1_1_1,
+ B1,
+ X1)
+ when is_list(RL1_0_1) ->
+ Fun1_0_1(element(1, Go1_0_1),
+ [{X1,Y1}|RL1_0_1],
+ Fun1_0_1,
+ Go1_0_1,
+ C1_3_1,
+ Y1,
+ C1_1_1,
+ B1,
+ X1);
+ (1,
+ RL1_0_1,
+ Fun1_0_1,
+ Go1_0_1,
+ C1_3_1,
+ Y1,
+ C1_1_1,
+ B1,
+ X1) ->
+ [{X1,Y1}|
+ % fun-info: {0,27702789,'-create_handle/0-fun-0-'}
+ fun() ->
+ Fun1_0_1(element(1,
+ Go1_0_1),
+ RL1_0_1,
+ Fun1_0_1,
+ Go1_0_1,
+ C1_3_1,
+ Y1,
+ C1_1_1,
+ B1,
+ X1)
+ end];
+ (2,
+ RL1_0_1,
+ Fun1_0_1,
+ Go1_0_1,
+ C1_3_1,
+ Y1,
+ _,
+ B1,
+ X1) ->
+ Fun1_0_1(3,
+ RL1_0_1,
+ Fun1_0_1,
+ Go1_0_1,
+ C1_3_1,
+ Y1,
+ element(4, Go1_0_1),
+ B1,
+ X1);
+ (3,
+ RL1_0_1,
+ Fun1_0_1,
+ Go1_0_1,
+ C1_3_1,
+ Y1,
+ [{B1,X1,_}|C1_0_1],
+ _,
+ _) ->
+ Fun1_0_1(element(3, Go1_0_1),
+ RL1_0_1,
+ Fun1_0_1,
+ Go1_0_1,
+ C1_3_1,
+ Y1,
+ C1_0_1,
+ B1,
+ X1);
+ (3,
+ RL1_0_1,
+ Fun1_0_1,
+ Go1_0_1,
+ C1_3_1,
+ Y1,
+ [_|C1_0_1],
+ _,
+ _) ->
+ Fun1_0_1(3,
+ RL1_0_1,
+ Fun1_0_1,
+ Go1_0_1,
+ C1_3_1,
+ Y1,
+ C1_0_1,
+ [],
+ []);
+ (3,
+ RL1_0_1,
+ Fun1_0_1,
+ Go1_0_1,
+ C1_3_1,
+ Y1,
+ [],
+ _,
+ _) ->
+ Fun1_0_1(element(2, Go1_0_1),
+ RL1_0_1,
+ Fun1_0_1,
+ Go1_0_1,
+ C1_3_1,
+ Y1,
+ [],
+ [],
+ []);
+ (3,
+ RL1_0_1,
+ Fun1_0_1,
+ Go1_0_1,
+ C1_3_1,
+ Y1,
+ C1_1_1,
+ _,
+ _) ->
+ case C1_1_1() of
+ [{B1,X1,_}|C1_0_1] ->
+ Fun1_0_1(element(3,
+ Go1_0_1),
+ RL1_0_1,
+ Fun1_0_1,
+ Go1_0_1,
+ C1_3_1,
+ Y1,
+ C1_0_1,
+ B1,
+ X1);
+ [_|C1_0_1] ->
+ Fun1_0_1(3,
+ RL1_0_1,
+ Fun1_0_1,
+ Go1_0_1,
+ C1_3_1,
+ Y1,
+ C1_0_1,
+ [],
+ []);
+ [] ->
+ Fun1_0_1(element(2,
+ Go1_0_1),
+ RL1_0_1,
+ Fun1_0_1,
+ Go1_0_1,
+ C1_3_1,
+ Y1,
+ [],
+ [],
+ []);
+ E1_0_1 ->
+ E1_0_1
+ end;
+ (4,
+ RL1_0_1,
+ Fun1_0_1,
+ Go1_0_1,
+ C1_3_1,
+ Y1,
+ C1_1_1,
+ B1,
+ X1) ->
+ if
+ B1 =:= 192.0 ->
+ Fun1_0_1(element(6,
+ Go1_0_1),
+ RL1_0_1,
+ Fun1_0_1,
+ Go1_0_1,
+ C1_3_1,
+ Y1,
+ C1_1_1,
+ B1,
+ X1);
+ true ->
+ Fun1_0_1(element(5,
+ Go1_0_1),
+ RL1_0_1,
+ Fun1_0_1,
+ Go1_0_1,
+ C1_3_1,
+ Y1,
+ C1_1_1,
+ B1,
+ X1)
+ end;
+ (5,
+ RL1_0_1,
+ Fun1_0_1,
+ Go1_0_1,
+ _,
+ Y1,
+ C1_1_1,
+ B1,
+ X1) ->
+ Fun1_0_1(6,
+ RL1_0_1,
+ Fun1_0_1,
+ Go1_0_1,
+ element(9, Go1_0_1),
+ Y1,
+ C1_1_1,
+ B1,
+ X1);
+ (6,
+ RL1_0_1,
+ Fun1_0_1,
+ Go1_0_1,
+ [{Y1}|C1_0_1],
+ _,
+ C1_1_1,
+ B1,
+ X1) ->
+ Fun1_0_1(element(8, Go1_0_1),
+ RL1_0_1,
+ Fun1_0_1,
+ Go1_0_1,
+ C1_0_1,
+ Y1,
+ C1_1_1,
+ B1,
+ X1);
+ (6,
+ RL1_0_1,
+ Fun1_0_1,
+ Go1_0_1,
+ [_|C1_0_1],
+ _,
+ C1_1_1,
+ B1,
+ X1) ->
+ Fun1_0_1(6,
+ RL1_0_1,
+ Fun1_0_1,
+ Go1_0_1,
+ C1_0_1,
+ [],
+ C1_1_1,
+ B1,
+ X1);
+ (6,
+ RL1_0_1,
+ Fun1_0_1,
+ Go1_0_1,
+ [],
+ _,
+ C1_1_1,
+ B1,
+ X1) ->
+ Fun1_0_1(element(7, Go1_0_1),
+ RL1_0_1,
+ Fun1_0_1,
+ Go1_0_1,
+ [],
+ [],
+ C1_1_1,
+ B1,
+ X1);
+ (6,
+ RL1_0_1,
+ Fun1_0_1,
+ Go1_0_1,
+ C1_3_1,
+ _,
+ C1_1_1,
+ B1,
+ X1) ->
+ case C1_3_1() of
+ [{Y1}|C1_0_1] ->
+ Fun1_0_1(element(8,
+ Go1_0_1),
+ RL1_0_1,
+ Fun1_0_1,
+ Go1_0_1,
+ C1_0_1,
+ Y1,
+ C1_1_1,
+ B1,
+ X1);
+ [_|C1_0_1] ->
+ Fun1_0_1(6,
+ RL1_0_1,
+ Fun1_0_1,
+ Go1_0_1,
+ C1_0_1,
+ [],
+ C1_1_1,
+ B1,
+ X1);
+ [] ->
+ Fun1_0_1(element(7,
+ Go1_0_1),
+ RL1_0_1,
+ Fun1_0_1,
+ Go1_0_1,
+ [],
+ [],
+ C1_1_1,
+ B1,
+ X1);
+ E1_0_1 ->
+ E1_0_1
+ end;
+ (7,
+ RL1_0_1,
+ Fun1_0_1,
+ Go1_0_1,
+ C1_3_1,
+ Y1,
+ C1_1_1,
+ B1,
+ X1) ->
+ if
+ X1 == Y1 ->
+ Fun1_0_1(element(11,
+ Go1_0_1),
+ RL1_0_1,
+ Fun1_0_1,
+ Go1_0_1,
+ C1_3_1,
+ Y1,
+ C1_1_1,
+ B1,
+ X1);
+ true ->
+ Fun1_0_1(element(10,
+ Go1_0_1),
+ RL1_0_1,
+ Fun1_0_1,
+ Go1_0_1,
+ C1_3_1,
+ Y1,
+ C1_1_1,
+ B1,
+ X1)
+ end;
+ (8,
+ RL1_0_1,
+ Fun1_0_1,
+ Go1_0_1,
+ C1_3_1,
+ Y1,
+ _,
+ B1,
+ X1) ->
+ Fun1_0_1(9,
+ RL1_0_1,
+ Fun1_0_1,
+ Go1_0_1,
+ C1_3_1,
+ Y1,
+ element(14, Go1_0_1),
+ B1,
+ X1);
+ (9,
+ RL1_0_1,
+ Fun1_0_1,
+ Go1_0_1,
+ C1_3_1,
+ _,
+ [[{B1,X1,_}|{Y1}]|C1_0_1],
+ _,
+ _) ->
+ Fun1_0_1(element(13, Go1_0_1),
+ RL1_0_1,
+ Fun1_0_1,
+ Go1_0_1,
+ C1_3_1,
+ Y1,
+ C1_0_1,
+ B1,
+ X1);
+ (9,
+ RL1_0_1,
+ Fun1_0_1,
+ Go1_0_1,
+ C1_3_1,
+ _,
+ [_|C1_0_1],
+ _,
+ _) ->
+ Fun1_0_1(9,
+ RL1_0_1,
+ Fun1_0_1,
+ Go1_0_1,
+ C1_3_1,
+ [],
+ C1_0_1,
+ [],
+ []);
+ (9,
+ RL1_0_1,
+ Fun1_0_1,
+ Go1_0_1,
+ C1_3_1,
+ _,
+ [],
+ _,
+ _) ->
+ Fun1_0_1(element(12, Go1_0_1),
+ RL1_0_1,
+ Fun1_0_1,
+ Go1_0_1,
+ C1_3_1,
+ [],
+ [],
+ [],
+ []);
+ (9,
+ RL1_0_1,
+ Fun1_0_1,
+ Go1_0_1,
+ C1_3_1,
+ _,
+ C1_1_1,
+ _,
+ _) ->
+ case C1_1_1() of
+ [[{B1,X1,_}|{Y1}]|C1_0_1] ->
+ Fun1_0_1(element(13,
+ Go1_0_1),
+ RL1_0_1,
+ Fun1_0_1,
+ Go1_0_1,
+ C1_3_1,
+ Y1,
+ C1_0_1,
+ B1,
+ X1);
+ [_|C1_0_1] ->
+ Fun1_0_1(9,
+ RL1_0_1,
+ Fun1_0_1,
+ Go1_0_1,
+ C1_3_1,
+ [],
+ C1_0_1,
+ [],
+ []);
+ [] ->
+ Fun1_0_1(element(12,
+ Go1_0_1),
+ RL1_0_1,
+ Fun1_0_1,
+ Go1_0_1,
+ C1_3_1,
+ [],
+ [],
+ [],
+ []);
+ E1_0_1 ->
+ E1_0_1
+ end
+ end,
+ Fun1_0_1(S01_0_1,
+ RL01_0_1,
+ Fun1_0_1,
+ Go01_0_1,
+ [],
+ [],
+ [],
+ [],
+ [])
+ end,
+ % fun-info: {3,41816426,'-create_handle/0-fun-3-'}
+ fun() ->
+ {<<$\203:8/integer-unit:1-unsigned-big,
+ $P:8/integer-unit:1-unsigned-big,
+ $\000:8/integer-unit:1-unsigned-big,
+ $\000:8/integer-unit:1-unsigned-big,
+ $\000:8/integer-unit:1-unsigned-big,
+ $.:8/integer-unit:1-unsigned-big,
+ $x:8/integer-unit:1-unsigned-big,
+ $\234:8/integer-unit:1-unsigned-big,
+ $�:8/integer-unit:1-unsigned-big,
+ $`:8/integer-unit:1-unsigned-big,
+ $N:8/integer-unit:1-unsigned-big,
+ $a:8/integer-unit:1-unsigned-big,
+ $`:8/integer-unit:1-unsigned-big,
+ $-:8/integer-unit:1-unsigned-big,
+ $):8/integer-unit:1-unsigned-big,
+ $-:8/integer-unit:1-unsigned-big,
+ $�:8/integer-unit:1-unsigned-big,
+ $I:8/integer-unit:1-unsigned-big,
+ $M:8/integer-unit:1-unsigned-big,
+ $�:8/integer-unit:1-unsigned-big,
+ $�:8/integer-unit:1-unsigned-big,
+ $a:8/integer-unit:1-unsigned-big,
+ $`:8/integer-unit:1-unsigned-big,
+ $`:8/integer-unit:1-unsigned-big,
+ $`:8/integer-unit:1-unsigned-big,
+ $�:8/integer-unit:1-unsigned-big,
+ $\000:8/integer-unit:1-unsigned-big,
+ $\n:8/integer-unit:1-unsigned-big,
+ $0:8/integer-unit:1-unsigned-big,
+ $\227:8/integer-unit:1-unsigned-big,
+ $%:8/integer-unit:1-unsigned-big,
+ $\026:8/integer-unit:1-unsigned-big,
+ $%:8/integer-unit:1-unsigned-big,
+ $r:8/integer-unit:1-unsigned-big,
+ $�:8/integer-unit:1-unsigned-big,
+ $0:8/integer-unit:1-unsigned-big,
+ $0:8/integer-unit:1-unsigned-big,
+ $F:8/integer-unit:1-unsigned-big,
+ $�:8/integer-unit:1-unsigned-big,
+ $�:8/integer-unit:1-unsigned-big,
+ $":8/integer-unit:1-unsigned-big,
+ $�:8/integer-unit:1-unsigned-big,
+ $\000:8/integer-unit:1-unsigned-big,
+ $�:8/integer-unit:1-unsigned-big,
+ $�:8/integer-unit:1-unsigned-big,
+ $\n:8/integer-unit:1-unsigned-big,
+ $�:8/integer-unit:1-unsigned-big>>,
+ <<$\203:8/integer-unit:1-unsigned-big,
+ $P:8/integer-unit:1-unsigned-big,
+ $\000:8/integer-unit:1-unsigned-big,
+ $\000:8/integer-unit:1-unsigned-big,
+ $\000:8/integer-unit:1-unsigned-big,
+ $<:8/integer-unit:1-unsigned-big,
+ $x:8/integer-unit:1-unsigned-big,
+ $\234:8/integer-unit:1-unsigned-big,
+ $�:8/integer-unit:1-unsigned-big,
+ $`:8/integer-unit:1-unsigned-big,
+ $N:8/integer-unit:1-unsigned-big,
+ $a:8/integer-unit:1-unsigned-big,
+ $`:8/integer-unit:1-unsigned-big,
+ $-:8/integer-unit:1-unsigned-big,
+ $):8/integer-unit:1-unsigned-big,
+ $-:8/integer-unit:1-unsigned-big,
+ $�:8/integer-unit:1-unsigned-big,
+ $I:8/integer-unit:1-unsigned-big,
+ $M:8/integer-unit:1-unsigned-big,
+ $�:8/integer-unit:1-unsigned-big,
+ $�:8/integer-unit:1-unsigned-big,
+ $a:8/integer-unit:1-unsigned-big,
+ $`:8/integer-unit:1-unsigned-big,
+ $`:8/integer-unit:1-unsigned-big,
+ $`:8/integer-unit:1-unsigned-big,
+ $�:8/integer-unit:1-unsigned-big,
+ $\000:8/integer-unit:1-unsigned-big,
+ $\n:8/integer-unit:1-unsigned-big,
+ $0:8/integer-unit:1-unsigned-big,
+ $\227:8/integer-unit:1-unsigned-big,
+ $%:8/integer-unit:1-unsigned-big,
+ $\026:8/integer-unit:1-unsigned-big,
+ $%:8/integer-unit:1-unsigned-big,
+ $r:8/integer-unit:1-unsigned-big,
+ $�:8/integer-unit:1-unsigned-big,
+ $0:8/integer-unit:1-unsigned-big,
+ $0:8/integer-unit:1-unsigned-big,
+ $::8/integer-unit:1-unsigned-big,
+ $�:8/integer-unit:1-unsigned-big,
+ $�:8/integer-unit:1-unsigned-big,
+ $":8/integer-unit:1-unsigned-big,
+ $P:8/integer-unit:1-unsigned-big,
+ $x:8/integer-unit:1-unsigned-big,
+ $�:8/integer-unit:1-unsigned-big,
+ $Y:8/integer-unit:1-unsigned-big,
+ $\000:8/integer-unit:1-unsigned-big,
+ $�:8/integer-unit:1-unsigned-big,
+ $9:8/integer-unit:1-unsigned-big,
+ $\r:8/integer-unit:1-unsigned-big,
+ $�:8/integer-unit:1-unsigned-big>>,
+ <<$\203:8/integer-unit:1-unsigned-big,
+ $P:8/integer-unit:1-unsigned-big,
+ $\000:8/integer-unit:1-unsigned-big,
+ $\000:8/integer-unit:1-unsigned-big,
+ $\000:8/integer-unit:1-unsigned-big,
+ $I:8/integer-unit:1-unsigned-big,
+ $x:8/integer-unit:1-unsigned-big,
+ $\234:8/integer-unit:1-unsigned-big,
+ $�:8/integer-unit:1-unsigned-big,
+ $`:8/integer-unit:1-unsigned-big,
+ $M:8/integer-unit:1-unsigned-big,
+ $a:8/integer-unit:1-unsigned-big,
+ $`:8/integer-unit:1-unsigned-big,
+ $�:8/integer-unit:1-unsigned-big,
+ $/:8/integer-unit:1-unsigned-big,
+ $H:8/integer-unit:1-unsigned-big,
+ $�:8/integer-unit:1-unsigned-big,
+ $N:8/integer-unit:1-unsigned-big,
+ $a:8/integer-unit:1-unsigned-big,
+ $`:8/integer-unit:1-unsigned-big,
+ $�:8/integer-unit:1-unsigned-big,
+ $�:8/integer-unit:1-unsigned-big,
+ $�:8/integer-unit:1-unsigned-big,
+ $�:8/integer-unit:1-unsigned-big,
+ $`:8/integer-unit:1-unsigned-big,
+ $\006:8/integer-unit:1-unsigned-big,
+ $�:8/integer-unit:1-unsigned-big,
+ $e:8/integer-unit:1-unsigned-big,
+ $\211:8/integer-unit:1-unsigned-big,
+ $E:8/integer-unit:1-unsigned-big,
+ $\s:8/integer-unit:1-unsigned-big,
+ $>:8/integer-unit:1-unsigned-big,
+ $�:8/integer-unit:1-unsigned-big,
+ $\023:8/integer-unit:1-unsigned-big,
+ $\210:8/integer-unit:1-unsigned-big,
+ $�:8/integer-unit:1-unsigned-big,
+ $\232:8/integer-unit:1-unsigned-big,
+ $\226:8/integer-unit:1-unsigned-big,
+ $\223:8/integer-unit:1-unsigned-big,
+ $\237:8/integer-unit:1-unsigned-big,
+ $X:8/integer-unit:1-unsigned-big,
+ $\222:8/integer-unit:1-unsigned-big,
+ $�:8/integer-unit:1-unsigned-big,
+ $\235:8/integer-unit:1-unsigned-big,
+ $l:8/integer-unit:1-unsigned-big,
+ $�:8/integer-unit:1-unsigned-big,
+ $g:8/integer-unit:1-unsigned-big,
+ $i:8/integer-unit:1-unsigned-big,
+ $d:8/integer-unit:1-unsigned-big,
+ $\200:8/integer-unit:1-unsigned-big,
+ $\001:8/integer-unit:1-unsigned-big,
+ $R:8/integer-unit:1-unsigned-big,
+ $�:8/integer-unit:1-unsigned-big,
+ $\r:8/integer-unit:1-unsigned-big,
+ $\214:8/integer-unit:1-unsigned-big,
+ $\030:8/integer-unit:1-unsigned-big,
+ $@:8/integer-unit:1-unsigned-big,
+ $\000:8/integer-unit:1-unsigned-big,
+ $\000:8/integer-unit:1-unsigned-big,
+ $c:8/integer-unit:1-unsigned-big,
+ $�:8/integer-unit:1-unsigned-big,
+ $\017:8/integer-unit:1-unsigned-big,
+ $=:8/integer-unit:1-unsigned-big>>,
+ <<$\203:8/integer-unit:1-unsigned-big,
+ $h:8/integer-unit:1-unsigned-big,
+ $\003:8/integer-unit:1-unsigned-big,
+ $d:8/integer-unit:1-unsigned-big,
+ $\000:8/integer-unit:1-unsigned-big,
+ $\005:8/integer-unit:1-unsigned-big,
+ $t:8/integer-unit:1-unsigned-big,
+ $u:8/integer-unit:1-unsigned-big,
+ $p:8/integer-unit:1-unsigned-big,
+ $l:8/integer-unit:1-unsigned-big,
+ $e:8/integer-unit:1-unsigned-big,
+ $a:8/integer-unit:1-unsigned-big,
+ $\f:8/integer-unit:1-unsigned-big,
+ $l:8/integer-unit:1-unsigned-big,
+ $\000:8/integer-unit:1-unsigned-big,
+ $\000:8/integer-unit:1-unsigned-big,
+ $\000:8/integer-unit:1-unsigned-big,
+ $\001:8/integer-unit:1-unsigned-big,
+ $h:8/integer-unit:1-unsigned-big,
+ $\003:8/integer-unit:1-unsigned-big,
+ $d:8/integer-unit:1-unsigned-big,
+ $\000:8/integer-unit:1-unsigned-big,
+ $\003:8/integer-unit:1-unsigned-big,
+ $v:8/integer-unit:1-unsigned-big,
+ $a:8/integer-unit:1-unsigned-big,
+ $r:8/integer-unit:1-unsigned-big,
+ $a:8/integer-unit:1-unsigned-big,
+ $\f:8/integer-unit:1-unsigned-big,
+ $d:8/integer-unit:1-unsigned-big,
+ $\000:8/integer-unit:1-unsigned-big,
+ $\001:8/integer-unit:1-unsigned-big,
+ $Y:8/integer-unit:1-unsigned-big,
+ $j:8/integer-unit:1-unsigned-big>>,
+ <<$\203:8/integer-unit:1-unsigned-big,
+ $P:8/integer-unit:1-unsigned-big,
+ $\000:8/integer-unit:1-unsigned-big,
+ $\000:8/integer-unit:1-unsigned-big,
+ $\000:8/integer-unit:1-unsigned-big,
+ $*:8/integer-unit:1-unsigned-big,
+ $x:8/integer-unit:1-unsigned-big,
+ $\234:8/integer-unit:1-unsigned-big,
+ $�:8/integer-unit:1-unsigned-big,
+ $`:8/integer-unit:1-unsigned-big,
+ $M:8/integer-unit:1-unsigned-big,
+ $a:8/integer-unit:1-unsigned-big,
+ $`:8/integer-unit:1-unsigned-big,
+ $�:8/integer-unit:1-unsigned-big,
+ $/:8/integer-unit:1-unsigned-big,
+ $H:8/integer-unit:1-unsigned-big,
+ $�:8/integer-unit:1-unsigned-big,
+ $\005:8/integer-unit:1-unsigned-big,
+ $R:8/integer-unit:1-unsigned-big,
+ $�:8/integer-unit:1-unsigned-big,
+ $�:8/integer-unit:1-unsigned-big,
+ $\031:8/integer-unit:1-unsigned-big,
+ $�:8/integer-unit:1-unsigned-big,
+ $):8/integer-unit:1-unsigned-big,
+ $\f:8/integer-unit:1-unsigned-big,
+ $�:8/integer-unit:1-unsigned-big,
+ $e:8/integer-unit:1-unsigned-big,
+ $\211:8/integer-unit:1-unsigned-big,
+ $E:8/integer-unit:1-unsigned-big,
+ $\s:8/integer-unit:1-unsigned-big,
+ $.:8/integer-unit:1-unsigned-big,
+ $c:8/integer-unit:1-unsigned-big,
+ $\004:8/integer-unit:1-unsigned-big,
+ $\n:8/integer-unit:1-unsigned-big,
+ $/:8/integer-unit:1-unsigned-big,
+ $\022:8/integer-unit:1-unsigned-big,
+ $\000:8/integer-unit:1-unsigned-big,
+ $�:8/integer-unit:1-unsigned-big,
+ $\205:8/integer-unit:1-unsigned-big,
+ $\t:8/integer-unit:1-unsigned-big,
+ $\216:8/integer-unit:1-unsigned-big>>,
+ <<$\203:8/integer-unit:1-unsigned-big,
+ $P:8/integer-unit:1-unsigned-big,
+ $\000:8/integer-unit:1-unsigned-big,
+ $\000:8/integer-unit:1-unsigned-big,
+ $\000:8/integer-unit:1-unsigned-big,
+ $j:8/integer-unit:1-unsigned-big,
+ $x:8/integer-unit:1-unsigned-big,
+ $\234:8/integer-unit:1-unsigned-big,
+ $�:8/integer-unit:1-unsigned-big,
+ $`:8/integer-unit:1-unsigned-big,
+ $I:8/integer-unit:1-unsigned-big,
+ $a:8/integer-unit:1-unsigned-big,
+ $`:8/integer-unit:1-unsigned-big,
+ $I:8/integer-unit:1-unsigned-big,
+ $�:8/integer-unit:1-unsigned-big,
+ $�:8/integer-unit:1-unsigned-big,
+ $+:8/integer-unit:1-unsigned-big,
+ $N:8/integer-unit:1-unsigned-big,
+ $�:8/integer-unit:1-unsigned-big,
+ $�:8/integer-unit:1-unsigned-big,
+ $�:8/integer-unit:1-unsigned-big,
+ $�:8/integer-unit:1-unsigned-big,
+ $�:8/integer-unit:1-unsigned-big,
+ $\f:8/integer-unit:1-unsigned-big,
+ $�:8/integer-unit:1-unsigned-big,
+ $\024:8/integer-unit:1-unsigned-big,
+ $\006:8/integer-unit:1-unsigned-big,
+ $�:8/integer-unit:1-unsigned-big,
+ $\222:8/integer-unit:1-unsigned-big,
+ $�:8/integer-unit:1-unsigned-big,
+ $\202:8/integer-unit:1-unsigned-big,
+ $\234:8/integer-unit:1-unsigned-big,
+ $�:8/integer-unit:1-unsigned-big,
+ $D:8/integer-unit:1-unsigned-big,
+ $�:8/integer-unit:1-unsigned-big,
+ $\034:8/integer-unit:1-unsigned-big,
+ $\006:8/integer-unit:1-unsigned-big,
+ $\006:8/integer-unit:1-unsigned-big,
+ $\006:8/integer-unit:1-unsigned-big,
+ $f:8/integer-unit:1-unsigned-big,
+ $\220:8/integer-unit:1-unsigned-big,
+ $\000:8/integer-unit:1-unsigned-big,
+ $s:8/integer-unit:1-unsigned-big,
+ $Y:8/integer-unit:1-unsigned-big,
+ $b:8/integer-unit:1-unsigned-big,
+ $Q:8/integer-unit:1-unsigned-big,
+ $":8/integer-unit:1-unsigned-big,
+ $W:8/integer-unit:1-unsigned-big,
+ $\n:8/integer-unit:1-unsigned-big,
+ $\003:8/integer-unit:1-unsigned-big,
+ $�:8/integer-unit:1-unsigned-big,
+ $\023:8/integer-unit:1-unsigned-big,
+ $\n:8/integer-unit:1-unsigned-big,
+ $/:8/integer-unit:1-unsigned-big,
+ $\002:8/integer-unit:1-unsigned-big,
+ $\205:8/integer-unit:1-unsigned-big,
+ $\027:8/integer-unit:1-unsigned-big,
+ $\237:8/integer-unit:1-unsigned-big,
+ $\205:8/integer-unit:1-unsigned-big,
+ $�:8/integer-unit:1-unsigned-big,
+ $\227:8/integer-unit:1-unsigned-big,
+ $\007:8/integer-unit:1-unsigned-big,
+ $�:8/integer-unit:1-unsigned-big,
+ $\227:8/integer-unit:1-unsigned-big,
+ $\021:8/integer-unit:1-unsigned-big,
+ $.:8/integer-unit:1-unsigned-big,
+ $�:8/integer-unit:1-unsigned-big,
+ $\003:8/integer-unit:1-unsigned-big,
+ $\224:8/integer-unit:1-unsigned-big,
+ $\217:8/integer-unit:1-unsigned-big,
+ $�:8/integer-unit:1-unsigned-big,
+ $\002:8/integer-unit:1-unsigned-big,
+ $\000:8/integer-unit:1-unsigned-big,
+ $\203:8/integer-unit:1-unsigned-big,
+ $>:8/integer-unit:1-unsigned-big,
+ $\034:8/integer-unit:1-unsigned-big,
+ $a:8/integer-unit:1-unsigned-big>>}
+ end,
+ [{1,
+ 2,
+ 2,
+ {gen,
+ % fun-info: {4,131674517,'-create_handle/0-fun-4-'}
+ fun() ->
+ H1
+ end}},
+ {2,5,4,fil},
+ {3,
+ 7,
+ 5,
+ {gen,
+ % fun-info: {5,108000324,'-create_handle/0-fun-5-'}
+ fun() ->
+ [{0},{1},{2}]
+ end}},
+ {4,10,7,fil},
+ {5,
+ 12,
+ 8,
+ {gen,
+ {join,
+ '==',
+ 1,
+ 3,
+ % fun-info: {9,59718458,'-create_handle/0-fun-9-'}
+ fun(H1_0_1) ->
+ F1_0_1 =
+ % fun-info: {7,779460,'-create_handle/0-fun-7-'}
+ fun(_, []) ->
+ [];
+ (F1_0_1, [O1_0_1|C1_0_1]) ->
+ case O1_0_1 of
+ {_,_,_}
+ when
+ 192.0
+ =:=
+ element(1, O1_0_1) ->
+ [O1_0_1|
+ % fun-info: {6,23729943,'-create_handle/0-fun-6-'}
+ fun() ->
+ F1_0_1(F1_0_1,
+ C1_0_1)
+ end];
+ _ ->
+ F1_0_1(F1_0_1, C1_0_1)
+ end;
+ (F1_0_1, C1_0_1)
+ when is_function(C1_0_1) ->
+ F1_0_1(F1_0_1, C1_0_1());
+ (_, C1_0_1) ->
+ C1_0_1
+ end,
+ % fun-info: {8,43652904,'-create_handle/0-fun-8-'}
+ fun() ->
+ F1_0_1(F1_0_1, H1_0_1)
+ end
+ end,
+ % fun-info: {13,102310144,'-create_handle/0-fun-13-'}
+ fun(H1_0_1) ->
+ F1_0_1 =
+ % fun-info: {11,74362432,'-create_handle/0-fun-11-'}
+ fun(_, []) ->
+ [];
+ (F1_0_1, [O1_0_1|C1_0_1]) ->
+ case O1_0_1 of
+ {_} ->
+ [O1_0_1|
+ % fun-info: {10,23729943,'-create_handle/0-fun-10-'}
+ fun() ->
+ F1_0_1(F1_0_1,
+ C1_0_1)
+ end];
+ _ ->
+ F1_0_1(F1_0_1, C1_0_1)
+ end;
+ (F1_0_1, C1_0_1)
+ when is_function(C1_0_1) ->
+ F1_0_1(F1_0_1, C1_0_1());
+ (_, C1_0_1) ->
+ C1_0_1
+ end,
+ % fun-info: {12,43652904,'-create_handle/0-fun-12-'}
+ fun() ->
+ F1_0_1(F1_0_1, H1_0_1)
+ end
+ end,
+ % fun-info: {14,17838355,'-create_handle/0-fun-14-'}
+ fun() ->
+ {[{1,[192.0]}],[],[]}
+ end}}}],
+ % fun-info: {22,31304647,'-create_handle/0-fun-22-'}
+ fun(join) ->
+ {[[{1,"\002"},{3,"\001"}]],[]};
+ (size) ->
+ % fun-info: {15,31963143,'-create_handle/0-fun-15-'}
+ fun(0) ->
+ 2;
+ (1) ->
+ 3;
+ (3) ->
+ 1;
+ (_) ->
+ undefined
+ end;
+ (template) ->
+ % fun-info: {16,113413274,'-create_handle/0-fun-16-'}
+ fun({1,2}, '=:=') ->
+ "\001";
+ ({1,2}, '==') ->
+ "\001\002";
+ ({3,1}, '=:=') ->
+ "\002";
+ ({3,1}, '==') ->
+ "\001\002";
+ (_, _) ->
+ []
+ end;
+ (constants) ->
+ % fun-info: {18,52148739,'-create_handle/0-fun-18-'}
+ fun(1) ->
+ % fun-info: {17,5864387,'-create_handle/0-fun-17-'}
+ fun(1) ->
+ {values,[192.0],{some,[2]}};
+ (_) ->
+ false
+ end;
+ (_) ->
+ no_column_fun
+ end;
+ (n_leading_constant_columns) ->
+ % fun-info: {19,82183172,'-create_handle/0-fun-19-'}
+ fun(1) ->
+ 1;
+ (_) ->
+ 0
+ end;
+ (constant_columns) ->
+ % fun-info: {20,80910005,'-create_handle/0-fun-20-'}
+ fun(1) ->
+ "\001";
+ (_) ->
+ []
+ end;
+ (match_specs) ->
+ % fun-info: {21,91764346,'-create_handle/0-fun-21-'}
+ fun(1) ->
+ {[{{'$1','$2','_'},
+ [{'=:=','$1',192.0}],
+ ['$_']}],
+ "\002"};
+ (_) ->
+ undefined
+ end;
+ (_) ->
+ undefined
+ end}
+ end,
+ undefined}).
+
+lookup_handle() ->
+ E = qlc_SUITE:table([{1,a},{2,b},{3,c}], 1, [1]),
+ qlc:q({qlc_lc,
+ % fun-info: {46,120768015,'-lookup_handle/0-fun-22-'}
+ fun() ->
+ {qlc_v1,
+ % fun-info: {26,82970908,'-lookup_handle/0-fun-2-'}
+ fun(S02_0_1, RL02_0_1, Go02_0_1) ->
+ Fun2_0_1 =
+ % fun-info: {25,75235357,'-lookup_handle/0-fun-1-'}
+ fun(0, RL2_0_1, _, _, _, _, _, _)
+ when is_list(RL2_0_1) ->
+ lists:reverse(RL2_0_1);
+ (0, _, _, _, _, _, _, _) ->
+ [];
+ (1,
+ RL2_0_1,
+ Fun2_0_1,
+ Go2_0_1,
+ C2_2_1,
+ Y2,
+ C2_1_1,
+ X2)
+ when is_list(RL2_0_1) ->
+ Fun2_0_1(element(1, Go2_0_1),
+ [{X2,Y2}|RL2_0_1],
+ Fun2_0_1,
+ Go2_0_1,
+ C2_2_1,
+ Y2,
+ C2_1_1,
+ X2);
+ (1,
+ RL2_0_1,
+ Fun2_0_1,
+ Go2_0_1,
+ C2_2_1,
+ Y2,
+ C2_1_1,
+ X2) ->
+ [{X2,Y2}|
+ % fun-info: {24,124255471,'-lookup_handle/0-fun-0-'}
+ fun() ->
+ Fun2_0_1(element(1,
+ Go2_0_1),
+ RL2_0_1,
+ Fun2_0_1,
+ Go2_0_1,
+ C2_2_1,
+ Y2,
+ C2_1_1,
+ X2)
+ end];
+ (2,
+ RL2_0_1,
+ Fun2_0_1,
+ Go2_0_1,
+ C2_2_1,
+ Y2,
+ _,
+ X2) ->
+ Fun2_0_1(3,
+ RL2_0_1,
+ Fun2_0_1,
+ Go2_0_1,
+ C2_2_1,
+ Y2,
+ element(4, Go2_0_1),
+ X2);
+ (3,
+ RL2_0_1,
+ Fun2_0_1,
+ Go2_0_1,
+ C2_2_1,
+ Y2,
+ [{X2,_}|C2_0_1],
+ _) ->
+ Fun2_0_1(element(3, Go2_0_1),
+ RL2_0_1,
+ Fun2_0_1,
+ Go2_0_1,
+ C2_2_1,
+ Y2,
+ C2_0_1,
+ X2);
+ (3,
+ RL2_0_1,
+ Fun2_0_1,
+ Go2_0_1,
+ C2_2_1,
+ Y2,
+ [_|C2_0_1],
+ _) ->
+ Fun2_0_1(3,
+ RL2_0_1,
+ Fun2_0_1,
+ Go2_0_1,
+ C2_2_1,
+ Y2,
+ C2_0_1,
+ []);
+ (3,
+ RL2_0_1,
+ Fun2_0_1,
+ Go2_0_1,
+ C2_2_1,
+ Y2,
+ [],
+ _) ->
+ Fun2_0_1(element(2, Go2_0_1),
+ RL2_0_1,
+ Fun2_0_1,
+ Go2_0_1,
+ C2_2_1,
+ Y2,
+ [],
+ []);
+ (3,
+ RL2_0_1,
+ Fun2_0_1,
+ Go2_0_1,
+ C2_2_1,
+ Y2,
+ C2_1_1,
+ _) ->
+ case C2_1_1() of
+ [{X2,_}|C2_0_1] ->
+ Fun2_0_1(element(3,
+ Go2_0_1),
+ RL2_0_1,
+ Fun2_0_1,
+ Go2_0_1,
+ C2_2_1,
+ Y2,
+ C2_0_1,
+ X2);
+ [_|C2_0_1] ->
+ Fun2_0_1(3,
+ RL2_0_1,
+ Fun2_0_1,
+ Go2_0_1,
+ C2_2_1,
+ Y2,
+ C2_0_1,
+ []);
+ [] ->
+ Fun2_0_1(element(2,
+ Go2_0_1),
+ RL2_0_1,
+ Fun2_0_1,
+ Go2_0_1,
+ C2_2_1,
+ Y2,
+ [],
+ []);
+ E2_0_1 ->
+ E2_0_1
+ end;
+ (4,
+ RL2_0_1,
+ Fun2_0_1,
+ Go2_0_1,
+ _,
+ Y2,
+ C2_1_1,
+ X2) ->
+ Fun2_0_1(5,
+ RL2_0_1,
+ Fun2_0_1,
+ Go2_0_1,
+ element(7, Go2_0_1),
+ Y2,
+ C2_1_1,
+ X2);
+ (5,
+ RL2_0_1,
+ Fun2_0_1,
+ Go2_0_1,
+ [{Y2}|C2_0_1],
+ _,
+ C2_1_1,
+ X2) ->
+ Fun2_0_1(element(6, Go2_0_1),
+ RL2_0_1,
+ Fun2_0_1,
+ Go2_0_1,
+ C2_0_1,
+ Y2,
+ C2_1_1,
+ X2);
+ (5,
+ RL2_0_1,
+ Fun2_0_1,
+ Go2_0_1,
+ [_|C2_0_1],
+ _,
+ C2_1_1,
+ X2) ->
+ Fun2_0_1(5,
+ RL2_0_1,
+ Fun2_0_1,
+ Go2_0_1,
+ C2_0_1,
+ [],
+ C2_1_1,
+ X2);
+ (5,
+ RL2_0_1,
+ Fun2_0_1,
+ Go2_0_1,
+ [],
+ _,
+ C2_1_1,
+ X2) ->
+ Fun2_0_1(element(5, Go2_0_1),
+ RL2_0_1,
+ Fun2_0_1,
+ Go2_0_1,
+ [],
+ [],
+ C2_1_1,
+ X2);
+ (5,
+ RL2_0_1,
+ Fun2_0_1,
+ Go2_0_1,
+ C2_2_1,
+ _,
+ C2_1_1,
+ X2) ->
+ case C2_2_1() of
+ [{Y2}|C2_0_1] ->
+ Fun2_0_1(element(6,
+ Go2_0_1),
+ RL2_0_1,
+ Fun2_0_1,
+ Go2_0_1,
+ C2_0_1,
+ Y2,
+ C2_1_1,
+ X2);
+ [_|C2_0_1] ->
+ Fun2_0_1(5,
+ RL2_0_1,
+ Fun2_0_1,
+ Go2_0_1,
+ C2_0_1,
+ [],
+ C2_1_1,
+ X2);
+ [] ->
+ Fun2_0_1(element(5,
+ Go2_0_1),
+ RL2_0_1,
+ Fun2_0_1,
+ Go2_0_1,
+ [],
+ [],
+ C2_1_1,
+ X2);
+ E2_0_1 ->
+ E2_0_1
+ end;
+ (6,
+ RL2_0_1,
+ Fun2_0_1,
+ Go2_0_1,
+ C2_2_1,
+ Y2,
+ C2_1_1,
+ X2) ->
+ if
+ X2 =:= Y2 ->
+ Fun2_0_1(element(9,
+ Go2_0_1),
+ RL2_0_1,
+ Fun2_0_1,
+ Go2_0_1,
+ C2_2_1,
+ Y2,
+ C2_1_1,
+ X2);
+ true ->
+ Fun2_0_1(element(8,
+ Go2_0_1),
+ RL2_0_1,
+ Fun2_0_1,
+ Go2_0_1,
+ C2_2_1,
+ Y2,
+ C2_1_1,
+ X2)
+ end;
+ (7,
+ RL2_0_1,
+ Fun2_0_1,
+ Go2_0_1,
+ C2_2_1,
+ Y2,
+ _,
+ X2) ->
+ Fun2_0_1(8,
+ RL2_0_1,
+ Fun2_0_1,
+ Go2_0_1,
+ C2_2_1,
+ Y2,
+ element(12, Go2_0_1),
+ X2);
+ (8,
+ RL2_0_1,
+ Fun2_0_1,
+ Go2_0_1,
+ C2_2_1,
+ _,
+ [[{X2,_}|{Y2}]|C2_0_1],
+ _) ->
+ Fun2_0_1(element(11, Go2_0_1),
+ RL2_0_1,
+ Fun2_0_1,
+ Go2_0_1,
+ C2_2_1,
+ Y2,
+ C2_0_1,
+ X2);
+ (8,
+ RL2_0_1,
+ Fun2_0_1,
+ Go2_0_1,
+ C2_2_1,
+ _,
+ [_|C2_0_1],
+ _) ->
+ Fun2_0_1(8,
+ RL2_0_1,
+ Fun2_0_1,
+ Go2_0_1,
+ C2_2_1,
+ [],
+ C2_0_1,
+ []);
+ (8,
+ RL2_0_1,
+ Fun2_0_1,
+ Go2_0_1,
+ C2_2_1,
+ _,
+ [],
+ _) ->
+ Fun2_0_1(element(10, Go2_0_1),
+ RL2_0_1,
+ Fun2_0_1,
+ Go2_0_1,
+ C2_2_1,
+ [],
+ [],
+ []);
+ (8,
+ RL2_0_1,
+ Fun2_0_1,
+ Go2_0_1,
+ C2_2_1,
+ _,
+ C2_1_1,
+ _) ->
+ case C2_1_1() of
+ [[{X2,_}|{Y2}]|C2_0_1] ->
+ Fun2_0_1(element(11,
+ Go2_0_1),
+ RL2_0_1,
+ Fun2_0_1,
+ Go2_0_1,
+ C2_2_1,
+ Y2,
+ C2_0_1,
+ X2);
+ [_|C2_0_1] ->
+ Fun2_0_1(8,
+ RL2_0_1,
+ Fun2_0_1,
+ Go2_0_1,
+ C2_2_1,
+ [],
+ C2_0_1,
+ []);
+ [] ->
+ Fun2_0_1(element(10,
+ Go2_0_1),
+ RL2_0_1,
+ Fun2_0_1,
+ Go2_0_1,
+ C2_2_1,
+ [],
+ [],
+ []);
+ E2_0_1 ->
+ E2_0_1
+ end
+ end,
+ Fun2_0_1(S02_0_1,
+ RL02_0_1,
+ Fun2_0_1,
+ Go02_0_1,
+ [],
+ [],
+ [],
+ [])
+ end,
+ % fun-info: {27,111349661,'-lookup_handle/0-fun-3-'}
+ fun() ->
+ {<<$\203:8/integer-unit:1-unsigned-big,
+ $P:8/integer-unit:1-unsigned-big,
+ $\000:8/integer-unit:1-unsigned-big,
+ $\000:8/integer-unit:1-unsigned-big,
+ $\000:8/integer-unit:1-unsigned-big,
+ $.:8/integer-unit:1-unsigned-big,
+ $x:8/integer-unit:1-unsigned-big,
+ $\234:8/integer-unit:1-unsigned-big,
+ $�:8/integer-unit:1-unsigned-big,
+ $`:8/integer-unit:1-unsigned-big,
+ $N:8/integer-unit:1-unsigned-big,
+ $a:8/integer-unit:1-unsigned-big,
+ $`:8/integer-unit:1-unsigned-big,
+ $-:8/integer-unit:1-unsigned-big,
+ $):8/integer-unit:1-unsigned-big,
+ $-:8/integer-unit:1-unsigned-big,
+ $�:8/integer-unit:1-unsigned-big,
+ $I:8/integer-unit:1-unsigned-big,
+ $M:8/integer-unit:1-unsigned-big,
+ $\024:8/integer-unit:1-unsigned-big,
+ $�:8/integer-unit:1-unsigned-big,
+ $a:8/integer-unit:1-unsigned-big,
+ $`:8/integer-unit:1-unsigned-big,
+ $`:8/integer-unit:1-unsigned-big,
+ $`:8/integer-unit:1-unsigned-big,
+ $�:8/integer-unit:1-unsigned-big,
+ $\000:8/integer-unit:1-unsigned-big,
+ $\n:8/integer-unit:1-unsigned-big,
+ $0:8/integer-unit:1-unsigned-big,
+ $\227:8/integer-unit:1-unsigned-big,
+ $%:8/integer-unit:1-unsigned-big,
+ $\026:8/integer-unit:1-unsigned-big,
+ $%:8/integer-unit:1-unsigned-big,
+ $\n:8/integer-unit:1-unsigned-big,
+ $�:8/integer-unit:1-unsigned-big,
+ $0:8/integer-unit:1-unsigned-big,
+ $0:8/integer-unit:1-unsigned-big,
+ $F:8/integer-unit:1-unsigned-big,
+ $�:8/integer-unit:1-unsigned-big,
+ $�:8/integer-unit:1-unsigned-big,
+ $":8/integer-unit:1-unsigned-big,
+ $�:8/integer-unit:1-unsigned-big,
+ $\000:8/integer-unit:1-unsigned-big,
+ $\000:8/integer-unit:1-unsigned-big,
+ $\206:8/integer-unit:1-unsigned-big,
+ $\n:8/integer-unit:1-unsigned-big,
+ $�:8/integer-unit:1-unsigned-big>>,
+ <<$\203:8/integer-unit:1-unsigned-big,
+ $P:8/integer-unit:1-unsigned-big,
+ $\000:8/integer-unit:1-unsigned-big,
+ $\000:8/integer-unit:1-unsigned-big,
+ $\000:8/integer-unit:1-unsigned-big,
+ $.:8/integer-unit:1-unsigned-big,
+ $x:8/integer-unit:1-unsigned-big,
+ $\234:8/integer-unit:1-unsigned-big,
+ $�:8/integer-unit:1-unsigned-big,
+ $`:8/integer-unit:1-unsigned-big,
+ $N:8/integer-unit:1-unsigned-big,
+ $a:8/integer-unit:1-unsigned-big,
+ $`:8/integer-unit:1-unsigned-big,
+ $-:8/integer-unit:1-unsigned-big,
+ $):8/integer-unit:1-unsigned-big,
+ $-:8/integer-unit:1-unsigned-big,
+ $�:8/integer-unit:1-unsigned-big,
+ $I:8/integer-unit:1-unsigned-big,
+ $M:8/integer-unit:1-unsigned-big,
+ $\024:8/integer-unit:1-unsigned-big,
+ $�:8/integer-unit:1-unsigned-big,
+ $a:8/integer-unit:1-unsigned-big,
+ $`:8/integer-unit:1-unsigned-big,
+ $`:8/integer-unit:1-unsigned-big,
+ $`:8/integer-unit:1-unsigned-big,
+ $�:8/integer-unit:1-unsigned-big,
+ $\000:8/integer-unit:1-unsigned-big,
+ $\n:8/integer-unit:1-unsigned-big,
+ $0:8/integer-unit:1-unsigned-big,
+ $\227:8/integer-unit:1-unsigned-big,
+ $%:8/integer-unit:1-unsigned-big,
+ $\026:8/integer-unit:1-unsigned-big,
+ $%:8/integer-unit:1-unsigned-big,
+ $\n:8/integer-unit:1-unsigned-big,
+ $�:8/integer-unit:1-unsigned-big,
+ $0:8/integer-unit:1-unsigned-big,
+ $0:8/integer-unit:1-unsigned-big,
+ $F:8/integer-unit:1-unsigned-big,
+ $�:8/integer-unit:1-unsigned-big,
+ $�:8/integer-unit:1-unsigned-big,
+ $�:8/integer-unit:1-unsigned-big,
+ $�:8/integer-unit:1-unsigned-big,
+ $\000:8/integer-unit:1-unsigned-big,
+ $\000:8/integer-unit:1-unsigned-big,
+ $\222:8/integer-unit:1-unsigned-big,
+ $\n:8/integer-unit:1-unsigned-big,
+ $�:8/integer-unit:1-unsigned-big>>,
+ <<$\203:8/integer-unit:1-unsigned-big,
+ $h:8/integer-unit:1-unsigned-big,
+ $\003:8/integer-unit:1-unsigned-big,
+ $d:8/integer-unit:1-unsigned-big,
+ $\000:8/integer-unit:1-unsigned-big,
+ $\005:8/integer-unit:1-unsigned-big,
+ $t:8/integer-unit:1-unsigned-big,
+ $u:8/integer-unit:1-unsigned-big,
+ $p:8/integer-unit:1-unsigned-big,
+ $l:8/integer-unit:1-unsigned-big,
+ $e:8/integer-unit:1-unsigned-big,
+ $a:8/integer-unit:1-unsigned-big,
+ $\022:8/integer-unit:1-unsigned-big,
+ $l:8/integer-unit:1-unsigned-big,
+ $\000:8/integer-unit:1-unsigned-big,
+ $\000:8/integer-unit:1-unsigned-big,
+ $\000:8/integer-unit:1-unsigned-big,
+ $\001:8/integer-unit:1-unsigned-big,
+ $h:8/integer-unit:1-unsigned-big,
+ $\003:8/integer-unit:1-unsigned-big,
+ $d:8/integer-unit:1-unsigned-big,
+ $\000:8/integer-unit:1-unsigned-big,
+ $\003:8/integer-unit:1-unsigned-big,
+ $v:8/integer-unit:1-unsigned-big,
+ $a:8/integer-unit:1-unsigned-big,
+ $r:8/integer-unit:1-unsigned-big,
+ $a:8/integer-unit:1-unsigned-big,
+ $\022:8/integer-unit:1-unsigned-big,
+ $d:8/integer-unit:1-unsigned-big,
+ $\000:8/integer-unit:1-unsigned-big,
+ $\001:8/integer-unit:1-unsigned-big,
+ $Y:8/integer-unit:1-unsigned-big,
+ $j:8/integer-unit:1-unsigned-big>>,
+ <<$\203:8/integer-unit:1-unsigned-big,
+ $P:8/integer-unit:1-unsigned-big,
+ $\000:8/integer-unit:1-unsigned-big,
+ $\000:8/integer-unit:1-unsigned-big,
+ $\000:8/integer-unit:1-unsigned-big,
+ $+:8/integer-unit:1-unsigned-big,
+ $x:8/integer-unit:1-unsigned-big,
+ $\234:8/integer-unit:1-unsigned-big,
+ $�:8/integer-unit:1-unsigned-big,
+ $`:8/integer-unit:1-unsigned-big,
+ $M:8/integer-unit:1-unsigned-big,
+ $a:8/integer-unit:1-unsigned-big,
+ $`:8/integer-unit:1-unsigned-big,
+ $�:8/integer-unit:1-unsigned-big,
+ $/:8/integer-unit:1-unsigned-big,
+ $H:8/integer-unit:1-unsigned-big,
+ $\024:8/integer-unit:1-unsigned-big,
+ $N:8/integer-unit:1-unsigned-big,
+ $a:8/integer-unit:1-unsigned-big,
+ $`:8/integer-unit:1-unsigned-big,
+ $�:8/integer-unit:1-unsigned-big,
+ $�:8/integer-unit:1-unsigned-big,
+ $�:8/integer-unit:1-unsigned-big,
+ $�:8/integer-unit:1-unsigned-big,
+ $`:8/integer-unit:1-unsigned-big,
+ $\006:8/integer-unit:1-unsigned-big,
+ $�:8/integer-unit:1-unsigned-big,
+ $e:8/integer-unit:1-unsigned-big,
+ $\211:8/integer-unit:1-unsigned-big,
+ $E:8/integer-unit:1-unsigned-big,
+ $\s:8/integer-unit:1-unsigned-big,
+ $>:8/integer-unit:1-unsigned-big,
+ $c:8/integer-unit:1-unsigned-big,
+ $\004:8/integer-unit:1-unsigned-big,
+ $\n:8/integer-unit:1-unsigned-big,
+ $/:8/integer-unit:1-unsigned-big,
+ $\022:8/integer-unit:1-unsigned-big,
+ $\000:8/integer-unit:1-unsigned-big,
+ $�:8/integer-unit:1-unsigned-big,
+ $\227:8/integer-unit:1-unsigned-big,
+ $\t:8/integer-unit:1-unsigned-big,
+ $�:8/integer-unit:1-unsigned-big>>,
+ <<$\203:8/integer-unit:1-unsigned-big,
+ $P:8/integer-unit:1-unsigned-big,
+ $\000:8/integer-unit:1-unsigned-big,
+ $\000:8/integer-unit:1-unsigned-big,
+ $\000:8/integer-unit:1-unsigned-big,
+ $\\:8/integer-unit:1-unsigned-big,
+ $x:8/integer-unit:1-unsigned-big,
+ $\234:8/integer-unit:1-unsigned-big,
+ $�:8/integer-unit:1-unsigned-big,
+ $`:8/integer-unit:1-unsigned-big,
+ $I:8/integer-unit:1-unsigned-big,
+ $a:8/integer-unit:1-unsigned-big,
+ $`:8/integer-unit:1-unsigned-big,
+ $I:8/integer-unit:1-unsigned-big,
+ $�:8/integer-unit:1-unsigned-big,
+ $�:8/integer-unit:1-unsigned-big,
+ $+:8/integer-unit:1-unsigned-big,
+ $N:8/integer-unit:1-unsigned-big,
+ $�:8/integer-unit:1-unsigned-big,
+ $�:8/integer-unit:1-unsigned-big,
+ $�:8/integer-unit:1-unsigned-big,
+ $�:8/integer-unit:1-unsigned-big,
+ $�:8/integer-unit:1-unsigned-big,
+ $\f:8/integer-unit:1-unsigned-big,
+ $�:8/integer-unit:1-unsigned-big,
+ $\024:8/integer-unit:1-unsigned-big,
+ $\006:8/integer-unit:1-unsigned-big,
+ $�:8/integer-unit:1-unsigned-big,
+ $\222:8/integer-unit:1-unsigned-big,
+ $�:8/integer-unit:1-unsigned-big,
+ $\202:8/integer-unit:1-unsigned-big,
+ $\234:8/integer-unit:1-unsigned-big,
+ $�:8/integer-unit:1-unsigned-big,
+ $D:8/integer-unit:1-unsigned-big,
+ $�:8/integer-unit:1-unsigned-big,
+ $\034:8/integer-unit:1-unsigned-big,
+ $\006:8/integer-unit:1-unsigned-big,
+ $\006:8/integer-unit:1-unsigned-big,
+ $\006:8/integer-unit:1-unsigned-big,
+ $&:8/integer-unit:1-unsigned-big,
+ $\220:8/integer-unit:1-unsigned-big,
+ $\000:8/integer-unit:1-unsigned-big,
+ $s:8/integer-unit:1-unsigned-big,
+ $Y:8/integer-unit:1-unsigned-big,
+ $b:8/integer-unit:1-unsigned-big,
+ $Q:8/integer-unit:1-unsigned-big,
+ $�:8/integer-unit:1-unsigned-big,
+ $`:8/integer-unit:1-unsigned-big,
+ $\n:8/integer-unit:1-unsigned-big,
+ $\003:8/integer-unit:1-unsigned-big,
+ $c:8/integer-unit:1-unsigned-big,
+ $\004:8/integer-unit:1-unsigned-big,
+ $\n:8/integer-unit:1-unsigned-big,
+ $/:8/integer-unit:1-unsigned-big,
+ $>:8/integer-unit:1-unsigned-big,
+ $\v:8/integer-unit:1-unsigned-big,
+ $I:8/integer-unit:1-unsigned-big,
+ $�:8/integer-unit:1-unsigned-big,
+ $\020:8/integer-unit:1-unsigned-big,
+ $H:8/integer-unit:1-unsigned-big,
+ $5:8/integer-unit:1-unsigned-big,
+ $#:8/integer-unit:1-unsigned-big,
+ $\\:8/integer-unit:1-unsigned-big,
+ $^:8/integer-unit:1-unsigned-big,
+ $\b:8/integer-unit:1-unsigned-big,
+ $(:8/integer-unit:1-unsigned-big,
+ $\037:8/integer-unit:1-unsigned-big,
+ $\231:8/integer-unit:1-unsigned-big,
+ $\005:8/integer-unit:1-unsigned-big,
+ $\000:8/integer-unit:1-unsigned-big,
+ $\024:8/integer-unit:1-unsigned-big,
+ $�:8/integer-unit:1-unsigned-big,
+ $\031:8/integer-unit:1-unsigned-big,
+ $M:8/integer-unit:1-unsigned-big>>}
+ end,
+ [{1,
+ 2,
+ 2,
+ {gen,
+ % fun-info: {28,75197307,'-lookup_handle/0-fun-4-'}
+ fun() ->
+ E
+ end}},
+ {2,
+ 5,
+ 4,
+ {gen,
+ % fun-info: {29,86826511,'-lookup_handle/0-fun-5-'}
+ fun() ->
+ [{0},{1},{2}]
+ end}},
+ {3,8,6,fil},
+ {4,
+ 10,
+ 7,
+ {gen,
+ {join,
+ '==',
+ 1,
+ 2,
+ % fun-info: {33,129609919,'-lookup_handle/0-fun-9-'}
+ fun(H2_0_1) ->
+ F2_0_1 =
+ % fun-info: {31,45768082,'-lookup_handle/0-fun-7-'}
+ fun(_, []) ->
+ [];
+ (F2_0_1, [O2_0_1|C2_0_1]) ->
+ case O2_0_1 of
+ {_,_} ->
+ [O2_0_1|
+ % fun-info: {30,28136696,'-lookup_handle/0-fun-6-'}
+ fun() ->
+ F2_0_1(F2_0_1,
+ C2_0_1)
+ end];
+ _ ->
+ F2_0_1(F2_0_1, C2_0_1)
+ end;
+ (F2_0_1, C2_0_1)
+ when is_function(C2_0_1) ->
+ F2_0_1(F2_0_1, C2_0_1());
+ (_, C2_0_1) ->
+ C2_0_1
+ end,
+ % fun-info: {32,48059625,'-lookup_handle/0-fun-8-'}
+ fun() ->
+ F2_0_1(F2_0_1, H2_0_1)
+ end
+ end,
+ % fun-info: {37,63676968,'-lookup_handle/0-fun-13-'}
+ fun(H2_0_1) ->
+ F2_0_1 =
+ % fun-info: {35,129320532,'-lookup_handle/0-fun-11-'}
+ fun(_, []) ->
+ [];
+ (F2_0_1, [O2_0_1|C2_0_1]) ->
+ case O2_0_1 of
+ {_} ->
+ [O2_0_1|
+ % fun-info: {34,28136696,'-lookup_handle/0-fun-10-'}
+ fun() ->
+ F2_0_1(F2_0_1,
+ C2_0_1)
+ end];
+ _ ->
+ F2_0_1(F2_0_1, C2_0_1)
+ end;
+ (F2_0_1, C2_0_1)
+ when is_function(C2_0_1) ->
+ F2_0_1(F2_0_1, C2_0_1());
+ (_, C2_0_1) ->
+ C2_0_1
+ end,
+ % fun-info: {36,48059625,'-lookup_handle/0-fun-12-'}
+ fun() ->
+ F2_0_1(F2_0_1, H2_0_1)
+ end
+ end,
+ % fun-info: {38,3236543,'-lookup_handle/0-fun-14-'}
+ fun() ->
+ {[],[],[]}
+ end}}}],
+ % fun-info: {45,56361026,'-lookup_handle/0-fun-21-'}
+ fun(join) ->
+ [[{1,"\001"},{2,"\001"}]];
+ (size) ->
+ % fun-info: {39,40607542,'-lookup_handle/0-fun-15-'}
+ fun(0) ->
+ 2;
+ (1) ->
+ 2;
+ (2) ->
+ 1;
+ (_) ->
+ undefined
+ end;
+ (template) ->
+ % fun-info: {40,34907048,'-lookup_handle/0-fun-16-'}
+ fun({1,1}, _) ->
+ "\001\002";
+ ({2,1}, _) ->
+ "\001\002";
+ (_, _) ->
+ []
+ end;
+ (constants) ->
+ % fun-info: {41,11686091,'-lookup_handle/0-fun-17-'}
+ fun(_) ->
+ no_column_fun
+ end;
+ (n_leading_constant_columns) ->
+ % fun-info: {42,21492441,'-lookup_handle/0-fun-18-'}
+ fun(_) ->
+ 0
+ end;
+ (constant_columns) ->
+ % fun-info: {43,55297177,'-lookup_handle/0-fun-19-'}
+ fun(_) ->
+ []
+ end;
+ (match_specs) ->
+ % fun-info: {44,55081557,'-lookup_handle/0-fun-20-'}
+ fun(_) ->
+ undefined
+ end;
+ (_) ->
+ undefined
+ end}
+ end,
+ undefined}).
diff --git a/lib/stdlib/test/re_SUITE.erl b/lib/stdlib/test/re_SUITE.erl
index c4817c0d38..3b2e637c84 100644
--- a/lib/stdlib/test/re_SUITE.erl
+++ b/lib/stdlib/test/re_SUITE.erl
@@ -454,115 +454,115 @@ error_handling(Config) when is_list(Config) ->
% The malformed precomiled RE is detected after
% the trap to re:grun from grun, in the grun function clause
% that handles precompiled expressions
- ?line {'EXIT',{badarg,[{re,run,["apa",{1,2,3,4},[global]]},
- {?MODULE, error_handling,1} | _]}} =
+ ?line {'EXIT',{badarg,[{re,run,["apa",{1,2,3,4},[global]],_},
+ {?MODULE,error_handling,1,_} | _]}} =
(catch re:run("apa",{1,2,3,4},[global])),
% An invalid capture list will also cause a badarg late,
% but with a non pre compiled RE, the exception should be thrown by the
% grun function clause that handles RE's compiled implicitly by
% the run/3 BIF before trapping.
- ?line {'EXIT',{badarg,[{re,run,["apa","p",[{capture,[1,{a}]},global]]},
- {?MODULE, error_handling,1} | _]}} =
+ ?line {'EXIT',{badarg,[{re,run,["apa","p",[{capture,[1,{a}]},global]],_},
+ {?MODULE,error_handling,1,_} | _]}} =
(catch re:run("apa","p",[{capture,[1,{a}]},global])),
% And so the case of a precompiled expression together with
% a compile-option (binary and list subject):
?line {ok,RE} = re:compile("(p)"),
?line {match,[[{1,1},{1,1}]]} = re:run(<<"apa">>,RE,[global]),
?line {match,[[{1,1},{1,1}]]} = re:run("apa",RE,[global]),
- {'EXIT',{badarg,[{re,run,
- [<<"apa">>,
- {re_pattern,1,0,_},
- [global,unicode]]},
- {?MODULE, error_handling,1} | _]}} =
+ ?line {'EXIT',{badarg,[{re,run,
+ [<<"apa">>,
+ {re_pattern,1,0,_},
+ [global,unicode]],_},
+ {?MODULE,error_handling,1,_} | _]}} =
(catch re:run(<<"apa">>,RE,[global,unicode])),
- {'EXIT',{badarg,[{re,run,
- ["apa",
- {re_pattern,1,0,_},
- [global,unicode]]},
- {?MODULE, error_handling,1} | _]}} =
+ ?line {'EXIT',{badarg,[{re,run,
+ ["apa",
+ {re_pattern,1,0,_},
+ [global,unicode]],_},
+ {?MODULE,error_handling,1,_} | _]}} =
(catch re:run("apa",RE,[global,unicode])),
?line {'EXIT',{badarg,_}} = (catch re:run("apa","(p",[])),
?line {'EXIT',{badarg,_}} = (catch re:run("apa","(p",[global])),
% The replace errors:
- ?line {'EXIT',{badarg,[{re,replace,["apa",{1,2,3,4},"X",[]]},
- {?MODULE, error_handling,1} | _]}} =
+ ?line {'EXIT',{badarg,[{re,replace,["apa",{1,2,3,4},"X",[]],_},
+ {?MODULE,error_handling,1,_} | _]}} =
(catch re:replace("apa",{1,2,3,4},"X",[])),
- ?line {'EXIT',{badarg,[{re,replace,["apa",{1,2,3,4},"X",[global]]},
- {?MODULE, error_handling,1} | _]}} =
+ ?line {'EXIT',{badarg,[{re,replace,["apa",{1,2,3,4},"X",[global]],_},
+ {?MODULE,error_handling,1,_} | _]}} =
(catch re:replace("apa",{1,2,3,4},"X",[global])),
?line {'EXIT',{badarg,[{re,replace,
["apa",
{re_pattern,1,0,_},
"X",
- [unicode]]},
- {?MODULE, error_handling,1} | _]}} =
+ [unicode]],_},
+ {?MODULE,error_handling,1,_} | _]}} =
(catch re:replace("apa",RE,"X",[unicode])),
?line <<"aXa">> = iolist_to_binary(re:replace("apa","p","X",[])),
?line {'EXIT',{badarg,[{re,replace,
- ["apa","p","X",[{capture,all,binary}]]},
- {?MODULE, error_handling,1} | _]}} =
+ ["apa","p","X",[{capture,all,binary}]],_},
+ {?MODULE,error_handling,1,_} | _]}} =
(catch iolist_to_binary(re:replace("apa","p","X",
[{capture,all,binary}]))),
?line {'EXIT',{badarg,[{re,replace,
- ["apa","p","X",[{capture,all}]]},
- {?MODULE, error_handling,1} | _]}} =
+ ["apa","p","X",[{capture,all}]],_},
+ {?MODULE,error_handling,1,_} | _]}} =
(catch iolist_to_binary(re:replace("apa","p","X",
[{capture,all}]))),
?line {'EXIT',{badarg,[{re,replace,
- ["apa","p","X",[{return,banana}]]},
- {?MODULE, error_handling,1} | _]}} =
+ ["apa","p","X",[{return,banana}]],_},
+ {?MODULE,error_handling,1,_} | _]}} =
(catch iolist_to_binary(re:replace("apa","p","X",
[{return,banana}]))),
?line {'EXIT',{badarg,_}} = (catch re:replace("apa","(p","X",[])),
% Badarg, not compile error.
?line {'EXIT',{badarg,[{re,replace,
- ["apa","(p","X",[{return,banana}]]},
- {?MODULE, error_handling,1} | _]}} =
+ ["apa","(p","X",[{return,banana}]],_},
+ {?MODULE,error_handling,1,_} | _]}} =
(catch iolist_to_binary(re:replace("apa","(p","X",
[{return,banana}]))),
% And the split errors:
?line [<<"a">>,<<"a">>] = (catch re:split("apa","p",[])),
?line [<<"a">>,<<"p">>,<<"a">>] = (catch re:split("apa",RE,[])),
- ?line {'EXIT',{badarg,[{re,split,["apa","p",[global]]},
- {?MODULE, error_handling,1} | _]}} =
+ ?line {'EXIT',{badarg,[{re,split,["apa","p",[global]],_},
+ {?MODULE,error_handling,1,_} | _]}} =
(catch re:split("apa","p",[global])),
- ?line {'EXIT',{badarg,[{re,split,["apa","p",[{capture,all}]]},
- {?MODULE, error_handling,1} | _]}} =
+ ?line {'EXIT',{badarg,[{re,split,["apa","p",[{capture,all}]],_},
+ {?MODULE,error_handling,1,_} | _]}} =
(catch re:split("apa","p",[{capture,all}])),
- ?line {'EXIT',{badarg,[{re,split,["apa","p",[{capture,all,binary}]]},
- {?MODULE, error_handling,1} | _]}} =
+ ?line {'EXIT',{badarg,[{re,split,["apa","p",[{capture,all,binary}]],_},
+ {?MODULE, error_handling,1,_} | _]}} =
(catch re:split("apa","p",[{capture,all,binary}])),
- ?line {'EXIT',{badarg,[{re,split,["apa",{1,2,3,4},[]]},
- {?MODULE, error_handling,1} | _]}} =
+ ?line {'EXIT',{badarg,[{re,split,["apa",{1,2,3,4},[]],_},
+ {?MODULE,error_handling,1,_} | _]}} =
(catch re:split("apa",{1,2,3,4})),
- ?line {'EXIT',{badarg,[{re,split,["apa",{1,2,3,4},[]]},
- {?MODULE, error_handling,1} | _]}} =
+ ?line {'EXIT',{badarg,[{re,split,["apa",{1,2,3,4},[]],_},
+ {?MODULE,error_handling,1,_} | _]}} =
(catch re:split("apa",{1,2,3,4},[])),
?line {'EXIT',{badarg,[{re,split,
["apa",
RE,
- [unicode]]},
- {?MODULE, error_handling,1} | _]}} =
+ [unicode]],_},
+ {?MODULE,error_handling,1,_} | _]}} =
(catch re:split("apa",RE,[unicode])),
?line {'EXIT',{badarg,[{re,split,
["apa",
RE,
- [{return,banana}]]},
- {?MODULE, error_handling,1} | _]}} =
+ [{return,banana}]],_},
+ {?MODULE,error_handling,1,_} | _]}} =
(catch re:split("apa",RE,[{return,banana}])),
?line {'EXIT',{badarg,[{re,split,
["apa",
RE,
- [banana]]},
- {?MODULE, error_handling,1} | _]}} =
+ [banana]],_},
+ {?MODULE,error_handling,1,_} | _]}} =
(catch re:split("apa",RE,[banana])),
?line {'EXIT',{badarg,_}} = (catch re:split("apa","(p")),
%Exception on bad argument, not compilation error
?line {'EXIT',{badarg,[{re,split,
["apa",
"(p",
- [banana]]},
- {?MODULE, error_handling,1} | _]}} =
+ [banana]],_},
+ {?MODULE,error_handling,1,_} | _]}} =
(catch re:split("apa","(p",[banana])),
?t:timetrap_cancel(Dog),
ok.
diff --git a/lib/stdlib/test/shell_SUITE.erl b/lib/stdlib/test/shell_SUITE.erl
index 8273377ba1..b6019b86f0 100644
--- a/lib/stdlib/test/shell_SUITE.erl
+++ b/lib/stdlib/test/shell_SUITE.erl
@@ -2388,12 +2388,12 @@ otp_6554(Config) when is_list(Config) ->
comm_err(<<"V = lists:seq(1, 20), case V of a -> ok end.">>),
?line "exception error: no function clause matching" =
comm_err(<<"fun(P) when is_pid(P) -> true end(a).">>),
- ?line "exception error: {function_clause,[{erl_eval,do_apply,[unproper|list]}"++_ =
+ ?line "exception error: {function_clause," =
comm_err(<<"erlang:error(function_clause, [unproper | list]).">>),
?line "exception error: function_clause" =
comm_err(<<"erlang:error(function_clause, 4).">>),
%% Cheating:
- ?line "exception error: no function clause matching erl_eval:do_apply(4)" =
+ ?line "exception error: no function clause matching erl_eval:do_apply(4)" ++ _ =
comm_err(<<"erlang:error(function_clause, [4]).">>),
?line "exception error: no function clause matching" ++ _ =
comm_err(<<"fun(a, b, c, d) -> foo end"
@@ -2406,7 +2406,7 @@ otp_6554(Config) when is_list(Config) ->
comm_err(<<"fun(P, q) when is_pid(P) -> true end(a, b).">>),
?line "exception error: no function clause matching lists:reverse(" ++ _ =
comm_err(<<"F=fun() -> hello end, lists:reverse(F).">>),
- ?line "exception error: no function clause matching lists:reverse(34)" =
+ ?line "exception error: no function clause matching lists:reverse(34) (lists.erl, line " ++ _ =
comm_err(<<"lists:reverse(34).">>),
?line "exception error: no true branch found when evaluating an if expression" =
comm_err(<<"if length([a,b]) > 17 -> a end.">>),
diff --git a/lib/stdlib/test/sofs_SUITE.erl b/lib/stdlib/test/sofs_SUITE.erl
index d6f88a655e..73b282149a 100644
--- a/lib/stdlib/test/sofs_SUITE.erl
+++ b/lib/stdlib/test/sofs_SUITE.erl
@@ -1879,11 +1879,11 @@ digraph(Conf) when is_list(Conf) ->
?line {'EXIT', {badarg, _}} =
(catch family_to_digraph(set([a]))),
- ?line {'EXIT', {badarg, [{sofs,family_to_digraph,[_,_]}|_]}} =
+ ?line {'EXIT', {badarg, [{sofs,family_to_digraph,[_,_],_}|_]}} =
(catch family_to_digraph(set([a]), [foo])),
- ?line {'EXIT', {badarg, [{sofs,family_to_digraph,[_,_]}|_]}} =
+ ?line {'EXIT', {badarg, [{sofs,family_to_digraph,[_,_],_}|_]}} =
(catch family_to_digraph(F, [foo])),
- ?line {'EXIT', {cyclic, [{sofs,family_to_digraph,[_,_]}|_]}} =
+ ?line {'EXIT', {cyclic, [{sofs,family_to_digraph,[_,_],_}|_]}} =
(catch family_to_digraph(family([{a,[a]}]),[acyclic])),
?line G1 = family_to_digraph(E),
diff --git a/lib/stdlib/test/stdlib_SUITE.erl b/lib/stdlib/test/stdlib_SUITE.erl
index 0cca030b3d..8a2cb5ea6b 100644
--- a/lib/stdlib/test/stdlib_SUITE.erl
+++ b/lib/stdlib/test/stdlib_SUITE.erl
@@ -33,8 +33,7 @@
-export([init_per_testcase/2, end_per_testcase/2]).
% Test cases must be exported.
--export([app_test/1]).
--define(cases, [app_test]).
+-export([app_test/1, appup_test/1]).
%%
%% all/1
@@ -42,7 +41,7 @@
suite() -> [{ct_hooks,[ts_install_cth]}].
all() ->
- [app_test].
+ [app_test, appup_test].
groups() ->
[].
@@ -79,3 +78,61 @@ app_test(Config) when is_list(Config) ->
?t:app_test(stdlib),
ok.
+%% Test that appup allows upgrade from/downgrade to a maximum of two
+%% major releases back.
+appup_test(_Config) ->
+ application:load(stdlib),
+ {_,_,Vsn} = lists:keyfind(stdlib,1,application:loaded_applications()),
+ AppupFile = filename:join([code:lib_dir(stdlib),ebin,"stdlib.appup"]),
+ {ok,[{Vsn,UpFrom,DownTo}=AppupScript]} = file:consult(AppupFile),
+ ct:log("~p~n",[AppupScript]),
+ {OkVsns,NokVsns} = create_test_vsns(Vsn),
+ check_appup(OkVsns,UpFrom,{ok,[restart_new_emulator]}),
+ check_appup(OkVsns,DownTo,{ok,[restart_new_emulator]}),
+ check_appup(NokVsns,UpFrom,error),
+ check_appup(NokVsns,DownTo,error),
+ ok.
+
+create_test_vsns(Current) ->
+ [XStr,YStr|Rest] = string:tokens(Current,"."),
+ X = list_to_integer(XStr),
+ Y = list_to_integer(YStr),
+ SecondMajor = vsn(X,Y-2),
+ SecondMinor = SecondMajor ++ ".1.3",
+ FirstMajor = vsn(X,Y-1),
+ FirstMinor = FirstMajor ++ ".57",
+ ThisMajor = vsn(X,Y),
+ This =
+ case Rest of
+ [] ->
+ [];
+ ["1"] ->
+ [ThisMajor];
+ _ ->
+ ThisMinor = ThisMajor ++ ".1",
+ [ThisMajor,ThisMinor]
+ end,
+ OkVsns = This ++ [FirstMajor, FirstMinor, SecondMajor, SecondMinor],
+
+ ThirdMajor = vsn(X,Y-3),
+ ThirdMinor = ThirdMajor ++ ".10.12",
+ Illegal = ThisMajor ++ ",1",
+ Newer1Major = vsn(X,Y+1),
+ Newer1Minor = Newer1Major ++ ".1",
+ Newer2Major = ThisMajor ++ "1",
+ NokVsns = [ThirdMajor,ThirdMinor,
+ Illegal,
+ Newer1Major,Newer1Minor,
+ Newer2Major],
+ {OkVsns,NokVsns}.
+
+vsn(X,Y) ->
+ integer_to_list(X) ++ "." ++ integer_to_list(Y).
+
+check_appup([Vsn|Vsns],Instrs,Expected) ->
+ case systools_relup:appup_search_for_version(Vsn, Instrs) of
+ Expected -> check_appup(Vsns,Instrs,Expected);
+ Other -> ct:fail({unexpected_result_for_vsn,Vsn,Other})
+ end;
+check_appup([],_,_) ->
+ ok.
diff --git a/lib/stdlib/test/supervisor_1.erl b/lib/stdlib/test/supervisor_1.erl
index 3198be0fed..f819594c46 100644
--- a/lib/stdlib/test/supervisor_1.erl
+++ b/lib/stdlib/test/supervisor_1.erl
@@ -62,6 +62,12 @@ handle_info(die, State) ->
handle_info(stop, State) ->
{stop, normal, State};
+handle_info({'EXIT',_,shutdown}, State) ->
+ {stop, shutdown, State};
+
+handle_info({'EXIT',_,{shutdown,Term}}, State) ->
+ {stop, {shutdown,Term}, State};
+
handle_info({sleep, Time}, State) ->
io:format("FOO: ~p~n", [Time]),
timer:sleep(Time),
diff --git a/lib/stdlib/test/supervisor_2.erl b/lib/stdlib/test/supervisor_2.erl
new file mode 100644
index 0000000000..67aacf5a9c
--- /dev/null
+++ b/lib/stdlib/test/supervisor_2.erl
@@ -0,0 +1,42 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 1996-2010. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+%% Description: Simulates the behaviour that a child process may have.
+%% Is used by the supervisor_SUITE test suite.
+-module(supervisor_2).
+
+-export([start_child/1, init/1]).
+
+-export([handle_call/3, handle_info/2, terminate/2]).
+
+start_child(Time) when is_integer(Time), Time > 0 ->
+ gen_server:start_link(?MODULE, Time, []).
+
+init(Time) ->
+ process_flag(trap_exit, true),
+ {ok, Time}.
+
+handle_call(Req, _From, State) ->
+ {reply, Req, State}.
+
+handle_info(_, State) ->
+ {noreply, State}.
+
+terminate(_Reason, Time) ->
+ timer:sleep(Time),
+ ok.
diff --git a/lib/stdlib/test/supervisor_SUITE.erl b/lib/stdlib/test/supervisor_SUITE.erl
index fce89e2185..d3d140abbc 100644
--- a/lib/stdlib/test/supervisor_SUITE.erl
+++ b/lib/stdlib/test/supervisor_SUITE.erl
@@ -29,7 +29,8 @@
end_per_testcase/2]).
%% Internal export
--export([init/1, terminate_all_children/1]).
+-export([init/1, terminate_all_children/1,
+ middle9212/0, gen_server9212/0, handle_info/2]).
%% API tests
-export([ sup_start_normal/1, sup_start_ignore_init/1,
@@ -41,6 +42,8 @@
%% Tests concept permanent, transient and temporary
-export([ permanent_normal/1, transient_normal/1,
temporary_normal/1,
+ permanent_shutdown/1, transient_shutdown/1,
+ temporary_shutdown/1,
permanent_abnormal/1, transient_abnormal/1,
temporary_abnormal/1, temporary_bystander/1]).
@@ -50,13 +53,14 @@
one_for_all_escalation/1,
simple_one_for_one/1, simple_one_for_one_escalation/1,
rest_for_one/1, rest_for_one_escalation/1,
- simple_one_for_one_extra/1]).
+ simple_one_for_one_extra/1, simple_one_for_one_shutdown/1]).
%% Misc tests
-export([child_unlink/1, tree/1, count_children_memory/1,
do_not_save_start_parameters_for_temporary_children/1,
do_not_save_child_specs_for_temporary_children/1,
- simple_one_for_one_scale_many_temporary_children/1]).
+ simple_one_for_one_scale_many_temporary_children/1,
+ simple_global_supervisor/1]).
%%-------------------------------------------------------------------------
@@ -71,10 +75,12 @@ all() ->
{group, restart_simple_one_for_one},
{group, restart_rest_for_one},
{group, normal_termination},
+ {group, shutdown_termination},
{group, abnormal_termination}, child_unlink, tree,
count_children_memory, do_not_save_start_parameters_for_temporary_children,
do_not_save_child_specs_for_temporary_children,
- simple_one_for_one_scale_many_temporary_children, temporary_bystander].
+ simple_one_for_one_scale_many_temporary_children, temporary_bystander,
+ simple_global_supervisor].
groups() ->
[{sup_start, [],
@@ -86,6 +92,8 @@ groups() ->
sup_stop_brutal_kill]},
{normal_termination, [],
[permanent_normal, transient_normal, temporary_normal]},
+ {shutdown_termination, [],
+ [permanent_shutdown, transient_shutdown, temporary_shutdown]},
{abnormal_termination, [],
[permanent_abnormal, transient_abnormal,
temporary_abnormal]},
@@ -94,8 +102,8 @@ groups() ->
{restart_one_for_all, [],
[one_for_all, one_for_all_escalation]},
{restart_simple_one_for_one, [],
- [simple_one_for_one, simple_one_for_one_extra,
- simple_one_for_one_escalation]},
+ [simple_one_for_one, simple_one_for_one_shutdown,
+ simple_one_for_one_extra, simple_one_for_one_escalation]},
{restart_rest_for_one, [],
[rest_for_one, rest_for_one_escalation]}].
@@ -209,8 +217,8 @@ sup_start_fail(Config) when is_list(Config) ->
%%-------------------------------------------------------------------------
sup_stop_infinity(doc) ->
- ["See sup_stop/1 when Shutdown = infinity, this walue is only allowed "
- "for children of type supervisor"];
+ ["See sup_stop/1 when Shutdown = infinity, this walue is allowed "
+ "for children of type supervisor _AND_ worker"];
sup_stop_infinity(suite) -> [];
sup_stop_infinity(Config) when is_list(Config) ->
@@ -221,12 +229,13 @@ sup_stop_infinity(Config) when is_list(Config) ->
Child2 = {child2, {supervisor_1, start_child, []}, permanent,
infinity, worker, []},
{ok, CPid1} = supervisor:start_child(sup_test, Child1),
+ {ok, CPid2} = supervisor:start_child(sup_test, Child2),
link(CPid1),
- {error, {invalid_shutdown,infinity}} =
- supervisor:start_child(sup_test, Child2),
+ link(CPid2),
terminate(Pid, shutdown),
- check_exit_reason(CPid1, shutdown).
+ check_exit_reason(CPid1, shutdown),
+ check_exit_reason(CPid2, shutdown).
%%-------------------------------------------------------------------------
@@ -458,9 +467,8 @@ child_specs(Config) when is_list(Config) ->
B2 = {child, {m,f,[a]}, prmanent, 1000, worker, []},
B3 = {child, {m,f,[a]}, permanent, -10, worker, []},
B4 = {child, {m,f,[a]}, permanent, 10, wrker, []},
- B5 = {child, {m,f,[a]}, permanent, infinity, worker, []},
- B6 = {child, {m,f,[a]}, permanent, 1000, worker, dy},
- B7 = {child, {m,f,[a]}, permanent, 1000, worker, [1,2,3]},
+ B5 = {child, {m,f,[a]}, permanent, 1000, worker, dy},
+ B6 = {child, {m,f,[a]}, permanent, 1000, worker, [1,2,3]},
%% Correct child specs!
%% <Modules> (last parameter in a child spec) can be [] as we do
@@ -469,6 +477,7 @@ child_specs(Config) when is_list(Config) ->
C2 = {child, {m,f,[a]}, permanent, 1000, supervisor, []},
C3 = {child, {m,f,[a]}, temporary, 1000, worker, dynamic},
C4 = {child, {m,f,[a]}, transient, 1000, worker, [m]},
+ C5 = {child, {m,f,[a]}, permanent, infinity, worker, [m]},
{error, {invalid_mfa,mfa}} = supervisor:start_child(sup_test, B1),
{error, {invalid_restart_type, prmanent}} =
@@ -477,9 +486,8 @@ child_specs(Config) when is_list(Config) ->
= supervisor:start_child(sup_test, B3),
{error, {invalid_child_type,wrker}}
= supervisor:start_child(sup_test, B4),
- {error, _} = supervisor:start_child(sup_test, B5),
{error, {invalid_modules,dy}}
- = supervisor:start_child(sup_test, B6),
+ = supervisor:start_child(sup_test, B5),
{error, {invalid_mfa,mfa}} = supervisor:check_childspecs([B1]),
{error, {invalid_restart_type,prmanent}} =
@@ -487,15 +495,15 @@ child_specs(Config) when is_list(Config) ->
{error, {invalid_shutdown,-10}} = supervisor:check_childspecs([B3]),
{error, {invalid_child_type,wrker}}
= supervisor:check_childspecs([B4]),
- {error, _} = supervisor:check_childspecs([B5]),
- {error, {invalid_modules,dy}} = supervisor:check_childspecs([B6]),
+ {error, {invalid_modules,dy}} = supervisor:check_childspecs([B5]),
{error, {invalid_module, 1}} =
- supervisor:check_childspecs([B7]),
+ supervisor:check_childspecs([B6]),
ok = supervisor:check_childspecs([C1]),
ok = supervisor:check_childspecs([C2]),
ok = supervisor:check_childspecs([C3]),
ok = supervisor:check_childspecs([C4]),
+ ok = supervisor:check_childspecs([C5]),
ok.
%%-------------------------------------------------------------------------
@@ -554,6 +562,87 @@ temporary_normal(Config) when is_list(Config) ->
[0,0,0,0] = get_child_counts(sup_test).
%%-------------------------------------------------------------------------
+permanent_shutdown(doc) ->
+ ["A permanent child should always be restarted"];
+permanent_shutdown(suite) -> [];
+permanent_shutdown(Config) when is_list(Config) ->
+ {ok, SupPid} = start_link({ok, {{one_for_one, 2, 3600}, []}}),
+ Child1 = {child1, {supervisor_1, start_child, []}, permanent, 1000,
+ worker, []},
+
+ {ok, CPid1} = supervisor:start_child(sup_test, Child1),
+
+ terminate(SupPid, CPid1, child1, shutdown),
+
+ [{child1, CPid2 ,worker,[]}] = supervisor:which_children(sup_test),
+ case is_pid(CPid2) of
+ true ->
+ ok;
+ false ->
+ test_server:fail({permanent_child_not_restarted, Child1})
+ end,
+ [1,1,0,1] = get_child_counts(sup_test),
+
+ terminate(SupPid, CPid2, child1, {shutdown, some_info}),
+
+ [{child1, CPid3 ,worker,[]}] = supervisor:which_children(sup_test),
+ case is_pid(CPid3) of
+ true ->
+ ok;
+ false ->
+ test_server:fail({permanent_child_not_restarted, Child1})
+ end,
+
+ [1,1,0,1] = get_child_counts(sup_test).
+
+%%-------------------------------------------------------------------------
+transient_shutdown(doc) ->
+ ["A transient child should not be restarted if it exits with "
+ "reason shutdown or {shutdown,Term}"];
+transient_shutdown(suite) -> [];
+transient_shutdown(Config) when is_list(Config) ->
+ {ok, SupPid} = start_link({ok, {{one_for_one, 2, 3600}, []}}),
+ Child1 = {child1, {supervisor_1, start_child, []}, transient, 1000,
+ worker, []},
+
+ {ok, CPid1} = supervisor:start_child(sup_test, Child1),
+
+ terminate(SupPid, CPid1, child1, shutdown),
+
+ [{child1,undefined,worker,[]}] = supervisor:which_children(sup_test),
+ [1,0,0,1] = get_child_counts(sup_test),
+
+ {ok, CPid2} = supervisor:restart_child(sup_test, child1),
+
+ terminate(SupPid, CPid2, child1, {shutdown, some_info}),
+
+ [{child1,undefined,worker,[]}] = supervisor:which_children(sup_test),
+ [1,0,0,1] = get_child_counts(sup_test).
+
+%%-------------------------------------------------------------------------
+temporary_shutdown(doc) ->
+ ["A temporary process should never be restarted"];
+temporary_shutdown(suite) -> [];
+temporary_shutdown(Config) when is_list(Config) ->
+ {ok, SupPid} = start_link({ok, {{one_for_one, 2, 3600}, []}}),
+ Child1 = {child1, {supervisor_1, start_child, []}, temporary, 1000,
+ worker, []},
+
+ {ok, CPid1} = supervisor:start_child(sup_test, Child1),
+
+ terminate(SupPid, CPid1, child1, shutdown),
+
+ [] = supervisor:which_children(sup_test),
+ [0,0,0,0] = get_child_counts(sup_test),
+
+ {ok, CPid2} = supervisor:start_child(sup_test, Child1),
+
+ terminate(SupPid, CPid2, child1, {shutdown, some_info}),
+
+ [] = supervisor:which_children(sup_test),
+ [0,0,0,0] = get_child_counts(sup_test).
+
+%%-------------------------------------------------------------------------
permanent_abnormal(doc) ->
["A permanent child should always be restarted"];
permanent_abnormal(suite) -> [];
@@ -787,6 +876,38 @@ simple_one_for_one(Config) when is_list(Config) ->
terminate(SupPid, Pid4, Id4, abnormal),
check_exit([SupPid]).
+
+%%-------------------------------------------------------------------------
+simple_one_for_one_shutdown(doc) ->
+ ["Test simple_one_for_one children shutdown accordingly to the "
+ "supervisor's shutdown strategy."];
+simple_one_for_one_shutdown(suite) -> [];
+simple_one_for_one_shutdown(Config) when is_list(Config) ->
+ process_flag(trap_exit, true),
+ ShutdownTime = 1000,
+ Child = {child, {supervisor_2, start_child, []},
+ permanent, 2*ShutdownTime, worker, []},
+ {ok, SupPid} = start_link({ok, {{simple_one_for_one, 2, 3600}, [Child]}}),
+
+ %% Will be gracefully shutdown
+ {ok, _CPid1} = supervisor:start_child(sup_test, [ShutdownTime]),
+ {ok, _CPid2} = supervisor:start_child(sup_test, [ShutdownTime]),
+
+ %% Will be killed after 2*ShutdownTime milliseconds
+ {ok, _CPid3} = supervisor:start_child(sup_test, [5*ShutdownTime]),
+
+ {T, ok} = timer:tc(fun terminate/2, [SupPid, shutdown]),
+ if T < 1000*ShutdownTime ->
+ %% Because supervisor's children wait before exiting, it can't
+ %% terminate quickly
+ test_server:fail({shutdown_too_short, T});
+ T >= 1000*5*ShutdownTime ->
+ test_server:fail({shutdown_too_long, T});
+ true ->
+ check_exit([SupPid])
+ end.
+
+
%%-------------------------------------------------------------------------
simple_one_for_one_extra(doc) ->
["Tests automatic restart of children "
@@ -1270,6 +1391,92 @@ terminate_all_children([]) ->
done.
+%%-------------------------------------------------------------------------
+%% OTP-9212. Restart of global supervisor.
+simple_global_supervisor(_Config) ->
+ kill_supervisor(),
+ kill_worker(),
+ exit_worker(),
+ restart_worker(),
+ ok.
+
+kill_supervisor() ->
+ {Top, Sup2_1, Server_1} = start9212(),
+
+ %% Killing a supervisor isn't really supported, but try it anyway...
+ exit(Sup2_1, kill),
+ timer:sleep(200),
+ Sup2_2 = global:whereis_name(sup2),
+ Server_2 = global:whereis_name(server),
+ true = is_pid(Sup2_2),
+ true = is_pid(Server_2),
+ true = Sup2_1 =/= Sup2_2,
+ true = Server_1 =/= Server_2,
+
+ stop9212(Top).
+
+handle_info({fail, With, After}, _State) ->
+ timer:sleep(After),
+ erlang:error(With).
+
+kill_worker() ->
+ {Top, _Sup2, Server_1} = start9212(),
+ exit(Server_1, kill),
+ timer:sleep(200),
+ Server_2 = global:whereis_name(server),
+ true = is_pid(Server_2),
+ true = Server_1 =/= Server_2,
+ stop9212(Top).
+
+exit_worker() ->
+ %% Very much the same as kill_worker().
+ {Top, _Sup2, Server_1} = start9212(),
+ Server_1 ! {fail, normal, 0},
+ timer:sleep(200),
+ Server_2 = global:whereis_name(server),
+ true = is_pid(Server_2),
+ true = Server_1 =/= Server_2,
+ stop9212(Top).
+
+restart_worker() ->
+ {Top, _Sup2, Server_1} = start9212(),
+ ok = supervisor:terminate_child({global, sup2}, child),
+ {ok, _Child} = supervisor:restart_child({global, sup2}, child),
+ Server_2 = global:whereis_name(server),
+ true = is_pid(Server_2),
+ true = Server_1 =/= Server_2,
+ stop9212(Top).
+
+start9212() ->
+ Middle = {middle,{?MODULE,middle9212,[]}, permanent,2000,supervisor,[]},
+ InitResult = {ok, {{one_for_all,3,60}, [Middle]}},
+ {ok, TopPid} = start_link(InitResult),
+
+ Sup2 = global:whereis_name(sup2),
+ Server = global:whereis_name(server),
+ true = is_pid(Sup2),
+ true = is_pid(Server),
+ {TopPid, Sup2, Server}.
+
+stop9212(Top) ->
+ Old = process_flag(trap_exit, true),
+ exit(Top, kill),
+ timer:sleep(200),
+ undefined = global:whereis_name(sup2),
+ undefined = global:whereis_name(server),
+ check_exit([Top]),
+ _ = process_flag(trap_exit, Old),
+ ok.
+
+middle9212() ->
+ Child = {child, {?MODULE,gen_server9212,[]},permanent, 2000, worker, []},
+ InitResult = {ok, {{one_for_all,3,60}, [Child]}},
+ supervisor:start_link({global,sup2}, ?MODULE, InitResult).
+
+gen_server9212() ->
+ InitResult = {ok, []},
+ gen_server:start_link({global,server}, ?MODULE, InitResult, []).
+
%%-------------------------------------------------------------------------
terminate(Pid, Reason) when Reason =/= supervisor ->
@@ -1291,6 +1498,13 @@ terminate(_, ChildPid, _, shutdown) ->
{'DOWN', Ref, process, ChildPid, shutdown} ->
ok
end;
+terminate(_, ChildPid, _, {shutdown, Term}) ->
+ Ref = erlang:monitor(process, ChildPid),
+ exit(ChildPid, {shutdown, Term}),
+ receive
+ {'DOWN', Ref, process, ChildPid, {shutdown, Term}} ->
+ ok
+ end;
terminate(_, ChildPid, _, normal) ->
Ref = erlang:monitor(process, ChildPid),
ChildPid ! stop,
diff --git a/lib/stdlib/test/supervisor_bridge_SUITE.erl b/lib/stdlib/test/supervisor_bridge_SUITE.erl
index c4d696564d..b3056ff41a 100644
--- a/lib/stdlib/test/supervisor_bridge_SUITE.erl
+++ b/lib/stdlib/test/supervisor_bridge_SUITE.erl
@@ -19,8 +19,9 @@
-module(supervisor_bridge_SUITE).
-export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1,
init_per_group/2,end_per_group/2,starting/1,
- mini_terminate/1,mini_die/1,badstart/1]).
--export([client/1,init/1,internal_loop_init/1,terminate/2]).
+ mini_terminate/1,mini_die/1,badstart/1,
+ simple_global_supervisor/1]).
+-export([client/1,init/1,internal_loop_init/1,terminate/2,server9212/0]).
-include_lib("test_server/include/test_server.hrl").
-define(bridge_name,supervisor_bridge_SUITE_server).
@@ -31,7 +32,7 @@
suite() -> [{ct_hooks,[ts_install_cth]}].
all() ->
- [starting, mini_terminate, mini_die, badstart].
+ [starting, mini_terminate, mini_die, badstart, simple_global_supervisor].
groups() ->
[].
@@ -138,7 +139,9 @@ init(3) ->
receive
{InternalPid,init_done} ->
{ok,InternalPid,self()}
- end.
+ end;
+init({4,Result}) ->
+ Result.
internal_loop_init(Parent) ->
register(?work_bridge_name, self()),
@@ -160,7 +163,9 @@ terminate(Reason,{Parent,Worker}) ->
io:format("Terminating bridge...\n"),
exit(Worker,kill),
Parent ! {dying,Reason},
- anything.
+ anything;
+terminate(_Reason, _State) ->
+ any.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -197,3 +202,30 @@ badstart(Config) when is_list(Config) ->
ok.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% OTP-9212. Restart of global supervisor.
+
+simple_global_supervisor(suite) -> [];
+simple_global_supervisor(doc) -> "Globally registered supervisor.";
+simple_global_supervisor(Config) when is_list(Config) ->
+ ?line Dog = test_server:timetrap({seconds,10}),
+
+ Child = {child, {?MODULE,server9212,[]}, permanent, 2000, worker, []},
+ InitResult = {ok, {{one_for_all,3,60}, [Child]}},
+ {ok, Sup} =
+ supervisor:start_link({local,bridge9212}, ?MODULE, {4,InitResult}),
+
+ BN_1 = global:whereis_name(?bridge_name),
+ ?line exit(BN_1, kill),
+ timer:sleep(200),
+ BN_2 = global:whereis_name(?bridge_name),
+ ?line true = is_pid(BN_2),
+ ?line true = BN_1 =/= BN_2,
+
+ ?line process_flag(trap_exit, true),
+ exit(Sup, kill),
+ ?line receive {'EXIT', Sup, killed} -> ok end,
+ ?line test_server:timetrap_cancel(Dog),
+ ok.
+
+server9212() ->
+ supervisor_bridge:start_link({global,?bridge_name}, ?MODULE, 3).
diff --git a/lib/stdlib/test/tar_SUITE.erl b/lib/stdlib/test/tar_SUITE.erl
index 9ad3936928..65ccdcb7a8 100644
--- a/lib/stdlib/test/tar_SUITE.erl
+++ b/lib/stdlib/test/tar_SUITE.erl
@@ -533,7 +533,7 @@ symlinks(Config) when is_list(Config) ->
?line ok = file:make_dir(Dir),
?line ABadSymlink = filename:join(Dir, "bad_symlink"),
?line PointsTo = "/a/definitely/non_existing/path",
- ?line Res = case file:make_symlink("/a/definitely/non_existing/path", ABadSymlink) of
+ ?line Res = case make_symlink("/a/definitely/non_existing/path", ABadSymlink) of
{error, enotsup} ->
{skip, "Symbolic links not supported on this platform"};
ok ->
@@ -544,7 +544,30 @@ symlinks(Config) when is_list(Config) ->
%% Clean up.
?line delete_files([Dir]),
Res.
-
+
+make_symlink(Path, Link) ->
+ case os:type() of
+ {win32,_} ->
+ %% Symlinks on Windows have two problems:
+ %% 1) file:read_link_info/1 cannot read out the target
+ %% of the symlink if the target does not exist.
+ %% That is possible (but not easy) to fix in the
+ %% efile driver.
+ %%
+ %% 2) Symlinks to files and directories are different
+ %% creatures. If the target is not existing, the
+ %% symlink will be created to be of the file-pointing
+ %% type. That can be partially worked around in erl_tar
+ %% by creating all symlinks when the end of the tar
+ %% file has been reached.
+ %%
+ %% But for now, pretend that there are no symlinks on
+ %% Windows.
+ {error, enotsup};
+ _ ->
+ file:make_symlink(Path, Link)
+ end.
+
symlinks(Dir, BadSymlink, PointsTo) ->
?line Tar = filename:join(Dir, "symlink.tar"),
?line DerefTar = filename:join(Dir, "dereference.tar"),
diff --git a/lib/stdlib/test/unicode_SUITE.erl b/lib/stdlib/test/unicode_SUITE.erl
index 9aa800209d..4055af2741 100644
--- a/lib/stdlib/test/unicode_SUITE.erl
+++ b/lib/stdlib/test/unicode_SUITE.erl
@@ -322,7 +322,7 @@ roundtrips(Config) when is_list(Config) ->
ex_roundtrips(Config) when is_list(Config) ->
?line L1 = ranges(0, 16#D800 - 1,
erlang:system_info(context_reductions) * 11),
- ?line L2 = ranges(16#DFFF + 1, 16#FFFE - 1,
+ ?line L2 = ranges(16#DFFF + 1, 16#10000 - 1,
erlang:system_info(context_reductions) * 11),
%?line L3 = ranges(16#FFFF + 1, 16#10FFFF,
% erlang:system_info(context_reductions) * 11),
@@ -569,7 +569,6 @@ utf16_illegal_sequences_bif(Config) when is_list(Config) ->
ex_utf16_illegal_sequences_bif(Config) when is_list(Config) ->
?line utf16_fail_range_bif_simple(16#10FFFF+1, 16#10FFFF+512), %Too large.
?line utf16_fail_range_bif(16#D800, 16#DFFF), %Reserved for UTF-16.
- ?line utf16_fail_range_bif(16#FFFE, 16#FFFF), %Non-characters.
?line lonely_hi_surrogate_bif(16#D800, 16#DBFF,incomplete),
?line lonely_hi_surrogate_bif(16#DC00, 16#DFFF,error),
@@ -644,7 +643,6 @@ utf8_illegal_sequences_bif(Config) when is_list(Config) ->
ex_utf8_illegal_sequences_bif(Config) when is_list(Config) ->
?line fail_range_bif(16#10FFFF+1, 16#10FFFF+512), %Too large.
?line fail_range_bif(16#D800, 16#DFFF), %Reserved for UTF-16.
- ?line fail_range_bif(16#FFFE, 16#FFFF), %Reserved (BOM).
%% Illegal first character.
?line [fail_bif(<<I,16#8F,16#8F,16#8F>>,unicode) || I <- lists:seq(16#80, 16#BF)],
diff --git a/lib/stdlib/vsn.mk b/lib/stdlib/vsn.mk
index 9d4ed17774..2f0ecd3863 100644
--- a/lib/stdlib/vsn.mk
+++ b/lib/stdlib/vsn.mk
@@ -1 +1 @@
-STDLIB_VSN = 1.17.5
+STDLIB_VSN = 1.18
diff --git a/lib/syntax_tools/doc/Makefile b/lib/syntax_tools/doc/Makefile
index 6afd16f669..d9981de880 100644
--- a/lib/syntax_tools/doc/Makefile
+++ b/lib/syntax_tools/doc/Makefile
@@ -78,12 +78,3 @@ release_docs_spec: docs
release_spec:
-
-
-
-# ----------------------------------------------------
-# Include dependency
-# ----------------------------------------------------
-#-include make.dep
-
-
diff --git a/lib/syntax_tools/doc/src/make.dep b/lib/syntax_tools/doc/src/make.dep
deleted file mode 100644
index acc76857bb..0000000000
--- a/lib/syntax_tools/doc/src/make.dep
+++ /dev/null
@@ -1,22 +0,0 @@
-# ----------------------------------------------------
-# >>>> Do not edit this file <<<<
-# This file was automaticly generated by
-# /home/otp/bin/docdepend
-# ----------------------------------------------------
-
-
-# ----------------------------------------------------
-# TeX files that the DVI file depend on
-# ----------------------------------------------------
-
-book.dvi: book.tex chapter.tex epp_dodger.tex erl_comment_scan.tex \
- erl_prettypr.tex erl_recomment.tex erl_syntax.tex \
- erl_syntax_lib.tex erl_tidy.tex igor.tex part.tex \
- prettypr.tex ref_man.tex
-
-# ----------------------------------------------------
-# Source inlined when transforming from source to LaTeX
-# ----------------------------------------------------
-
-book.tex: ref_man.xml
-
diff --git a/lib/syntax_tools/src/erl_syntax.erl b/lib/syntax_tools/src/erl_syntax.erl
index 9df5f26454..7f58fda519 100644
--- a/lib/syntax_tools/src/erl_syntax.erl
+++ b/lib/syntax_tools/src/erl_syntax.erl
@@ -6093,11 +6093,16 @@ implicit_fun_name(Node) ->
{'fun', Pos, {function, Atom, Arity}} ->
arity_qualifier(set_pos(atom(Atom), Pos),
set_pos(integer(Arity), Pos));
- {'fun', Pos, {function, Module, Atom, Arity}} ->
+ {'fun', Pos, {function, Module, Atom, Arity}}
+ when is_atom(Module), is_atom(Atom), is_integer(Arity) ->
+ %% Backward compatibility with pre-R15 abstract format.
module_qualifier(set_pos(atom(Module), Pos),
arity_qualifier(
set_pos(atom(Atom), Pos),
set_pos(integer(Arity), Pos)));
+ {'fun', Pos, {function, Module, Atom, Arity}} ->
+ %% New in R15: fun M:F/A.
+ module_qualifier(Module, arity_qualifier(Atom, Arity));
Node1 ->
data(Node1)
end.
diff --git a/lib/syntax_tools/src/erl_tidy.erl b/lib/syntax_tools/src/erl_tidy.erl
index 1cfdc7234a..09efc9c392 100644
--- a/lib/syntax_tools/src/erl_tidy.erl
+++ b/lib/syntax_tools/src/erl_tidy.erl
@@ -103,7 +103,7 @@ dir(Dir) ->
%% <dt>{regexp, string()}</dt>
%%
%% <dd>The value denotes a regular expression (see module
-%% `regexp'). Tidying will only be applied to those
+%% `re'). Tidying will only be applied to those
%% regular files whose names match this pattern. The default
%% value is `".*\\.erl$"', which matches normal
%% Erlang source file names.</dd>
@@ -124,7 +124,7 @@ dir(Dir) ->
%%
%% See the function {@link file/2} for further options.
%%
-%% @see //stdlib/regexp
+%% @see //stdlib/re
%% @see file/2
-record(dir, {follow_links = false :: boolean(),
diff --git a/lib/test_server/doc/src/Makefile b/lib/test_server/doc/src/Makefile
index c7ba415e5b..f0be284324 100644
--- a/lib/test_server/doc/src/Makefile
+++ b/lib/test_server/doc/src/Makefile
@@ -133,9 +133,3 @@ release_docs_spec: docs
release_spec:
release_tests_spec:
-
-# ----------------------------------------------------
-# Include dependency
-# ----------------------------------------------------
-
-include make.dep
diff --git a/lib/test_server/doc/src/make.dep b/lib/test_server/doc/src/make.dep
deleted file mode 100644
index ee9100bd08..0000000000
--- a/lib/test_server/doc/src/make.dep
+++ /dev/null
@@ -1,24 +0,0 @@
-# ----------------------------------------------------
-# >>>> Do not edit this file <<<<
-# This file was automaticly generated by
-# /home/otp/bin/docdepend
-# ----------------------------------------------------
-
-
-# ----------------------------------------------------
-# TeX files that the DVI file depend on
-# ----------------------------------------------------
-
-book.dvi: basics_chapter.tex book.tex example_chapter.tex \
- part.tex ref_man.tex run_test_chapter.tex \
- test_server_app.tex test_server_ctrl.tex \
- test_server.tex test_spec_chapter.tex \
- write_framework_chapter.tex \
- write_test_chapter.tex
-
-# ----------------------------------------------------
-# Source inlined when transforming from source to LaTeX
-# ----------------------------------------------------
-
-book.tex: ref_man.xml
-
diff --git a/lib/test_server/include/test_server.hrl b/lib/test_server/include/test_server.hrl
index 4b96d84ace..36e7e1f83d 100644
--- a/lib/test_server/include/test_server.hrl
+++ b/lib/test_server/include/test_server.hrl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2009. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2011. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -20,11 +20,10 @@
-ifdef(line_trace).
-line_trace(true).
-define(line,
- put(test_server_loc,{?MODULE,?LINE}),
io:format(lists:concat([?MODULE,",",integer_to_list(?LINE),": ~p"]),
[erlang:now()]),).
-else.
--define(line,put(test_server_loc,{?MODULE,?LINE}),).
+-define(line,).
-endif.
-define(t,test_server).
-define(config,test_server:lookup_config).
diff --git a/lib/test_server/include/test_server_line.hrl b/lib/test_server/include/test_server_line.hrl
index 60ef860883..3c309d3ee5 100644
--- a/lib/test_server/include/test_server_line.hrl
+++ b/lib/test_server/include/test_server_line.hrl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2009. All Rights Reserved.
+%% Copyright Ericsson AB 2004-2011. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -16,5 +16,4 @@
%%
%% %CopyrightEnd%
%%
--compile({parse_transform,test_server_line}).
diff --git a/lib/test_server/src/Makefile b/lib/test_server/src/Makefile
index 63a585d526..4bc51873c2 100644
--- a/lib/test_server/src/Makefile
+++ b/lib/test_server/src/Makefile
@@ -43,7 +43,6 @@ MODULES= test_server_ctrl \
test_server_node \
test_server \
test_server_sup \
- test_server_line \
test_server_h \
erl2html2 \
vxworks_client
diff --git a/lib/test_server/src/erl2html2.erl b/lib/test_server/src/erl2html2.erl
index c94d4627f9..e2fd951d9e 100644
--- a/lib/test_server/src/erl2html2.erl
+++ b/lib/test_server/src/erl2html2.erl
@@ -32,32 +32,34 @@
%--------------------------------------------------------------------
-module(erl2html2).
--export([convert/2]).
+-export([convert/2, convert/3]).
convert([], _Dest) -> % Fake clause.
ok;
convert(File, Dest) ->
+ %% The generated code uses the BGCOLOR attribute in the
+ %% BODY tag, which wasn't valid until HTML 3.2. Also,
+ %% good HTML should either override all colour attributes
+ %% or none of them -- *never* just a few.
+ %%
+ %% FIXME: The colours should *really* be set with
+ %% stylesheets...
+ Header = ["<!DOCTYPE HTML PUBLIC "
+ "\"-//W3C//DTD HTML 3.2 Final//EN\">\n"
+ "<!-- autogenerated by '"++atom_to_list(?MODULE)++"'. -->\n"
+ "<html>\n"
+ "<head><title>", File, "</title></head>\n\n"
+ "<body bgcolor=\"white\" text=\"black\""
+ " link=\"blue\" vlink=\"purple\" alink=\"red\">\n"],
+ convert(File, Dest, Header).
+
+convert(File, Dest, Header) ->
case file:read_file(File) of
{ok, Bin} ->
Code=binary_to_list(Bin),
statistics(runtime),
- %% The generated code uses the BGCOLOR attribute in the
- %% BODY tag, which wasn't valid until HTML 3.2. Also,
- %% good HTML should either override all colour attributes
- %% or none of them -- *never* just a few.
- %%
- %% FIXME: The colours should *really* be set with
- %% stylesheets...
- Html0
- = ["<!DOCTYPE HTML PUBLIC "
- "\"-//W3C//DTD HTML 3.2 Final//EN\">\n"
- "<!-- autogenerated by '"++atom_to_list(?MODULE)++"'. -->\n"
- "<html>\n"
- "<head><title>", File, "</title></head>\n\n"
- "<body bgcolor=\"white\" text=\"black\""
- " link=\"blue\" vlink=\"purple\" alink=\"red\">\n"],
{Html1, Lines} = root(Code, [], 1),
- Html = [Html0,
+ Html = [Header,
"<pre>\n", Html1, "</pre>\n",
footer(Lines),"</body>\n</html>\n"],
file:write_file(Dest, Html);
@@ -173,10 +175,11 @@ linenum(Line) ->
end,
[A,Pred,integer_to_list(Line),":"].
-footer(Lines) ->
- {_, Time} = statistics(runtime),
-% io:format("Converted ~p lines in ~.2f Seconds.~n",
-% [Lines, Time/1000]),
- S = "<i>The transformation of this file (~p lines) took ~.2f seconds</i>",
- F = lists:flatten(io_lib:format(S, [Lines, Time/1000])),
- ["<hr size=1>",F,"<br>\n"].
+footer(_Lines) ->
+ "".
+%% {_, Time} = statistics(runtime),
+%% io:format("Converted ~p lines in ~.2f Seconds.~n",
+%% [Lines, Time/1000]),
+%% S = "<i>The transformation of this file (~p lines) took ~.2f seconds</i>",
+%% F = lists:flatten(io_lib:format(S, [Lines, Time/1000])),
+%% ["<hr size=1>",F,"<br>\n"].
diff --git a/lib/test_server/src/test_server.app.src b/lib/test_server/src/test_server.app.src
index af2d4dc2cb..7e87583a7b 100644
--- a/lib/test_server/src/test_server.app.src
+++ b/lib/test_server/src/test_server.app.src
@@ -24,7 +24,6 @@
test_server_ctrl,
test_server,
test_server_h,
- test_server_line,
test_server_node,
test_server_sup
]},
diff --git a/lib/test_server/src/test_server.erl b/lib/test_server/src/test_server.erl
index 244207e140..743e6c1d29 100644
--- a/lib/test_server/src/test_server.erl
+++ b/lib/test_server/src/test_server.erl
@@ -611,6 +611,7 @@ do_run_test_case_apply(Mod, Func, Args, Name, RunInit, TimetrapData) ->
print(minor, "Test case started with:\n~s:~s(~p)\n", [Mod,Func,Args2Print]),
print(minor, "Current directory is ~p\n", [Cwd]),
print_timestamp(minor,"Started at "),
+ print(minor, "", []),
TCCallback = get(test_server_testcase_callback),
LogOpts = get(test_server_logopts),
Ref = make_ref(),
@@ -768,7 +769,6 @@ run_test_case_msgloop(Ref, Pid, CaptureStdout, Terminate, Comment, CurrConf) ->
run_test_case_msgloop(Ref,Pid,CaptureStdout,Terminate,
Comment,undefined);
Loc1 ->
- {Mod,Func} = get_mf(Loc1),
%% call end_per_testcase on a separate process,
%% only so that the user has a chance to clean up
%% after init_per_testcase, even after a timetrap timeout
@@ -784,6 +784,7 @@ run_test_case_msgloop(Ref, Pid, CaptureStdout, Terminate, Comment, CurrConf) ->
TVal),
{EndConfPid,{Mod,Func},Conf};
_ ->
+ {Mod,Func} = get_mf(Loc1),
%% The framework functions mustn't execute on this
%% group leader process or io will cause deadlock,
%% so we spawn a dedicated process for the operation
@@ -821,7 +822,6 @@ run_test_case_msgloop(Ref, Pid, CaptureStdout, Terminate, Comment, CurrConf) ->
run_test_case_msgloop(Ref,Pid,CaptureStdout,Terminate,
Comment,undefined);
Loc1 ->
- {Mod,Func} = get_mf(Loc1),
%% call end_per_testcase on a separate process, only so
%% that the user has a chance to clean up after init_per_testcase,
%% even after abortion
@@ -839,6 +839,7 @@ run_test_case_msgloop(Ref, Pid, CaptureStdout, Terminate, Comment, CurrConf) ->
TVal),
{EndConfPid,{Mod,Func},Conf};
_ ->
+ {Mod,Func} = get_mf(Loc1),
spawn_fw_call(Mod,Func,CurrConf,Pid,ErrorMsg,
Loc1,self(),Comment),
undefined
@@ -1388,57 +1389,62 @@ init_per_testcase(Mod, Func, Args) ->
false -> code:load_file(Mod);
_ -> ok
end,
- %% init_per_testcase defined, returns new configuration
- case erlang:function_exported(Mod,init_per_testcase,2) of
+ case erlang:function_exported(Mod, init_per_testcase, 2) of
true ->
- case catch my_apply(Mod, init_per_testcase, [Func|Args]) of
- {'$test_server_ok',{Skip,Reason}} when Skip==skip;
- Skip==skipped ->
- {skip,Reason};
- {'$test_server_ok',Res={skip_and_save,_,_}} ->
- Res;
- {'$test_server_ok',NewConf} when is_list(NewConf) ->
- case lists:filter(fun(T) when is_tuple(T) -> false;
- (_) -> true end, NewConf) of
- [] ->
- {ok,NewConf};
- Bad ->
- group_leader() ! {printout,12,
- "ERROR! init_per_testcase has returned "
- "bad elements in Config: ~p\n",[Bad]},
- {skip,{failed,{Mod,init_per_testcase,bad_return}}}
- end;
- {'$test_server_ok',Res={fail,_Reason}} ->
- Res;
- {'$test_server_ok',_Other} ->
- group_leader() ! {printout,12,
- "ERROR! init_per_testcase did not return "
- "a Config list.\n",[]},
- {skip,{failed,{Mod,init_per_testcase,bad_return}}};
- {'EXIT',Reason} ->
- Line = get_loc(),
- FormattedLoc = test_server_sup:format_loc(mod_loc(Line)),
- group_leader() ! {printout,12,
- "ERROR! init_per_testcase crashed!\n"
- "\tLocation: ~s\n\tReason: ~p\n",
- [FormattedLoc,Reason]},
- {skip,{failed,{Mod,init_per_testcase,Reason}}};
- Other ->
- Line = get_loc(),
- FormattedLoc = test_server_sup:format_loc(mod_loc(Line)),
- group_leader() ! {printout,12,
- "ERROR! init_per_testcase thrown!\n"
- "\tLocation: ~s\n\tReason: ~p\n",
- [FormattedLoc, Other]},
- {skip,{failed,{Mod,init_per_testcase,Other}}}
- end;
+ do_init_per_testcase(Mod, [Func|Args]);
false ->
-%% Optional init_per_testcase not defined
-%% keep quiet.
+ %% Optional init_per_testcase is not defined -- keep quiet.
[Config] = Args,
{ok, Config}
end.
+do_init_per_testcase(Mod, Args) ->
+ try apply(Mod, init_per_testcase, Args) of
+ {Skip,Reason} when Skip =:= skip; Skip =:= skipped ->
+ {skip,Reason};
+ {skip_and_save,_,_}=Res ->
+ Res;
+ NewConf when is_list(NewConf) ->
+ case lists:filter(fun(T) when is_tuple(T) -> false;
+ (_) -> true end, NewConf) of
+ [] ->
+ {ok,NewConf};
+ Bad ->
+ group_leader() ! {printout,12,
+ "ERROR! init_per_testcase has returned "
+ "bad elements in Config: ~p\n",[Bad]},
+ {skip,{failed,{Mod,init_per_testcase,bad_return}}}
+ end;
+ {fail,_Reason}=Res ->
+ Res;
+ _Other ->
+ group_leader() ! {printout,12,
+ "ERROR! init_per_testcase did not return "
+ "a Config list.\n",[]},
+ {skip,{failed,{Mod,init_per_testcase,bad_return}}}
+ catch
+ throw:Other ->
+ set_loc(erlang:get_stacktrace()),
+ Line = get_loc(),
+ FormattedLoc = test_server_sup:format_loc(mod_loc(Line)),
+ group_leader() ! {printout,12,
+ "ERROR! init_per_testcase thrown!\n"
+ "\tLocation: ~s\n\tReason: ~p\n",
+ [FormattedLoc, Other]},
+ {skip,{failed,{Mod,init_per_testcase,Other}}};
+ _:Reason0 ->
+ Stk = erlang:get_stacktrace(),
+ Reason = {Reason0,Stk},
+ set_loc(Stk),
+ Line = get_loc(),
+ FormattedLoc = test_server_sup:format_loc(mod_loc(Line)),
+ group_leader() ! {printout,12,
+ "ERROR! init_per_testcase crashed!\n"
+ "\tLocation: ~s\n\tReason: ~p\n",
+ [FormattedLoc,Reason]},
+ {skip,{failed,{Mod,init_per_testcase,Reason}}}
+ end.
+
end_per_testcase(Mod, Func, Conf) ->
case erlang:function_exported(Mod,end_per_testcase,2) of
true ->
@@ -1456,65 +1462,87 @@ end_per_testcase(Mod, Func, Conf) ->
do_end_per_testcase(Mod,EndFunc,Func,Conf) ->
put(test_server_init_or_end_conf,{EndFunc,Func}),
put(test_server_loc, {Mod,{EndFunc,Func}}),
- case catch my_apply(Mod, EndFunc, [Func,Conf]) of
- {'$test_server_ok',SaveCfg={save_config,_}} ->
+ try Mod:EndFunc(Func, Conf) of
+ {save_config,_}=SaveCfg ->
SaveCfg;
- {'$test_server_ok',{fail,_}=Fail} ->
+ {fail,_}=Fail ->
Fail;
- {'$test_server_ok',_} ->
- ok;
- {'EXIT',Reason} = Why ->
+ _ ->
+ ok
+ catch
+ throw:Other ->
Comment0 = case read_comment() of
"" -> "";
Cmt -> Cmt ++ "<br>"
end,
+ set_loc(erlang:get_stacktrace()),
comment(io_lib:format("~s<font color=\"red\">"
- "WARNING: ~w crashed!"
+ "WARNING: ~w thrown!"
"</font>\n",[Comment0,EndFunc])),
group_leader() ! {printout,12,
- "WARNING: ~w crashed!\n"
+ "WARNING: ~w thrown!\n"
"Reason: ~p\n"
"Line: ~s\n",
- [EndFunc, Reason,
+ [EndFunc, Other,
test_server_sup:format_loc(
mod_loc(get_loc()))]},
- {failed,{Mod,end_per_testcase,Why}};
- Other ->
+ {failed,{Mod,end_per_testcase,Other}};
+ Class:Reason ->
+ Stk = erlang:get_stacktrace(),
+ set_loc(Stk),
+ Why = case Class of
+ exit -> {'EXIT',Reason};
+ error -> {'EXIT',{Reason,Stk}}
+ end,
Comment0 = case read_comment() of
"" -> "";
Cmt -> Cmt ++ "<br>"
end,
comment(io_lib:format("~s<font color=\"red\">"
- "WARNING: ~w thrown!"
+ "WARNING: ~w crashed!"
"</font>\n",[Comment0,EndFunc])),
group_leader() ! {printout,12,
- "WARNING: ~w thrown!\n"
+ "WARNING: ~w crashed!\n"
"Reason: ~p\n"
"Line: ~s\n",
- [EndFunc, Other,
+ [EndFunc, Reason,
test_server_sup:format_loc(
mod_loc(get_loc()))]},
- {failed,{Mod,end_per_testcase,Other}}
+ {failed,{Mod,end_per_testcase,Why}}
end.
get_loc() ->
- case catch test_server_line:get_lines() of
- [] ->
- get(test_server_loc);
- {'EXIT',_} ->
- get(test_server_loc);
- Loc ->
- Loc
- end.
+ get(test_server_loc).
get_loc(Pid) ->
- {dictionary,Dict} = process_info(Pid, dictionary),
- lists:foreach(fun({Key,Val}) -> put(Key,Val) end,Dict),
+ [{current_stacktrace,Stk0},{dictionary,Dict}] =
+ process_info(Pid, [current_stacktrace,dictionary]),
+ lists:foreach(fun({Key,Val}) -> put(Key, Val) end, Dict),
+ Stk = [rewrite_loc_item(Loc) || Loc <- Stk0],
+ put(test_server_loc, Stk),
get_loc().
-get_mf([{M,F,_}|_]) -> {M,F};
-get_mf([{M,F}|_]) -> {M,F};
-get_mf(_) -> {undefined,undefined}.
+%% find the latest known Suite:Testcase
+get_mf(MFs) ->
+ get_mf(MFs, {undefined,undefined}).
+
+get_mf([MF|MFs], _Found) when is_tuple(MF) ->
+ ModFunc = {Mod,_} = case MF of
+ {M,F,_} -> {M,F};
+ MF -> MF
+ end,
+ case is_suite(Mod) of
+ true -> ModFunc;
+ false -> get_mf(MFs, ModFunc)
+ end;
+get_mf(_, Found) ->
+ Found.
+
+is_suite(Mod) ->
+ case lists:reverse(atom_to_list(Mod)) of
+ "ETIUS" ++ _ -> true;
+ _ -> false
+ end.
mod_loc(Loc) ->
%% handle diff line num versions
@@ -1587,16 +1615,22 @@ lookup_config(Key,Config) ->
%% timer:tc/3
ts_tc(M, F, A) ->
Before = erlang:now(),
- Val = (catch my_apply(M, F, A)),
+ Result = try
+ apply(M, F, A)
+ catch
+ Type:Reason ->
+ Stk = erlang:get_stacktrace(),
+ set_loc(Stk),
+ case Type of
+ throw ->
+ {failed,{thrown,Reason}};
+ error ->
+ {'EXIT',{Reason,Stk}};
+ exit ->
+ {'EXIT',Reason}
+ end
+ end,
After = erlang:now(),
- Result = case Val of
- {'$test_server_ok', R} ->
- R; % test case ok
- {'EXIT',_Reason} = R ->
- R; % test case crashed
- Other ->
- {failed, {thrown,Other}} % test case was thrown
- end,
Elapsed =
(element(1,After)*1000000000000
+element(2,After)*1000000+element(3,After)) -
@@ -1604,8 +1638,12 @@ ts_tc(M, F, A) ->
+element(2,Before)*1000000+element(3,Before)),
{Elapsed, Result}.
-my_apply(M, F, A) ->
- {'$test_server_ok',apply(M, F, A)}.
+set_loc(Stk) ->
+ Loc = [rewrite_loc_item(I) || {_,_,_,_}=I <- Stk],
+ put(test_server_loc, Loc).
+
+rewrite_loc_item({M,F,_,Loc}) ->
+ {M,F,proplists:get_value(line, Loc, 0)}.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -1768,7 +1806,16 @@ adjusted_sleep(MSecs) ->
%% to read when using this function, rather than exit directly.
fail(Reason) ->
comment(cast_to_list(Reason)),
- exit({suite_failed,Reason}).
+ try
+ exit({suite_failed,Reason})
+ catch
+ Class:R ->
+ case erlang:get_stacktrace() of
+ [{?MODULE,fail,1,_}|Stk] -> ok;
+ Stk -> ok
+ end,
+ erlang:raise(Class, R, Stk)
+ end.
cast_to_list(X) when is_list(X) -> X;
cast_to_list(X) when is_atom(X) -> atom_to_list(X);
@@ -1782,7 +1829,16 @@ cast_to_list(X) -> lists:flatten(io_lib:format("~p", [X])).
%% Immediately calls exit. Included because test suites are easier
%% to read when using this function, rather than exit directly.
fail() ->
- exit(suite_failed).
+ try
+ exit(suite_failed)
+ catch
+ Class:R ->
+ case erlang:get_stacktrace() of
+ [{?MODULE,fail,0,_}|Stk] -> ok;
+ Stk -> ok
+ end,
+ erlang:raise(Class, R, Stk)
+ end.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% break(Comment) -> ok
diff --git a/lib/test_server/src/test_server_ctrl.erl b/lib/test_server/src/test_server_ctrl.erl
index 4fad86d16d..9fd0adbfc8 100644
--- a/lib/test_server/src/test_server_ctrl.erl
+++ b/lib/test_server/src/test_server_ctrl.erl
@@ -214,6 +214,9 @@
X == auto_skip -> skipped;
true -> X end).
+-define(auto_skip_color, "#FFA64D").
+-define(user_skip_color, "#FF8000").
+
-record(state,{jobs=[],levels={1,19,10},
multiply_timetraps=1,scale_timetraps=true,
finish=false,
@@ -1668,7 +1671,7 @@ do_test_cases(TopCases, SkipCases,
do_test_cases(TopCases, SkipCases,
Config, TimetrapData) when is_list(TopCases),
is_tuple(TimetrapData) ->
- start_log_file(),
+ {ok,TestDir} = start_log_file(),
FwMod =
case os:getenv("TEST_SERVER_FRAMEWORK") of
FW when FW =:= false; FW =:= "undefined" -> ?MODULE;
@@ -1692,60 +1695,86 @@ do_test_cases(TopCases, SkipCases,
[print_if_known(N, {", ~w test cases",[N]},
{" (with repeated test cases)",[]})]),
Test = get(test_server_name),
- test_server_sup:framework_call(report, [tests_start,{Test,N}]),
+ TestName = if is_list(Test) ->
+ lists:flatten(io_lib:format("~s", [Test]));
+ true ->
+ lists:flatten(io_lib:format("~p", [Test]))
+ end,
+ TestDescr = "Test " ++ TestName ++ " results",
- Header =
- case test_server_sup:framework_call(overview_html_header, [Test], "") of
- "" ->
- TestName = lists:flatten(io_lib:format("~p", [Test])),
- ["<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 3.2 Final//EN\">\n",
- "<!-- autogenerated by '", atom_to_list(?MODULE), "'. -->\n",
- "<html>\n",
- "<head><title>Test ", TestName, " results</title>\n",
- "<meta http-equiv=\"cache-control\" content=\"no-cache\">\n",
- "</head>\n",
- "<body bgcolor=\"white\" text=\"black\" ",
- "link=\"blue\" vlink=\"purple\" alink=\"red\">",
- "<h2>Results from test ", TestName, "</h2>\n"];
- Html ->
- ["<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 3.2 Final//EN\">\n",
- "<!-- autogenerated by '", atom_to_list(?MODULE), "'. -->\n" | Html]
+ test_server_sup:framework_call(report, [tests_start,{Test,N}]),
+ {Header,Footer} =
+ case test_server_sup:framework_call(get_html_wrapper,
+ [TestDescr,true,TestDir], "") of
+ Empty when (Empty == "") ; (element(2,Empty) == "") ->
+ put(basic_html, true),
+ {["<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 3.2 Final//EN\">\n",
+ "<!-- autogenerated by '", atom_to_list(?MODULE), "'. -->\n",
+ "<html>\n",
+ "<head><title>", TestDescr, "</title>\n",
+ "<meta http-equiv=\"cache-control\" content=\"no-cache\">\n",
+ "</head>\n",
+ "<body bgcolor=\"white\" text=\"black\" ",
+ "link=\"blue\" vlink=\"purple\" alink=\"red\">",
+ "<h2>Results for test ", TestName, "</h2>\n"],
+ "\n</body>\n</html>\n"};
+ {basic_html,Html0,Html1} ->
+ put(basic_html, true),
+ {Html0++["<h1>Results for <i>",TestName,"</i></h1>\n"],
+ Html1};
+ {xhtml,Html0,Html1} ->
+ put(basic_html, false),
+ {Html0++["<h1>Results for <i>",TestName,"</i></h1>\n"],
+ Html1}
end,
- print(html, Header, []),
- print_timestamp(html, "Test started at "),
- print(html, "<p>Host:<br>\n"),
+ print(html, Header),
+
+ print(html, xhtml("<p>", "<h4>")),
+ print_timestamp(html, "Test started at "),
+ print(html, xhtml("</p>", "</h4>")),
+
+ print(html, xhtml("\n<p><b>Host info:</b><br>\n",
+ "\n<p><b>Host info:</b><br />\n")),
print_who(test_server_sup:hoststr(), test_server_sup:get_username()),
- print(html, "<br>Used Erlang ~s in <tt>~s</tt>.\n",
+ print(html, xhtml("<br>Used Erlang v~s in <tt>~s</tt></p>\n",
+ "<br />Used Erlang v~s in \"~s\"</p>\n"),
[erlang:system_info(version), code:root_dir()]),
-
+
if FwMod == ?MODULE ->
- print(html, "<p>Target:<br>\n"),
+ print(html, xhtml("\n<p><b>Target Info:</b><br>\n",
+ "\n<p><b>Target Info:</b><br />\n")),
print_who(TI#target_info.host, TI#target_info.username),
- print(html, "<br>Used Erlang ~s in <tt>~s</tt>.\n",
+ print(html, xhtml("<br>Used Erlang v~s in <tt>~s</tt></p>\n",
+ "<br />Used Erlang v~s in \"~s\"</p>\n"),
[TI#target_info.version, TI#target_info.root_dir]);
- true ->
+ true ->
case test_server_sup:framework_call(target_info, []) of
TargetInfo when is_list(TargetInfo),
length(TargetInfo) > 0 ->
- print(html, "<p>Target:<br>\n"),
- print(html, "~s\n", [TargetInfo]);
+ print(html, xhtml("\n<p><b>Target info:</b><br>\n",
+ "\n<p><b>Target info:</b><br />\n")),
+ print(html, "~s</p>\n", [TargetInfo]);
_ ->
ok
end
end,
-
+
print(html,
- "<p><a href=\"~s\">Full textual log</a>\n"
- "<br><a href=\"~s\">Coverage log</a>\n",
+ "<p><ul>\n"
+ "<li><a href=\"~s\">Full textual log</a></li>\n"
+ "<li><a href=\"~s\">Coverage log</a></li>\n</ul></p>\n",
[?suitelog_name,?coverlog_name]),
- print(html,"<p>~s"
- "<p>\n"
- "<table bgcolor=\"white\" border=\"3\" cellpadding=\"5\">"
- "<tr><th>Num</th><th>Module</th><th>Case</th><th>Log</th>"
- "<th>Time</th><th>Result</th><th>Comment</th></tr>\n",
- [print_if_known(N, {"Suite contains ~p test cases.\n",[N]},
+ print(html,
+ "<p>~s</p>\n" ++
+ xhtml("<table bgcolor=\"white\" border=\"3\" cellpadding=\"5\">",
+ "<table>") ++
+ "<tr><th>Num</th><th>Module</th><th>Case</th><th>Log</th>"
+ "<th>Time</th><th>Result</th><th>Comment</th></tr>\n",
+ [print_if_known(N, {"<i>Executing <b>~p</b> test cases...</i>\n",[N]},
{"",[]})]),
+ print(html, xhtml("<br>", "<br />")),
+
print(major, "=cases ~p", [get(test_server_cases)]),
print(major, "=user ~s", [TI#target_info.username]),
print(major, "=host ~s", [TI#target_info.host]),
@@ -1764,6 +1793,9 @@ do_test_cases(TopCases, SkipCases,
print(major, "=otp_release ~s", [TI#target_info.otp_release]),
print(major, "=started ~s",
[lists:flatten(timestamp_get(""))]),
+
+ put(test_server_html_footer, Footer),
+
run_test_cases(TestSpec, Config, TimetrapData)
end;
@@ -1773,7 +1805,7 @@ do_test_cases(TopCase, SkipCases, Config, TimetrapSpec) ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% start_log_file() -> ok | exit({Error,Reason})
+%% start_log_file() -> {ok,TestDirName} | exit({Error,Reason})
%% Stem = string()
%%
%% Creates the log directories, the major log file and the html log file.
@@ -1824,7 +1856,7 @@ start_log_file() ->
LogInfo = [{topdir,Dir},{rundir,lists:flatten(TestDir)}],
test_server_sup:framework_call(report, [loginfo,LogInfo]),
- ok.
+ {ok,TestDir}.
make_html_link(LinkName, Target, Explanation) ->
%% if possible use a relative reference to Target.
@@ -1881,16 +1913,32 @@ start_minor_log_file1(Mod, Func, LogDir, AbsName) ->
{ok,Fd} = file:open(AbsName, [write]),
Lev = get(test_server_minor_level)+1000, %% far down in the minor levels
put(test_server_minor_fd, Fd),
- io:fwrite(Fd,
- "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 3.2 Final//EN\">\n"
- "<!-- autogenerated by '"++atom_to_list(?MODULE)++"'. -->\n"
- "<html>\n"
- "<head><title>"++cast_to_list(Mod)++"</title>\n"
- "<meta http-equiv=\"cache-control\" content=\"no-cache\">\n"
- "</head>\n"
- "<body bgcolor=\"white\" text=\"black\""
- " link=\"blue\" vlink=\"purple\" alink=\"red\">\n",
- []),
+
+ TestDescr = io_lib:format("Test ~p:~p result", [Mod,Func]),
+ {Header,Footer} =
+ case test_server_sup:framework_call(get_html_wrapper,
+ [TestDescr,false,
+ filename:dirname(AbsName)], "") of
+ Empty when (Empty == "") ; (element(2,Empty) == "") ->
+ put(basic_html, true),
+ {["<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 3.2 Final//EN\">\n",
+ "<!-- autogenerated by '", atom_to_list(?MODULE), "'. -->\n",
+ "<html>\n",
+ "<head><title>", TestDescr, "</title>\n",
+ "<meta http-equiv=\"cache-control\" content=\"no-cache\">\n",
+ "</head>\n",
+ "<body bgcolor=\"white\" text=\"black\" ",
+ "link=\"blue\" vlink=\"purple\" alink=\"red\">\n"],
+ "\n</body>\n</html>\n"};
+ {basic_html,Html0,Html1} ->
+ put(basic_html, true),
+ {Html0,Html1};
+ {xhtml,Html0,Html1} ->
+ put(basic_html, false),
+ {Html0,Html1}
+ end,
+ put(test_server_minor_footer, Footer),
+ io:fwrite(Fd, Header, []),
SrcListing = downcase(cast_to_list(Mod)) ++ ?src_listing_ext,
case {filelib:is_file(filename:join(LogDir, SrcListing)),
@@ -1913,7 +1961,8 @@ start_minor_log_file1(Mod, Func, LogDir, AbsName) ->
stop_minor_log_file() ->
Fd = get(test_server_minor_fd),
- io:fwrite(Fd, "</pre>\n</body>\n</html>\n", []),
+ Footer = get(test_server_minor_footer),
+ io:fwrite(Fd, "</pre>\n" ++ Footer, []),
file:close(Fd),
put(test_server_minor_fd, undefined).
@@ -1992,12 +2041,29 @@ html_convert_modules([]) -> ok.
%% Convert source code to HTML if possible and needed.
html_possibly_convert(Src, SrcInfo, Dest) ->
case file:read_file_info(Dest) of
- {error,_Reason} -> % no dest file
- erl2html2:convert(Src, Dest);
- {ok,DestInfo} when DestInfo#file_info.mtime < SrcInfo#file_info.mtime ->
- erl2html2:convert(Src, Dest);
- {ok,_DestInfo} ->
- ok % dest file up to date
+ {ok,DestInfo} when DestInfo#file_info.mtime >= SrcInfo#file_info.mtime ->
+ ok; % dest file up to date
+ _ ->
+ OutDir = get(test_server_log_dir_base),
+ Header =
+ case test_server_sup:framework_call(get_html_wrapper,
+ ["Module "++Src,false,
+ OutDir], "") of
+ Empty when (Empty == "") ; (element(2,Empty) == "") ->
+ ["<!DOCTYPE HTML PUBLIC",
+ "\"-//W3C//DTD HTML 3.2 Final//EN\">\n",
+ "<!-- autogenerated by 'erl2html2' -->\n",
+ "<html>\n",
+ "<head><title>Module ", Src, "</title>\n",
+ "<meta http-equiv=\"cache-control\" ",
+ "content=\"no-cache\">\n",
+ "</head>\n",
+ "<body bgcolor=\"white\" text=\"black\" ",
+ "link=\"blue\" vlink=\"purple\" alink=\"red\">\n"];
+ {_,Html,_} ->
+ Html
+ end,
+ erl2html2:convert(Src, Dest, Header)
end.
%% Copy all HTML files in InDir to OutDir.
@@ -3153,8 +3219,8 @@ skip_case(Type, Ref, CaseNum, Case, Comment, SendSync, Mode) ->
skip_case1(Type, CaseNum, Mod, Func, Comment, Mode) ->
{{Col0,Col1},_} = get_font_style((CaseNum > 0), Mode),
- ResultCol = if Type == auto -> "#ffcc99";
- Type == user -> "#ff9933"
+ ResultCol = if Type == auto -> ?auto_skip_color;
+ Type == user -> ?user_skip_color
end,
Comment1 = reason_to_string(Comment),
@@ -3163,9 +3229,9 @@ skip_case1(Type, CaseNum, Mod, Func, Comment, Mode) ->
print(major, "=started ~s", [lists:flatten(timestamp_get(""))]),
print(major, "=result skipped: ~s", [Comment1]),
print(2,"*** Skipping test case #~w ~p ***", [CaseNum,{Mod,Func}]),
+ TR = xhtml("<tr valign=\"top\">", ["<tr class=\"",odd_or_even(),"\">"]),
print(html,
- "<tr valign=top>"
- "<td>" ++ Col0 ++ "~s" ++ Col1 ++ "</td>"
+ TR ++ "<td>" ++ Col0 ++ "~s" ++ Col1 ++ "</td>"
"<td>" ++ Col0 ++ "~p" ++ Col1 ++ "</td>"
"<td>" ++ Col0 ++ "~p" ++ Col1 ++ "</td>"
"<td>" ++ Col0 ++ "< >" ++ Col1 ++ "</td>"
@@ -3561,17 +3627,18 @@ run_test_case1(Ref, Num, Mod, Func, Args, RunInit, Where,
test_server_sup:framework_call(report, [tc_start,{?pl2a(Mod),Func}]),
print(major, "=case ~p:~p", [Mod, Func]),
MinorName = start_minor_log_file(Mod, Func),
- print(minor, "<a name=top></a>", []),
+ print(minor, "<a name=\"top\"></a>", []),
MinorBase = filename:basename(MinorName),
print(major, "=logfile ~s", [filename:basename(MinorName)]),
print_props((RunInit==skip_init), get_props(Mode)),
print(major, "=started ~s", [lists:flatten(timestamp_get(""))]),
{{Col0,Col1},Style} = get_font_style((RunInit==run_init), Mode),
- print(html, "<tr valign=top><td>" ++ Col0 ++ "~s" ++ Col1 ++ "</td>"
- "<td>" ++ Col0 ++ "~p" ++ Col1 ++ "</td>"
- "<td><a href=\"~s\">~p</a></td>"
- "<td><a href=\"~s#top\"><</a> <a href=\"~s#end\">></a></td>",
- [num2str(Num),Mod,MinorBase,Func,MinorBase,MinorBase]),
+ TR = xhtml("<tr valign=\"top\">", ["<tr class=\"",odd_or_even(),"\">"]),
+ print(html, TR ++ "<td>" ++ Col0 ++ "~s" ++ Col1 ++ "</td>"
+ "<td>" ++ Col0 ++ "~p" ++ Col1 ++ "</td>"
+ "<td><a href=\"~s\">~p</a></td>"
+ "<td><a href=\"~s#top\"><</a> <a href=\"~s#end\">></a></td>",
+ [num2str(Num),Mod,MinorBase,Func,MinorBase,MinorBase]),
do_if_parallel(Main, ok, fun erlang:yield/0),
%% run the test case
@@ -3584,7 +3651,7 @@ run_test_case1(Ref, Num, Mod, Func, Args, RunInit, Where,
{died,DReason,DLoc,DCmt} -> {died,DReason,DLoc,[],DCmt}
end,
- print(minor, "<a name=end></a>", []),
+ print(minor, "<a name=\"end\"></a>", []),
print_timestamp(minor, "Ended at "),
print(major, "=ended ~s", [lists:flatten(timestamp_get(""))]),
@@ -3838,9 +3905,10 @@ check_new_crash_dumps(Where) ->
progress(skip, CaseNum, Mod, Func, Loc, Reason, Time,
Comment, {St0,St1}) ->
- {Reason1,{Color,Ret}} = if_auto_skip(Reason,
- fun() -> {"#ffcc99",auto_skip} end,
- fun() -> {"#ff9933",skip} end),
+ {Reason1,{Color,Ret}} =
+ if_auto_skip(Reason,
+ fun() -> {?auto_skip_color,auto_skip} end,
+ fun() -> {?user_skip_color,skip} end),
print(major, "=result skipped", []),
print(1, "*** SKIPPED *** ~s",
[get_info_str(Func, CaseNum, get(test_server_cases))]),
@@ -3857,7 +3925,7 @@ progress(skip, CaseNum, Mod, Func, Loc, Reason, Time,
end,
Comment1 = case Comment of
"" -> "";
- _ -> "<br>(" ++ to_string(Comment) ++ ")"
+ _ -> xhtml("<br>(","<br />(") ++ to_string(Comment) ++ ")"
end,
print(html,
"<td>" ++ St0 ++ "~.3fs" ++ St1 ++ "</td>"
@@ -3882,8 +3950,8 @@ progress(failed, CaseNum, Mod, Func, Loc, timetrap_timeout, T,
Comment =
case Comment0 of
"" -> "<font color=\"red\">" ++ ErrorReason ++ "</font>";
- _ -> "<font color=\"red\">" ++ ErrorReason ++ "</font><br>" ++
- to_string(Comment0)
+ _ -> "<font color=\"red\">" ++ ErrorReason ++
+ xhtml("</font><br>","</font><br />") ++ to_string(Comment0)
end,
print(html,
"<td>" ++ St0 ++ "~.3fs" ++ St1 ++ "</td>"
@@ -3908,8 +3976,8 @@ progress(failed, CaseNum, Mod, Func, Loc, {testcase_aborted,Reason}, _T,
Comment =
case Comment0 of
"" -> "<font color=\"red\">" ++ ErrorReason ++ "</font>";
- _ -> "<font color=\"red\">" ++ ErrorReason ++ "</font><br>" ++
- to_string(Comment0)
+ _ -> "<font color=\"red\">" ++ ErrorReason ++
+ xhtml("</font><br>","</font><br />") ++ to_string(Comment0)
end,
print(html,
"<td>" ++ St0 ++ "died" ++ St1 ++ "</td>"
@@ -3943,7 +4011,8 @@ progress(failed, CaseNum, Mod, Func, unknown, Reason, Time,
Comment =
case Comment0 of
"" -> "<font color=\"red\">" ++ ErrorReason2 ++ "</font>";
- _ -> "<font color=\"red\">" ++ ErrorReason2 ++ "</font><br>" ++
+ _ -> "<font color=\"red\">" ++ ErrorReason2 ++
+ xhtml("</font><br>","</font><br />") ++
to_string(Comment0)
end,
print(html,
@@ -3953,7 +4022,7 @@ progress(failed, CaseNum, Mod, Func, unknown, Reason, Time,
[TimeStr,Comment]),
print(minor, "=== location ~s", [unknown]),
{FStr,FormattedReason} = format_exception(Reason),
- print(minor, "=== reason = "++FStr, [FormattedReason]),
+ print(minor, "=== reason = " ++ FStr, [FormattedReason]),
failed;
progress(failed, CaseNum, Mod, Func, Loc, Reason, Time,
@@ -3969,7 +4038,7 @@ progress(failed, CaseNum, Mod, Func, Loc, Reason, Time,
Comment =
case Comment0 of
"" -> "";
- _ -> "<br>" ++ to_string(Comment0)
+ _ -> xhtml("<br>","<br />") ++ to_string(Comment0)
end,
FormatLastLoc = test_server_sup:format_loc(get_last_loc(Loc)),
print(html,
@@ -3980,7 +4049,7 @@ progress(failed, CaseNum, Mod, Func, Loc, Reason, Time,
FormatLoc = test_server_sup:format_loc(Loc),
print(minor, "=== location ~s", [FormatLoc]),
{FStr,FormattedReason} = format_exception(Reason),
- print(minor, "=== reason = "++FStr, [FormattedReason]),
+ print(minor, "=== reason = " ++ FStr, [FormattedReason]),
failed;
progress(ok, _CaseNum, Mod, Func, _Loc, RetVal, Time,
@@ -3999,7 +4068,7 @@ progress(ok, _CaseNum, Mod, Func, _Loc, RetVal, Time,
_ ->
print(major, "=result ok", []),
case Comment0 of
- "" -> "";
+ "" -> "<td></td>";
_ -> "<td>" ++ to_string(Comment0) ++ "</td>"
end
end,
@@ -4349,7 +4418,13 @@ output({html,Msg}, _Sender) ->
%% We are writing to a seekable file. Finalise so
%% we get complete valid (and viewable) HTML code.
%% Then rewind to overwrite the finalising code.
- io:put_chars(Fd, "\n</table>\n</body>\n</html>\n"),
+ io:put_chars(Fd, "\n</table>\n"),
+ case get(test_server_html_footer) of
+ undefined ->
+ io:put_chars(Fd, "</body>\n</html>\n");
+ Footer ->
+ io:put_chars(Fd, Footer)
+ end,
file:position(Fd, Pos);
{error, epipe} ->
%% The file is not seekable. We cannot erase what
@@ -4394,6 +4469,28 @@ output_to_fd(Fd, Msg, _Sender) ->
end.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% xhtml(BasicHtml, XHtml) -> BasicHtml | XHtml
+%%
+xhtml(HTML, XHTML) ->
+ case get(basic_html) of
+ true -> HTML;
+ _ -> XHTML
+ end.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% odd_or_even() -> "odd" | "even"
+%%
+odd_or_even() ->
+ case get(odd_or_even) of
+ even ->
+ put(odd_or_even, odd),
+ "even";
+ _ ->
+ put(odd_or_even, even),
+ "odd"
+ end.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% timestamp_filename_get(Leader) -> string()
%% Leader = string()
%%
@@ -5499,9 +5596,10 @@ write_default_cross_coverlog(TestDir) ->
file:open(filename:join(TestDir,?cross_coverlog_name), [write]),
write_coverlog_header(CrossCoverLog),
io:fwrite(CrossCoverLog,
- "No cross cover modules exist for this application,<br>"
- "or cross cover analysis is not completed.\n"
- "</body></html>\n", []),
+ ["No cross cover modules exist for this application,",
+ xhtml("<br>","<br />"),
+ "or cross cover analysis is not completed.\n"
+ "</body></html>\n"], []),
file:close(CrossCoverLog).
write_cover_result_table(CoverLog,Coverage) ->
diff --git a/lib/test_server/src/test_server_line.erl b/lib/test_server/src/test_server_line.erl
deleted file mode 100644
index 848a9c23dd..0000000000
--- a/lib/test_server/src/test_server_line.erl
+++ /dev/null
@@ -1,387 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2004-2010. All Rights Reserved.
-%%
-%% The contents of this file are subject to the Erlang Public License,
-%% Version 1.1, (the "License"); you may not use this file except in
-%% compliance with the License. You should have received a copy of the
-%% Erlang Public License along with this software. If not, it can be
-%% retrieved online at http://www.erlang.org/.
-%%
-%% Software distributed under the License is distributed on an "AS IS"
-%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
-%% the License for the specific language governing rights and limitations
-%% under the License.
-%%
-%% %CopyrightEnd%
-%%
--module(test_server_line).
-
-%% User interface
--export([get_lines/0]).
--export([clear/0]).
-
-%% Parse transform functions
--export([parse_transform/2]).
--export(['$test_server_line'/3]).
--export(['$test_server_lineQ'/3]).
--export([trace_line/3]).
-
--define(TEST_SERVER_LINE_SIZE, 10).
-%-define(STORAGE_FUNCTION, '$test_server_line').
--define(STORAGE_FUNCTION, '$test_server_lineQ').
-
--include("test_server.hrl").
-
--record(vars, {module, % atom() Module name
- function, % atom() Function name
- arity, % int() Function arity
- lines, % [int()] seen lines
- is_guard=false, % boolean()
- no_lines=[], % [{atom(),integer()}]
- % Functions to exclude
- line_trace=false
- }).
-
-
-
-
-%% Process dictionary littering variant
-%%
-
-'$test_server_line'(Mod, Func, Line) ->
- {Prev,Next} =
- case get('$test_server_line') of
- I when is_integer(I) ->
- if 1 =< I, I < ?TEST_SERVER_LINE_SIZE -> {I,I+1};
- true -> {?TEST_SERVER_LINE_SIZE,1}
- end;
- _ -> {?TEST_SERVER_LINE_SIZE,1}
- end,
- PrevTag = {'$test_server_line',Prev},
- case get(PrevTag) of
- {Mod,Func,_} -> put(PrevTag, {Mod,Func,Line});
- _ ->
- put({'$test_server_line',Next}, {Mod,Func,Line}),
- put('$test_server_line', Next)
- end, ok.
-
-test_server_line_get() ->
- case get('$test_server_line') of
- I when is_integer(I), 1 =< I, I =< ?TEST_SERVER_LINE_SIZE ->
- test_server_line_get_1(?TEST_SERVER_LINE_SIZE, I, []);
- _ -> []
- end.
-
-test_server_line_get_1(0, _I, R) ->
- R;
-test_server_line_get_1(Cnt, I, R) ->
- J = if I < ?TEST_SERVER_LINE_SIZE -> I+1;
- true -> 1 end,
- case get({'$test_server_line',J}) of
- undefined ->
- %% Less than ?TEST_SERVER_LINE_SIZE number of lines stored
- %% Start from line 1 and stop at actutual number of lines
- case get({'$test_server_line',1}) of
- undefined -> R; % no lines at all stored
- E -> test_server_line_get_1(I-1,1,[E|R])
- end;
- E ->
- test_server_line_get_1(Cnt-1, J, [E|R])
- end.
-
-test_server_line_clear() ->
- Is = lists:seq(1,?TEST_SERVER_LINE_SIZE),
- lists:foreach(fun (I) -> erase({'$test_server_line',I}) end, Is),
- erase('$test_server_line'),
- ok.
-
-
-%% Queue variant, uses just one process dictionary entry
-%%
-
-'$test_server_lineQ'(Mod, Func, Line) ->
- case get('$test_server_lineQ') of
- {I,Q} when is_integer(I), 1 =< I, I =< ?TEST_SERVER_LINE_SIZE ->
- case queue:head(Q) of
- {Mod,Func,_} ->
- %% Replace queue head
- put('$test_server_lineQ',
- {I,queue:cons({Mod,Func,Line}, queue:tail(Q))});
- _ when I < ?TEST_SERVER_LINE_SIZE ->
- put('$test_server_lineQ',
- {I+1,queue:cons({Mod,Func,Line}, Q)});
- _ ->
- %% Waste last in queue
- put('$test_server_lineQ',
- {I,queue:cons({Mod,Func,Line}, queue:lait(Q))})
- end;
- _ ->
- Q = queue:new(),
- put('$test_server_lineQ', {1,queue:cons({Mod,Func,Line}, Q)})
- end, ok.
-
-%test_server_lineQ_get() ->
-% case get('$test_server_lineQ') of
-% {I,Q} when integer(I), 1 =< I, I =< ?TEST_SERVER_LINE_SIZE ->
-% queue:to_list(Q);
-% _ -> []
-% end.
-
-test_server_lineQ_clear() ->
- erase('$test_server_lineQ'),
- ok.
-
-
-%% Get line - check if queue or dictionary is used, then get the lines
-%%
-
-get_lines() ->
- case get('$test_server_lineQ') of
- {I,Q} when is_integer(I), 1 =< I, I =< ?TEST_SERVER_LINE_SIZE ->
- queue:to_list(Q);
- _ ->
- test_server_line_get()
- end.
-
-%% Clear all dictionary entries
-%%
-clear() ->
- test_server_line_clear(),
- test_server_lineQ_clear().
-
-
-trace_line(Mod,Func,Line) ->
- io:format(lists:concat([Mod,":",Func,",",integer_to_list(Line),": ~p"]),
- [erlang:now()]).
-
-
-%%%=================================================================
-%%%========= **** PARSE TRANSFORM **** ========================
-%%%=================================================================
-parse_transform(Forms, _Options) ->
- transform(Forms, _Options).
-
-%% forms(Fs) -> lists:map(fun (F) -> form(F) end, Fs).
-
-transform(Forms, _Options)->
- Vars0 = #vars{},
- {ok, MungedForms, _Vars} = transform(Forms, [], Vars0),
- MungedForms.
-
-
-transform([Form|Forms], MungedForms, Vars) ->
- case munge(Form, Vars) of
- ignore ->
- transform(Forms, MungedForms, Vars);
- {MungedForm, Vars2} ->
- transform(Forms, [MungedForm|MungedForms], Vars2)
- end;
-transform([], MungedForms, Vars) ->
- {ok, lists:reverse(MungedForms), Vars}.
-
-%% This code traverses the abstract code, stored as the abstract_code
-%% chunk in the BEAM file, as described in absform(3) for Erlang/OTP R8B
-%% (Vsn=abstract_v2).
-%% The abstract format after preprocessing differs slightly from the abstract
-%% format given eg using epp:parse_form, this has been noted in comments.
-munge(Form={attribute,_,module,Module}, Vars) ->
- Vars2 = Vars#vars{module=Module},
- {Form, Vars2};
-
-munge(Form={attribute,_,no_lines,Funcs}, Vars) ->
- Vars2 = Vars#vars{no_lines=Funcs},
- {Form, Vars2};
-
-munge(Form={attribute,_,line_trace,_}, Vars) ->
- Vars2 = Vars#vars{line_trace=true},
- {Form, Vars2};
-
-munge({function,0,module_info,_Arity,_Clauses}, _Vars) ->
- ignore; % module_info will be added again when the forms are recompiled
-munge(Form = {function,Line,Function,Arity,Clauses}, Vars) ->
- case lists:member({Function,Arity},Vars#vars.no_lines) of
- true ->
- %% Line numbers in this function shall not be stored
- {Form,Vars};
- false ->
- Vars2 = Vars#vars{function=Function,
- arity=Arity,
- lines=[]},
- {MungedClauses, Vars3} = munge_clauses(Clauses, Vars2, []),
- {{function,Line,Function,Arity,MungedClauses}, Vars3}
- end;
-munge(Form, Vars) -> % attributes
- {Form, Vars}.
-
-munge_clauses([{clause,Line,Pattern,Guards,Body}|Clauses], Vars, MClauses) ->
- {MungedGuards, _Vars} = munge_exprs(Guards, Vars#vars{is_guard=true},[]),
- {MungedBody, Vars2} = munge_body(Body, Vars, []),
- munge_clauses(Clauses, Vars2,
- [{clause,Line,Pattern,MungedGuards,MungedBody}|
- MClauses]);
-munge_clauses([], Vars, MungedClauses) ->
- {lists:reverse(MungedClauses), Vars}.
-
-munge_body([Expr|Body], Vars, MungedBody) ->
- %% Here is the place to add a call to storage function!
- Line = element(2, Expr),
- Lines = Vars#vars.lines,
- case lists:member(Line,Lines) of
- true -> % already a bump at this line!
- {MungedExpr, Vars2} = munge_expr(Expr, Vars),
- munge_body(Body, Vars2, [MungedExpr|MungedBody]);
- false ->
- Bump = {call, 0, {remote,0,
- {atom,0,?MODULE},
- {atom,0,?STORAGE_FUNCTION}},
- [{atom,0,Vars#vars.module},
- {atom, 0, Vars#vars.function},
- {integer, 0, Line}]},
- Lines2 = [Line|Lines],
-
- {MungedExpr, Vars2} = munge_expr(Expr, Vars#vars{lines=Lines2}),
- MungedBody2 =
- if Vars#vars.line_trace ->
- LineTrace = {call, 0, {remote,0,
- {atom,0,?MODULE},
- {atom,0,trace_line}},
- [{atom,0,Vars#vars.module},
- {atom, 0, Vars#vars.function},
- {integer, 0, Line}]},
- [MungedExpr,LineTrace,Bump|MungedBody];
- true ->
- [MungedExpr,Bump|MungedBody]
- end,
- munge_body(Body, Vars2, MungedBody2)
- end;
-munge_body([], Vars, MungedBody) ->
- {lists:reverse(MungedBody), Vars}.
-
-munge_expr({match,Line,ExprL,ExprR}, Vars) ->
- {MungedExprL, Vars2} = munge_expr(ExprL, Vars),
- {MungedExprR, Vars3} = munge_expr(ExprR, Vars2),
- {{match,Line,MungedExprL,MungedExprR}, Vars3};
-munge_expr({tuple,Line,Exprs}, Vars) ->
- {MungedExprs, Vars2} = munge_exprs(Exprs, Vars, []),
- {{tuple,Line,MungedExprs}, Vars2};
-munge_expr({record,Line,Expr,Exprs}, Vars) ->
- %% Only for Vsn=raw_abstract_v1
- {MungedExprName, Vars2} = munge_expr(Expr, Vars),
- {MungedExprFields, Vars3} = munge_exprs(Exprs, Vars2, []),
- {{record,Line,MungedExprName,MungedExprFields}, Vars3};
-munge_expr({record_field,Line,ExprL,ExprR}, Vars) ->
- %% Only for Vsn=raw_abstract_v1
- {MungedExprL, Vars2} = munge_expr(ExprL, Vars),
- {MungedExprR, Vars3} = munge_expr(ExprR, Vars2),
- {{record_field,Line,MungedExprL,MungedExprR}, Vars3};
-munge_expr({cons,Line,ExprH,ExprT}, Vars) ->
- {MungedExprH, Vars2} = munge_expr(ExprH, Vars),
- {MungedExprT, Vars3} = munge_expr(ExprT, Vars2),
- {{cons,Line,MungedExprH,MungedExprT}, Vars3};
-munge_expr({op,Line,Op,ExprL,ExprR}, Vars) ->
- {MungedExprL, Vars2} = munge_expr(ExprL, Vars),
- {MungedExprR, Vars3} = munge_expr(ExprR, Vars2),
- {{op,Line,Op,MungedExprL,MungedExprR}, Vars3};
-munge_expr({op,Line,Op,Expr}, Vars) ->
- {MungedExpr, Vars2} = munge_expr(Expr, Vars),
- {{op,Line,Op,MungedExpr}, Vars2};
-munge_expr({'catch',Line,Expr}, Vars) ->
- {MungedExpr, Vars2} = munge_expr(Expr, Vars),
- {{'catch',Line,MungedExpr}, Vars2};
-munge_expr({call,Line1,{remote,Line2,ExprM,ExprF},Exprs},
- Vars) when Vars#vars.is_guard==false->
- {MungedExprM, Vars2} = munge_expr(ExprM, Vars),
- {MungedExprF, Vars3} = munge_expr(ExprF, Vars2),
- {MungedExprs, Vars4} = munge_exprs(Exprs, Vars3, []),
- {{call,Line1,{remote,Line2,MungedExprM,MungedExprF},MungedExprs}, Vars4};
-munge_expr({call,Line1,{remote,_Line2,_ExprM,ExprF},Exprs},
- Vars) when Vars#vars.is_guard==true ->
- %% Difference in abstract format after preprocessing: BIF calls in guards
- %% are translated to {remote,...} (which is not allowed as source form)
- %% NOT NECESSARY FOR Vsn=raw_abstract_v1
- munge_expr({call,Line1,ExprF,Exprs}, Vars);
-munge_expr({call,Line,Expr,Exprs}, Vars) ->
- {MungedExpr, Vars2} = munge_expr(Expr, Vars),
- {MungedExprs, Vars3} = munge_exprs(Exprs, Vars2, []),
- {{call,Line,MungedExpr,MungedExprs}, Vars3};
-munge_expr({lc,Line,Expr,LC}, Vars) ->
- {MungedExpr, Vars2} = munge_expr(Expr, Vars),
- {MungedLC, Vars3} = munge_lc(LC, Vars2, []),
- {{lc,Line,MungedExpr,MungedLC}, Vars3};
-munge_expr({block,Line,Body}, Vars) ->
- {MungedBody, Vars2} = munge_body(Body, Vars, []),
- {{block,Line,MungedBody}, Vars2};
-munge_expr({'if',Line,Clauses}, Vars) ->
- {MungedClauses,Vars2} = munge_clauses(Clauses, Vars, []),
- {{'if',Line,MungedClauses}, Vars2};
-munge_expr({'case',Line,Expr,Clauses}, Vars) ->
- {MungedExpr,Vars2} = munge_expr(Expr,Vars),
- {MungedClauses,Vars3} = munge_clauses(Clauses, Vars2, []),
- {{'case',Line,MungedExpr,MungedClauses}, Vars3};
-munge_expr({'receive',Line,Clauses}, Vars) ->
- {MungedClauses,Vars2} = munge_clauses(Clauses, Vars, []),
- {{'receive',Line,MungedClauses}, Vars2};
-munge_expr({'receive',Line,Clauses,Expr,Body}, Vars) ->
- {MungedClauses,Vars2} = munge_clauses(Clauses, Vars, []),
- {MungedExpr, Vars3} = munge_expr(Expr, Vars2),
- {MungedBody, Vars4} = munge_body(Body, Vars3, []),
- {{'receive',Line,MungedClauses,MungedExpr,MungedBody}, Vars4};
-munge_expr({'try',Line,Exprs,Clauses,CatchClauses,After}, Vars) ->
- {MungedExprs, Vars1} = munge_exprs(Exprs, Vars, []),
- {MungedClauses, Vars2} = munge_clauses(Clauses, Vars1, []),
- {MungedCatchClauses, Vars3} = munge_clauses(CatchClauses, Vars2, []),
- {MungedAfter, Vars4} = munge_body(After, Vars3, []),
- {{'try',Line,MungedExprs,MungedClauses,MungedCatchClauses,MungedAfter},
- Vars4};
-%% Difference in abstract format after preprocessing: Funs get an extra
-%% element Extra.
-%% NOT NECESSARY FOR Vsn=raw_abstract_v1
-munge_expr({'fun',Line,{function,Name,Arity},_Extra}, Vars) ->
- {{'fun',Line,{function,Name,Arity}}, Vars};
-munge_expr({'fun',Line,{clauses,Clauses},_Extra}, Vars) ->
- {MungedClauses,Vars2}=munge_clauses(Clauses, Vars, []),
- {{'fun',Line,{clauses,MungedClauses}}, Vars2};
-munge_expr({'fun',Line,{clauses,Clauses}}, Vars) ->
- %% Only for Vsn=raw_abstract_v1
- {MungedClauses,Vars2}=munge_clauses(Clauses, Vars, []),
- {{'fun',Line,{clauses,MungedClauses}}, Vars2};
-munge_expr({bc,Line,Expr,LC}, Vars) ->
- {MungedExpr, Vars2} = munge_expr(Expr, Vars),
- {MungedLC, Vars3} = munge_lc(LC, Vars2, []),
- {{bc,Line,MungedExpr,MungedLC}, Vars3};
-munge_expr(Form, Vars) -> % var|char|integer|float|string|atom|nil|bin|eof
- {Form, Vars}.
-
-munge_exprs([Expr|Exprs], Vars, MungedExprs) when Vars#vars.is_guard==true,
- is_list(Expr) ->
- {MungedExpr, _Vars} = munge_exprs(Expr, Vars, []),
- munge_exprs(Exprs, Vars, [MungedExpr|MungedExprs]);
-munge_exprs([Expr|Exprs], Vars, MungedExprs) ->
- {MungedExpr, Vars2} = munge_expr(Expr, Vars),
- munge_exprs(Exprs, Vars2, [MungedExpr|MungedExprs]);
-munge_exprs([], Vars, MungedExprs) ->
- {lists:reverse(MungedExprs), Vars}.
-
-munge_lc([{generate,Line,Pattern,Expr}|LC], Vars, MungedLC) ->
- {MungedExpr, Vars2} = munge_expr(Expr, Vars),
- munge_lc(LC, Vars2, [{generate,Line,Pattern,MungedExpr}|MungedLC]);
-munge_lc([{b_generate,Line,Pattern,Expr}|LC], Vars, MungedLC) ->
- {MungedExpr, Vars2} = munge_expr(Expr, Vars),
- munge_lc(LC, Vars2, [{b_generate,Line,Pattern,MungedExpr}|MungedLC]);
-munge_lc([Expr|LC], Vars, MungedLC) ->
- {MungedExpr, Vars2} = munge_expr(Expr, Vars),
- munge_lc(LC, Vars2, [MungedExpr|MungedLC]);
-munge_lc([], Vars, MungedLC) ->
- {lists:reverse(MungedLC), Vars}.
-
-
-
-
-
-
-
-
-
-
diff --git a/lib/test_server/src/test_server_sup.erl b/lib/test_server/src/test_server_sup.erl
index 77d364d5cb..875f45eea6 100644
--- a/lib/test_server/src/test_server_sup.erl
+++ b/lib/test_server/src/test_server_sup.erl
@@ -51,18 +51,19 @@ timetrap(Timeout0, Scale, Pid) ->
Timeout = if not Scale -> Timeout0;
true -> test_server:timetrap_scale_factor() * Timeout0
end,
+ TruncTO = trunc(Timeout),
receive
- after trunc(Timeout) ->
- Line = test_server:get_loc(Pid),
+ after TruncTO ->
+ MFLs = test_server:get_loc(Pid),
Mon = erlang:monitor(process, Pid),
Trap =
case get(test_server_init_or_end_conf) of
undefined ->
- {timetrap_timeout,trunc(Timeout),Line};
+ {timetrap_timeout,TruncTO,MFLs};
InitOrEnd ->
- {timetrap_timeout,trunc(Timeout),Line,InitOrEnd}
+ {timetrap_timeout,TruncTO,MFLs,InitOrEnd}
end,
- exit(Pid,Trap),
+ exit(Pid, Trap),
receive
{'DOWN', Mon, process, Pid, _} ->
ok
diff --git a/lib/toolbar/doc/src/make.dep b/lib/toolbar/doc/src/make.dep
deleted file mode 100644
index d93ff2a315..0000000000
--- a/lib/toolbar/doc/src/make.dep
+++ /dev/null
@@ -1,26 +0,0 @@
-# ----------------------------------------------------
-# >>>> Do not edit this file <<<<
-# This file was automaticly generated by
-# /home/otp/bin/docdepend
-# ----------------------------------------------------
-
-
-# ----------------------------------------------------
-# TeX files that the DVI file depend on
-# ----------------------------------------------------
-
-book.dvi: book.tex part.tex ref_man.tex toolbar.tex \
- toolbar_chapter.tex
-
-# ----------------------------------------------------
-# Source inlined when transforming from source to LaTeX
-# ----------------------------------------------------
-
-book.tex: ref_man.xml
-
-# ----------------------------------------------------
-# Pictures that the DVI file depend on
-# ----------------------------------------------------
-
-book.dvi: bar.ps create_tool.ps
-
diff --git a/lib/tools/c_src/Makefile.in b/lib/tools/c_src/Makefile.in
index 65a7f5f424..6921193154 100644
--- a/lib/tools/c_src/Makefile.in
+++ b/lib/tools/c_src/Makefile.in
@@ -142,7 +142,9 @@ EMEM_OBJS = $(addprefix $(EMEM_OBJ_DIR)/,$(notdir $(EMEM_SRCS:.c=.o)))
# Misc targets
#
-all: $(CREATE_DIRS) erts_lib $(PROGS) $(DRIVERS)
+_create_dirs := $(shell mkdir -p $(CREATE_DIRS))
+
+all: erts_lib $(PROGS) $(DRIVERS)
erts_lib:
cd $(ERL_TOP)/erts/lib_src && $(MAKE) $(TYPE)
@@ -158,13 +160,6 @@ clean:
.PHONY: all erts_lib docs clean
#
-# Make dir targets
-#
-
-$(CREATE_DIRS):
- $(MKDIR) -p $@
-
-#
# Object targets
#
diff --git a/lib/tools/doc/src/eprof.xml b/lib/tools/doc/src/eprof.xml
index 6d68c90768..1dbc41ec8e 100644
--- a/lib/tools/doc/src/eprof.xml
+++ b/lib/tools/doc/src/eprof.xml
@@ -147,7 +147,7 @@
</type>
<desc>
<p>This function ensures that the results displayed by
- <c>analyse/0</c> and <c>total_analyse/0</c> are printed both to
+ <c>analyze/0,1,2</c> are printed both to
the file <c>File</c> and the screen.</p>
</desc>
</func>
diff --git a/lib/tools/doc/src/make.dep b/lib/tools/doc/src/make.dep
deleted file mode 100644
index 11fa090d6f..0000000000
--- a/lib/tools/doc/src/make.dep
+++ /dev/null
@@ -1,33 +0,0 @@
-# ----------------------------------------------------
-# >>>> Do not edit this file <<<<
-# This file was automaticly generated by
-# /home/otp/bin/docdepend
-# ----------------------------------------------------
-
-
-# ----------------------------------------------------
-# TeX files that the DVI file depend on
-# ----------------------------------------------------
-
-book.dvi: book.tex cover.tex cover_chapter.tex cprof.tex \
- cprof_chapter.tex eprof.tex erlang_mode.tex \
- erlang_mode_chapter.tex fprof.tex fprof_chapter.tex \
- instrument.tex make.tex part.tex ref_man.tex \
- tags.tex xref.tex xref_chapter.tex
-
-# ----------------------------------------------------
-# Source inlined when transforming from source to LaTeX
-# ----------------------------------------------------
-
-book.tex: ref_man.xml
-
-cprof.tex: ../../../../system/doc/definitions/term.defs
-
-xref.tex: ../../../../system/doc/definitions/term.defs
-
-# ----------------------------------------------------
-# Pictures that the DVI file depend on
-# ----------------------------------------------------
-
-book.dvi: venn1.ps venn2.ps
-
diff --git a/lib/tools/src/cover.erl b/lib/tools/src/cover.erl
index fb9744d759..e21bd1b88c 100644
--- a/lib/tools/src/cover.erl
+++ b/lib/tools/src/cover.erl
@@ -522,7 +522,7 @@ call(Request) ->
{?SERVER,Reply} ->
Reply
end,
- erlang:demonitor(Ref),
+ erlang:demonitor(Ref, [flush]),
Return
end.
@@ -545,7 +545,7 @@ remote_call(Node,Request) ->
{?SERVER,Reply} ->
Reply
end,
- erlang:demonitor(Ref),
+ erlang:demonitor(Ref, [flush]),
Return
end.
diff --git a/lib/tools/src/fprof.erl b/lib/tools/src/fprof.erl
index 155965a65a..1d85a55bd7 100644
--- a/lib/tools/src/fprof.erl
+++ b/lib/tools/src/fprof.erl
@@ -87,8 +87,10 @@ dbg(_, _, _) ->
-apply({M, F} = Function, Args)
+apply({M, F}, Args)
when is_atom(M), is_atom(F), is_list(Args) ->
+ Arity = length(Args),
+ Function = fun M:F/Arity,
apply_1(Function, Args, []);
apply(Fun, Args)
when is_function(Fun), is_list(Args) ->
@@ -98,8 +100,10 @@ apply(A, B) ->
apply(M, F, Args) when is_atom(M), is_atom(F), is_list(Args) ->
apply_1({M, F}, Args, []);
-apply({M, F} = Function, Args, Options)
+apply({M, F}, Args, Options)
when is_atom(M), is_atom(F), is_list(Args), is_list(Options) ->
+ Arity = length(Args),
+ Function = fun M:F/Arity,
apply_1(Function, Args, Options);
apply(Fun, Args, Options)
when is_function(Fun), is_list(Args), is_list(Options) ->
@@ -109,7 +113,9 @@ apply(A, B, C) ->
apply(Module, Function, Args, Options)
when is_atom(Module), is_atom(Function), is_list(Args), is_list(Options) ->
- apply_1({Module, Function}, Args, Options);
+ Arity = length(Args),
+ Fun = fun Module:Function/Arity,
+ apply_1(Fun, Args, Options);
apply(A, B, C, D) ->
erlang:error(badarg, [A, B, C, D]).
diff --git a/lib/tools/src/xref_compiler.erl b/lib/tools/src/xref_compiler.erl
index 1445e135be..e6f492c62b 100644
--- a/lib/tools/src/xref_compiler.erl
+++ b/lib/tools/src/xref_compiler.erl
@@ -736,8 +736,11 @@ find_nodes(Tuple, I, T) when is_tuple(Tuple) ->
end,
{NL, NI, T1} = foldl(Fun, {[], I, T}, L),
Tag = case Tag0 of
- _ when is_function(Tag0) -> Tag0;
- _ when is_atom(Tag0) -> {sofs, Tag0}
+ _ when is_function(Tag0) ->
+ Tag0;
+ _ when is_atom(Tag0) ->
+ Arity = length(NL),
+ fun sofs:Tag0/Arity
end,
find_node({apply, Tag, NL}, NI, T1).
diff --git a/lib/tools/src/xref_reader.erl b/lib/tools/src/xref_reader.erl
index d22f0df164..92f0c45c7b 100644
--- a/lib/tools/src/xref_reader.erl
+++ b/lib/tools/src/xref_reader.erl
@@ -158,15 +158,20 @@ expr({'try',_Line,Es,Scs,Ccs,As}, S) ->
S2 = clauses(Scs, S1),
S3 = clauses(Ccs, S2),
expr(As, S3);
-expr({call, Line,
- {remote, _, {atom,_,erlang}, {atom,_,make_fun}},
- [{atom,_,Mod}, {atom,_,Fun}, {integer,_,Arity}]}, S) ->
- %% Added in R10B-6. M:F/A.
- expr({'fun', Line, {function, Mod, Fun, Arity}}, S);
-expr({'fun', Line, {function, Mod, Name, Arity}}, S) ->
- %% Added in R10B-6. M:F/A.
+expr({'fun', Line, {function, {atom,_,Mod},
+ {atom,_,Name},
+ {integer,_,Arity}}}, S) ->
+ %% New format in R15. M:F/A (literals).
As = lists:duplicate(Arity, {atom, Line, foo}),
external_call(Mod, Name, As, Line, false, S);
+expr({'fun', Line, {function, Mod, Name, {integer,_,Arity}}}, S) ->
+ %% New format in R15. M:F/A (one or more variables).
+ As = lists:duplicate(Arity, {atom, Line, foo}),
+ external_call(erlang, apply, [Mod, Name, list2term(As)], Line, true, S);
+expr({'fun', Line, {function, Mod, Name, _Arity}}, S) ->
+ %% New format in R15. M:F/A (one or more variables).
+ As = {var, Line, '_'},
+ external_call(erlang, apply, [Mod, Name, As], Line, true, S);
expr({'fun', Line, {function, Name, Arity}, _Extra}, S) ->
%% Added in R8.
handle_call(local, S#xrefr.module, Name, Arity, Line, S);
@@ -286,10 +291,10 @@ check_funarg(W, ArgsList, Line, S) ->
expr(ArgsList, S1).
funarg({'fun', _, _Clauses, _Extra}, _S) -> true;
-funarg({var, _, Var}, S) -> member(Var, S#xrefr.funvars);
-funarg({call,_,{remote,_,{atom,_,erlang},{atom,_,make_fun}},_MFA}, _S) ->
- %% R10B-6. M:F/A.
+funarg({'fun', _, {function,_,_,_}}, _S) ->
+ %% New abstract format for fun M:F/A in R15.
true;
+funarg({var, _, Var}, S) -> member(Var, S#xrefr.funvars);
funarg(_, _S) -> false.
fun_args(apply2, [FunArg, Args]) -> {FunArg, Args};
diff --git a/lib/tools/test/cover_SUITE.erl b/lib/tools/test/cover_SUITE.erl
index fe7f92de78..881a3c2997 100644
--- a/lib/tools/test/cover_SUITE.erl
+++ b/lib/tools/test/cover_SUITE.erl
@@ -583,21 +583,14 @@ otp_6115_1(Config) ->
%% called -- running cover compiled code when there is no cover
%% server and thus no ets tables to bump counters in, makes no
%% sense.
- ?line Pid1 = f1:start_fail(),
-
- %% If f1 is cover compiled, a process P is started with a
- %% reference to the fun created in start_ok/0, and
- %% cover:stop() is called, then P should survive.
- %% This is because (the fun held by) P always references the current
- %% version of the module, and is thus not affected by the cover
- %% compiled version being unloaded.
- ?line Pid2 = f1:start_ok(),
+ Pid1 = f1:start_a(),
+ Pid2 = f1:start_b(),
%% Now stop cover
?line cover:stop(),
- %% Ensure that f1 is loaded (and not cover compiled), that Pid1
- %% is dead and Pid2 is alive, but with no reference to old code
+ %% Ensure that f1 is loaded (and not cover compiled), and that
+ %% both Pid1 and Pid2 are dead.
case code:which(f1) of
Beam when is_list(Beam) ->
ok;
@@ -608,19 +601,15 @@ otp_6115_1(Config) ->
undefined ->
ok;
_PI1 ->
- RefToOldP = erlang:check_process_code(Pid1, f1),
- ?line ?t:fail({"Pid1 still alive", RefToOldP})
+ RefToOldP1 = erlang:check_process_code(Pid1, f1),
+ ?t:fail({"Pid1 still alive", RefToOldP1})
end,
case process_info(Pid2) of
- PI2 when is_list(PI2) ->
- case erlang:check_process_code(Pid2, f2) of
- false ->
- ok;
- true ->
- ?line ?t:fail("Pid2 has ref to old code")
- end;
undefined ->
- ?line ?t:fail("Pid2 has died")
+ ok;
+ _PI2 ->
+ RefToOldP2 = erlang:check_process_code(Pid1, f2),
+ ?t:fail({"Pid2 still alive", RefToOldP2})
end,
?line file:set_cwd(CWD),
diff --git a/lib/tools/test/cover_SUITE_data/otp_6115/f1.erl b/lib/tools/test/cover_SUITE_data/otp_6115/f1.erl
index b659e5d818..5399b33f19 100644
--- a/lib/tools/test/cover_SUITE_data/otp_6115/f1.erl
+++ b/lib/tools/test/cover_SUITE_data/otp_6115/f1.erl
@@ -1,12 +1,13 @@
-module(f1).
--export([start_fail/0, start_ok/0]).
+-export([start_a/0, start_b/0]).
-start_fail() ->
+start_a() ->
f2:start(fun() ->
- io:format("this does not work\n",[])
+ ok
end).
-start_ok() ->
+start_b() ->
f2:start(fun fun1/0).
+
fun1() ->
- io:format("this works\n",[]).
+ ok.
diff --git a/lib/tools/test/eprof_SUITE_data/ed.script b/lib/tools/test/eprof_SUITE_data/ed.script
index 94531a9e98..fe1625bc50 100644
--- a/lib/tools/test/eprof_SUITE_data/ed.script
+++ b/lib/tools/test/eprof_SUITE_data/ed.script
@@ -1,5 +1,7 @@
H
r eed.erl
+1,$s/Created :/Skapad :/p
+/^cmd_line/,/^file/-1p
g/^[a-z][a-zA-Z_]*\(/i\
%%% -------------------------------------------------------------\
%%% A stupid function header.\
diff --git a/lib/tools/test/eprof_SUITE_data/eed.erl b/lib/tools/test/eprof_SUITE_data/eed.erl
index 0175abdd0e..520c5f3dd1 100644
--- a/lib/tools/test/eprof_SUITE_data/eed.erl
+++ b/lib/tools/test/eprof_SUITE_data/eed.erl
@@ -10,6 +10,8 @@
-export([edit/0, edit/1, file/1, cmd_line/1]).
+-compile({no_auto_import,[error/1]}).
+
-record(state, {dot = 0, % Line number of dot.
upto_dot = [], % Lines up to dot (reversed).
after_dot = [], % Lines after dot.
@@ -60,7 +62,7 @@ loop(St0) ->
ok;
{error, Reason} ->
loop(print_error(Reason, St1));
- St2 when record(St2, state) ->
+ St2 when is_record(St2, state) ->
loop(St2)
end.
@@ -68,7 +70,7 @@ command(Cmd, St) ->
case parse_command(Cmd, St) of
quit ->
quit;
- St1 when function(St1#state.print) ->
+ St1 when is_function(St1#state.print) ->
if
St1#state.dot /= 0 ->
print_current(St1);
@@ -76,7 +78,7 @@ command(Cmd, St) ->
ok
end,
St1#state{print=false};
- St1 when record(St1, state) ->
+ St1 when is_record(St1, state) ->
St1
end.
@@ -103,13 +105,13 @@ get_input([C|Rest], St, Result) ->
get_line1(Io, Prompt, Result) ->
get_line2(Io, io:get_line(Io, Prompt), Result).
-get_line2(Io, eof, []) ->
+get_line2(_Io, eof, []) ->
eof;
-get_line2(Io, eof, Result) ->
+get_line2(_Io, eof, Result) ->
lists:reverse(Result);
get_line2(Io, [$\\, $\n], Result) ->
get_line1(Io, '', [$\n|Result]);
-get_line2(Io, [$\n], Result) ->
+get_line2(_Io, [$\n], Result) ->
lists:reverse(Result, [$\n]);
get_line2(Io, [C|Rest], Result) ->
get_line2(Io, Rest, [C|Result]).
@@ -193,7 +195,7 @@ get_one1([$+|Rest], Sum, St) ->
get_one2({ok, 1, Rest}, 1, Sum, St);
get_one1([$-|Rest], Sum, St) ->
get_one2({ok, 1, Rest}, -1, Sum, St);
-get_one1(Cmd, false, St) ->
+get_one1(_Cmd, false, _St) ->
false;
get_one1(Cmd, Sum, St) ->
{ok, Sum, Cmd, St}.
@@ -222,13 +224,13 @@ get_address([$', Mark|Rest], St) when $a =< Mark, Mark =< $z ->
false ->
{ok, 0, Rest, St}
end;
-get_address([$'|Rest], State) ->
+get_address([$'|_Rest], _State) ->
error(bad_mark);
get_address([$/|Rest], State) ->
scan_forward($/, Rest, State);
-get_address([$?|Rest], State) ->
+get_address([$?|_Rest], _State) ->
error(not_implemented);
-get_address(Cmd, St) ->
+get_address(_Cmd, _St) ->
false.
scan_forward(End, Patt0, State) ->
@@ -238,8 +240,8 @@ scan_forward(End, Patt0, State) ->
scan_forward1(Dot+1, After, NewState, Rest).
scan_forward1(Linenum, [Line|Rest], State, RestCmd) ->
- case regexp:first_match(Line#line.contents, State#state.pattern) of
- {match, _, _} ->
+ case re:run(Line#line.contents, State#state.pattern, [{capture, none}]) of
+ match ->
{ok, Linenum, RestCmd, State};
nomatch ->
scan_forward1(Linenum+1, Rest, State, RestCmd)
@@ -254,13 +256,14 @@ scan_forward1(_, [], State, RestCmd) ->
Other
end.
-scan_forward2(0, [], State, RestCmd) ->
+scan_forward2(0, [], _State, _RestCmd) ->
false;
scan_forward2(Linenum, [Line|Rest], State, RestCmd) ->
case scan_forward2(Linenum-1, Rest, State, RestCmd) of
false ->
- case regexp:first_match(Line#line.contents, State#state.pattern) of
- {match, _, _} ->
+ case re:run(Line#line.contents, State#state.pattern,
+ [{capture, none}]) of
+ match ->
{ok, Linenum, RestCmd, State};
nomatch ->
false
@@ -296,7 +299,7 @@ parse_cmd_char($t, Cont) -> Cont(fun transpose_command/3, 2, dot);
parse_cmd_char($u, Cont) -> Cont(fun undo_command/3, 0, none);
parse_cmd_char($v, Cont) -> Cont(fun vglobal_command/3, 2, all);
parse_cmd_char($w, Cont) -> Cont(fun write_command/3, 2, all);
-parse_cmd_char(_, Cont) -> error(bad_command).
+parse_cmd_char(_, _Cont) -> error(bad_command).
execute_command(Fun, NumLines, Def, State, Nums, Rest) ->
Lines = check_lines(NumLines, Def, Nums, State),
@@ -380,7 +383,7 @@ change_command(Rest, Lines, St0) ->
%% (.,.)d - delete lines
-delete_command(Rest, [0, Last], St) ->
+delete_command(_Rest, [0, _Last], _St) ->
error(bad_linenum);
delete_command(Rest, [First, Last], St0) ->
St1 = check_trailing_p(Rest, save_for_undo(St0)),
@@ -396,7 +399,7 @@ delete(Left, St0) ->
%% e file - replace buffer with new file
-enter_command(Name, [], St) when St#state.modified == true ->
+enter_command(_Name, [], St) when St#state.modified == true ->
error(buffer_modified);
enter_command(Name, [], St0) ->
enter_always_command(Name, [], St0).
@@ -439,7 +442,7 @@ mark(Sense, [First, Last], St0) ->
St1 = move_to(Last, St0),
mark1(Sense, First-1, St1).
-mark1(Sense, First, St) when St#state.dot == First ->
+mark1(_Sense, First, St) when St#state.dot == First ->
St;
mark1(Sense, First, St) ->
[Line|Prev] = St#state.upto_dot,
@@ -507,16 +510,16 @@ help_always_command([], [], St) ->
%% (.)i - insert text
-insert_command(Rest, [0], State) ->
+insert_command(_Rest, [0], _State) ->
error(bad_linenum);
insert_command(Rest, [Line], State) ->
append_command(Rest, [Line-1], State).
%% (.)kx - mark line
-mark_command(_, [0], St) ->
+mark_command(_, [0], _St) ->
error(bad_linenum);
-mark_command([Mark|Rest], [Line], St) when $a =< Mark, Mark =< $z ->
+mark_command([Mark|_Rest], [_Line], _St) when $a =< Mark, Mark =< $z ->
error(not_implemented);
mark_command(_, _, _) ->
error(bad_mark).
@@ -528,12 +531,12 @@ list_command(Rest, Lines, St) ->
%% (.,.)m - move lines
-move_command(Cmd, [First, Last], St) ->
+move_command(_Cmd, [_First, _Last], _St) ->
error(not_implemented).
%% (.,.)t - copy lines
-transpose_command(Cmd, [First, Last], St) ->
+transpose_command(_Cmd, [_First, _Last], _St) ->
error(not_implemented).
%% (.,.)n - print lines with line numbers
@@ -604,39 +607,41 @@ read(After, Name, St0) ->
subst_command(_, [0, _], _) ->
error(bad_linenum);
-subst_command([$ |Cmd0], [First, Last], St0) ->
+subst_command([$ |_Cmd0], [_First, _Last], _St0) ->
error(bad_delimiter);
-subst_command([$\n|Cmd0], [First, Last], St0) ->
+subst_command([$\n|_Cmd0], [_First, _Last], _St0) ->
error(bad_delimiter);
subst_command([Sep|Cmd0], [First, Last], St0) ->
St1 = save_for_undo(St0),
{ok, Cmd1, St2} = get_pattern(Sep, Cmd0, St1),
{ok, Replacement, Cmd2} = get_replacement(Sep, Cmd1),
- {ok, Sub, Cmd3} = subst_check_gflag(Cmd2),
+ {ok, Opts, Cmd3} = subst_check_gflag(Cmd2),
St3 = check_trailing_p(Cmd3, St2),
- subst_command(Last-First+1, Sub, Replacement, move_to(First-1, St3), nomatch);
+ subst_command(Last-First+1, Opts, Replacement,
+ move_to(First-1, St3), nomatch);
subst_command([], _, _) ->
error(bad_delimiter).
subst_command(0, _, _, _, nomatch) ->
error(nomatch);
-subst_command(0, _, _, _, StLast) when record(StLast, state) ->
+subst_command(0, _, _, _, StLast) when is_record(StLast, state) ->
StLast;
-subst_command(Left, Sub, Repl, St0, LastMatch) ->
+subst_command(Left, Opts, Repl, St0, LastMatch) ->
St1 = next_line(St0),
[Line|_] = St1#state.upto_dot,
- case regexp:Sub(Line#line.contents, St1#state.pattern, Repl) of
- {ok, _, 0} ->
- subst_command(Left-1, Sub, Repl, St1, LastMatch);
- {ok, NewContents, _} ->
+ Contents = Line#line.contents,
+ case re:replace(Contents, St1#state.pattern, Repl, Opts) of
+ Contents ->
+ subst_command(Left-1, Opts, Repl, St1, LastMatch);
+ NewContents ->
%% XXX This doesn't work with marks.
St2 = delete_current_line(St1),
St3 = insert_line(NewContents, St2),
- subst_command(Left-1, Sub, Repl, St3, St3)
+ subst_command(Left-1, Opts, Repl, St3, St3)
end.
-subst_check_gflag([$g|Cmd]) -> {ok, gsub, Cmd};
-subst_check_gflag(Cmd) -> {ok, sub, Cmd}.
+subst_check_gflag([$g|Cmd]) -> {ok, [global,{return,list}], Cmd};
+subst_check_gflag(Cmd) -> {ok, [{return,list}], Cmd}.
%% u - undo
@@ -649,7 +654,7 @@ undo_command(_, _, _) ->
%% (1,$)w - write buffer to file
-write_command(Cmd, [First, Last], St) ->
+write_command(_Cmd, [_First, _Last], _St) ->
error(not_implemented).
@@ -721,7 +726,7 @@ get_pattern(End, Cmd, State) ->
get_pattern(End, [End|Rest], State, []) when State#state.pattern /= undefined ->
{ok, Rest, State};
get_pattern(End, [End|Rest], State, Result) ->
- case regexp:parse(lists:reverse(Result)) of
+ case re:compile(lists:reverse(Result)) of
{error, _} ->
error(bad_pattern);
{ok, Re} ->
@@ -754,7 +759,7 @@ check_trailing_p([$p], St) ->
St#state{print=fun(Line, _) -> io:put_chars(Line) end};
check_trailing_p([], State) ->
State;
-check_trailing_p(Other, State) ->
+check_trailing_p(_Other, _State) ->
error(garbage_after_command).
error(Reason) ->
@@ -765,9 +770,9 @@ match(State) when State#state.dot == 0 ->
match(State) ->
[Line|_] = State#state.upto_dot,
Re = State#state.pattern,
- case regexp:first_match(Line#line.contents, Re) of
- {match, _, _} -> true;
- nomatch -> false
+ case re:run(Line#line.contents, Re, [{capture, none}]) of
+ match -> true;
+ nomatch -> false
end.
skip_blanks([$ |Rest]) ->
diff --git a/lib/tools/test/xref_SUITE.erl b/lib/tools/test/xref_SUITE.erl
index 2f83ab4995..e0876381ca 100644
--- a/lib/tools/test/xref_SUITE.erl
+++ b/lib/tools/test/xref_SUITE.erl
@@ -46,7 +46,8 @@
-export([
add/1, default/1, info/1, lib/1, read/1, read2/1, remove/1,
replace/1, update/1, deprecated/1, trycatch/1,
- abstract_modules/1, fun_mfa/1, qlc/1]).
+ abstract_modules/1, fun_mfa/1, fun_mfa_r14/1,
+ fun_mfa_vars/1, qlc/1]).
-export([
analyze/1, basic/1, md/1, q/1, variables/1, unused_locals/1]).
@@ -82,7 +83,7 @@ groups() ->
{files, [],
[add, default, info, lib, read, read2, remove, replace,
update, deprecated, trycatch, abstract_modules, fun_mfa,
- qlc]},
+ fun_mfa_r14, fun_mfa_vars, qlc]},
{analyses, [],
[analyze, basic, md, q, variables, unused_locals]},
{misc, [], [format_error, otp_7423, otp_7831]}].
@@ -1771,6 +1772,88 @@ fun_mfa(Conf) when is_list(Conf) ->
?line ok = file:delete(Beam),
ok.
+%% Same as the previous test case, except that we use a BEAM file
+%% that was compiled by an R14 compiler to test backward compatibility.
+fun_mfa_r14(Conf) when is_list(Conf) ->
+ Dir = ?config(data_dir, Conf),
+ MFile = fname(Dir, "fun_mfa_r14"),
+
+ A = fun_mfa_r14,
+ {ok, _} = xref:start(s),
+ {ok, A} = xref:add_module(s, MFile, {warnings,false}),
+ {ok, [{{{A,t,0},{'$M_EXPR','$F_EXPR',0}},[7]},
+ {{{A,t,0},{A,t,0}},[6]},
+ {{{A,t1,0},{'$M_EXPR','$F_EXPR',0}},[11]},
+ {{{A,t1,0},{A,t,0}},[10]},
+ {{{A,t2,0},{A,t,0}},[14]},
+ {{{A,t3,0},{A,t3,0}},[17]}]} =
+ xref:q(s, "(Lin) E"),
+
+ ok = check_state(s),
+ xref:stop(s),
+
+ ok.
+
+%% fun M:F/A with varibles.
+fun_mfa_vars(Conf) when is_list(Conf) ->
+ Dir = ?copydir,
+ File = fname(Dir, "fun_mfa_vars.erl"),
+ MFile = fname(Dir, "fun_mfa_vars"),
+ Beam = fname(Dir, "fun_mfa_vars.beam"),
+ Test = <<"-module(fun_mfa_vars).
+
+ -export([t/1, t1/1, t2/3]).
+
+ t(Mod) ->
+ F = fun Mod:bar/2,
+ (F)(a, b).
+
+ t1(Name) ->
+ F = fun ?MODULE:Name/1,
+ (F)(a).
+
+ t2(Mod, Name, Arity) ->
+ F = fun Mod:Name/Arity,
+ (F)(a).
+
+ t3(Arity) ->
+ F = fun ?MODULE:t/Arity,
+ (F)(1, 2, 3).
+
+ t4(Mod, Name) ->
+ F = fun Mod:Name/3,
+ (F)(a, b, c).
+
+ t5(Mod, Arity) ->
+ F = fun Mod:t/Arity,
+ (F)().
+ ">>,
+
+ ok = file:write_file(File, Test),
+ A = fun_mfa_vars,
+ {ok, A} = compile:file(File, [report,debug_info,{outdir,Dir}]),
+ {ok, _} = xref:start(s),
+ {ok, A} = xref:add_module(s, MFile, {warnings,false}),
+ {ok, [{{{A,t,1},{'$M_EXPR','$F_EXPR',2}},[7]},
+ {{{A,t,1},{'$M_EXPR',bar,2}},[6]},
+ {{{A,t1,1},{'$M_EXPR','$F_EXPR',1}},[11]},
+ {{{A,t1,1},{A,'$F_EXPR',1}},[10]},
+ {{{A,t2,3},{'$M_EXPR','$F_EXPR',-1}},[14]},
+ {{{A,t2,3},{'$M_EXPR','$F_EXPR',1}},[15]},
+ {{{A,t3,1},{'$M_EXPR','$F_EXPR',3}},[19]},
+ {{{A,t3,1},{fun_mfa_vars,t,-1}},[18]},
+ {{{A,t4,2},{'$M_EXPR','$F_EXPR',3}},[22,23]},
+ {{{A,t5,2},{'$M_EXPR','$F_EXPR',0}},[27]},
+ {{{A,t5,2},{'$M_EXPR',t,-1}},[26]}]} =
+ xref:q(s, "(Lin) E"),
+
+ ok = check_state(s),
+ xref:stop(s),
+
+ ok = file:delete(File),
+ ok = file:delete(Beam),
+ ok.
+
qlc(suite) -> [];
qlc(doc) -> ["OTP-5195: A bug fix when using qlc:q/1,2."];
qlc(Conf) when is_list(Conf) ->
diff --git a/lib/tools/test/xref_SUITE_data/fun_mfa_r14.beam b/lib/tools/test/xref_SUITE_data/fun_mfa_r14.beam
new file mode 100644
index 0000000000..4645525690
--- /dev/null
+++ b/lib/tools/test/xref_SUITE_data/fun_mfa_r14.beam
Binary files differ
diff --git a/lib/tools/test/xref_SUITE_data/fun_mfa_r14.erl b/lib/tools/test/xref_SUITE_data/fun_mfa_r14.erl
new file mode 100644
index 0000000000..293bd83a8b
--- /dev/null
+++ b/lib/tools/test/xref_SUITE_data/fun_mfa_r14.erl
@@ -0,0 +1,18 @@
+-module(fun_mfa_r14).
+
+-export([t/0, t1/0, t2/0, t3/0]).
+
+t() ->
+ F = fun ?MODULE:t/0,
+ (F)().
+
+t1() ->
+ F = fun t/0,
+ (F)().
+
+t2() ->
+ fun ?MODULE:t/0().
+
+t3() ->
+ fun t3/0().
+
diff --git a/lib/tv/doc/src/Makefile b/lib/tv/doc/src/Makefile
index f30e0307a9..5a41b28d48 100644
--- a/lib/tv/doc/src/Makefile
+++ b/lib/tv/doc/src/Makefile
@@ -26,14 +26,6 @@ VSN=$(TV_VSN)
APPLICATION=tv
# ----------------------------------------------------
-# Include dependency
-# ----------------------------------------------------
-
-ifndef DOCSUPPORT
-include make.dep
-endif
-
-# ----------------------------------------------------
# Release directory specification
# ----------------------------------------------------
RELSYSDIR = $(RELEASE_PATH)/lib/$(APPLICATION)-$(VSN)
@@ -89,32 +81,10 @@ EXTRA_FILES = \
MAN3_FILES = $(XML_REF3_FILES:%.xml=$(MAN3DIR)/%.3)
-ifdef DOCSUPPORT
-
HTML_REF_MAN_FILE = $(HTMLDIR)/index.html
TOP_PDF_FILE = $(PDFDIR)/$(APPLICATION)-$(VSN).pdf
-else
-
-TEX_FILES_BOOK = \
- $(BOOK_FILES:%.xml=%.tex)
-TEX_FILES_REF_MAN = $(XML_REF3_FILES:%.xml=%.tex) \
- $(XML_APPLICATION_FILES:%.xml=%.tex)
-TEX_FILES_USERS_GUIDE = \
- $(XML_CHAPTER_FILES:%.xml=%.tex)
-
-TOP_PDF_FILE = tv-$(VSN).pdf
-TOP_PS_FILE = tv-$(VSN).ps
-
-$(TOP_PDF_FILE): book.dvi ../../vsn.mk
- $(DVI2PS) $(DVIPS_FLAGS) -f $< | $(DISTILL) $(DISTILL_FLAGS) > $@
-
-$(TOP_PS_FILE): book.dvi ../../vsn.mk
- $(DVI2PS) $(DVIPS_FLAGS) -f $< > $@
-
-endif
-
# ----------------------------------------------------
# FLAGS
# ----------------------------------------------------
@@ -127,8 +97,6 @@ DVIPS_FLAGS +=
$(HTMLDIR)/%.gif: %.gif
$(INSTALL_DATA) $< $@
-ifdef DOCSUPPORT
-
docs: pdf html man
$(TOP_PDF_FILE): $(XML_FILES)
@@ -144,31 +112,6 @@ clean clean_docs:
rm -f $(TOP_PDF_FILE) $(TOP_PDF_FILE:%.pdf=%.fo)
rm -f errs core *~
-else
-
-ifeq ($(DOCTYPE),pdf)
-docs: pdf
-else
-ifeq ($(DOCTYPE),ps)
-docs: ps
-else
-docs: html gifs man
-endif
-endif
-
-pdf: $(TOP_PDF_FILE)
-
-ps: $(TOP_PS_FILE)
-
-html: $(HTML_FILES) gifs
-
-clean clean_docs clean_tex:
- rm -f $(TEX_FILES_USERS_GUIDE) $(TEX_FILES_REF_MAN) $(TEX_FILES_BOOK)
- rm -f $(HTML_FILES) $(MAN3_FILES)
- rm -f $(TOP_PDF_FILE) $(TOP_PS_FILE)
- rm -f errs core *~ $(LATEX_CLEAN)
-endif
-
man: $(MAN3_FILES)
gifs: $(GIF_FILES:%=$(HTMLDIR)/%)
@@ -181,8 +124,6 @@ debug opt:
# ----------------------------------------------------
include $(ERL_TOP)/make/otp_release_targets.mk
-ifdef DOCSUPPORT
-
release_docs_spec: docs
$(INSTALL_DIR) $(RELSYSDIR)/doc/pdf
$(INSTALL_DATA) $(TOP_PDF_FILE) $(RELSYSDIR)/doc/pdf
@@ -193,29 +134,5 @@ release_docs_spec: docs
$(INSTALL_DIR) $(RELEASE_PATH)/man/man3
$(INSTALL_DATA) $(MAN3_FILES) $(RELEASE_PATH)/man/man3
-else
-
-ifeq ($(DOCTYPE),pdf)
-release_docs_spec: pdf
- $(INSTALL_DIR) $(RELEASE_PATH)/pdf
- $(INSTALL_DATA) $(TOP_PDF_FILE) $(RELEASE_PATH)/pdf
-else
-ifeq ($(DOCTYPE),ps)
-release_docs_spec: ps
- $(INSTALL_DIR) $(RELEASE_PATH)/ps
- $(INSTALL_DATA) $(TOP_PS_FILE) $(RELEASE_PATH)/ps
-else
-release_docs_spec: docs
- $(INSTALL_DIR) $(RELSYSDIR)/doc/html
- $(INSTALL_DATA) $(GIF_FILES) $(EXTRA_FILES) $(HTML_FILES) \
- $(RELSYSDIR)/doc/html
- $(INSTALL_DATA) $(INFO_FILE) $(RELSYSDIR)
- $(INSTALL_DIR) $(RELEASE_PATH)/man/man3
- $(INSTALL_DATA) $(MAN3_FILES) $(RELEASE_PATH)/man/man3
-endif
-endif
-
-endif
-
release_spec:
diff --git a/lib/tv/doc/src/make.dep b/lib/tv/doc/src/make.dep
deleted file mode 100644
index 8437e320c6..0000000000
--- a/lib/tv/doc/src/make.dep
+++ /dev/null
@@ -1,32 +0,0 @@
-# ----------------------------------------------------
-# >>>> Do not edit this file <<<<
-# This file was automaticly generated by
-# /home/otp/bin/docdepend
-# ----------------------------------------------------
-
-
-# ----------------------------------------------------
-# TeX files that the DVI file depend on
-# ----------------------------------------------------
-
-book.dvi: book.tex part.tex ref_man.tex table_visualizer_chapter.tex \
- tv.tex
-
-# ----------------------------------------------------
-# Source inlined when transforming from source to LaTeX
-# ----------------------------------------------------
-
-book.tex: ref_man.xml
-
-# ----------------------------------------------------
-# Pictures that the DVI file depend on
-# ----------------------------------------------------
-
-book.dvi: info_window.ps set_poll_int.ps tv_create_table.ps \
- tv_record_editor_mnesia.ps tv_row_marked.ps \
- tv_row_marked_popup.ps tv_search_result.ps \
- tv_search_window.ps tv_start.ps tv_start_mnesia.ps \
- tv_start_other_node.ps tv_start_pid_sorted.ps \
- tv_start_system.ps tv_start_system_unreadable.ps \
- tv_table_browser.ps tv_table_browser_updated.ps
-
diff --git a/lib/tv/src/tv_db_search.erl b/lib/tv/src/tv_db_search.erl
index edd3c188e2..7634bc63b6 100644
--- a/lib/tv/src/tv_db_search.erl
+++ b/lib/tv/src/tv_db_search.erl
@@ -244,10 +244,10 @@ get_entry_text() ->
string_to_regexp(Str) ->
- case regexp:parse(Str) of
+ case re:compile(Str) of
{ok, RegExp} ->
{ok, RegExp};
- _Error ->
+ {error, _Error} ->
case get(error_msg_mode) of
normal ->
{error, {not_a_regexp, "Please enter a regular expression!"}};
@@ -410,33 +410,11 @@ search_for_regexp(Pattern, Elem, ListAsStr) ->
lists:flatten(tv_io_lib:write(Elem))
end,
- case regexp:first_match(ListToSearch, Pattern) of
- {match, _, _} ->
+ case re:run(ListToSearch, Pattern, [{capture,none}]) of
+ match ->
found;
- _Other ->
+ nomatch ->
not_found
- %% The code below shall be used instead if it is desired to
- %% compare each *element* in the tuples to the regular expression,
- %% i.e., treat each element as a new line/string.
- %% The difference is most easily explained through an example:
- %% If we treat each tuple as a new line/string, the regular expression
- %% "^{win" will match the string "{win, 1, 2, 3}", but not the string
- %% "{1, {win,2}}".
- %% If we treat each element as a new line/string, the RE "^{win" will match
- %% both strings above.
-
- %% SearchList = tuple_to_list(Elem),
- %% case lists:dropwhile(
- %% fun(H) ->
- %% nomatch == regexp:first_match(lists:flatten(io_lib:write(H)),
- %% Pattern)
- %% end,
- %% SearchList) of
- %% [] ->
- %% not_found;
- %% _AnyList ->
- %% found
- %% end
end.
diff --git a/lib/tv/src/tv_main.erl b/lib/tv/src/tv_main.erl
index 2f743c2397..283ba4c967 100644
--- a/lib/tv/src/tv_main.erl
+++ b/lib/tv/src/tv_main.erl
@@ -312,7 +312,7 @@ analyze_error(Cause, Node, Table) ->
handle_error(mnesia_not_started, Node, Table);
{badrpc, {'EXIT', {aborted, {node_not_running,_ErrNode}}}} ->
handle_error(mnesia_not_started, Node, Table);
- {'EXIT', {undef, {mnesia,_Fcn,_Args}}} ->
+ {'EXIT', {undef, {mnesia,_Fcn,_Args,_}}} ->
handle_error(mnesia_not_started, Node, Table);
{'EXIT', Reason} ->
diff --git a/lib/tv/src/tv_mnesia_rpc.erl b/lib/tv/src/tv_mnesia_rpc.erl
index a2385714ec..4a75994145 100644
--- a/lib/tv/src/tv_mnesia_rpc.erl
+++ b/lib/tv/src/tv_mnesia_rpc.erl
@@ -87,6 +87,8 @@ chk(Result) ->
throw(mnesia_not_started);
{badrpc, _Reason} ->
throw(mnesia_not_started);
+ {'EXIT', {undef, {mnesia,_Fcn,_Args,_}}} ->
+ throw(mnesia_not_started);
{'EXIT', {undef, {mnesia,_Fcn,_Args}}} ->
throw(mnesia_not_started);
diff --git a/lib/typer/src/typer.erl b/lib/typer/src/typer.erl
index f2a70f49b7..fd39b55dd4 100644
--- a/lib/typer/src/typer.erl
+++ b/lib/typer/src/typer.erl
@@ -119,9 +119,9 @@ extract(#analysis{macros = Macros,
{ok, RecDict} ->
Mod = list_to_atom(filename:basename(File, ".erl")),
case dialyzer_utils:get_spec_info(Mod, AbstractCode, RecDict) of
- {ok, SpecDict} ->
+ {ok, SpecDict, CbDict} ->
CS1 = dialyzer_codeserver:store_temp_records(Mod, RecDict, CS),
- dialyzer_codeserver:store_temp_contracts(Mod, SpecDict, CS1);
+ dialyzer_codeserver:store_temp_contracts(Mod, SpecDict, CbDict, CS1);
{error, Reason} -> compile_error([Reason])
end;
{error, Reason} -> compile_error([Reason])
@@ -873,16 +873,16 @@ collect_one_file_info(File, Analysis) ->
Mod = cerl:concrete(cerl:module_name(Core)),
case dialyzer_utils:get_spec_info(Mod, AbstractCode, Records) of
{error, Reason} -> compile_error([Reason]);
- {ok, SpecInfo} ->
+ {ok, SpecInfo, CbInfo} ->
ExpTypes = get_exported_types_from_core(Core),
- analyze_core_tree(Core, Records, SpecInfo, ExpTypes,
- Analysis, File)
+ analyze_core_tree(Core, Records, SpecInfo, CbInfo,
+ ExpTypes, Analysis, File)
end
end
end
end.
-analyze_core_tree(Core, Records, SpecInfo, ExpTypes, Analysis, File) ->
+analyze_core_tree(Core, Records, SpecInfo, CbInfo, ExpTypes, Analysis, File) ->
Module = cerl:concrete(cerl:module_name(Core)),
TmpTree = cerl:from_records(Core),
CS1 = Analysis#analysis.codeserver,
@@ -894,7 +894,8 @@ analyze_core_tree(Core, Records, SpecInfo, ExpTypes, Analysis, File) ->
CS5 =
case Analysis#analysis.no_spec of
true -> CS4;
- false -> dialyzer_codeserver:store_temp_contracts(Module, SpecInfo, CS4)
+ false ->
+ dialyzer_codeserver:store_temp_contracts(Module, SpecInfo, CbInfo, CS4)
end,
OldExpTypes = dialyzer_codeserver:get_temp_exported_types(CS5),
MergedExpTypes = sets:union(ExpTypes, OldExpTypes),
diff --git a/lib/webtool/doc/src/make.dep b/lib/webtool/doc/src/make.dep
deleted file mode 100644
index 87526b3f73..0000000000
--- a/lib/webtool/doc/src/make.dep
+++ /dev/null
@@ -1,20 +0,0 @@
-# ----------------------------------------------------
-# >>>> Do not edit this file <<<<
-# This file was automaticly generated by
-# /home/otp/bin/docdepend
-# ----------------------------------------------------
-
-
-# ----------------------------------------------------
-# TeX files that the DVI file depend on
-# ----------------------------------------------------
-
-book.dvi: book.tex part.tex ref_man.tex start_webtool.tex \
- webtool.tex webtool_chapter.tex
-
-# ----------------------------------------------------
-# Source inlined when transforming from source to LaTeX
-# ----------------------------------------------------
-
-book.tex: ref_man.xml
-
diff --git a/lib/wx/api_gen/wx_doxygen.conf b/lib/wx/api_gen/wx_doxygen.conf
index df150fd154..829702cbbf 100644
--- a/lib/wx/api_gen/wx_doxygen.conf
+++ b/lib/wx/api_gen/wx_doxygen.conf
@@ -251,6 +251,7 @@ PREDEFINED = \
wxUSE_DATAOBJ=1 \
wxUSE_SLIDER=1 \
wxUSE_CLIPBOARD=1 \
+ wxUSE_SYSTEM_OPTIONS=1 \
wxABI_VERSION=20809 \
__WXGTK24__=1 \
__WXGTK20__=1 \
diff --git a/lib/wx/api_gen/wx_gen_cpp.erl b/lib/wx/api_gen/wx_gen_cpp.erl
index 4632fdbffe..1b4c32db24 100644
--- a/lib/wx/api_gen/wx_gen_cpp.erl
+++ b/lib/wx/api_gen/wx_gen_cpp.erl
@@ -1034,6 +1034,7 @@ gen_macros() ->
w("#include <wx/html/htmlwin.h>~n"),
w("#include <wx/html/htmlcell.h>~n"),
w("#include <wx/filename.h>~n"),
+ w("#include <wx/sysopt.h>~n"),
w("~n~n", []),
w("#ifndef wxICON_DEFAULT_BITMAP_TYPE~n",[]),
diff --git a/lib/wx/api_gen/wx_gen_erl.erl b/lib/wx/api_gen/wx_gen_erl.erl
index e882ae87ca..5d73d93ead 100644
--- a/lib/wx/api_gen/wx_gen_erl.erl
+++ b/lib/wx/api_gen/wx_gen_erl.erl
@@ -830,7 +830,7 @@ doc_arg_type3(#type{base={comp,_,Tup}}) ->
Doc = fun({int,V}) -> V ++ "::integer()";
({double,V}) -> V ++ "::float()"
end,
- "{" ++ args(Doc, ",", Tup) ++ "}";
+ "{" ++ args(Doc, ", ", Tup) ++ "}";
doc_arg_type3(T) -> ?error({unknown_type,T}).
doc_return_types(T, Ps) ->
@@ -839,9 +839,9 @@ doc_return_types2(void, []) -> "ok";
doc_return_types2(void, [#param{type=T}]) -> doc_arg_type2(T);
doc_return_types2(T, []) -> doc_arg_type2(T);
doc_return_types2(void, Ps) ->
- "{" ++ args(fun doc_arg_type/1,",",Ps) ++ "}";
+ "{" ++ args(fun doc_arg_type/1,", ",Ps) ++ "}";
doc_return_types2(T, Ps) ->
- "{" ++ doc_arg_type2(T) ++ "," ++ args(fun doc_arg_type/1,",",Ps) ++ "}".
+ "{" ++ doc_arg_type2(T) ++ ", " ++ args(fun doc_arg_type/1,", ",Ps) ++ "}".
break(xhtml) -> "<br />";
break(_) -> "".
diff --git a/lib/wx/api_gen/wxapi.conf b/lib/wx/api_gen/wxapi.conf
index 8ee4451057..ff618faf04 100644
--- a/lib/wx/api_gen/wxapi.conf
+++ b/lib/wx/api_gen/wxapi.conf
@@ -1755,6 +1755,9 @@
'GetColour','GetFont','GetMetric','GetScreenType'
]}.
+{class, wxSystemOptions, object, [],
+ ['GetOption', 'GetOptionInt', 'HasOption', 'IsFalse', 'SetOption']}.
+
{class, wxAuiNotebookEvent, wxNotifyEvent,
[{acc, [{old_selection, "GetOldSelection()"},
{selection, "GetSelection()"},
diff --git a/lib/wx/c_src/Makefile.in b/lib/wx/c_src/Makefile.in
index 69418f62ef..ae5a149d14 100644
--- a/lib/wx/c_src/Makefile.in
+++ b/lib/wx/c_src/Makefile.in
@@ -31,6 +31,8 @@ override TYPE=opt
endif
SO_EXT = @SO_EXT@
+OBJC_CC=@OBJC_CC@
+OBJC_CFLAGS=@OBJC_CFLAGS@
GENERAL = wxe_driver wxe_ps_init wxe_impl wxePrintout wxe_return wxe_gl
GENERAL_H = wxe_driver.h wxe_impl.h wxe_return.h
@@ -116,6 +118,7 @@ endif
GL_LIBS = @GL_LIBS@
CC_O = $(CC) -c $(CFLAGS) $(WX_CFLAGS) $(COMMON_CFLAGS)
+OBJC_CC_O = $(OBJC_CC) -c $(CFLAGS) $(OBJC_CFLAGS) $(WX_CFLAGS) $(COMMON_CFLAGS)
CPP_O = $(CPP) -c $(CXX_FLAGS) $(WX_CXX_FLAGS) $(COMMON_CFLAGS)
# Targets
@@ -152,6 +155,10 @@ $(SYS_TYPE)/%.o: %.c
mkdir -p $(SYS_TYPE)
$(CC_O) $< -o $@
+$(SYS_TYPE)/wxe_ps_init.o: wxe_ps_init.c
+ mkdir -p $(SYS_TYPE)
+ $(OBJC_CC_O) $< -o $@
+
$(SYS_TYPE)/%.o: gen/%.cpp
mkdir -p $(SYS_TYPE)
$(CPP_O) $< -o $@
diff --git a/lib/wx/c_src/egl_impl.cpp b/lib/wx/c_src/egl_impl.cpp
index 6d873abc44..1379f07523 100644
--- a/lib/wx/c_src/egl_impl.cpp
+++ b/lib/wx/c_src/egl_impl.cpp
@@ -70,8 +70,8 @@ typedef char DL_CHAR;
# define OPENGL_LIB "/System/Library/Frameworks/OpenGL.framework/Versions/A/Libraries/libGL.dylib"
# define OPENGLU_LIB "/System/Library/Frameworks/OpenGL.framework/Versions/A/Libraries/libGLU.dylib"
# else
-# define OPENGL_LIB "libGL.so"
-# define OPENGLU_LIB "libGLU.so"
+# define OPENGL_LIB "libGL.so.1"
+# define OPENGLU_LIB "libGLU.so.1"
# endif
#endif
extern "C" {
@@ -121,7 +121,7 @@ int load_gl_functions() {
}
}
}
- dlclose(LIBhandle);
+ // dlclose(LIBhandle);
// fprintf(stderr, "OPENGL library is loaded\r\n");
} else {
fprintf(stderr, "Could NOT load OpenGL library: %s\r\n", DLName);
@@ -150,7 +150,7 @@ int load_gl_functions() {
}
}
}
- dlclose(LIBhandle);
+ // dlclose(LIBhandle);
// fprintf(stderr, "GLU library is loaded\r\n");
} else {
fprintf(stderr, "Could NOT load OpenGL GLU library: %s\r\n", DLName);
@@ -195,7 +195,7 @@ egl_ogla_error(GLenum errorCode)
// msg.Printf(wxT("Tesselation error: %d: "), (int)errorCode);
// msg += wxString::FromAscii((char *) err);
// send_msg("error", &msg);
- fprintf(stderr, "Tesselation error: %d\r\n", (int) errorCode);
+ fprintf(stderr, "Tesselation error: %d: %s\r\n", (int) errorCode, err);
}
void CALLBACK
@@ -250,7 +250,7 @@ int erl_tess_impl(char* buff, ErlDrvPort port, ErlDrvTermData caller)
int *vertices;
int num_vertices;
GLdouble *n;
- int n_pos, AP, res;
+ int n_pos, AP;
num_vertices = * (int *) buff; buff += 8; /* Align */
n = (double *) buff; buff += 8*3;
@@ -293,7 +293,7 @@ int erl_tess_impl(char* buff, ErlDrvPort port, ErlDrvTermData caller)
rt[AP++] = ERL_DRV_TUPLE; rt[AP++] = 2; // Return tuple {list, Bin}
rt[AP++] = ERL_DRV_TUPLE; rt[AP++] = 2; // Result tuple
- res = driver_send_term(port,caller,rt,AP);
+ driver_send_term(port,caller,rt,AP);
/* fprintf(stderr, "List %d: %d %d %d \r\n", */
/* res, */
/* n_pos, */
diff --git a/lib/wx/c_src/gen/wxe_events.cpp b/lib/wx/c_src/gen/wxe_events.cpp
index b9769318af..cda98bfc3f 100644
--- a/lib/wx/c_src/gen/wxe_events.cpp
+++ b/lib/wx/c_src/gen/wxe_events.cpp
@@ -266,41 +266,41 @@ void initEventTable()
{wxEVT_COMMAND_SPLITTER_DOUBLECLICKED, 218, "command_splitter_doubleclicked"},
{wxEVT_COMMAND_SPLITTER_UNSPLIT, 218, "command_splitter_unsplit"},
{wxEVT_COMMAND_HTML_LINK_CLICKED, 220, "command_html_link_clicked"},
- {wxEVT_COMMAND_AUINOTEBOOK_PAGE_CLOSE, 222, "command_auinotebook_page_close"},
- {wxEVT_COMMAND_AUINOTEBOOK_PAGE_CHANGED, 222, "command_auinotebook_page_changed"},
- {wxEVT_COMMAND_AUINOTEBOOK_PAGE_CHANGING, 222, "command_auinotebook_page_changing"},
- {wxEVT_COMMAND_AUINOTEBOOK_BUTTON, 222, "command_auinotebook_button"},
- {wxEVT_COMMAND_AUINOTEBOOK_BEGIN_DRAG, 222, "command_auinotebook_begin_drag"},
- {wxEVT_COMMAND_AUINOTEBOOK_END_DRAG, 222, "command_auinotebook_end_drag"},
- {wxEVT_COMMAND_AUINOTEBOOK_DRAG_MOTION, 222, "command_auinotebook_drag_motion"},
- {wxEVT_COMMAND_AUINOTEBOOK_ALLOW_DND, 222, "command_auinotebook_allow_dnd"},
+ {wxEVT_COMMAND_AUINOTEBOOK_PAGE_CLOSE, 223, "command_auinotebook_page_close"},
+ {wxEVT_COMMAND_AUINOTEBOOK_PAGE_CHANGED, 223, "command_auinotebook_page_changed"},
+ {wxEVT_COMMAND_AUINOTEBOOK_PAGE_CHANGING, 223, "command_auinotebook_page_changing"},
+ {wxEVT_COMMAND_AUINOTEBOOK_BUTTON, 223, "command_auinotebook_button"},
+ {wxEVT_COMMAND_AUINOTEBOOK_BEGIN_DRAG, 223, "command_auinotebook_begin_drag"},
+ {wxEVT_COMMAND_AUINOTEBOOK_END_DRAG, 223, "command_auinotebook_end_drag"},
+ {wxEVT_COMMAND_AUINOTEBOOK_DRAG_MOTION, 223, "command_auinotebook_drag_motion"},
+ {wxEVT_COMMAND_AUINOTEBOOK_ALLOW_DND, 223, "command_auinotebook_allow_dnd"},
#if wxCHECK_VERSION(2,8,5)
- {wxEVT_COMMAND_AUINOTEBOOK_TAB_MIDDLE_DOWN, 222, "command_auinotebook_tab_middle_down"},
+ {wxEVT_COMMAND_AUINOTEBOOK_TAB_MIDDLE_DOWN, 223, "command_auinotebook_tab_middle_down"},
#endif
#if wxCHECK_VERSION(2,8,5)
- {wxEVT_COMMAND_AUINOTEBOOK_TAB_MIDDLE_UP, 222, "command_auinotebook_tab_middle_up"},
+ {wxEVT_COMMAND_AUINOTEBOOK_TAB_MIDDLE_UP, 223, "command_auinotebook_tab_middle_up"},
#endif
#if wxCHECK_VERSION(2,8,5)
- {wxEVT_COMMAND_AUINOTEBOOK_TAB_RIGHT_DOWN, 222, "command_auinotebook_tab_right_down"},
+ {wxEVT_COMMAND_AUINOTEBOOK_TAB_RIGHT_DOWN, 223, "command_auinotebook_tab_right_down"},
#endif
#if wxCHECK_VERSION(2,8,5)
- {wxEVT_COMMAND_AUINOTEBOOK_TAB_RIGHT_UP, 222, "command_auinotebook_tab_right_up"},
+ {wxEVT_COMMAND_AUINOTEBOOK_TAB_RIGHT_UP, 223, "command_auinotebook_tab_right_up"},
#endif
#if wxCHECK_VERSION(2,8,5)
- {wxEVT_COMMAND_AUINOTEBOOK_PAGE_CLOSED, 222, "command_auinotebook_page_closed"},
+ {wxEVT_COMMAND_AUINOTEBOOK_PAGE_CLOSED, 223, "command_auinotebook_page_closed"},
#endif
#if wxCHECK_VERSION(2,8,5)
- {wxEVT_COMMAND_AUINOTEBOOK_DRAG_DONE, 222, "command_auinotebook_drag_done"},
+ {wxEVT_COMMAND_AUINOTEBOOK_DRAG_DONE, 223, "command_auinotebook_drag_done"},
#endif
#if wxCHECK_VERSION(2,8,5)
- {wxEVT_COMMAND_AUINOTEBOOK_BG_DCLICK, 222, "command_auinotebook_bg_dclick"},
+ {wxEVT_COMMAND_AUINOTEBOOK_BG_DCLICK, 223, "command_auinotebook_bg_dclick"},
#endif
- {wxEVT_AUI_PANE_BUTTON, 223, "aui_pane_button"},
- {wxEVT_AUI_PANE_CLOSE, 223, "aui_pane_close"},
- {wxEVT_AUI_PANE_MAXIMIZE, 223, "aui_pane_maximize"},
- {wxEVT_AUI_PANE_RESTORE, 223, "aui_pane_restore"},
- {wxEVT_AUI_RENDER, 223, "aui_render"},
- {wxEVT_AUI_FIND_MANAGER, 223, "aui_find_manager"},
+ {wxEVT_AUI_PANE_BUTTON, 224, "aui_pane_button"},
+ {wxEVT_AUI_PANE_CLOSE, 224, "aui_pane_close"},
+ {wxEVT_AUI_PANE_MAXIMIZE, 224, "aui_pane_maximize"},
+ {wxEVT_AUI_PANE_RESTORE, 224, "aui_pane_restore"},
+ {wxEVT_AUI_RENDER, 224, "aui_render"},
+ {wxEVT_AUI_FIND_MANAGER, 224, "aui_find_manager"},
{-1, 0, }
};
for(int i=0; event_types[i].ev_type != -1; i++) {
@@ -778,7 +778,7 @@ case 220: {// wxHtmlLinkEvent
rt.addTupleCount(3);
break;
}
-case 222: {// wxAuiNotebookEvent
+case 223: {// wxAuiNotebookEvent
wxAuiNotebookEvent * ev = (wxAuiNotebookEvent *) event;
wxAuiNotebook * GetDragSource = ev->GetDragSource();
evClass = (char*)"wxAuiNotebookEvent";
@@ -790,7 +790,7 @@ case 222: {// wxAuiNotebookEvent
rt.addTupleCount(5);
break;
}
-case 223: {// wxAuiManagerEvent
+case 224: {// wxAuiManagerEvent
wxAuiManagerEvent * ev = (wxAuiManagerEvent *) event;
wxAuiManager * GetManager = ev->GetManager();
wxAuiPaneInfo * GetPane = ev->GetPane();
diff --git a/lib/wx/c_src/gen/wxe_funcs.cpp b/lib/wx/c_src/gen/wxe_funcs.cpp
index afef2990b4..f456bd3287 100644
--- a/lib/wx/c_src/gen/wxe_funcs.cpp
+++ b/lib/wx/c_src/gen/wxe_funcs.cpp
@@ -31160,6 +31160,56 @@ case wxSystemSettings_GetScreenType: { // wxSystemSettings::GetScreenType
rt.addInt(Result);
break;
}
+case wxSystemOptions_GetOption: { // wxSystemOptions::GetOption
+ int * nameLen = (int *) bp; bp += 4;
+ wxString name = wxString(bp, wxConvUTF8);
+ bp += *nameLen+((8-((4+ *nameLen) & 7)) & 7);
+ wxString Result = wxSystemOptions::GetOption(name);
+ rt.add(Result);
+ break;
+}
+case wxSystemOptions_GetOptionInt: { // wxSystemOptions::GetOptionInt
+ int * nameLen = (int *) bp; bp += 4;
+ wxString name = wxString(bp, wxConvUTF8);
+ bp += *nameLen+((8-((4+ *nameLen) & 7)) & 7);
+ int Result = wxSystemOptions::GetOptionInt(name);
+ rt.addInt(Result);
+ break;
+}
+case wxSystemOptions_HasOption: { // wxSystemOptions::HasOption
+ int * nameLen = (int *) bp; bp += 4;
+ wxString name = wxString(bp, wxConvUTF8);
+ bp += *nameLen+((8-((4+ *nameLen) & 7)) & 7);
+ bool Result = wxSystemOptions::HasOption(name);
+ rt.addBool(Result);
+ break;
+}
+case wxSystemOptions_IsFalse: { // wxSystemOptions::IsFalse
+ int * nameLen = (int *) bp; bp += 4;
+ wxString name = wxString(bp, wxConvUTF8);
+ bp += *nameLen+((8-((4+ *nameLen) & 7)) & 7);
+ bool Result = wxSystemOptions::IsFalse(name);
+ rt.addBool(Result);
+ break;
+}
+case wxSystemOptions_SetOption_2_1: { // wxSystemOptions::SetOption
+ int * nameLen = (int *) bp; bp += 4;
+ wxString name = wxString(bp, wxConvUTF8);
+ bp += *nameLen+((8-((4+ *nameLen) & 7)) & 7);
+ int * valueLen = (int *) bp; bp += 4;
+ wxString value = wxString(bp, wxConvUTF8);
+ bp += *valueLen+((8-((4+ *valueLen) & 7)) & 7);
+ wxSystemOptions::SetOption(name,value);
+ break;
+}
+case wxSystemOptions_SetOption_2_0: { // wxSystemOptions::SetOption
+ int * nameLen = (int *) bp; bp += 4;
+ wxString name = wxString(bp, wxConvUTF8);
+ bp += *nameLen+((8-((4+ *nameLen) & 7)) & 7);
+ int * value = (int *) bp; bp += 4;
+ wxSystemOptions::SetOption(name,(int) *value);
+ break;
+}
case wxAuiNotebookEvent_SetSelection: { // wxAuiNotebookEvent::SetSelection
wxAuiNotebookEvent *This = (wxAuiNotebookEvent *) getPtr(bp,memenv); bp += 4;
int * s = (int *) bp; bp += 4;
@@ -31294,7 +31344,7 @@ case wxAuiManagerEvent_CanVeto: { // wxAuiManagerEvent::CanVeto
}
case wxLogNull_new: { // wxLogNull::wxLogNull
wxLogNull * Result = new wxLogNull();
- newPtr((void *) Result, 224, memenv);
+ newPtr((void *) Result, 225, memenv);
rt.addRef(getRef((void *)Result,memenv), "wxLogNull");
break;
}
@@ -31347,7 +31397,7 @@ void WxeApp::delete_object(void *ptr, wxeRefData *refd) {
case 212: /* delete (wxFileDataObject *) ptr;These objects must be deleted by owner object */ break;
case 213: /* delete (wxTextDataObject *) ptr;These objects must be deleted by owner object */ break;
case 214: /* delete (wxBitmapDataObject *) ptr;These objects must be deleted by owner object */ break;
- case 224: delete (wxLogNull *) ptr; break;
+ case 225: delete (wxLogNull *) ptr; break;
default: delete (wxObject *) ptr;
}}
diff --git a/lib/wx/c_src/gen/wxe_macros.h b/lib/wx/c_src/gen/wxe_macros.h
index be0481564f..ddc7c0155f 100644
--- a/lib/wx/c_src/gen/wxe_macros.h
+++ b/lib/wx/c_src/gen/wxe_macros.h
@@ -60,6 +60,7 @@
#include <wx/html/htmlwin.h>
#include <wx/html/htmlcell.h>
#include <wx/filename.h>
+#include <wx/sysopt.h>
#ifndef wxICON_DEFAULT_BITMAP_TYPE
@@ -3318,25 +3319,31 @@
#define wxSystemSettings_GetFont 3489
#define wxSystemSettings_GetMetric 3490
#define wxSystemSettings_GetScreenType 3491
-#define wxAuiNotebookEvent_SetSelection 3492
-#define wxAuiNotebookEvent_GetSelection 3493
-#define wxAuiNotebookEvent_SetOldSelection 3494
-#define wxAuiNotebookEvent_GetOldSelection 3495
-#define wxAuiNotebookEvent_SetDragSource 3496
-#define wxAuiNotebookEvent_GetDragSource 3497
-#define wxAuiManagerEvent_SetManager 3498
-#define wxAuiManagerEvent_GetManager 3499
-#define wxAuiManagerEvent_SetPane 3500
-#define wxAuiManagerEvent_GetPane 3501
-#define wxAuiManagerEvent_SetButton 3502
-#define wxAuiManagerEvent_GetButton 3503
-#define wxAuiManagerEvent_SetDC 3504
-#define wxAuiManagerEvent_GetDC 3505
-#define wxAuiManagerEvent_Veto 3506
-#define wxAuiManagerEvent_GetVeto 3507
-#define wxAuiManagerEvent_SetCanVeto 3508
-#define wxAuiManagerEvent_CanVeto 3509
-#define wxLogNull_new 3510
-#define wxLogNull_destroy 3511
+#define wxSystemOptions_GetOption 3492
+#define wxSystemOptions_GetOptionInt 3493
+#define wxSystemOptions_HasOption 3494
+#define wxSystemOptions_IsFalse 3495
+#define wxSystemOptions_SetOption_2_1 3496
+#define wxSystemOptions_SetOption_2_0 3497
+#define wxAuiNotebookEvent_SetSelection 3498
+#define wxAuiNotebookEvent_GetSelection 3499
+#define wxAuiNotebookEvent_SetOldSelection 3500
+#define wxAuiNotebookEvent_GetOldSelection 3501
+#define wxAuiNotebookEvent_SetDragSource 3502
+#define wxAuiNotebookEvent_GetDragSource 3503
+#define wxAuiManagerEvent_SetManager 3504
+#define wxAuiManagerEvent_GetManager 3505
+#define wxAuiManagerEvent_SetPane 3506
+#define wxAuiManagerEvent_GetPane 3507
+#define wxAuiManagerEvent_SetButton 3508
+#define wxAuiManagerEvent_GetButton 3509
+#define wxAuiManagerEvent_SetDC 3510
+#define wxAuiManagerEvent_GetDC 3511
+#define wxAuiManagerEvent_Veto 3512
+#define wxAuiManagerEvent_GetVeto 3513
+#define wxAuiManagerEvent_SetCanVeto 3514
+#define wxAuiManagerEvent_CanVeto 3515
+#define wxLogNull_new 3516
+#define wxLogNull_destroy 3517
diff --git a/lib/wx/c_src/wxe_impl.cpp b/lib/wx/c_src/wxe_impl.cpp
index e430fbc7a2..69fcd4e362 100644
--- a/lib/wx/c_src/wxe_impl.cpp
+++ b/lib/wx/c_src/wxe_impl.cpp
@@ -331,9 +331,9 @@ void handle_event_callback(ErlDrvPort port, ErlDrvTermData process)
driver_monitor_process(port, process, &monitor);
// Should we be able to handle commands when recursing? probably
erl_drv_mutex_lock(wxe_batch_locker_m);
- // fprintf(stderr, "\r\nCB EV Start ");fflush(stderr);
+ //fprintf(stderr, "\r\nCB EV Start %lu \r\n", process);fflush(stderr);
app->dispatch_cb(wxe_batch, wxe_batch_cb_saved, process);
- // fprintf(stderr, ".. done \r\n");fflush(stderr);
+ //fprintf(stderr, "CB EV done %lu \r\n", process);fflush(stderr);
wxe_batch_caller = 0;
erl_drv_mutex_unlock(wxe_batch_locker_m);
driver_demonitor_process(port, &monitor);
@@ -430,8 +430,9 @@ void WxeApp::dispatch_cb(wxList * batch, wxList * temp, ErlDrvTermData process)
wxeCommand *event = (wxeCommand *)node->GetData();
wxeMemEnv *memenv = getMemEnv(event->port);
batch->Erase(node);
+ // fprintf(stderr, " Ev %d %lu\r\n", event->op, event->caller);
if(event->caller == process || // Callbacks from CB process only
- event->op == WXE_CB_START || // Recursive event callback allow
+ event->op == WXE_CB_START || // Event callback start change process
// Allow connect_cb during CB i.e. msg from wxe_server.
(memenv && event->caller == memenv->owner))
{
@@ -453,6 +454,7 @@ void WxeApp::dispatch_cb(wxList * batch, wxList * temp, ErlDrvTermData process)
break;
default:
erl_drv_mutex_unlock(wxe_batch_locker_m);
+ size_t start=temp->GetCount();
if(event->op < OPENGL_START) {
// fprintf(stderr, " cb %d \r\n", event->op);
wxe_dispatch(*event);
@@ -460,9 +462,23 @@ void WxeApp::dispatch_cb(wxList * batch, wxList * temp, ErlDrvTermData process)
gl_dispatch(event->op,event->buffer,event->caller,event->bin);
}
erl_drv_mutex_lock(wxe_batch_locker_m);
- break;
+ if(temp->GetCount() > start) {
+ // We have recursed dispatch_cb and messages for this
+ // callback may be saved on temp list move them
+ // to orig list
+ for(wxList::compatibility_iterator node = temp->Item(start);
+ node;
+ node = node->GetNext()) {
+ wxeCommand *ev = (wxeCommand *)node->GetData();
+ if(ev->caller == process) {
+ batch->Append(ev);
+ temp->Erase(node);
+ }
+ }
+ }
if(callback_returned)
return;
+ break;
}
delete event;
} else {
diff --git a/lib/wx/configure.in b/lib/wx/configure.in
index f7128db23a..e5dc83b27e 100755
--- a/lib/wx/configure.in
+++ b/lib/wx/configure.in
@@ -138,10 +138,65 @@ esac
PTHR_CFLAGS="-D_THREAD_SAFE -D_REENTRANT"
+OBJC_CC=$CC
+OBJC_CFLAGS=""
+
dnl NOTE: CPPFLAGS will be included in CFLAGS at the end
case $host_os in
darwin*)
- C_ONLY_FLAGS="-ObjC"
+ AC_MSG_CHECKING([if compiler accepts -ObjC])
+ saved_CFLAGS=$CFLAGS
+ CFLAGS="$CFLAGS -ObjC"
+ AC_TRY_COMPILE([],[;], accept_objc_flag=true, accept_objc_flag=false)
+ if test "X$accept_objc_flag" = "Xtrue"; then
+ AC_MSG_RESULT([yes])
+ C_ONLY_FLAGS="-ObjC"
+ else
+ dnl We are probebly trying to build with a non-Apple gcc,
+ dnl which is good as long as we do not try to build Cocoa
+ dnl code. We need an Apple compiler for just that (Objective C)
+ AC_MSG_RESULT([no])
+ AC_MSG_CHECKING([for a Cocoa compliant Objective C compiler])
+ SEARCHFOR=""
+ save_IFS=$IFS
+ IFS=:
+ set $PATH
+ IFS=$save_IFS
+ while test X"$1" != X""; do
+ dnl Add all possible paths to a real apple gcc
+ SEARCHFOR="$1/gcc-apple-4.2 $SEARCHFOR"
+ shift
+ done
+ dnl Add LLVM compilers, they will work in this case
+ SEARCHFOR="/usr/bin/clang /usr/bin/gcc $SEARCHFOR"
+ APPLE_CC=""
+ dnl SEARCHFOR is reversed, so we want to find the last existing
+ dnl executable in the list
+ for x in $SEARCHFOR; do
+ if test -x $x; then
+ APPLE_CC=$x
+ fi
+ done
+ if test X$APPLE_CC = X; then
+ AC_MSG_RESULT([no])
+ dnl Complete failure, we cannot build Cocoa code
+ if test X"$WX_BUILDING_INSIDE_ERLSRC" != X"true" ; then
+ AC_MSG_ERROR([Can not find compiler to compile Cocoa applications])
+ else
+ echo "Can not find compiler to compile Cocoa applications" > ./CONF_INFO
+ WXERL_CAN_BUILD_DRIVER=false
+ AC_MSG_WARN([Can not find compiler to compile Cocoa applications])
+ fi
+ WXERL_CAN_BUILD_DRIVER=false
+ else
+ dnl We think we found an Apple compiler and will add
+ dnl Apple specific options
+ AC_MSG_RESULT($APPLE_CC)
+ OBJC_CC=$APPLE_CC
+ OBJC_CFLAGS="-ObjC"
+ fi
+ fi
+ CFLAGS=$saved_CFLAGS
CPPFLAGS="$CPPFLAGS -D_MACOSX $PTHR_CFLAGS"
;;
mingw32)
@@ -159,10 +214,16 @@ case $host_os in
;;
esac
+AC_SUBST(OBJC_CC)
+AC_SUBST(OBJC_CFLAGS)
+
case $host_os in
darwin*)
- CFLAGS="-no-cpp-precomp $CFLAGS"
LDFLAGS="-bundle -flat_namespace -undefined warning -fPIC $LDFLAGS"
+ # Check sizof_void_p as future will hold 64bit MacOS wx
+ if test $ac_cv_sizeof_void_p = 4; then
+ LDFLAGS="-m32 $LDFLAGS"
+ fi
GL_LIBS="-framework OpenGL"
;;
win32)
diff --git a/lib/wx/doc/src/make.dep b/lib/wx/doc/src/make.dep
deleted file mode 100644
index 91001be438..0000000000
--- a/lib/wx/doc/src/make.dep
+++ /dev/null
@@ -1,13 +0,0 @@
-# ----------------------------------------------------
-# >>>> Do not edit this file <<<<
-# This file was automaticly generated by
-# /home/otp/bin/docdepend
-# ----------------------------------------------------
-
-
-# ----------------------------------------------------
-# TeX files that the DVI file depend on
-# ----------------------------------------------------
-
-book.dvi: book.tex chapter.tex part.tex
-
diff --git a/lib/wx/examples/demo/Makefile b/lib/wx/examples/demo/Makefile
index 98d7c6a130..8afa0e780e 100755..100644
--- a/lib/wx/examples/demo/Makefile
+++ b/lib/wx/examples/demo/Makefile
@@ -80,7 +80,7 @@ include $(ERL_TOP)/make/otp_release_targets.mk
docs:
-release_spec:
+release_spec: opt
$(INSTALL_DIR) $(EXRELSYSDIR)
$(INSTALL_DATA) $(TESTSRC) $(EXRELSYSDIR)
$(INSTALL_DATA) $(TESTTARGETS) $(EXRELSYSDIR)
diff --git a/lib/wx/examples/simple/Makefile b/lib/wx/examples/simple/Makefile
index 41f0b46eb1..66f5952f0d 100644
--- a/lib/wx/examples/simple/Makefile
+++ b/lib/wx/examples/simple/Makefile
@@ -51,7 +51,7 @@ include $(ERL_TOP)/make/otp_release_targets.mk
docs:
-release_spec:
+release_spec: opt
$(INSTALL_DIR) $(EXRELSYSDIR)
$(INSTALL_DATA) $(TESTSRC) $(EXRELSYSDIR)
$(INSTALL_DATA) copy.xpm sample.xpm $(TESTTARGETS) $(EXRELSYSDIR)
diff --git a/lib/wx/examples/simple/hello.erl b/lib/wx/examples/simple/hello.erl
index dc845ddfbb..dc845ddfbb 100755..100644
--- a/lib/wx/examples/simple/hello.erl
+++ b/lib/wx/examples/simple/hello.erl
diff --git a/lib/wx/examples/simple/menu.erl b/lib/wx/examples/simple/menu.erl
index d573fcf13a..d573fcf13a 100755..100644
--- a/lib/wx/examples/simple/menu.erl
+++ b/lib/wx/examples/simple/menu.erl
diff --git a/lib/wx/examples/simple/minimal.erl b/lib/wx/examples/simple/minimal.erl
index dca4adc643..dca4adc643 100755..100644
--- a/lib/wx/examples/simple/minimal.erl
+++ b/lib/wx/examples/simple/minimal.erl
diff --git a/lib/wx/examples/simple/sample.xpm b/lib/wx/examples/simple/sample.xpm
index 3263b15f8a..3263b15f8a 100755..100644
--- a/lib/wx/examples/simple/sample.xpm
+++ b/lib/wx/examples/simple/sample.xpm
diff --git a/lib/wx/examples/sudoku/Makefile b/lib/wx/examples/sudoku/Makefile
index b86c654fdd..33725756b7 100755..100644
--- a/lib/wx/examples/sudoku/Makefile
+++ b/lib/wx/examples/sudoku/Makefile
@@ -51,7 +51,7 @@ include $(ERL_TOP)/make/otp_release_targets.mk
docs:
-release_spec:
+release_spec: opt
$(INSTALL_DIR) $(EXRELSYSDIR)
$(INSTALL_DATA) $(TESTSRC) sudoku.hrl $(EXRELSYSDIR)
$(INSTALL_DATA) $(TESTTARGETS) $(EXRELSYSDIR)
diff --git a/lib/wx/examples/sudoku/sudoku.erl b/lib/wx/examples/sudoku/sudoku.erl
index 01caeb9524..01caeb9524 100755..100644
--- a/lib/wx/examples/sudoku/sudoku.erl
+++ b/lib/wx/examples/sudoku/sudoku.erl
diff --git a/lib/wx/examples/sudoku/sudoku.hrl b/lib/wx/examples/sudoku/sudoku.hrl
index 775b563bdc..775b563bdc 100755..100644
--- a/lib/wx/examples/sudoku/sudoku.hrl
+++ b/lib/wx/examples/sudoku/sudoku.hrl
diff --git a/lib/wx/examples/sudoku/sudoku_board.erl b/lib/wx/examples/sudoku/sudoku_board.erl
index 756837582f..756837582f 100755..100644
--- a/lib/wx/examples/sudoku/sudoku_board.erl
+++ b/lib/wx/examples/sudoku/sudoku_board.erl
diff --git a/lib/wx/examples/sudoku/sudoku_game.erl b/lib/wx/examples/sudoku/sudoku_game.erl
index 470aee0e3b..470aee0e3b 100755..100644
--- a/lib/wx/examples/sudoku/sudoku_game.erl
+++ b/lib/wx/examples/sudoku/sudoku_game.erl
diff --git a/lib/wx/examples/sudoku/sudoku_gui.erl b/lib/wx/examples/sudoku/sudoku_gui.erl
index 4aaecfe086..4aaecfe086 100755..100644
--- a/lib/wx/examples/sudoku/sudoku_gui.erl
+++ b/lib/wx/examples/sudoku/sudoku_gui.erl
diff --git a/lib/wx/examples/xrc/Makefile b/lib/wx/examples/xrc/Makefile
index 1dfaae9689..aba58e0d0f 100755..100644
--- a/lib/wx/examples/xrc/Makefile
+++ b/lib/wx/examples/xrc/Makefile
@@ -28,7 +28,8 @@ TESTMODS = xrc
TESTTARGETS = $(TESTMODS:%=%.beam)
TESTSRC = $(TESTMODS:%=%.erl)
-RESOURCEFILES = appicon.ico basicdlg.xpm custclas.xpm fileopen.gif menu.xrc \
+RESOURCEFILES = \
+ appicon.ico basicdlg.xpm custclas.xpm fileopen.gif menu.xrc \
resource.xrc uncenter.xpm variable.xrc appicon.xpm basicdlg.xrc \
custclas.xrc filesave.gif platform.xpm stop.xpm uncenter.xrc \
artprov.xpm controls.xpm derivdlg.xpm frame.xrc platform.xrc \
@@ -59,7 +60,7 @@ include $(ERL_TOP)/make/otp_release_targets.mk
docs:
-release_spec:
+release_spec: opt
$(INSTALL_DIR) $(EXRELSYSDIR)
$(INSTALL_DATA) $(TESTSRC) $(EXRELSYSDIR)
$(INSTALL_DATA) $(TESTTARGETS) $(EXRELSYSDIR)
diff --git a/lib/wx/include/wx.hrl b/lib/wx/include/wx.hrl
index 8659b71985..029b9a88df 100644
--- a/lib/wx/include/wx.hrl
+++ b/lib/wx/include/wx.hrl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2010. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2011. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -36,12 +36,12 @@
%% Callback event: {@link wxNavigationKeyEvent}
-record(wxNavigationKey,{type, flags,focus}).
-%% @type wxSash() = #wxSash{type=wxEventType(),edge=WxSashEdgePosition,dragRect={X::integer(),Y::integer(),W::integer(),H::integer()},dragStatus=WxSashDragStatus}.
+%% @type wxSash() = #wxSash{type=wxEventType(),edge=WxSashEdgePosition,dragRect={X::integer(), Y::integer(), W::integer(), H::integer()},dragStatus=WxSashDragStatus}.
%% <dl><dt>EventType:</dt> <dd><em>sash_dragged</em></dd></dl>
%% Callback event: {@link wxSashEvent}
-record(wxSash,{type, edge,dragRect,dragStatus}).
-%% @type wxList() = #wxList{type=wxEventType(),code=integer(),oldItemIndex=integer(),itemIndex=integer(),col=integer(),pointDrag={X::integer(),Y::integer()}}.
+%% @type wxList() = #wxList{type=wxEventType(),code=integer(),oldItemIndex=integer(),itemIndex=integer(),col=integer(),pointDrag={X::integer(), Y::integer()}}.
%% <dl><dt>EventType:</dt> <dd><em>command_list_begin_drag</em>, <em>command_list_begin_rdrag</em>, <em>command_list_begin_label_edit</em>, <em>command_list_end_label_edit</em>, <em>command_list_delete_item</em>, <em>command_list_delete_all_items</em>, <em>command_list_key_down</em>, <em>command_list_insert_item</em>, <em>command_list_col_click</em>, <em>command_list_col_right_click</em>, <em>command_list_col_begin_drag</em>, <em>command_list_col_dragging</em>, <em>command_list_col_end_drag</em>, <em>command_list_item_selected</em>, <em>command_list_item_deselected</em>, <em>command_list_item_right_click</em>, <em>command_list_item_middle_click</em>, <em>command_list_item_activated</em>, <em>command_list_item_focused</em>, <em>command_list_cache_hint</em></dd></dl>
%% Callback event: {@link wxListEvent}
-record(wxList,{type, code,oldItemIndex,itemIndex,col,pointDrag}).
@@ -186,7 +186,7 @@
%% Callback event: {@link wxUpdateUIEvent}
-record(wxUpdateUI, {type}).
-%% @type wxSize() = #wxSize{type=wxEventType(),size={W::integer(),H::integer()},rect={X::integer(),Y::integer(),W::integer(),H::integer()}}.
+%% @type wxSize() = #wxSize{type=wxEventType(),size={W::integer(), H::integer()},rect={X::integer(), Y::integer(), W::integer(), H::integer()}}.
%% <dl><dt>EventType:</dt> <dd><em>size</em></dd></dl>
%% Callback event: {@link wxSizeEvent}
-record(wxSize,{type, size,rect}).
@@ -261,7 +261,7 @@
%% Callback event: {@link wxColourPickerEvent}
-record(wxColourPicker,{type, colour}).
-%% @type wxTree() = #wxTree{type=wxEventType(),item=integer(),itemOld=integer(),pointDrag={X::integer(),Y::integer()}}.
+%% @type wxTree() = #wxTree{type=wxEventType(),item=integer(),itemOld=integer(),pointDrag={X::integer(), Y::integer()}}.
%% <dl><dt>EventType:</dt> <dd><em>command_tree_begin_drag</em>, <em>command_tree_begin_rdrag</em>, <em>command_tree_begin_label_edit</em>, <em>command_tree_end_label_edit</em>, <em>command_tree_delete_item</em>, <em>command_tree_get_info</em>, <em>command_tree_set_info</em>, <em>command_tree_item_expanded</em>, <em>command_tree_item_expanding</em>, <em>command_tree_item_collapsed</em>, <em>command_tree_item_collapsing</em>, <em>command_tree_sel_changed</em>, <em>command_tree_sel_changing</em>, <em>command_tree_key_down</em>, <em>command_tree_item_activated</em>, <em>command_tree_item_right_click</em>, <em>command_tree_item_middle_click</em>, <em>command_tree_end_drag</em>, <em>command_tree_state_image_click</em>, <em>command_tree_item_gettooltip</em>, <em>command_tree_item_menu</em></dd></dl>
%% Callback event: {@link wxTreeEvent}
-record(wxTree,{type, item,itemOld,pointDrag}).
diff --git a/lib/wx/src/gen/wxArtProvider.erl b/lib/wx/src/gen/wxArtProvider.erl
index 7a45b0d79d..1955bd2e29 100644
--- a/lib/wx/src/gen/wxArtProvider.erl
+++ b/lib/wx/src/gen/wxArtProvider.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2010. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2011. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -39,7 +39,7 @@ getBitmap(Id)
getBitmap(Id, []).
%% @spec (Id::string(), [Option]) -> wxBitmap:wxBitmap()
-%% Option = {client, string()} | {size, {W::integer(),H::integer()}}
+%% Option = {client, string()} | {size, {W::integer(), H::integer()}}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxartprovider.html#wxartprovidergetbitmap">external documentation</a>.
getBitmap(Id, Options)
when is_list(Id),is_list(Options) ->
@@ -58,7 +58,7 @@ getIcon(Id)
getIcon(Id, []).
%% @spec (Id::string(), [Option]) -> wxIcon:wxIcon()
-%% Option = {client, string()} | {size, {W::integer(),H::integer()}}
+%% Option = {client, string()} | {size, {W::integer(), H::integer()}}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxartprovider.html#wxartprovidergeticon">external documentation</a>.
getIcon(Id, Options)
when is_list(Id),is_list(Options) ->
diff --git a/lib/wx/src/gen/wxAuiManager.erl b/lib/wx/src/gen/wxAuiManager.erl
index ad0af6652d..893867cec1 100644
--- a/lib/wx/src/gen/wxAuiManager.erl
+++ b/lib/wx/src/gen/wxAuiManager.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2010. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2011. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -91,7 +91,7 @@ addPane(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=WindowT,ref=WindowRef},#wx_
wxe_util:call(?wxAuiManager_AddPane_2_1,
<<ThisRef:32/?UI,WindowRef:32/?UI,Pane_infoRef:32/?UI>>).
-%% @spec (This::wxAuiManager(), Window::wxWindow:wxWindow(), Pane_info::wxAuiPaneInfo:wxAuiPaneInfo(), Drop_pos::{X::integer(),Y::integer()}) -> bool()
+%% @spec (This::wxAuiManager(), Window::wxWindow:wxWindow(), Pane_info::wxAuiPaneInfo:wxAuiPaneInfo(), Drop_pos::{X::integer(), Y::integer()}) -> bool()
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxauimanager.html#wxauimanageraddpane">external documentation</a>.
addPane(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=WindowT,ref=WindowRef},#wx_ref{type=Pane_infoT,ref=Pane_infoRef},{Drop_posX,Drop_posY})
when is_integer(Drop_posX),is_integer(Drop_posY) ->
@@ -123,7 +123,7 @@ getArtProvider(#wx_ref{type=ThisT,ref=ThisRef}) ->
wxe_util:call(?wxAuiManager_GetArtProvider,
<<ThisRef:32/?UI>>).
-%% @spec (This::wxAuiManager()) -> {Width_pct::float(),Height_pct::float()}
+%% @spec (This::wxAuiManager()) -> {Width_pct::float(), Height_pct::float()}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxauimanager.html#wxauimanagergetdocksizeconstraint">external documentation</a>.
getDockSizeConstraint(#wx_ref{type=ThisT,ref=ThisRef}) ->
?CLASS(ThisT,wxAuiManager),
@@ -275,7 +275,7 @@ setManagedWindow(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=Managed_wndT,ref=M
wxe_util:cast(?wxAuiManager_SetManagedWindow,
<<ThisRef:32/?UI,Managed_wndRef:32/?UI>>).
-%% @spec (This::wxAuiManager(), Rect::{X::integer(),Y::integer(),W::integer(),H::integer()}) -> ok
+%% @spec (This::wxAuiManager(), Rect::{X::integer(), Y::integer(), W::integer(), H::integer()}) -> ok
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxauimanager.html#wxauimanagershowhint">external documentation</a>.
showHint(#wx_ref{type=ThisT,ref=ThisRef},{RectX,RectY,RectW,RectH})
when is_integer(RectX),is_integer(RectY),is_integer(RectW),is_integer(RectH) ->
diff --git a/lib/wx/src/gen/wxAuiNotebook.erl b/lib/wx/src/gen/wxAuiNotebook.erl
index 5d486aeaa2..5862bb26c7 100644
--- a/lib/wx/src/gen/wxAuiNotebook.erl
+++ b/lib/wx/src/gen/wxAuiNotebook.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2010. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2011. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -92,7 +92,7 @@ new(Parent)
new(Parent, []).
%% @spec (Parent::wxWindow:wxWindow(), [Option]) -> wxAuiNotebook()
-%% Option = {id, integer()} | {pos, {X::integer(),Y::integer()}} | {size, {W::integer(),H::integer()}} | {style, integer()}
+%% Option = {id, integer()} | {pos, {X::integer(), Y::integer()}} | {size, {W::integer(), H::integer()}} | {style, integer()}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxauinotebook.html#wxauinotebookwxauinotebook">external documentation</a>.
new(#wx_ref{type=ParentT,ref=ParentRef}, Options)
when is_list(Options) ->
@@ -134,7 +134,7 @@ create(This,Parent)
create(This,Parent, []).
%% @spec (This::wxAuiNotebook(), Parent::wxWindow:wxWindow(), [Option]) -> bool()
-%% Option = {id, integer()} | {pos, {X::integer(),Y::integer()}} | {size, {W::integer(),H::integer()}} | {style, integer()}
+%% Option = {id, integer()} | {pos, {X::integer(), Y::integer()}} | {size, {W::integer(), H::integer()}} | {style, integer()}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxauinotebook.html#wxauinotebookcreate">external documentation</a>.
create(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=ParentT,ref=ParentRef}, Options)
when is_list(Options) ->
@@ -289,7 +289,7 @@ setTabCtrlHeight(#wx_ref{type=ThisT,ref=ThisRef},Height)
wxe_util:cast(?wxAuiNotebook_SetTabCtrlHeight,
<<ThisRef:32/?UI,Height:32/?UI>>).
-%% @spec (This::wxAuiNotebook(), Size::{W::integer(),H::integer()}) -> ok
+%% @spec (This::wxAuiNotebook(), Size::{W::integer(), H::integer()}) -> ok
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxauinotebook.html#wxauinotebooksetuniformbitmapsize">external documentation</a>.
setUniformBitmapSize(#wx_ref{type=ThisT,ref=ThisRef},{SizeW,SizeH})
when is_integer(SizeW),is_integer(SizeH) ->
diff --git a/lib/wx/src/gen/wxAuiPaneInfo.erl b/lib/wx/src/gen/wxAuiPaneInfo.erl
index 7b1401b069..b15f91c675 100644
--- a/lib/wx/src/gen/wxAuiPaneInfo.erl
+++ b/lib/wx/src/gen/wxAuiPaneInfo.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2010. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2011. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -60,7 +60,7 @@ new(#wx_ref{type=CT,ref=CRef}) ->
wxe_util:construct(?wxAuiPaneInfo_new_1,
<<CRef:32/?UI>>).
-%% @spec (This::wxAuiPaneInfo(), Size::{W::integer(),H::integer()}) -> wxAuiPaneInfo()
+%% @spec (This::wxAuiPaneInfo(), Size::{W::integer(), H::integer()}) -> wxAuiPaneInfo()
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxauipaneinfo.html#wxauipaneinfobestsize">external documentation</a>.
bestSize(#wx_ref{type=ThisT,ref=ThisRef},{SizeW,SizeH})
when is_integer(SizeW),is_integer(SizeH) ->
@@ -250,7 +250,7 @@ floatable(#wx_ref{type=ThisT,ref=ThisRef}, Options)
wxe_util:call(?wxAuiPaneInfo_Floatable,
<<ThisRef:32/?UI, 0:32,BinOpt/binary>>).
-%% @spec (This::wxAuiPaneInfo(), Pos::{X::integer(),Y::integer()}) -> wxAuiPaneInfo()
+%% @spec (This::wxAuiPaneInfo(), Pos::{X::integer(), Y::integer()}) -> wxAuiPaneInfo()
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxauipaneinfo.html#wxauipaneinfofloatingposition">external documentation</a>.
floatingPosition(#wx_ref{type=ThisT,ref=ThisRef},{PosX,PosY})
when is_integer(PosX),is_integer(PosY) ->
@@ -266,7 +266,7 @@ floatingPosition(#wx_ref{type=ThisT,ref=ThisRef},X,Y)
wxe_util:call(?wxAuiPaneInfo_FloatingPosition_2,
<<ThisRef:32/?UI,X:32/?UI,Y:32/?UI>>).
-%% @spec (This::wxAuiPaneInfo(), Size::{W::integer(),H::integer()}) -> wxAuiPaneInfo()
+%% @spec (This::wxAuiPaneInfo(), Size::{W::integer(), H::integer()}) -> wxAuiPaneInfo()
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxauipaneinfo.html#wxauipaneinfofloatingsize">external documentation</a>.
floatingSize(#wx_ref{type=ThisT,ref=ThisRef},{SizeW,SizeH})
when is_integer(SizeW),is_integer(SizeH) ->
@@ -513,7 +513,7 @@ leftDockable(#wx_ref{type=ThisT,ref=ThisRef}, Options)
wxe_util:call(?wxAuiPaneInfo_LeftDockable,
<<ThisRef:32/?UI, 0:32,BinOpt/binary>>).
-%% @spec (This::wxAuiPaneInfo(), Size::{W::integer(),H::integer()}) -> wxAuiPaneInfo()
+%% @spec (This::wxAuiPaneInfo(), Size::{W::integer(), H::integer()}) -> wxAuiPaneInfo()
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxauipaneinfo.html#wxauipaneinfomaxsize">external documentation</a>.
maxSize(#wx_ref{type=ThisT,ref=ThisRef},{SizeW,SizeH})
when is_integer(SizeW),is_integer(SizeH) ->
@@ -547,7 +547,7 @@ maximizeButton(#wx_ref{type=ThisT,ref=ThisRef}, Options)
wxe_util:call(?wxAuiPaneInfo_MaximizeButton,
<<ThisRef:32/?UI, 0:32,BinOpt/binary>>).
-%% @spec (This::wxAuiPaneInfo(), Size::{W::integer(),H::integer()}) -> wxAuiPaneInfo()
+%% @spec (This::wxAuiPaneInfo(), Size::{W::integer(), H::integer()}) -> wxAuiPaneInfo()
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxauipaneinfo.html#wxauipaneinfominsize">external documentation</a>.
minSize(#wx_ref{type=ThisT,ref=ThisRef},{SizeW,SizeH})
when is_integer(SizeW),is_integer(SizeH) ->
diff --git a/lib/wx/src/gen/wxBitmap.erl b/lib/wx/src/gen/wxBitmap.erl
index 53c57e4393..bd2f83c6eb 100644
--- a/lib/wx/src/gen/wxBitmap.erl
+++ b/lib/wx/src/gen/wxBitmap.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2010. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2011. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -194,7 +194,7 @@ getWidth(#wx_ref{type=ThisT,ref=ThisRef}) ->
wxe_util:call(?wxBitmap_GetWidth,
<<ThisRef:32/?UI>>).
-%% @spec (This::wxBitmap(), Rect::{X::integer(),Y::integer(),W::integer(),H::integer()}) -> wxBitmap()
+%% @spec (This::wxBitmap(), Rect::{X::integer(), Y::integer(), W::integer(), H::integer()}) -> wxBitmap()
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxbitmap.html#wxbitmapgetsubbitmap">external documentation</a>.
getSubBitmap(#wx_ref{type=ThisT,ref=ThisRef},{RectX,RectY,RectW,RectH})
when is_integer(RectX),is_integer(RectY),is_integer(RectW),is_integer(RectH) ->
diff --git a/lib/wx/src/gen/wxBitmapButton.erl b/lib/wx/src/gen/wxBitmapButton.erl
index 0c187bf1c1..d2353466e7 100644
--- a/lib/wx/src/gen/wxBitmapButton.erl
+++ b/lib/wx/src/gen/wxBitmapButton.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2010. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2011. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -92,7 +92,7 @@ new(Parent,Id,Bitmap)
new(Parent,Id,Bitmap, []).
%% @spec (Parent::wxWindow:wxWindow(), Id::integer(), Bitmap::wxBitmap:wxBitmap(), [Option]) -> wxBitmapButton()
-%% Option = {pos, {X::integer(),Y::integer()}} | {size, {W::integer(),H::integer()}} | {style, integer()} | {validator, wx:wx()}
+%% Option = {pos, {X::integer(), Y::integer()}} | {size, {W::integer(), H::integer()}} | {style, integer()} | {validator, wx:wx()}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxbitmapbutton.html#wxbitmapbuttonwxbitmapbutton">external documentation</a>.
new(#wx_ref{type=ParentT,ref=ParentRef},Id,#wx_ref{type=BitmapT,ref=BitmapRef}, Options)
when is_integer(Id),is_list(Options) ->
@@ -114,7 +114,7 @@ create(This,Parent,Id,Bitmap)
create(This,Parent,Id,Bitmap, []).
%% @spec (This::wxBitmapButton(), Parent::wxWindow:wxWindow(), Id::integer(), Bitmap::wxBitmap:wxBitmap(), [Option]) -> bool()
-%% Option = {pos, {X::integer(),Y::integer()}} | {size, {W::integer(),H::integer()}} | {style, integer()} | {validator, wx:wx()}
+%% Option = {pos, {X::integer(), Y::integer()}} | {size, {W::integer(), H::integer()}} | {style, integer()} | {validator, wx:wx()}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxbitmapbutton.html#wxbitmapbuttoncreate">external documentation</a>.
create(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=ParentT,ref=ParentRef},Id,#wx_ref{type=BitmapT,ref=BitmapRef}, Options)
when is_integer(Id),is_list(Options) ->
diff --git a/lib/wx/src/gen/wxBufferedDC.erl b/lib/wx/src/gen/wxBufferedDC.erl
index 6e341a8552..9096f95612 100644
--- a/lib/wx/src/gen/wxBufferedDC.erl
+++ b/lib/wx/src/gen/wxBufferedDC.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2010. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2011. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -74,7 +74,7 @@ new(Dc)
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxbuffereddc.html#wxbuffereddcwxbuffereddc">external documentation</a>.
%% <br /> Alternatives:
%% <p><c>
-%% new(Dc::wxDC:wxDC(), Area::{W::integer(),H::integer()}) -> new(Dc,Area, []) </c></p>
+%% new(Dc::wxDC:wxDC(), Area::{W::integer(), H::integer()}) -> new(Dc,Area, []) </c></p>
%% <p><c>
%% new(Dc::wxDC:wxDC(), [Option]) -> wxBufferedDC() </c>
%%<br /> Option = {buffer, wxBitmap:wxBitmap()} | {style, integer()}
@@ -93,7 +93,7 @@ new(#wx_ref{type=DcT,ref=DcRef}, Options)
wxe_util:construct(?wxBufferedDC_new_2,
<<DcRef:32/?UI, 0:32,BinOpt/binary>>).
-%% @spec (Dc::wxDC:wxDC(), Area::{W::integer(),H::integer()}, [Option]) -> wxBufferedDC()
+%% @spec (Dc::wxDC:wxDC(), Area::{W::integer(), H::integer()}, [Option]) -> wxBufferedDC()
%% Option = {style, integer()}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxbuffereddc.html#wxbuffereddcwxbuffereddc">external documentation</a>.
new(#wx_ref{type=DcT,ref=DcRef},{AreaW,AreaH}, Options)
@@ -115,7 +115,7 @@ init(This,Dc)
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxbuffereddc.html#wxbuffereddcinit">external documentation</a>.
%% <br /> Alternatives:
%% <p><c>
-%% init(This::wxBufferedDC(), Dc::wxDC:wxDC(), Area::{W::integer(),H::integer()}) -> init(This,Dc,Area, []) </c></p>
+%% init(This::wxBufferedDC(), Dc::wxDC:wxDC(), Area::{W::integer(), H::integer()}) -> init(This,Dc,Area, []) </c></p>
%% <p><c>
%% init(This::wxBufferedDC(), Dc::wxDC:wxDC(), [Option]) -> ok </c>
%%<br /> Option = {buffer, wxBitmap:wxBitmap()} | {style, integer()}
@@ -135,7 +135,7 @@ init(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=DcT,ref=DcRef}, Options)
wxe_util:cast(?wxBufferedDC_Init_2,
<<ThisRef:32/?UI,DcRef:32/?UI, BinOpt/binary>>).
-%% @spec (This::wxBufferedDC(), Dc::wxDC:wxDC(), Area::{W::integer(),H::integer()}, [Option]) -> ok
+%% @spec (This::wxBufferedDC(), Dc::wxDC:wxDC(), Area::{W::integer(), H::integer()}, [Option]) -> ok
%% Option = {style, integer()}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxbuffereddc.html#wxbuffereddcinit">external documentation</a>.
init(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=DcT,ref=DcRef},{AreaW,AreaH}, Options)
diff --git a/lib/wx/src/gen/wxButton.erl b/lib/wx/src/gen/wxButton.erl
index c0e21a5657..a75c45c5a3 100644
--- a/lib/wx/src/gen/wxButton.erl
+++ b/lib/wx/src/gen/wxButton.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2010. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2011. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -89,7 +89,7 @@ new(Parent,Id)
new(Parent,Id, []).
%% @spec (Parent::wxWindow:wxWindow(), Id::integer(), [Option]) -> wxButton()
-%% Option = {label, string()} | {pos, {X::integer(),Y::integer()}} | {size, {W::integer(),H::integer()}} | {style, integer()} | {validator, wx:wx()}
+%% Option = {label, string()} | {pos, {X::integer(), Y::integer()}} | {size, {W::integer(), H::integer()}} | {style, integer()} | {validator, wx:wx()}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxbutton.html#wxbuttonwxbutton">external documentation</a>.
new(#wx_ref{type=ParentT,ref=ParentRef},Id, Options)
when is_integer(Id),is_list(Options) ->
@@ -111,7 +111,7 @@ create(This,Parent,Id)
create(This,Parent,Id, []).
%% @spec (This::wxButton(), Parent::wxWindow:wxWindow(), Id::integer(), [Option]) -> bool()
-%% Option = {label, string()} | {pos, {X::integer(),Y::integer()}} | {size, {W::integer(),H::integer()}} | {style, integer()} | {validator, wx:wx()}
+%% Option = {label, string()} | {pos, {X::integer(), Y::integer()}} | {size, {W::integer(), H::integer()}} | {style, integer()} | {validator, wx:wx()}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxbutton.html#wxbuttoncreate">external documentation</a>.
create(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=ParentT,ref=ParentRef},Id, Options)
when is_integer(Id),is_list(Options) ->
@@ -127,7 +127,7 @@ create(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=ParentT,ref=ParentRef},Id, O
wxe_util:call(?wxButton_Create,
<<ThisRef:32/?UI,ParentRef:32/?UI,Id:32/?UI, 0:32,BinOpt/binary>>).
-%% @spec () -> {W::integer(),H::integer()}
+%% @spec () -> {W::integer(), H::integer()}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxbutton.html#wxbuttongetdefaultsize">external documentation</a>.
getDefaultSize() ->
wxe_util:call(?wxButton_GetDefaultSize,
diff --git a/lib/wx/src/gen/wxCalendarCtrl.erl b/lib/wx/src/gen/wxCalendarCtrl.erl
index 8ad4d5954b..1bb4ecb1fa 100644
--- a/lib/wx/src/gen/wxCalendarCtrl.erl
+++ b/lib/wx/src/gen/wxCalendarCtrl.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2010. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2011. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -93,7 +93,7 @@ new(Parent,Id)
new(Parent,Id, []).
%% @spec (Parent::wxWindow:wxWindow(), Id::integer(), [Option]) -> wxCalendarCtrl()
-%% Option = {date, wx:datetime()} | {pos, {X::integer(),Y::integer()}} | {size, {W::integer(),H::integer()}} | {style, integer()}
+%% Option = {date, wx:datetime()} | {pos, {X::integer(), Y::integer()}} | {size, {W::integer(), H::integer()}} | {style, integer()}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxcalendarctrl.html#wxcalendarctrlwxcalendarctrl">external documentation</a>.
new(#wx_ref{type=ParentT,ref=ParentRef},Id, Options)
when is_integer(Id),is_list(Options) ->
@@ -114,7 +114,7 @@ create(This,Parent,Id)
create(This,Parent,Id, []).
%% @spec (This::wxCalendarCtrl(), Parent::wxWindow:wxWindow(), Id::integer(), [Option]) -> bool()
-%% Option = {date, wx:datetime()} | {pos, {X::integer(),Y::integer()}} | {size, {W::integer(),H::integer()}} | {style, integer()}
+%% Option = {date, wx:datetime()} | {pos, {X::integer(), Y::integer()}} | {size, {W::integer(), H::integer()}} | {style, integer()}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxcalendarctrl.html#wxcalendarctrlcreate">external documentation</a>.
create(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=ParentT,ref=ParentRef},Id, Options)
when is_integer(Id),is_list(Options) ->
@@ -297,7 +297,7 @@ resetAttr(#wx_ref{type=ThisT,ref=ThisRef},Day)
wxe_util:cast(?wxCalendarCtrl_ResetAttr,
<<ThisRef:32/?UI,Day:32/?UI>>).
-%% @spec (This::wxCalendarCtrl(), Pos::{X::integer(),Y::integer()}) -> {WxCalendarHitTestResult,Date::wx:datetime(),Wd::WeekDay}
+%% @spec (This::wxCalendarCtrl(), Pos::{X::integer(), Y::integer()}) -> {WxCalendarHitTestResult, Date::wx:datetime(), Wd::WeekDay}
%% WxCalendarHitTestResult = integer()
%% WeekDay = integer()
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxcalendarctrl.html#wxcalendarctrlhittest">external documentation</a>.
diff --git a/lib/wx/src/gen/wxCaret.erl b/lib/wx/src/gen/wxCaret.erl
index 3e1a3d544c..cbd868f388 100644
--- a/lib/wx/src/gen/wxCaret.erl
+++ b/lib/wx/src/gen/wxCaret.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2010. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2011. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -34,7 +34,7 @@
%% @hidden
parent_class(_Class) -> erlang:error({badtype, ?MODULE}).
-%% @spec (Window::wxWindow:wxWindow(), Size::{W::integer(),H::integer()}) -> wxCaret()
+%% @spec (Window::wxWindow:wxWindow(), Size::{W::integer(), H::integer()}) -> wxCaret()
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxcaret.html#wxcaretwxcaret">external documentation</a>.
new(#wx_ref{type=WindowT,ref=WindowRef},{SizeW,SizeH})
when is_integer(SizeW),is_integer(SizeH) ->
@@ -50,7 +50,7 @@ new(#wx_ref{type=WindowT,ref=WindowRef},Width,Height)
wxe_util:construct(?wxCaret_new_3,
<<WindowRef:32/?UI,Width:32/?UI,Height:32/?UI>>).
-%% @spec (This::wxCaret(), Window::wxWindow:wxWindow(), Size::{W::integer(),H::integer()}) -> bool()
+%% @spec (This::wxCaret(), Window::wxWindow:wxWindow(), Size::{W::integer(), H::integer()}) -> bool()
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxcaret.html#wxcaretcreate">external documentation</a>.
create(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=WindowT,ref=WindowRef},{SizeW,SizeH})
when is_integer(SizeW),is_integer(SizeH) ->
@@ -74,14 +74,14 @@ getBlinkTime() ->
wxe_util:call(?wxCaret_GetBlinkTime,
<<>>).
-%% @spec (This::wxCaret()) -> {X::integer(),Y::integer()}
+%% @spec (This::wxCaret()) -> {X::integer(), Y::integer()}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxcaret.html#wxcaretgetposition">external documentation</a>.
getPosition(#wx_ref{type=ThisT,ref=ThisRef}) ->
?CLASS(ThisT,wxCaret),
wxe_util:call(?wxCaret_GetPosition,
<<ThisRef:32/?UI>>).
-%% @spec (This::wxCaret()) -> {W::integer(),H::integer()}
+%% @spec (This::wxCaret()) -> {W::integer(), H::integer()}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxcaret.html#wxcaretgetsize">external documentation</a>.
getSize(#wx_ref{type=ThisT,ref=ThisRef}) ->
?CLASS(ThisT,wxCaret),
@@ -116,7 +116,7 @@ isVisible(#wx_ref{type=ThisT,ref=ThisRef}) ->
wxe_util:call(?wxCaret_IsVisible,
<<ThisRef:32/?UI>>).
-%% @spec (This::wxCaret(), Pt::{X::integer(),Y::integer()}) -> ok
+%% @spec (This::wxCaret(), Pt::{X::integer(), Y::integer()}) -> ok
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxcaret.html#wxcaretmove">external documentation</a>.
move(#wx_ref{type=ThisT,ref=ThisRef},{PtX,PtY})
when is_integer(PtX),is_integer(PtY) ->
@@ -139,7 +139,7 @@ setBlinkTime(Milliseconds)
wxe_util:cast(?wxCaret_SetBlinkTime,
<<Milliseconds:32/?UI>>).
-%% @spec (This::wxCaret(), Size::{W::integer(),H::integer()}) -> ok
+%% @spec (This::wxCaret(), Size::{W::integer(), H::integer()}) -> ok
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxcaret.html#wxcaretsetsize">external documentation</a>.
setSize(#wx_ref{type=ThisT,ref=ThisRef},{SizeW,SizeH})
when is_integer(SizeW),is_integer(SizeH) ->
diff --git a/lib/wx/src/gen/wxCheckBox.erl b/lib/wx/src/gen/wxCheckBox.erl
index c484483379..19f01645c1 100644
--- a/lib/wx/src/gen/wxCheckBox.erl
+++ b/lib/wx/src/gen/wxCheckBox.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2010. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2011. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -90,7 +90,7 @@ new(Parent,Id,Label)
new(Parent,Id,Label, []).
%% @spec (Parent::wxWindow:wxWindow(), Id::integer(), Label::string(), [Option]) -> wxCheckBox()
-%% Option = {pos, {X::integer(),Y::integer()}} | {size, {W::integer(),H::integer()}} | {style, integer()} | {validator, wx:wx()}
+%% Option = {pos, {X::integer(), Y::integer()}} | {size, {W::integer(), H::integer()}} | {style, integer()} | {validator, wx:wx()}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxcheckbox.html#wxcheckboxwxcheckbox">external documentation</a>.
new(#wx_ref{type=ParentT,ref=ParentRef},Id,Label, Options)
when is_integer(Id),is_list(Label),is_list(Options) ->
@@ -112,7 +112,7 @@ create(This,Parent,Id,Label)
create(This,Parent,Id,Label, []).
%% @spec (This::wxCheckBox(), Parent::wxWindow:wxWindow(), Id::integer(), Label::string(), [Option]) -> bool()
-%% Option = {pos, {X::integer(),Y::integer()}} | {size, {W::integer(),H::integer()}} | {style, integer()} | {validator, wx:wx()}
+%% Option = {pos, {X::integer(), Y::integer()}} | {size, {W::integer(), H::integer()}} | {style, integer()} | {validator, wx:wx()}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxcheckbox.html#wxcheckboxcreate">external documentation</a>.
create(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=ParentT,ref=ParentRef},Id,Label, Options)
when is_integer(Id),is_list(Label),is_list(Options) ->
diff --git a/lib/wx/src/gen/wxCheckListBox.erl b/lib/wx/src/gen/wxCheckListBox.erl
index c692997311..a1a07e1eec 100644
--- a/lib/wx/src/gen/wxCheckListBox.erl
+++ b/lib/wx/src/gen/wxCheckListBox.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2010. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2011. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -96,7 +96,7 @@ new(Parent,Id)
new(Parent,Id, []).
%% @spec (Parent::wxWindow:wxWindow(), Id::integer(), [Option]) -> wxCheckListBox()
-%% Option = {pos, {X::integer(),Y::integer()}} | {size, {W::integer(),H::integer()}} | {choices, [[string()]]} | {style, integer()} | {validator, wx:wx()}
+%% Option = {pos, {X::integer(), Y::integer()}} | {size, {W::integer(), H::integer()}} | {choices, [[string()]]} | {style, integer()} | {validator, wx:wx()}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxchecklistbox.html#wxchecklistboxwxchecklistbox">external documentation</a>.
new(#wx_ref{type=ParentT,ref=ParentRef},Id, Options)
when is_integer(Id),is_list(Options) ->
diff --git a/lib/wx/src/gen/wxChoice.erl b/lib/wx/src/gen/wxChoice.erl
index eaf2f0352f..fa967d8487 100644
--- a/lib/wx/src/gen/wxChoice.erl
+++ b/lib/wx/src/gen/wxChoice.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2010. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2011. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -94,7 +94,7 @@ new(Parent,Id)
new(Parent,Id, []).
%% @spec (Parent::wxWindow:wxWindow(), Id::integer(), [Option]) -> wxChoice()
-%% Option = {pos, {X::integer(),Y::integer()}} | {size, {W::integer(),H::integer()}} | {choices, [[string()]]} | {style, integer()} | {validator, wx:wx()}
+%% Option = {pos, {X::integer(), Y::integer()}} | {size, {W::integer(), H::integer()}} | {choices, [[string()]]} | {style, integer()} | {validator, wx:wx()}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxchoice.html#wxchoicewxchoice">external documentation</a>.
new(#wx_ref{type=ParentT,ref=ParentRef},Id, Options)
when is_integer(Id),is_list(Options) ->
@@ -109,13 +109,13 @@ new(#wx_ref{type=ParentT,ref=ParentRef},Id, Options)
wxe_util:construct(?wxChoice_new_3,
<<ParentRef:32/?UI,Id:32/?UI, BinOpt/binary>>).
-%% @spec (This::wxChoice(), Parent::wxWindow:wxWindow(), Id::integer(), Pos::{X::integer(),Y::integer()}, Size::{W::integer(),H::integer()}, Choices::[[string()]]) -> bool()
+%% @spec (This::wxChoice(), Parent::wxWindow:wxWindow(), Id::integer(), Pos::{X::integer(), Y::integer()}, Size::{W::integer(), H::integer()}, Choices::[[string()]]) -> bool()
%% @equiv create(This,Parent,Id,Pos,Size,Choices, [])
create(This,Parent,Id,Pos={PosX,PosY},Size={SizeW,SizeH},Choices)
when is_record(This, wx_ref),is_record(Parent, wx_ref),is_integer(Id),is_integer(PosX),is_integer(PosY),is_integer(SizeW),is_integer(SizeH),is_list(Choices) ->
create(This,Parent,Id,Pos,Size,Choices, []).
-%% @spec (This::wxChoice(), Parent::wxWindow:wxWindow(), Id::integer(), Pos::{X::integer(),Y::integer()}, Size::{W::integer(),H::integer()}, Choices::[[string()]], [Option]) -> bool()
+%% @spec (This::wxChoice(), Parent::wxWindow:wxWindow(), Id::integer(), Pos::{X::integer(), Y::integer()}, Size::{W::integer(), H::integer()}, Choices::[[string()]], [Option]) -> bool()
%% Option = {style, integer()} | {validator, wx:wx()}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxchoice.html#wxchoicecreate">external documentation</a>.
create(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=ParentT,ref=ParentRef},Id,{PosX,PosY},{SizeW,SizeH},Choices, Options)
diff --git a/lib/wx/src/gen/wxChoicebook.erl b/lib/wx/src/gen/wxChoicebook.erl
index b724d0cad2..f37457f0ed 100644
--- a/lib/wx/src/gen/wxChoicebook.erl
+++ b/lib/wx/src/gen/wxChoicebook.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2009-2010. All Rights Reserved.
+%% Copyright Ericsson AB 2009-2011. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -93,7 +93,7 @@ new(Parent,Id)
new(Parent,Id, []).
%% @spec (Parent::wxWindow:wxWindow(), Id::integer(), [Option]) -> wxChoicebook()
-%% Option = {pos, {X::integer(),Y::integer()}} | {size, {W::integer(),H::integer()}} | {style, integer()}
+%% Option = {pos, {X::integer(), Y::integer()}} | {size, {W::integer(), H::integer()}} | {style, integer()}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxchoicebook.html#wxchoicebookwxchoicebook">external documentation</a>.
new(#wx_ref{type=ParentT,ref=ParentRef},Id, Options)
when is_integer(Id),is_list(Options) ->
@@ -160,7 +160,7 @@ create(This,Parent,Id)
create(This,Parent,Id, []).
%% @spec (This::wxChoicebook(), Parent::wxWindow:wxWindow(), Id::integer(), [Option]) -> bool()
-%% Option = {pos, {X::integer(),Y::integer()}} | {size, {W::integer(),H::integer()}} | {style, integer()}
+%% Option = {pos, {X::integer(), Y::integer()}} | {size, {W::integer(), H::integer()}} | {style, integer()}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxchoicebook.html#wxchoicebookcreate">external documentation</a>.
create(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=ParentT,ref=ParentRef},Id, Options)
when is_integer(Id),is_list(Options) ->
@@ -249,7 +249,7 @@ getSelection(#wx_ref{type=ThisT,ref=ThisRef}) ->
wxe_util:call(?wxChoicebook_GetSelection,
<<ThisRef:32/?UI>>).
-%% @spec (This::wxChoicebook(), Pt::{X::integer(),Y::integer()}) -> {integer(),Flags::integer()}
+%% @spec (This::wxChoicebook(), Pt::{X::integer(), Y::integer()}) -> {integer(), Flags::integer()}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxchoicebook.html#wxchoicebookhittest">external documentation</a>.
hitTest(#wx_ref{type=ThisT,ref=ThisRef},{PtX,PtY})
when is_integer(PtX),is_integer(PtY) ->
@@ -286,7 +286,7 @@ setImageList(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=ImageListT,ref=ImageLi
wxe_util:cast(?wxChoicebook_SetImageList,
<<ThisRef:32/?UI,ImageListRef:32/?UI>>).
-%% @spec (This::wxChoicebook(), Size::{W::integer(),H::integer()}) -> ok
+%% @spec (This::wxChoicebook(), Size::{W::integer(), H::integer()}) -> ok
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxchoicebook.html#wxchoicebooksetpagesize">external documentation</a>.
setPageSize(#wx_ref{type=ThisT,ref=ThisRef},{SizeW,SizeH})
when is_integer(SizeW),is_integer(SizeH) ->
diff --git a/lib/wx/src/gen/wxColourPickerCtrl.erl b/lib/wx/src/gen/wxColourPickerCtrl.erl
index 4f0816e1fd..60776925b9 100644
--- a/lib/wx/src/gen/wxColourPickerCtrl.erl
+++ b/lib/wx/src/gen/wxColourPickerCtrl.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2010. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2011. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -94,7 +94,7 @@ new(Parent,Id)
new(Parent,Id, []).
%% @spec (Parent::wxWindow:wxWindow(), Id::integer(), [Option]) -> wxColourPickerCtrl()
-%% Option = {col, wx:colour()} | {pos, {X::integer(),Y::integer()}} | {size, {W::integer(),H::integer()}} | {style, integer()} | {validator, wx:wx()}
+%% Option = {col, wx:colour()} | {pos, {X::integer(), Y::integer()}} | {size, {W::integer(), H::integer()}} | {style, integer()} | {validator, wx:wx()}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxcolourpickerctrl.html#wxcolourpickerctrlwxcolourpickerctrl">external documentation</a>.
new(#wx_ref{type=ParentT,ref=ParentRef},Id, Options)
when is_integer(Id),is_list(Options) ->
@@ -116,7 +116,7 @@ create(This,Parent,Id)
create(This,Parent,Id, []).
%% @spec (This::wxColourPickerCtrl(), Parent::wxWindow:wxWindow(), Id::integer(), [Option]) -> bool()
-%% Option = {col, wx:colour()} | {pos, {X::integer(),Y::integer()}} | {size, {W::integer(),H::integer()}} | {style, integer()} | {validator, wx:wx()}
+%% Option = {col, wx:colour()} | {pos, {X::integer(), Y::integer()}} | {size, {W::integer(), H::integer()}} | {style, integer()} | {validator, wx:wx()}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxcolourpickerctrl.html#wxcolourpickerctrlcreate">external documentation</a>.
create(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=ParentT,ref=ParentRef},Id, Options)
when is_integer(Id),is_list(Options) ->
diff --git a/lib/wx/src/gen/wxComboBox.erl b/lib/wx/src/gen/wxComboBox.erl
index 061e886734..f743df4e93 100644
--- a/lib/wx/src/gen/wxComboBox.erl
+++ b/lib/wx/src/gen/wxComboBox.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2010. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2011. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -96,7 +96,7 @@ new(Parent,Id)
new(Parent,Id, []).
%% @spec (Parent::wxWindow:wxWindow(), Id::integer(), [Option]) -> wxComboBox()
-%% Option = {value, string()} | {pos, {X::integer(),Y::integer()}} | {size, {W::integer(),H::integer()}} | {choices, [[string()]]} | {style, integer()} | {validator, wx:wx()}
+%% Option = {value, string()} | {pos, {X::integer(), Y::integer()}} | {size, {W::integer(), H::integer()}} | {choices, [[string()]]} | {style, integer()} | {validator, wx:wx()}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxcombobox.html#wxcomboboxwxcombobox">external documentation</a>.
new(#wx_ref{type=ParentT,ref=ParentRef},Id, Options)
when is_integer(Id),is_list(Options) ->
@@ -112,13 +112,13 @@ new(#wx_ref{type=ParentT,ref=ParentRef},Id, Options)
wxe_util:construct(?wxComboBox_new_3,
<<ParentRef:32/?UI,Id:32/?UI, BinOpt/binary>>).
-%% @spec (This::wxComboBox(), Parent::wxWindow:wxWindow(), Id::integer(), Value::string(), Pos::{X::integer(),Y::integer()}, Size::{W::integer(),H::integer()}, Choices::[[string()]]) -> bool()
+%% @spec (This::wxComboBox(), Parent::wxWindow:wxWindow(), Id::integer(), Value::string(), Pos::{X::integer(), Y::integer()}, Size::{W::integer(), H::integer()}, Choices::[[string()]]) -> bool()
%% @equiv create(This,Parent,Id,Value,Pos,Size,Choices, [])
create(This,Parent,Id,Value,Pos={PosX,PosY},Size={SizeW,SizeH},Choices)
when is_record(This, wx_ref),is_record(Parent, wx_ref),is_integer(Id),is_list(Value),is_integer(PosX),is_integer(PosY),is_integer(SizeW),is_integer(SizeH),is_list(Choices) ->
create(This,Parent,Id,Value,Pos,Size,Choices, []).
-%% @spec (This::wxComboBox(), Parent::wxWindow:wxWindow(), Id::integer(), Value::string(), Pos::{X::integer(),Y::integer()}, Size::{W::integer(),H::integer()}, Choices::[[string()]], [Option]) -> bool()
+%% @spec (This::wxComboBox(), Parent::wxWindow:wxWindow(), Id::integer(), Value::string(), Pos::{X::integer(), Y::integer()}, Size::{W::integer(), H::integer()}, Choices::[[string()]], [Option]) -> bool()
%% Option = {style, integer()} | {validator, wx:wx()}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxcombobox.html#wxcomboboxcreate">external documentation</a>.
create(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=ParentT,ref=ParentRef},Id,Value,{PosX,PosY},{SizeW,SizeH},Choices, Options)
diff --git a/lib/wx/src/gen/wxContextMenuEvent.erl b/lib/wx/src/gen/wxContextMenuEvent.erl
index 56ed82f37c..0050b97b89 100644
--- a/lib/wx/src/gen/wxContextMenuEvent.erl
+++ b/lib/wx/src/gen/wxContextMenuEvent.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2010. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2011. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -45,14 +45,14 @@ parent_class(wxCommandEvent) -> true;
parent_class(wxEvent) -> true;
parent_class(_Class) -> erlang:error({badtype, ?MODULE}).
-%% @spec (This::wxContextMenuEvent()) -> {X::integer(),Y::integer()}
+%% @spec (This::wxContextMenuEvent()) -> {X::integer(), Y::integer()}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxcontextmenuevent.html#wxcontextmenueventgetposition">external documentation</a>.
getPosition(#wx_ref{type=ThisT,ref=ThisRef}) ->
?CLASS(ThisT,wxContextMenuEvent),
wxe_util:call(?wxContextMenuEvent_GetPosition,
<<ThisRef:32/?UI>>).
-%% @spec (This::wxContextMenuEvent(), Pos::{X::integer(),Y::integer()}) -> ok
+%% @spec (This::wxContextMenuEvent(), Pos::{X::integer(), Y::integer()}) -> ok
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxcontextmenuevent.html#wxcontextmenueventsetposition">external documentation</a>.
setPosition(#wx_ref{type=ThisT,ref=ThisRef},{PosX,PosY})
when is_integer(PosX),is_integer(PosY) ->
diff --git a/lib/wx/src/gen/wxDC.erl b/lib/wx/src/gen/wxDC.erl
index 9bce1249f8..ba498c651a 100644
--- a/lib/wx/src/gen/wxDC.erl
+++ b/lib/wx/src/gen/wxDC.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2010. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2011. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -52,14 +52,14 @@
%% @hidden
parent_class(_Class) -> erlang:error({badtype, ?MODULE}).
-%% @spec (This::wxDC(), DestPt::{X::integer(),Y::integer()}, Sz::{W::integer(),H::integer()}, Source::wxDC(), SrcPt::{X::integer(),Y::integer()}) -> bool()
+%% @spec (This::wxDC(), DestPt::{X::integer(), Y::integer()}, Sz::{W::integer(), H::integer()}, Source::wxDC(), SrcPt::{X::integer(), Y::integer()}) -> bool()
%% @equiv blit(This,DestPt,Sz,Source,SrcPt, [])
blit(This,DestPt={DestPtX,DestPtY},Sz={SzW,SzH},Source,SrcPt={SrcPtX,SrcPtY})
when is_record(This, wx_ref),is_integer(DestPtX),is_integer(DestPtY),is_integer(SzW),is_integer(SzH),is_record(Source, wx_ref),is_integer(SrcPtX),is_integer(SrcPtY) ->
blit(This,DestPt,Sz,Source,SrcPt, []).
-%% @spec (This::wxDC(), DestPt::{X::integer(),Y::integer()}, Sz::{W::integer(),H::integer()}, Source::wxDC(), SrcPt::{X::integer(),Y::integer()}, [Option]) -> bool()
-%% Option = {rop, integer()} | {useMask, bool()} | {srcPtMask, {X::integer(),Y::integer()}}
+%% @spec (This::wxDC(), DestPt::{X::integer(), Y::integer()}, Sz::{W::integer(), H::integer()}, Source::wxDC(), SrcPt::{X::integer(), Y::integer()}, [Option]) -> bool()
+%% Option = {rop, integer()} | {useMask, bool()} | {srcPtMask, {X::integer(), Y::integer()}}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxdc.html#wxdcblit">external documentation</a>.
blit(#wx_ref{type=ThisT,ref=ThisRef},{DestPtX,DestPtY},{SzW,SzH},#wx_ref{type=SourceT,ref=SourceRef},{SrcPtX,SrcPtY}, Options)
when is_integer(DestPtX),is_integer(DestPtY),is_integer(SzW),is_integer(SzH),is_integer(SrcPtX),is_integer(SrcPtY),is_list(Options) ->
@@ -95,7 +95,7 @@ computeScaleAndOrigin(#wx_ref{type=ThisT,ref=ThisRef}) ->
wxe_util:cast(?wxDC_ComputeScaleAndOrigin,
<<ThisRef:32/?UI>>).
-%% @spec (This::wxDC(), Pt::{X::integer(),Y::integer()}) -> ok
+%% @spec (This::wxDC(), Pt::{X::integer(), Y::integer()}) -> ok
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxdc.html#wxdccrosshair">external documentation</a>.
crossHair(#wx_ref{type=ThisT,ref=ThisRef},{PtX,PtY})
when is_integer(PtX),is_integer(PtY) ->
@@ -142,7 +142,7 @@ deviceToLogicalYRel(#wx_ref{type=ThisT,ref=ThisRef},Y)
wxe_util:call(?wxDC_DeviceToLogicalYRel,
<<ThisRef:32/?UI,Y:32/?UI>>).
-%% @spec (This::wxDC(), Pt1::{X::integer(),Y::integer()}, Pt2::{X::integer(),Y::integer()}, Centre::{X::integer(),Y::integer()}) -> ok
+%% @spec (This::wxDC(), Pt1::{X::integer(), Y::integer()}, Pt2::{X::integer(), Y::integer()}, Centre::{X::integer(), Y::integer()}) -> ok
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxdc.html#wxdcdrawarc">external documentation</a>.
drawArc(#wx_ref{type=ThisT,ref=ThisRef},{Pt1X,Pt1Y},{Pt2X,Pt2Y},{CentreX,CentreY})
when is_integer(Pt1X),is_integer(Pt1Y),is_integer(Pt2X),is_integer(Pt2Y),is_integer(CentreX),is_integer(CentreY) ->
@@ -150,13 +150,13 @@ drawArc(#wx_ref{type=ThisT,ref=ThisRef},{Pt1X,Pt1Y},{Pt2X,Pt2Y},{CentreX,CentreY
wxe_util:cast(?wxDC_DrawArc,
<<ThisRef:32/?UI,Pt1X:32/?UI,Pt1Y:32/?UI,Pt2X:32/?UI,Pt2Y:32/?UI,CentreX:32/?UI,CentreY:32/?UI>>).
-%% @spec (This::wxDC(), Bmp::wxBitmap:wxBitmap(), Pt::{X::integer(),Y::integer()}) -> ok
+%% @spec (This::wxDC(), Bmp::wxBitmap:wxBitmap(), Pt::{X::integer(), Y::integer()}) -> ok
%% @equiv drawBitmap(This,Bmp,Pt, [])
drawBitmap(This,Bmp,Pt={PtX,PtY})
when is_record(This, wx_ref),is_record(Bmp, wx_ref),is_integer(PtX),is_integer(PtY) ->
drawBitmap(This,Bmp,Pt, []).
-%% @spec (This::wxDC(), Bmp::wxBitmap:wxBitmap(), Pt::{X::integer(),Y::integer()}, [Option]) -> ok
+%% @spec (This::wxDC(), Bmp::wxBitmap:wxBitmap(), Pt::{X::integer(), Y::integer()}, [Option]) -> ok
%% Option = {useMask, bool()}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxdc.html#wxdcdrawbitmap">external documentation</a>.
drawBitmap(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=BmpT,ref=BmpRef},{PtX,PtY}, Options)
@@ -169,7 +169,7 @@ drawBitmap(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=BmpT,ref=BmpRef},{PtX,Pt
wxe_util:cast(?wxDC_DrawBitmap,
<<ThisRef:32/?UI,BmpRef:32/?UI,PtX:32/?UI,PtY:32/?UI, BinOpt/binary>>).
-%% @spec (This::wxDC(), Rect::{X::integer(),Y::integer(),W::integer(),H::integer()}) -> ok
+%% @spec (This::wxDC(), Rect::{X::integer(), Y::integer(), W::integer(), H::integer()}) -> ok
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxdc.html#wxdcdrawcheckmark">external documentation</a>.
drawCheckMark(#wx_ref{type=ThisT,ref=ThisRef},{RectX,RectY,RectW,RectH})
when is_integer(RectX),is_integer(RectY),is_integer(RectW),is_integer(RectH) ->
@@ -177,7 +177,7 @@ drawCheckMark(#wx_ref{type=ThisT,ref=ThisRef},{RectX,RectY,RectW,RectH})
wxe_util:cast(?wxDC_DrawCheckMark,
<<ThisRef:32/?UI,RectX:32/?UI,RectY:32/?UI,RectW:32/?UI,RectH:32/?UI>>).
-%% @spec (This::wxDC(), Pt::{X::integer(),Y::integer()}, Radius::integer()) -> ok
+%% @spec (This::wxDC(), Pt::{X::integer(), Y::integer()}, Radius::integer()) -> ok
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxdc.html#wxdcdrawcircle">external documentation</a>.
drawCircle(#wx_ref{type=ThisT,ref=ThisRef},{PtX,PtY},Radius)
when is_integer(PtX),is_integer(PtY),is_integer(Radius) ->
@@ -185,7 +185,7 @@ drawCircle(#wx_ref{type=ThisT,ref=ThisRef},{PtX,PtY},Radius)
wxe_util:cast(?wxDC_DrawCircle,
<<ThisRef:32/?UI,PtX:32/?UI,PtY:32/?UI,Radius:32/?UI>>).
-%% @spec (This::wxDC(), Rect::{X::integer(),Y::integer(),W::integer(),H::integer()}) -> ok
+%% @spec (This::wxDC(), Rect::{X::integer(), Y::integer(), W::integer(), H::integer()}) -> ok
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxdc.html#wxdcdrawellipse">external documentation</a>.
drawEllipse(#wx_ref{type=ThisT,ref=ThisRef},{RectX,RectY,RectW,RectH})
when is_integer(RectX),is_integer(RectY),is_integer(RectW),is_integer(RectH) ->
@@ -193,7 +193,7 @@ drawEllipse(#wx_ref{type=ThisT,ref=ThisRef},{RectX,RectY,RectW,RectH})
wxe_util:cast(?wxDC_DrawEllipse_1,
<<ThisRef:32/?UI,RectX:32/?UI,RectY:32/?UI,RectW:32/?UI,RectH:32/?UI>>).
-%% @spec (This::wxDC(), Pt::{X::integer(),Y::integer()}, Sz::{W::integer(),H::integer()}) -> ok
+%% @spec (This::wxDC(), Pt::{X::integer(), Y::integer()}, Sz::{W::integer(), H::integer()}) -> ok
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxdc.html#wxdcdrawellipse">external documentation</a>.
drawEllipse(#wx_ref{type=ThisT,ref=ThisRef},{PtX,PtY},{SzW,SzH})
when is_integer(PtX),is_integer(PtY),is_integer(SzW),is_integer(SzH) ->
@@ -201,7 +201,7 @@ drawEllipse(#wx_ref{type=ThisT,ref=ThisRef},{PtX,PtY},{SzW,SzH})
wxe_util:cast(?wxDC_DrawEllipse_2,
<<ThisRef:32/?UI,PtX:32/?UI,PtY:32/?UI,SzW:32/?UI,SzH:32/?UI>>).
-%% @spec (This::wxDC(), Pt::{X::integer(),Y::integer()}, Sz::{W::integer(),H::integer()}, Sa::float(), Ea::float()) -> ok
+%% @spec (This::wxDC(), Pt::{X::integer(), Y::integer()}, Sz::{W::integer(), H::integer()}, Sa::float(), Ea::float()) -> ok
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxdc.html#wxdcdrawellipticarc">external documentation</a>.
drawEllipticArc(#wx_ref{type=ThisT,ref=ThisRef},{PtX,PtY},{SzW,SzH},Sa,Ea)
when is_integer(PtX),is_integer(PtY),is_integer(SzW),is_integer(SzH),is_float(Sa),is_float(Ea) ->
@@ -209,7 +209,7 @@ drawEllipticArc(#wx_ref{type=ThisT,ref=ThisRef},{PtX,PtY},{SzW,SzH},Sa,Ea)
wxe_util:cast(?wxDC_DrawEllipticArc,
<<ThisRef:32/?UI,PtX:32/?UI,PtY:32/?UI,SzW:32/?UI,SzH:32/?UI,0:32,Sa:64/?F,Ea:64/?F>>).
-%% @spec (This::wxDC(), Icon::wxIcon:wxIcon(), Pt::{X::integer(),Y::integer()}) -> ok
+%% @spec (This::wxDC(), Icon::wxIcon:wxIcon(), Pt::{X::integer(), Y::integer()}) -> ok
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxdc.html#wxdcdrawicon">external documentation</a>.
drawIcon(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=IconT,ref=IconRef},{PtX,PtY})
when is_integer(PtX),is_integer(PtY) ->
@@ -218,13 +218,13 @@ drawIcon(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=IconT,ref=IconRef},{PtX,Pt
wxe_util:cast(?wxDC_DrawIcon,
<<ThisRef:32/?UI,IconRef:32/?UI,PtX:32/?UI,PtY:32/?UI>>).
-%% @spec (This::wxDC(), Text::string(), Rect::{X::integer(),Y::integer(),W::integer(),H::integer()}) -> ok
+%% @spec (This::wxDC(), Text::string(), Rect::{X::integer(), Y::integer(), W::integer(), H::integer()}) -> ok
%% @equiv drawLabel(This,Text,Rect, [])
drawLabel(This,Text,Rect={RectX,RectY,RectW,RectH})
when is_record(This, wx_ref),is_list(Text),is_integer(RectX),is_integer(RectY),is_integer(RectW),is_integer(RectH) ->
drawLabel(This,Text,Rect, []).
-%% @spec (This::wxDC(), Text::string(), Rect::{X::integer(),Y::integer(),W::integer(),H::integer()}, [Option]) -> ok
+%% @spec (This::wxDC(), Text::string(), Rect::{X::integer(), Y::integer(), W::integer(), H::integer()}, [Option]) -> ok
%% Option = {alignment, integer()} | {indexAccel, integer()}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxdc.html#wxdcdrawlabel">external documentation</a>.
drawLabel(#wx_ref{type=ThisT,ref=ThisRef},Text,{RectX,RectY,RectW,RectH}, Options)
@@ -238,7 +238,7 @@ drawLabel(#wx_ref{type=ThisT,ref=ThisRef},Text,{RectX,RectY,RectW,RectH}, Option
wxe_util:cast(?wxDC_DrawLabel,
<<ThisRef:32/?UI,(byte_size(Text_UC)):32/?UI,(Text_UC)/binary, 0:(((8- ((0+byte_size(Text_UC)) band 16#7)) band 16#7))/unit:8,RectX:32/?UI,RectY:32/?UI,RectW:32/?UI,RectH:32/?UI, BinOpt/binary>>).
-%% @spec (This::wxDC(), Pt1::{X::integer(),Y::integer()}, Pt2::{X::integer(),Y::integer()}) -> ok
+%% @spec (This::wxDC(), Pt1::{X::integer(), Y::integer()}, Pt2::{X::integer(), Y::integer()}) -> ok
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxdc.html#wxdcdrawline">external documentation</a>.
drawLine(#wx_ref{type=ThisT,ref=ThisRef},{Pt1X,Pt1Y},{Pt2X,Pt2Y})
when is_integer(Pt1X),is_integer(Pt1Y),is_integer(Pt2X),is_integer(Pt2Y) ->
@@ -246,13 +246,13 @@ drawLine(#wx_ref{type=ThisT,ref=ThisRef},{Pt1X,Pt1Y},{Pt2X,Pt2Y})
wxe_util:cast(?wxDC_DrawLine,
<<ThisRef:32/?UI,Pt1X:32/?UI,Pt1Y:32/?UI,Pt2X:32/?UI,Pt2Y:32/?UI>>).
-%% @spec (This::wxDC(), Points::[{X::integer(),Y::integer()}]) -> ok
+%% @spec (This::wxDC(), Points::[{X::integer(), Y::integer()}]) -> ok
%% @equiv drawLines(This,Points, [])
drawLines(This,Points)
when is_record(This, wx_ref),is_list(Points) ->
drawLines(This,Points, []).
-%% @spec (This::wxDC(), Points::[{X::integer(),Y::integer()}], [Option]) -> ok
+%% @spec (This::wxDC(), Points::[{X::integer(), Y::integer()}], [Option]) -> ok
%% Option = {xoffset, integer()} | {yoffset, integer()}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxdc.html#wxdcdrawlines">external documentation</a>.
drawLines(#wx_ref{type=ThisT,ref=ThisRef},Points, Options)
@@ -266,13 +266,13 @@ drawLines(#wx_ref{type=ThisT,ref=ThisRef},Points, Options)
<<ThisRef:32/?UI,(length(Points)):32/?UI,
(<< <<X:32/?I,Y:32/?I>> || {X,Y} <- Points>>)/binary, BinOpt/binary>>).
-%% @spec (This::wxDC(), Points::[{X::integer(),Y::integer()}]) -> ok
+%% @spec (This::wxDC(), Points::[{X::integer(), Y::integer()}]) -> ok
%% @equiv drawPolygon(This,Points, [])
drawPolygon(This,Points)
when is_record(This, wx_ref),is_list(Points) ->
drawPolygon(This,Points, []).
-%% @spec (This::wxDC(), Points::[{X::integer(),Y::integer()}], [Option]) -> ok
+%% @spec (This::wxDC(), Points::[{X::integer(), Y::integer()}], [Option]) -> ok
%% Option = {xoffset, integer()} | {yoffset, integer()} | {fillStyle, integer()}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxdc.html#wxdcdrawpolygon">external documentation</a>.
drawPolygon(#wx_ref{type=ThisT,ref=ThisRef},Points, Options)
@@ -287,7 +287,7 @@ drawPolygon(#wx_ref{type=ThisT,ref=ThisRef},Points, Options)
<<ThisRef:32/?UI,(length(Points)):32/?UI,
(<< <<X:32/?I,Y:32/?I>> || {X,Y} <- Points>>)/binary, BinOpt/binary>>).
-%% @spec (This::wxDC(), Pt::{X::integer(),Y::integer()}) -> ok
+%% @spec (This::wxDC(), Pt::{X::integer(), Y::integer()}) -> ok
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxdc.html#wxdcdrawpoint">external documentation</a>.
drawPoint(#wx_ref{type=ThisT,ref=ThisRef},{PtX,PtY})
when is_integer(PtX),is_integer(PtY) ->
@@ -295,7 +295,7 @@ drawPoint(#wx_ref{type=ThisT,ref=ThisRef},{PtX,PtY})
wxe_util:cast(?wxDC_DrawPoint,
<<ThisRef:32/?UI,PtX:32/?UI,PtY:32/?UI>>).
-%% @spec (This::wxDC(), Rect::{X::integer(),Y::integer(),W::integer(),H::integer()}) -> ok
+%% @spec (This::wxDC(), Rect::{X::integer(), Y::integer(), W::integer(), H::integer()}) -> ok
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxdc.html#wxdcdrawrectangle">external documentation</a>.
drawRectangle(#wx_ref{type=ThisT,ref=ThisRef},{RectX,RectY,RectW,RectH})
when is_integer(RectX),is_integer(RectY),is_integer(RectW),is_integer(RectH) ->
@@ -303,7 +303,7 @@ drawRectangle(#wx_ref{type=ThisT,ref=ThisRef},{RectX,RectY,RectW,RectH})
wxe_util:cast(?wxDC_DrawRectangle_1,
<<ThisRef:32/?UI,RectX:32/?UI,RectY:32/?UI,RectW:32/?UI,RectH:32/?UI>>).
-%% @spec (This::wxDC(), Pt::{X::integer(),Y::integer()}, Sz::{W::integer(),H::integer()}) -> ok
+%% @spec (This::wxDC(), Pt::{X::integer(), Y::integer()}, Sz::{W::integer(), H::integer()}) -> ok
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxdc.html#wxdcdrawrectangle">external documentation</a>.
drawRectangle(#wx_ref{type=ThisT,ref=ThisRef},{PtX,PtY},{SzW,SzH})
when is_integer(PtX),is_integer(PtY),is_integer(SzW),is_integer(SzH) ->
@@ -311,7 +311,7 @@ drawRectangle(#wx_ref{type=ThisT,ref=ThisRef},{PtX,PtY},{SzW,SzH})
wxe_util:cast(?wxDC_DrawRectangle_2,
<<ThisRef:32/?UI,PtX:32/?UI,PtY:32/?UI,SzW:32/?UI,SzH:32/?UI>>).
-%% @spec (This::wxDC(), Text::string(), Pt::{X::integer(),Y::integer()}, Angle::float()) -> ok
+%% @spec (This::wxDC(), Text::string(), Pt::{X::integer(), Y::integer()}, Angle::float()) -> ok
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxdc.html#wxdcdrawrotatedtext">external documentation</a>.
drawRotatedText(#wx_ref{type=ThisT,ref=ThisRef},Text,{PtX,PtY},Angle)
when is_list(Text),is_integer(PtX),is_integer(PtY),is_float(Angle) ->
@@ -320,7 +320,7 @@ drawRotatedText(#wx_ref{type=ThisT,ref=ThisRef},Text,{PtX,PtY},Angle)
wxe_util:cast(?wxDC_DrawRotatedText,
<<ThisRef:32/?UI,(byte_size(Text_UC)):32/?UI,(Text_UC)/binary, 0:(((8- ((0+byte_size(Text_UC)) band 16#7)) band 16#7))/unit:8,PtX:32/?UI,PtY:32/?UI,Angle:64/?F>>).
-%% @spec (This::wxDC(), R::{X::integer(),Y::integer(),W::integer(),H::integer()}, Radius::float()) -> ok
+%% @spec (This::wxDC(), R::{X::integer(), Y::integer(), W::integer(), H::integer()}, Radius::float()) -> ok
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxdc.html#wxdcdrawroundedrectangle">external documentation</a>.
drawRoundedRectangle(#wx_ref{type=ThisT,ref=ThisRef},{RX,RY,RW,RH},Radius)
when is_integer(RX),is_integer(RY),is_integer(RW),is_integer(RH),is_float(Radius) ->
@@ -328,7 +328,7 @@ drawRoundedRectangle(#wx_ref{type=ThisT,ref=ThisRef},{RX,RY,RW,RH},Radius)
wxe_util:cast(?wxDC_DrawRoundedRectangle_2,
<<ThisRef:32/?UI,RX:32/?UI,RY:32/?UI,RW:32/?UI,RH:32/?UI,0:32,Radius:64/?F>>).
-%% @spec (This::wxDC(), Pt::{X::integer(),Y::integer()}, Sz::{W::integer(),H::integer()}, Radius::float()) -> ok
+%% @spec (This::wxDC(), Pt::{X::integer(), Y::integer()}, Sz::{W::integer(), H::integer()}, Radius::float()) -> ok
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxdc.html#wxdcdrawroundedrectangle">external documentation</a>.
drawRoundedRectangle(#wx_ref{type=ThisT,ref=ThisRef},{PtX,PtY},{SzW,SzH},Radius)
when is_integer(PtX),is_integer(PtY),is_integer(SzW),is_integer(SzH),is_float(Radius) ->
@@ -336,7 +336,7 @@ drawRoundedRectangle(#wx_ref{type=ThisT,ref=ThisRef},{PtX,PtY},{SzW,SzH},Radius)
wxe_util:cast(?wxDC_DrawRoundedRectangle_3,
<<ThisRef:32/?UI,PtX:32/?UI,PtY:32/?UI,SzW:32/?UI,SzH:32/?UI,0:32,Radius:64/?F>>).
-%% @spec (This::wxDC(), Text::string(), Pt::{X::integer(),Y::integer()}) -> ok
+%% @spec (This::wxDC(), Text::string(), Pt::{X::integer(), Y::integer()}) -> ok
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxdc.html#wxdcdrawtext">external documentation</a>.
drawText(#wx_ref{type=ThisT,ref=ThisRef},Text,{PtX,PtY})
when is_list(Text),is_integer(PtX),is_integer(PtY) ->
@@ -359,13 +359,13 @@ endPage(#wx_ref{type=ThisT,ref=ThisRef}) ->
wxe_util:cast(?wxDC_EndPage,
<<ThisRef:32/?UI>>).
-%% @spec (This::wxDC(), Pt::{X::integer(),Y::integer()}, Col::wx:colour()) -> bool()
+%% @spec (This::wxDC(), Pt::{X::integer(), Y::integer()}, Col::wx:colour()) -> bool()
%% @equiv floodFill(This,Pt,Col, [])
floodFill(This,Pt={PtX,PtY},Col)
when is_record(This, wx_ref),is_integer(PtX),is_integer(PtY),tuple_size(Col) =:= 3; tuple_size(Col) =:= 4 ->
floodFill(This,Pt,Col, []).
-%% @spec (This::wxDC(), Pt::{X::integer(),Y::integer()}, Col::wx:colour(), [Option]) -> bool()
+%% @spec (This::wxDC(), Pt::{X::integer(), Y::integer()}, Col::wx:colour(), [Option]) -> bool()
%% Option = {style, integer()}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxdc.html#wxdcfloodfill">external documentation</a>.
floodFill(#wx_ref{type=ThisT,ref=ThisRef},{PtX,PtY},Col, Options)
@@ -412,7 +412,7 @@ getCharWidth(#wx_ref{type=ThisT,ref=ThisRef}) ->
wxe_util:call(?wxDC_GetCharWidth,
<<ThisRef:32/?UI>>).
-%% @spec (This::wxDC(), Rect::{X::integer(),Y::integer(),W::integer(),H::integer()}) -> ok
+%% @spec (This::wxDC(), Rect::{X::integer(), Y::integer(), W::integer(), H::integer()}) -> ok
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxdc.html#wxdcgetclippingbox">external documentation</a>.
getClippingBox(#wx_ref{type=ThisT,ref=ThisRef},{RectX,RectY,RectW,RectH})
when is_integer(RectX),is_integer(RectY),is_integer(RectW),is_integer(RectH) ->
@@ -450,7 +450,7 @@ getMapMode(#wx_ref{type=ThisT,ref=ThisRef}) ->
wxe_util:call(?wxDC_GetMapMode,
<<ThisRef:32/?UI>>).
-%% @spec (This::wxDC(), String::string()) -> {W::integer(),H::integer()}
+%% @spec (This::wxDC(), String::string()) -> {W::integer(), H::integer()}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxdc.html#wxdcgetmultilinetextextent">external documentation</a>.
getMultiLineTextExtent(#wx_ref{type=ThisT,ref=ThisRef},String)
when is_list(String) ->
@@ -459,7 +459,7 @@ getMultiLineTextExtent(#wx_ref{type=ThisT,ref=ThisRef},String)
wxe_util:call(?wxDC_GetMultiLineTextExtent_1,
<<ThisRef:32/?UI,(byte_size(String_UC)):32/?UI,(String_UC)/binary, 0:(((8- ((0+byte_size(String_UC)) band 16#7)) band 16#7))/unit:8>>).
-%% @spec (This::wxDC(), String::string(), [Option]) -> {Width::integer(),Height::integer(),HeightLine::integer()}
+%% @spec (This::wxDC(), String::string(), [Option]) -> {Width::integer(), Height::integer(), HeightLine::integer()}
%% Option = {font, wxFont:wxFont()}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxdc.html#wxdcgetmultilinetextextent">external documentation</a>.
getMultiLineTextExtent(#wx_ref{type=ThisT,ref=ThisRef},String, Options)
@@ -489,7 +489,7 @@ getPen(#wx_ref{type=ThisT,ref=ThisRef}) ->
wxe_util:call(?wxDC_GetPen,
<<ThisRef:32/?UI>>).
-%% @spec (This::wxDC(), Pt::{X::integer(),Y::integer()}, Col::wx:colour()) -> bool()
+%% @spec (This::wxDC(), Pt::{X::integer(), Y::integer()}, Col::wx:colour()) -> bool()
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxdc.html#wxdcgetpixel">external documentation</a>.
getPixel(#wx_ref{type=ThisT,ref=ThisRef},{PtX,PtY},Col)
when is_integer(PtX),is_integer(PtY),tuple_size(Col) =:= 3; tuple_size(Col) =:= 4 ->
@@ -497,21 +497,21 @@ getPixel(#wx_ref{type=ThisT,ref=ThisRef},{PtX,PtY},Col)
wxe_util:call(?wxDC_GetPixel,
<<ThisRef:32/?UI,PtX:32/?UI,PtY:32/?UI,(wxe_util:colour_bin(Col)):16/binary>>).
-%% @spec (This::wxDC()) -> {W::integer(),H::integer()}
+%% @spec (This::wxDC()) -> {W::integer(), H::integer()}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxdc.html#wxdcgetppi">external documentation</a>.
getPPI(#wx_ref{type=ThisT,ref=ThisRef}) ->
?CLASS(ThisT,wxDC),
wxe_util:call(?wxDC_GetPPI,
<<ThisRef:32/?UI>>).
-%% @spec (This::wxDC()) -> {W::integer(),H::integer()}
+%% @spec (This::wxDC()) -> {W::integer(), H::integer()}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxdc.html#wxdcgetsize">external documentation</a>.
getSize(#wx_ref{type=ThisT,ref=ThisRef}) ->
?CLASS(ThisT,wxDC),
wxe_util:call(?wxDC_GetSize,
<<ThisRef:32/?UI>>).
-%% @spec (This::wxDC()) -> {W::integer(),H::integer()}
+%% @spec (This::wxDC()) -> {W::integer(), H::integer()}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxdc.html#wxdcgetsizemm">external documentation</a>.
getSizeMM(#wx_ref{type=ThisT,ref=ThisRef}) ->
?CLASS(ThisT,wxDC),
@@ -525,7 +525,7 @@ getTextBackground(#wx_ref{type=ThisT,ref=ThisRef}) ->
wxe_util:call(?wxDC_GetTextBackground,
<<ThisRef:32/?UI>>).
-%% @spec (This::wxDC(), String::string()) -> {W::integer(),H::integer()}
+%% @spec (This::wxDC(), String::string()) -> {W::integer(), H::integer()}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxdc.html#wxdcgettextextent">external documentation</a>.
getTextExtent(#wx_ref{type=ThisT,ref=ThisRef},String)
when is_list(String) ->
@@ -534,7 +534,7 @@ getTextExtent(#wx_ref{type=ThisT,ref=ThisRef},String)
wxe_util:call(?wxDC_GetTextExtent_1,
<<ThisRef:32/?UI,(byte_size(String_UC)):32/?UI,(String_UC)/binary, 0:(((8- ((0+byte_size(String_UC)) band 16#7)) band 16#7))/unit:8>>).
-%% @spec (This::wxDC(), String::string(), [Option]) -> {X::integer(),Y::integer(),Descent::integer(),ExternalLeading::integer()}
+%% @spec (This::wxDC(), String::string(), [Option]) -> {X::integer(), Y::integer(), Descent::integer(), ExternalLeading::integer()}
%% Option = {theFont, wxFont:wxFont()}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxdc.html#wxdcgettextextent">external documentation</a>.
getTextExtent(#wx_ref{type=ThisT,ref=ThisRef},String, Options)
@@ -554,14 +554,14 @@ getTextForeground(#wx_ref{type=ThisT,ref=ThisRef}) ->
wxe_util:call(?wxDC_GetTextForeground,
<<ThisRef:32/?UI>>).
-%% @spec (This::wxDC()) -> {X::float(),Y::float()}
+%% @spec (This::wxDC()) -> {X::float(), Y::float()}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxdc.html#wxdcgetuserscale">external documentation</a>.
getUserScale(#wx_ref{type=ThisT,ref=ThisRef}) ->
?CLASS(ThisT,wxDC),
wxe_util:call(?wxDC_GetUserScale,
<<ThisRef:32/?UI>>).
-%% @spec (This::wxDC(), Rect::{X::integer(),Y::integer(),W::integer(),H::integer()}, InitialColour::wx:colour(), DestColour::wx:colour()) -> ok
+%% @spec (This::wxDC(), Rect::{X::integer(), Y::integer(), W::integer(), H::integer()}, InitialColour::wx:colour(), DestColour::wx:colour()) -> ok
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxdc.html#wxdcgradientfillconcentric">external documentation</a>.
gradientFillConcentric(#wx_ref{type=ThisT,ref=ThisRef},{RectX,RectY,RectW,RectH},InitialColour,DestColour)
when is_integer(RectX),is_integer(RectY),is_integer(RectW),is_integer(RectH),tuple_size(InitialColour) =:= 3; tuple_size(InitialColour) =:= 4,tuple_size(DestColour) =:= 3; tuple_size(DestColour) =:= 4 ->
@@ -569,7 +569,7 @@ gradientFillConcentric(#wx_ref{type=ThisT,ref=ThisRef},{RectX,RectY,RectW,RectH}
wxe_util:cast(?wxDC_GradientFillConcentric_3,
<<ThisRef:32/?UI,RectX:32/?UI,RectY:32/?UI,RectW:32/?UI,RectH:32/?UI,(wxe_util:colour_bin(InitialColour)):16/binary,(wxe_util:colour_bin(DestColour)):16/binary>>).
-%% @spec (This::wxDC(), Rect::{X::integer(),Y::integer(),W::integer(),H::integer()}, InitialColour::wx:colour(), DestColour::wx:colour(), CircleCenter::{X::integer(),Y::integer()}) -> ok
+%% @spec (This::wxDC(), Rect::{X::integer(), Y::integer(), W::integer(), H::integer()}, InitialColour::wx:colour(), DestColour::wx:colour(), CircleCenter::{X::integer(), Y::integer()}) -> ok
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxdc.html#wxdcgradientfillconcentric">external documentation</a>.
gradientFillConcentric(#wx_ref{type=ThisT,ref=ThisRef},{RectX,RectY,RectW,RectH},InitialColour,DestColour,{CircleCenterX,CircleCenterY})
when is_integer(RectX),is_integer(RectY),is_integer(RectW),is_integer(RectH),tuple_size(InitialColour) =:= 3; tuple_size(InitialColour) =:= 4,tuple_size(DestColour) =:= 3; tuple_size(DestColour) =:= 4,is_integer(CircleCenterX),is_integer(CircleCenterY) ->
@@ -577,13 +577,13 @@ gradientFillConcentric(#wx_ref{type=ThisT,ref=ThisRef},{RectX,RectY,RectW,RectH}
wxe_util:cast(?wxDC_GradientFillConcentric_4,
<<ThisRef:32/?UI,RectX:32/?UI,RectY:32/?UI,RectW:32/?UI,RectH:32/?UI,(wxe_util:colour_bin(InitialColour)):16/binary,(wxe_util:colour_bin(DestColour)):16/binary,CircleCenterX:32/?UI,CircleCenterY:32/?UI>>).
-%% @spec (This::wxDC(), Rect::{X::integer(),Y::integer(),W::integer(),H::integer()}, InitialColour::wx:colour(), DestColour::wx:colour()) -> ok
+%% @spec (This::wxDC(), Rect::{X::integer(), Y::integer(), W::integer(), H::integer()}, InitialColour::wx:colour(), DestColour::wx:colour()) -> ok
%% @equiv gradientFillLinear(This,Rect,InitialColour,DestColour, [])
gradientFillLinear(This,Rect={RectX,RectY,RectW,RectH},InitialColour,DestColour)
when is_record(This, wx_ref),is_integer(RectX),is_integer(RectY),is_integer(RectW),is_integer(RectH),tuple_size(InitialColour) =:= 3; tuple_size(InitialColour) =:= 4,tuple_size(DestColour) =:= 3; tuple_size(DestColour) =:= 4 ->
gradientFillLinear(This,Rect,InitialColour,DestColour, []).
-%% @spec (This::wxDC(), Rect::{X::integer(),Y::integer(),W::integer(),H::integer()}, InitialColour::wx:colour(), DestColour::wx:colour(), [Option]) -> ok
+%% @spec (This::wxDC(), Rect::{X::integer(), Y::integer(), W::integer(), H::integer()}, InitialColour::wx:colour(), DestColour::wx:colour(), [Option]) -> ok
%% Option = {nDirection, WxDirection}
%% WxDirection = integer()
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxdc.html#wxdcgradientfilllinear">external documentation</a>.
@@ -710,7 +710,7 @@ setBrush(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=BrushT,ref=BrushRef}) ->
%% setClippingRegion(This::wxDC(), Region::wxRegion:wxRegion()) -> ok </c>
%% </p>
%% <p><c>
-%% setClippingRegion(This::wxDC(), Rect::{X::integer(),Y::integer(),W::integer(),H::integer()}) -> ok </c>
+%% setClippingRegion(This::wxDC(), Rect::{X::integer(), Y::integer(), W::integer(), H::integer()}) -> ok </c>
%% </p>
setClippingRegion(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=RegionT,ref=RegionRef}) ->
?CLASS(ThisT,wxDC),
@@ -723,7 +723,7 @@ setClippingRegion(#wx_ref{type=ThisT,ref=ThisRef},{RectX,RectY,RectW,RectH})
wxe_util:cast(?wxDC_SetClippingRegion_1_1,
<<ThisRef:32/?UI,RectX:32/?UI,RectY:32/?UI,RectW:32/?UI,RectH:32/?UI>>).
-%% @spec (This::wxDC(), Pt::{X::integer(),Y::integer()}, Sz::{W::integer(),H::integer()}) -> ok
+%% @spec (This::wxDC(), Pt::{X::integer(), Y::integer()}, Sz::{W::integer(), H::integer()}) -> ok
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxdc.html#wxdcsetclippingregion">external documentation</a>.
setClippingRegion(#wx_ref{type=ThisT,ref=ThisRef},{PtX,PtY},{SzW,SzH})
when is_integer(PtX),is_integer(PtY),is_integer(SzW),is_integer(SzH) ->
diff --git a/lib/wx/src/gen/wxDatePickerCtrl.erl b/lib/wx/src/gen/wxDatePickerCtrl.erl
index 2de51ce71d..8a1700e9cd 100644
--- a/lib/wx/src/gen/wxDatePickerCtrl.erl
+++ b/lib/wx/src/gen/wxDatePickerCtrl.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2010. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2011. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -94,7 +94,7 @@ new(Parent,Id)
new(Parent,Id, []).
%% @spec (Parent::wxWindow:wxWindow(), Id::integer(), [Option]) -> wxDatePickerCtrl()
-%% Option = {date, wx:datetime()} | {pos, {X::integer(),Y::integer()}} | {size, {W::integer(),H::integer()}} | {style, integer()} | {validator, wx:wx()}
+%% Option = {date, wx:datetime()} | {pos, {X::integer(), Y::integer()}} | {size, {W::integer(), H::integer()}} | {style, integer()} | {validator, wx:wx()}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxdatepickerctrl.html#wxdatepickerctrlwxdatepickerctrl">external documentation</a>.
new(#wx_ref{type=ParentT,ref=ParentRef},Id, Options)
when is_integer(Id),is_list(Options) ->
diff --git a/lib/wx/src/gen/wxDialog.erl b/lib/wx/src/gen/wxDialog.erl
index 8c0bd2cd76..514a62813e 100644
--- a/lib/wx/src/gen/wxDialog.erl
+++ b/lib/wx/src/gen/wxDialog.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2010. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2011. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -95,7 +95,7 @@ new(Parent,Id,Title)
new(Parent,Id,Title, []).
%% @spec (Parent::wxWindow:wxWindow(), Id::integer(), Title::string(), [Option]) -> wxDialog()
-%% Option = {pos, {X::integer(),Y::integer()}} | {size, {W::integer(),H::integer()}} | {style, integer()}
+%% Option = {pos, {X::integer(), Y::integer()}} | {size, {W::integer(), H::integer()}} | {style, integer()}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxdialog.html#wxdialogwxdialog">external documentation</a>.
new(#wx_ref{type=ParentT,ref=ParentRef},Id,Title, Options)
when is_integer(Id),is_list(Title),is_list(Options) ->
@@ -116,7 +116,7 @@ create(This,Parent,Id,Title)
create(This,Parent,Id,Title, []).
%% @spec (This::wxDialog(), Parent::wxWindow:wxWindow(), Id::integer(), Title::string(), [Option]) -> bool()
-%% Option = {pos, {X::integer(),Y::integer()}} | {size, {W::integer(),H::integer()}} | {style, integer()}
+%% Option = {pos, {X::integer(), Y::integer()}} | {size, {W::integer(), H::integer()}} | {style, integer()}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxdialog.html#wxdialogcreate">external documentation</a>.
create(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=ParentT,ref=ParentRef},Id,Title, Options)
when is_integer(Id),is_list(Title),is_list(Options) ->
diff --git a/lib/wx/src/gen/wxDirDialog.erl b/lib/wx/src/gen/wxDirDialog.erl
index 7849dce0a7..28db3daf1d 100644
--- a/lib/wx/src/gen/wxDirDialog.erl
+++ b/lib/wx/src/gen/wxDirDialog.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2010. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2011. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -91,7 +91,7 @@ new(Parent)
new(Parent, []).
%% @spec (Parent::wxWindow:wxWindow(), [Option]) -> wxDirDialog()
-%% Option = {title, string()} | {defaultPath, string()} | {style, integer()} | {pos, {X::integer(),Y::integer()}} | {sz, {W::integer(),H::integer()}}
+%% Option = {title, string()} | {defaultPath, string()} | {style, integer()} | {pos, {X::integer(), Y::integer()}} | {sz, {W::integer(), H::integer()}}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxdirdialog.html#wxdirdialogwxdirdialog">external documentation</a>.
new(#wx_ref{type=ParentT,ref=ParentRef}, Options)
when is_list(Options) ->
diff --git a/lib/wx/src/gen/wxDirPickerCtrl.erl b/lib/wx/src/gen/wxDirPickerCtrl.erl
index 7fb70b71e3..2b24bc4bb0 100644
--- a/lib/wx/src/gen/wxDirPickerCtrl.erl
+++ b/lib/wx/src/gen/wxDirPickerCtrl.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2010. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2011. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -94,7 +94,7 @@ new(Parent,Id)
new(Parent,Id, []).
%% @spec (Parent::wxWindow:wxWindow(), Id::integer(), [Option]) -> wxDirPickerCtrl()
-%% Option = {path, string()} | {message, string()} | {pos, {X::integer(),Y::integer()}} | {size, {W::integer(),H::integer()}} | {style, integer()} | {validator, wx:wx()}
+%% Option = {path, string()} | {message, string()} | {pos, {X::integer(), Y::integer()}} | {size, {W::integer(), H::integer()}} | {style, integer()} | {validator, wx:wx()}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxdirpickerctrl.html#wxdirpickerctrlwxdirpickerctrl">external documentation</a>.
new(#wx_ref{type=ParentT,ref=ParentRef},Id, Options)
when is_integer(Id),is_list(Options) ->
@@ -117,7 +117,7 @@ create(This,Parent,Id)
create(This,Parent,Id, []).
%% @spec (This::wxDirPickerCtrl(), Parent::wxWindow:wxWindow(), Id::integer(), [Option]) -> bool()
-%% Option = {path, string()} | {message, string()} | {pos, {X::integer(),Y::integer()}} | {size, {W::integer(),H::integer()}} | {style, integer()} | {validator, wx:wx()}
+%% Option = {path, string()} | {message, string()} | {pos, {X::integer(), Y::integer()}} | {size, {W::integer(), H::integer()}} | {style, integer()} | {validator, wx:wx()}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxdirpickerctrl.html#wxdirpickerctrlcreate">external documentation</a>.
create(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=ParentT,ref=ParentRef},Id, Options)
when is_integer(Id),is_list(Options) ->
diff --git a/lib/wx/src/gen/wxFileDialog.erl b/lib/wx/src/gen/wxFileDialog.erl
index cba9705335..c6779927e9 100644
--- a/lib/wx/src/gen/wxFileDialog.erl
+++ b/lib/wx/src/gen/wxFileDialog.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2010. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2011. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -93,7 +93,7 @@ new(Parent)
new(Parent, []).
%% @spec (Parent::wxWindow:wxWindow(), [Option]) -> wxFileDialog()
-%% Option = {message, string()} | {defaultDir, string()} | {defaultFile, string()} | {wildCard, string()} | {style, integer()} | {pos, {X::integer(),Y::integer()}} | {sz, {W::integer(),H::integer()}}
+%% Option = {message, string()} | {defaultDir, string()} | {defaultFile, string()} | {wildCard, string()} | {style, integer()} | {pos, {X::integer(), Y::integer()}} | {sz, {W::integer(), H::integer()}}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxfiledialog.html#wxfiledialogwxfiledialog">external documentation</a>.
new(#wx_ref{type=ParentT,ref=ParentRef}, Options)
when is_list(Options) ->
diff --git a/lib/wx/src/gen/wxFilePickerCtrl.erl b/lib/wx/src/gen/wxFilePickerCtrl.erl
index a3034aaa86..93bfa72380 100644
--- a/lib/wx/src/gen/wxFilePickerCtrl.erl
+++ b/lib/wx/src/gen/wxFilePickerCtrl.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2010. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2011. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -94,7 +94,7 @@ new(Parent,Id)
new(Parent,Id, []).
%% @spec (Parent::wxWindow:wxWindow(), Id::integer(), [Option]) -> wxFilePickerCtrl()
-%% Option = {path, string()} | {message, string()} | {wildcard, string()} | {pos, {X::integer(),Y::integer()}} | {size, {W::integer(),H::integer()}} | {style, integer()} | {validator, wx:wx()}
+%% Option = {path, string()} | {message, string()} | {wildcard, string()} | {pos, {X::integer(), Y::integer()}} | {size, {W::integer(), H::integer()}} | {style, integer()} | {validator, wx:wx()}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxfilepickerctrl.html#wxfilepickerctrlwxfilepickerctrl">external documentation</a>.
new(#wx_ref{type=ParentT,ref=ParentRef},Id, Options)
when is_integer(Id),is_list(Options) ->
@@ -118,7 +118,7 @@ create(This,Parent,Id)
create(This,Parent,Id, []).
%% @spec (This::wxFilePickerCtrl(), Parent::wxWindow:wxWindow(), Id::integer(), [Option]) -> bool()
-%% Option = {path, string()} | {message, string()} | {wildcard, string()} | {pos, {X::integer(),Y::integer()}} | {size, {W::integer(),H::integer()}} | {style, integer()} | {validator, wx:wx()}
+%% Option = {path, string()} | {message, string()} | {wildcard, string()} | {pos, {X::integer(), Y::integer()}} | {size, {W::integer(), H::integer()}} | {style, integer()} | {validator, wx:wx()}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxfilepickerctrl.html#wxfilepickerctrlcreate">external documentation</a>.
create(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=ParentT,ref=ParentRef},Id, Options)
when is_integer(Id),is_list(Options) ->
diff --git a/lib/wx/src/gen/wxFontPickerCtrl.erl b/lib/wx/src/gen/wxFontPickerCtrl.erl
index 93d63cc930..3050011b60 100644
--- a/lib/wx/src/gen/wxFontPickerCtrl.erl
+++ b/lib/wx/src/gen/wxFontPickerCtrl.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2010. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2011. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -95,7 +95,7 @@ new(Parent,Id)
new(Parent,Id, []).
%% @spec (Parent::wxWindow:wxWindow(), Id::integer(), [Option]) -> wxFontPickerCtrl()
-%% Option = {initial, wxFont:wxFont()} | {pos, {X::integer(),Y::integer()}} | {size, {W::integer(),H::integer()}} | {style, integer()} | {validator, wx:wx()}
+%% Option = {initial, wxFont:wxFont()} | {pos, {X::integer(), Y::integer()}} | {size, {W::integer(), H::integer()}} | {style, integer()} | {validator, wx:wx()}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxfontpickerctrl.html#wxfontpickerctrlwxfontpickerctrl">external documentation</a>.
new(#wx_ref{type=ParentT,ref=ParentRef},Id, Options)
when is_integer(Id),is_list(Options) ->
@@ -117,7 +117,7 @@ create(This,Parent,Id)
create(This,Parent,Id, []).
%% @spec (This::wxFontPickerCtrl(), Parent::wxWindow:wxWindow(), Id::integer(), [Option]) -> bool()
-%% Option = {initial, wxFont:wxFont()} | {pos, {X::integer(),Y::integer()}} | {size, {W::integer(),H::integer()}} | {style, integer()} | {validator, wx:wx()}
+%% Option = {initial, wxFont:wxFont()} | {pos, {X::integer(), Y::integer()}} | {size, {W::integer(), H::integer()}} | {style, integer()} | {validator, wx:wx()}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxfontpickerctrl.html#wxfontpickerctrlcreate">external documentation</a>.
create(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=ParentT,ref=ParentRef},Id, Options)
when is_integer(Id),is_list(Options) ->
diff --git a/lib/wx/src/gen/wxFrame.erl b/lib/wx/src/gen/wxFrame.erl
index 5cd1e3dfd3..7e25bc8762 100644
--- a/lib/wx/src/gen/wxFrame.erl
+++ b/lib/wx/src/gen/wxFrame.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2010. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2011. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -97,7 +97,7 @@ new(Parent,Id,Title)
new(Parent,Id,Title, []).
%% @spec (Parent::wxWindow:wxWindow(), Id::integer(), Title::string(), [Option]) -> wxFrame()
-%% Option = {pos, {X::integer(),Y::integer()}} | {size, {W::integer(),H::integer()}} | {style, integer()}
+%% Option = {pos, {X::integer(), Y::integer()}} | {size, {W::integer(), H::integer()}} | {style, integer()}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxframe.html#wxframewxframe">external documentation</a>.
new(#wx_ref{type=ParentT,ref=ParentRef},Id,Title, Options)
when is_integer(Id),is_list(Title),is_list(Options) ->
@@ -118,7 +118,7 @@ create(This,Parent,Id,Title)
create(This,Parent,Id,Title, []).
%% @spec (This::wxFrame(), Parent::wxWindow:wxWindow(), Id::integer(), Title::string(), [Option]) -> bool()
-%% Option = {pos, {X::integer(),Y::integer()}} | {size, {W::integer(),H::integer()}} | {style, integer()}
+%% Option = {pos, {X::integer(), Y::integer()}} | {size, {W::integer(), H::integer()}} | {style, integer()}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxframe.html#wxframecreate">external documentation</a>.
create(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=ParentT,ref=ParentRef},Id,Title, Options)
when is_integer(Id),is_list(Title),is_list(Options) ->
@@ -172,7 +172,7 @@ createToolBar(#wx_ref{type=ThisT,ref=ThisRef}, Options)
wxe_util:call(?wxFrame_CreateToolBar,
<<ThisRef:32/?UI, 0:32,BinOpt/binary>>).
-%% @spec (This::wxFrame()) -> {X::integer(),Y::integer()}
+%% @spec (This::wxFrame()) -> {X::integer(), Y::integer()}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxframe.html#wxframegetclientareaorigin">external documentation</a>.
getClientAreaOrigin(#wx_ref{type=ThisT,ref=ThisRef}) ->
?CLASS(ThisT,wxFrame),
diff --git a/lib/wx/src/gen/wxGLCanvas.erl b/lib/wx/src/gen/wxGLCanvas.erl
index 032d42535d..a30d8cefd9 100644
--- a/lib/wx/src/gen/wxGLCanvas.erl
+++ b/lib/wx/src/gen/wxGLCanvas.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2010. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2011. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -86,7 +86,7 @@ new(Parent)
%% new(Parent::wxWindow:wxWindow(), Shared::wxGLContext:wxGLContext() | wxGLCanvas()) -> new(Parent,Shared, []) </c></p>
%% <p><c>
%% new(Parent::wxWindow:wxWindow(), [Option]) -> wxGLCanvas() </c>
-%%<br /> Option = {id, integer()} | {pos, {X::integer(),Y::integer()}} | {size, {W::integer(),H::integer()}} | {style, integer()} | {name, string()} | {attribList, [integer()]} | {palette, wxPalette:wxPalette()}
+%%<br /> Option = {id, integer()} | {pos, {X::integer(), Y::integer()}} | {size, {W::integer(), H::integer()}} | {style, integer()} | {name, string()} | {attribList, [integer()]} | {palette, wxPalette:wxPalette()}
%% </p>
new(Parent,Shared)
@@ -109,7 +109,7 @@ new(#wx_ref{type=ParentT,ref=ParentRef}, Options)
<<ParentRef:32/?UI, 0:32,BinOpt/binary>>).
%% @spec (Parent::wxWindow:wxWindow(), Shared::wxGLContext:wxGLContext() | wxGLCanvas(), [Option]) -> wxGLCanvas()
-%% Option = {id, integer()} | {pos, {X::integer(),Y::integer()}} | {size, {W::integer(),H::integer()}} | {style, integer()} | {name, string()} | {attribList, [integer()]} | {palette, wxPalette:wxPalette()}
+%% Option = {id, integer()} | {pos, {X::integer(), Y::integer()}} | {size, {W::integer(), H::integer()}} | {style, integer()} | {name, string()} | {attribList, [integer()]} | {palette, wxPalette:wxPalette()}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxglcanvas.html#wxglcanvaswxglcanvas">external documentation</a>.
new(#wx_ref{type=ParentT,ref=ParentRef},#wx_ref{type=SharedT,ref=SharedRef}, Options)
when is_list(Options) ->
diff --git a/lib/wx/src/gen/wxGauge.erl b/lib/wx/src/gen/wxGauge.erl
index 5028b29bba..484fd36936 100644
--- a/lib/wx/src/gen/wxGauge.erl
+++ b/lib/wx/src/gen/wxGauge.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2010. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2011. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -90,7 +90,7 @@ new(Parent,Id,Range)
new(Parent,Id,Range, []).
%% @spec (Parent::wxWindow:wxWindow(), Id::integer(), Range::integer(), [Option]) -> wxGauge()
-%% Option = {pos, {X::integer(),Y::integer()}} | {size, {W::integer(),H::integer()}} | {style, integer()} | {validator, wx:wx()}
+%% Option = {pos, {X::integer(), Y::integer()}} | {size, {W::integer(), H::integer()}} | {style, integer()} | {validator, wx:wx()}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxgauge.html#wxgaugewxgauge">external documentation</a>.
new(#wx_ref{type=ParentT,ref=ParentRef},Id,Range, Options)
when is_integer(Id),is_integer(Range),is_list(Options) ->
@@ -111,7 +111,7 @@ create(This,Parent,Id,Range)
create(This,Parent,Id,Range, []).
%% @spec (This::wxGauge(), Parent::wxWindow:wxWindow(), Id::integer(), Range::integer(), [Option]) -> bool()
-%% Option = {pos, {X::integer(),Y::integer()}} | {size, {W::integer(),H::integer()}} | {style, integer()} | {validator, wx:wx()}
+%% Option = {pos, {X::integer(), Y::integer()}} | {size, {W::integer(), H::integer()}} | {style, integer()} | {validator, wx:wx()}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxgauge.html#wxgaugecreate">external documentation</a>.
create(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=ParentT,ref=ParentRef},Id,Range, Options)
when is_integer(Id),is_integer(Range),is_list(Options) ->
diff --git a/lib/wx/src/gen/wxGenericDirCtrl.erl b/lib/wx/src/gen/wxGenericDirCtrl.erl
index 97944710f0..626a454d2a 100644
--- a/lib/wx/src/gen/wxGenericDirCtrl.erl
+++ b/lib/wx/src/gen/wxGenericDirCtrl.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2010. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2011. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -91,7 +91,7 @@ new(Parent)
new(Parent, []).
%% @spec (Parent::wxWindow:wxWindow(), [Option]) -> wxGenericDirCtrl()
-%% Option = {id, integer()} | {dir, string()} | {pos, {X::integer(),Y::integer()}} | {size, {W::integer(),H::integer()}} | {style, integer()} | {filter, string()} | {defaultFilter, integer()}
+%% Option = {id, integer()} | {dir, string()} | {pos, {X::integer(), Y::integer()}} | {size, {W::integer(), H::integer()}} | {style, integer()} | {filter, string()} | {defaultFilter, integer()}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxgenericdirctrl.html#wxgenericdirctrlwxgenericdirctrl">external documentation</a>.
new(#wx_ref{type=ParentT,ref=ParentRef}, Options)
when is_list(Options) ->
@@ -115,7 +115,7 @@ create(This,Parent)
create(This,Parent, []).
%% @spec (This::wxGenericDirCtrl(), Parent::wxWindow:wxWindow(), [Option]) -> bool()
-%% Option = {id, integer()} | {dir, string()} | {pos, {X::integer(),Y::integer()}} | {size, {W::integer(),H::integer()}} | {style, integer()} | {filter, string()} | {defaultFilter, integer()}
+%% Option = {id, integer()} | {dir, string()} | {pos, {X::integer(), Y::integer()}} | {size, {W::integer(), H::integer()}} | {style, integer()} | {filter, string()} | {defaultFilter, integer()}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxgenericdirctrl.html#wxgenericdirctrlcreate">external documentation</a>.
create(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=ParentT,ref=ParentRef}, Options)
when is_list(Options) ->
diff --git a/lib/wx/src/gen/wxGraphicsContext.erl b/lib/wx/src/gen/wxGraphicsContext.erl
index 040867cb11..05c56dd4b2 100644
--- a/lib/wx/src/gen/wxGraphicsContext.erl
+++ b/lib/wx/src/gen/wxGraphicsContext.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2010. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2011. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -192,13 +192,13 @@ drawIcon(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=IconT,ref=IconRef},X,Y,W,H
wxe_util:cast(?wxGraphicsContext_DrawIcon,
<<ThisRef:32/?UI,IconRef:32/?UI,X:64/?F,Y:64/?F,W:64/?F,H:64/?F>>).
-%% @spec (This::wxGraphicsContext(), N::integer(), Points::{X::float(),Y::float()}) -> ok
+%% @spec (This::wxGraphicsContext(), N::integer(), Points::{X::float(), Y::float()}) -> ok
%% @equiv drawLines(This,N,Points, [])
drawLines(This,N,Points={PointsX,PointsY})
when is_record(This, wx_ref),is_integer(N),is_number(PointsX),is_number(PointsY) ->
drawLines(This,N,Points, []).
-%% @spec (This::wxGraphicsContext(), N::integer(), Points::{X::float(),Y::float()}, [Option]) -> ok
+%% @spec (This::wxGraphicsContext(), N::integer(), Points::{X::float(), Y::float()}, [Option]) -> ok
%% Option = {fillStyle, integer()}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxgraphicscontext.html#wxgraphicscontextdrawlines">external documentation</a>.
drawLines(#wx_ref{type=ThisT,ref=ThisRef},N,{PointsX,PointsY}, Options)
@@ -331,7 +331,7 @@ getPartialTextExtents(#wx_ref{type=ThisT,ref=ThisRef},Text,Widths)
<<ThisRef:32/?UI,(byte_size(Text_UC)):32/?UI,(Text_UC)/binary, 0:(((8- ((0+byte_size(Text_UC)) band 16#7)) band 16#7))/unit:8,(length(Widths)):32/?UI,
0:32, (<< <<C:64/float>> || C <- Widths>>)/binary>>).
-%% @spec (This::wxGraphicsContext(), Text::string()) -> {Width::float(),Height::float(),Descent::float(),ExternalLeading::float()}
+%% @spec (This::wxGraphicsContext(), Text::string()) -> {Width::float(), Height::float(), Descent::float(), ExternalLeading::float()}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxgraphicscontext.html#wxgraphicscontextgettextextent">external documentation</a>.
getTextExtent(#wx_ref{type=ThisT,ref=ThisRef},Text)
when is_list(Text) ->
@@ -438,7 +438,7 @@ strokeLine(#wx_ref{type=ThisT,ref=ThisRef},X1,Y1,X2,Y2)
wxe_util:cast(?wxGraphicsContext_StrokeLine,
<<ThisRef:32/?UI,0:32,X1:64/?F,Y1:64/?F,X2:64/?F,Y2:64/?F>>).
-%% @spec (This::wxGraphicsContext(), N::integer(), Points::{X::float(),Y::float()}) -> ok
+%% @spec (This::wxGraphicsContext(), N::integer(), Points::{X::float(), Y::float()}) -> ok
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxgraphicscontext.html#wxgraphicscontextstrokelines">external documentation</a>.
strokeLines(#wx_ref{type=ThisT,ref=ThisRef},N,{PointsX,PointsY})
when is_integer(N),is_number(PointsX),is_number(PointsY) ->
@@ -446,7 +446,7 @@ strokeLines(#wx_ref{type=ThisT,ref=ThisRef},N,{PointsX,PointsY})
wxe_util:cast(?wxGraphicsContext_StrokeLines_2,
<<ThisRef:32/?UI,N:32/?UI,PointsX:64/float,PointsY:64/float>>).
-%% @spec (This::wxGraphicsContext(), N::integer(), BeginPoints::{X::float(),Y::float()}, EndPoints::{X::float(),Y::float()}) -> ok
+%% @spec (This::wxGraphicsContext(), N::integer(), BeginPoints::{X::float(), Y::float()}, EndPoints::{X::float(), Y::float()}) -> ok
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxgraphicscontext.html#wxgraphicscontextstrokelines">external documentation</a>.
strokeLines(#wx_ref{type=ThisT,ref=ThisRef},N,{BeginPointsX,BeginPointsY},{EndPointsX,EndPointsY})
when is_integer(N),is_number(BeginPointsX),is_number(BeginPointsY),is_number(EndPointsX),is_number(EndPointsY) ->
diff --git a/lib/wx/src/gen/wxGraphicsMatrix.erl b/lib/wx/src/gen/wxGraphicsMatrix.erl
index 38ea007c58..635a2027b3 100644
--- a/lib/wx/src/gen/wxGraphicsMatrix.erl
+++ b/lib/wx/src/gen/wxGraphicsMatrix.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2010. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2011. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -45,7 +45,7 @@ concat(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=TT,ref=TRef}) ->
wxe_util:cast(?wxGraphicsMatrix_Concat,
<<ThisRef:32/?UI,TRef:32/?UI>>).
-%% @spec (This::wxGraphicsMatrix()) -> {A::float(),B::float(),C::float(),D::float(),Tx::float(),Ty::float()}
+%% @spec (This::wxGraphicsMatrix()) -> {A::float(), B::float(), C::float(), D::float(), Tx::float(), Ty::float()}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxgraphicsmatrix.html#wxgraphicsmatrixget">external documentation</a>.
get(#wx_ref{type=ThisT,ref=ThisRef}) ->
?CLASS(ThisT,wxGraphicsMatrix),
@@ -128,14 +128,14 @@ set(#wx_ref{type=ThisT,ref=ThisRef}, Options)
wxe_util:cast(?wxGraphicsMatrix_Set,
<<ThisRef:32/?UI, 0:32,BinOpt/binary>>).
-%% @spec (This::wxGraphicsMatrix()) -> {X::float(),Y::float()}
+%% @spec (This::wxGraphicsMatrix()) -> {X::float(), Y::float()}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxgraphicsmatrix.html#wxgraphicsmatrixtransformpoint">external documentation</a>.
transformPoint(#wx_ref{type=ThisT,ref=ThisRef}) ->
?CLASS(ThisT,wxGraphicsMatrix),
wxe_util:call(?wxGraphicsMatrix_TransformPoint,
<<ThisRef:32/?UI>>).
-%% @spec (This::wxGraphicsMatrix()) -> {Dx::float(),Dy::float()}
+%% @spec (This::wxGraphicsMatrix()) -> {Dx::float(), Dy::float()}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxgraphicsmatrix.html#wxgraphicsmatrixtransformdistance">external documentation</a>.
transformDistance(#wx_ref{type=ThisT,ref=ThisRef}) ->
?CLASS(ThisT,wxGraphicsMatrix),
diff --git a/lib/wx/src/gen/wxGraphicsPath.erl b/lib/wx/src/gen/wxGraphicsPath.erl
index ff2dfb07a4..e41496c641 100644
--- a/lib/wx/src/gen/wxGraphicsPath.erl
+++ b/lib/wx/src/gen/wxGraphicsPath.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2010. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2011. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -40,7 +40,7 @@
parent_class(wxGraphicsObject) -> true;
parent_class(_Class) -> erlang:error({badtype, ?MODULE}).
-%% @spec (This::wxGraphicsPath(), P::{X::float(),Y::float()}) -> ok
+%% @spec (This::wxGraphicsPath(), P::{X::float(), Y::float()}) -> ok
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxgraphicspath.html#wxgraphicspathmovetopoint">external documentation</a>.
moveToPoint(#wx_ref{type=ThisT,ref=ThisRef},{PX,PY})
when is_number(PX),is_number(PY) ->
@@ -56,7 +56,7 @@ moveToPoint(#wx_ref{type=ThisT,ref=ThisRef},X,Y)
wxe_util:cast(?wxGraphicsPath_MoveToPoint_2,
<<ThisRef:32/?UI,0:32,X:64/?F,Y:64/?F>>).
-%% @spec (This::wxGraphicsPath(), C::{X::float(),Y::float()}, R::float(), StartAngle::float(), EndAngle::float(), Clockwise::bool()) -> ok
+%% @spec (This::wxGraphicsPath(), C::{X::float(), Y::float()}, R::float(), StartAngle::float(), EndAngle::float(), Clockwise::bool()) -> ok
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxgraphicspath.html#wxgraphicspathaddarc">external documentation</a>.
addArc(#wx_ref{type=ThisT,ref=ThisRef},{CX,CY},R,StartAngle,EndAngle,Clockwise)
when is_number(CX),is_number(CY),is_float(R),is_float(StartAngle),is_float(EndAngle),is_boolean(Clockwise) ->
@@ -88,7 +88,7 @@ addCircle(#wx_ref{type=ThisT,ref=ThisRef},X,Y,R)
wxe_util:cast(?wxGraphicsPath_AddCircle,
<<ThisRef:32/?UI,0:32,X:64/?F,Y:64/?F,R:64/?F>>).
-%% @spec (This::wxGraphicsPath(), C1::{X::float(),Y::float()}, C2::{X::float(),Y::float()}, E::{X::float(),Y::float()}) -> ok
+%% @spec (This::wxGraphicsPath(), C1::{X::float(), Y::float()}, C2::{X::float(), Y::float()}, E::{X::float(), Y::float()}) -> ok
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxgraphicspath.html#wxgraphicspathaddcurvetopoint">external documentation</a>.
addCurveToPoint(#wx_ref{type=ThisT,ref=ThisRef},{C1X,C1Y},{C2X,C2Y},{EX,EY})
when is_number(C1X),is_number(C1Y),is_number(C2X),is_number(C2Y),is_number(EX),is_number(EY) ->
@@ -112,7 +112,7 @@ addEllipse(#wx_ref{type=ThisT,ref=ThisRef},X,Y,W,H)
wxe_util:cast(?wxGraphicsPath_AddEllipse,
<<ThisRef:32/?UI,0:32,X:64/?F,Y:64/?F,W:64/?F,H:64/?F>>).
-%% @spec (This::wxGraphicsPath(), P::{X::float(),Y::float()}) -> ok
+%% @spec (This::wxGraphicsPath(), P::{X::float(), Y::float()}) -> ok
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxgraphicspath.html#wxgraphicspathaddlinetopoint">external documentation</a>.
addLineToPoint(#wx_ref{type=ThisT,ref=ThisRef},{PX,PY})
when is_number(PX),is_number(PY) ->
@@ -167,7 +167,7 @@ closeSubpath(#wx_ref{type=ThisT,ref=ThisRef}) ->
wxe_util:cast(?wxGraphicsPath_CloseSubpath,
<<ThisRef:32/?UI>>).
-%% @spec (This::wxGraphicsPath(), C::{X::float(),Y::float()}) -> bool()
+%% @spec (This::wxGraphicsPath(), C::{X::float(), Y::float()}) -> bool()
%% @equiv contains(This,C, [])
contains(This,C={CX,CY})
when is_record(This, wx_ref),is_number(CX),is_number(CY) ->
@@ -179,7 +179,7 @@ contains(This,C={CX,CY})
%% <p><c>
%% contains(This::wxGraphicsPath(), X::float(), Y::float()) -> contains(This,X,Y, []) </c></p>
%% <p><c>
-%% contains(This::wxGraphicsPath(), C::{X::float(),Y::float()}, [Option]) -> bool() </c>
+%% contains(This::wxGraphicsPath(), C::{X::float(), Y::float()}, [Option]) -> bool() </c>
%%<br /> Option = {fillStyle, integer()}
%% </p>
@@ -207,14 +207,14 @@ contains(#wx_ref{type=ThisT,ref=ThisRef},X,Y, Options)
wxe_util:call(?wxGraphicsPath_Contains_3,
<<ThisRef:32/?UI,0:32,X:64/?F,Y:64/?F, BinOpt/binary>>).
-%% @spec (This::wxGraphicsPath()) -> {X::float(),Y::float(),W::float(),H::float()}
+%% @spec (This::wxGraphicsPath()) -> {X::float(), Y::float(), W::float(), H::float()}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxgraphicspath.html#wxgraphicspathgetbox">external documentation</a>.
getBox(#wx_ref{type=ThisT,ref=ThisRef}) ->
?CLASS(ThisT,wxGraphicsPath),
wxe_util:call(?wxGraphicsPath_GetBox,
<<ThisRef:32/?UI>>).
-%% @spec (This::wxGraphicsPath()) -> {X::float(),Y::float()}
+%% @spec (This::wxGraphicsPath()) -> {X::float(), Y::float()}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxgraphicspath.html#wxgraphicspathgetcurrentpoint">external documentation</a>.
getCurrentPoint(#wx_ref{type=ThisT,ref=ThisRef}) ->
?CLASS(ThisT,wxGraphicsPath),
diff --git a/lib/wx/src/gen/wxGrid.erl b/lib/wx/src/gen/wxGrid.erl
index 7b62ec33a4..531fed05c1 100644
--- a/lib/wx/src/gen/wxGrid.erl
+++ b/lib/wx/src/gen/wxGrid.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2010. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2011. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -151,7 +151,7 @@ new(Parent,Id)
%% new(Parent::wxWindow:wxWindow(), X::integer(), Y::integer()) -> new(Parent,X,Y, []) </c></p>
%% <p><c>
%% new(Parent::wxWindow:wxWindow(), Id::integer(), [Option]) -> wxGrid() </c>
-%%<br /> Option = {pos, {X::integer(),Y::integer()}} | {size, {W::integer(),H::integer()}} | {style, integer()}
+%%<br /> Option = {pos, {X::integer(), Y::integer()}} | {size, {W::integer(), H::integer()}} | {style, integer()}
%% </p>
new(Parent,X,Y)
@@ -306,7 +306,7 @@ beginBatch(#wx_ref{type=ThisT,ref=ThisRef}) ->
wxe_util:cast(?wxGrid_BeginBatch,
<<ThisRef:32/?UI>>).
-%% @spec (This::wxGrid(), TopLeft::{R::integer(),C::integer()}, BottomRight::{R::integer(),C::integer()}) -> {X::integer(),Y::integer(),W::integer(),H::integer()}
+%% @spec (This::wxGrid(), TopLeft::{R::integer(), C::integer()}, BottomRight::{R::integer(), C::integer()}) -> {X::integer(), Y::integer(), W::integer(), H::integer()}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxgrid.html#wxgridblocktodevicerect">external documentation</a>.
blockToDeviceRect(#wx_ref{type=ThisT,ref=ThisRef},{TopLeftR,TopLeftC},{BottomRightR,BottomRightC})
when is_integer(TopLeftR),is_integer(TopLeftC),is_integer(BottomRightR),is_integer(BottomRightC) ->
@@ -342,7 +342,7 @@ canEnableCellControl(#wx_ref{type=ThisT,ref=ThisRef}) ->
wxe_util:call(?wxGrid_CanEnableCellControl,
<<ThisRef:32/?UI>>).
-%% @spec (This::wxGrid(), Coords::{R::integer(),C::integer()}) -> {X::integer(),Y::integer(),W::integer(),H::integer()}
+%% @spec (This::wxGrid(), Coords::{R::integer(), C::integer()}) -> {X::integer(), Y::integer(), W::integer(), H::integer()}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxgrid.html#wxgridcelltorect">external documentation</a>.
cellToRect(#wx_ref{type=ThisT,ref=ThisRef},{CoordsR,CoordsC})
when is_integer(CoordsR),is_integer(CoordsC) ->
@@ -350,7 +350,7 @@ cellToRect(#wx_ref{type=ThisT,ref=ThisRef},{CoordsR,CoordsC})
wxe_util:call(?wxGrid_CellToRect_1,
<<ThisRef:32/?UI,CoordsR:32/?UI,CoordsC:32/?UI>>).
-%% @spec (This::wxGrid(), Row::integer(), Col::integer()) -> {X::integer(),Y::integer(),W::integer(),H::integer()}
+%% @spec (This::wxGrid(), Row::integer(), Col::integer()) -> {X::integer(), Y::integer(), W::integer(), H::integer()}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxgrid.html#wxgridcelltorect">external documentation</a>.
cellToRect(#wx_ref{type=ThisT,ref=ThisRef},Row,Col)
when is_integer(Row),is_integer(Col) ->
@@ -586,7 +586,7 @@ getBatchCount(#wx_ref{type=ThisT,ref=ThisRef}) ->
wxe_util:call(?wxGrid_GetBatchCount,
<<ThisRef:32/?UI>>).
-%% @spec (This::wxGrid(), Row::integer(), Col::integer()) -> {Horiz::integer(),Vert::integer()}
+%% @spec (This::wxGrid(), Row::integer(), Col::integer()) -> {Horiz::integer(), Vert::integer()}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxgrid.html#wxgridgetcellalignment">external documentation</a>.
getCellAlignment(#wx_ref{type=ThisT,ref=ThisRef},Row,Col)
when is_integer(Row),is_integer(Col) ->
@@ -634,7 +634,7 @@ getCellTextColour(#wx_ref{type=ThisT,ref=ThisRef},Row,Col)
wxe_util:call(?wxGrid_GetCellTextColour,
<<ThisRef:32/?UI,Row:32/?UI,Col:32/?UI>>).
-%% @spec (This::wxGrid(), Coords::{R::integer(),C::integer()}) -> string()
+%% @spec (This::wxGrid(), Coords::{R::integer(), C::integer()}) -> string()
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxgrid.html#wxgridgetcellvalue">external documentation</a>.
getCellValue(#wx_ref{type=ThisT,ref=ThisRef},{CoordsR,CoordsC})
when is_integer(CoordsR),is_integer(CoordsC) ->
@@ -650,7 +650,7 @@ getCellValue(#wx_ref{type=ThisT,ref=ThisRef},Row,Col)
wxe_util:call(?wxGrid_GetCellValue_2,
<<ThisRef:32/?UI,Row:32/?UI,Col:32/?UI>>).
-%% @spec (This::wxGrid()) -> {Horiz::integer(),Vert::integer()}
+%% @spec (This::wxGrid()) -> {Horiz::integer(), Vert::integer()}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxgrid.html#wxgridgetcollabelalignment">external documentation</a>.
getColLabelAlignment(#wx_ref{type=ThisT,ref=ThisRef}) ->
?CLASS(ThisT,wxGrid),
@@ -679,7 +679,7 @@ getColMinimalAcceptableWidth(#wx_ref{type=ThisT,ref=ThisRef}) ->
wxe_util:call(?wxGrid_GetColMinimalAcceptableWidth,
<<ThisRef:32/?UI>>).
-%% @spec (This::wxGrid()) -> {Horiz::integer(),Vert::integer()}
+%% @spec (This::wxGrid()) -> {Horiz::integer(), Vert::integer()}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxgrid.html#wxgridgetdefaultcellalignment">external documentation</a>.
getDefaultCellAlignment(#wx_ref{type=ThisT,ref=ThisRef}) ->
?CLASS(ThisT,wxGrid),
@@ -728,7 +728,7 @@ getDefaultEditor(#wx_ref{type=ThisT,ref=ThisRef}) ->
wxe_util:call(?wxGrid_GetDefaultEditor,
<<ThisRef:32/?UI>>).
-%% @spec (This::wxGrid(), C::{R::integer(),C::integer()}) -> wxGridCellEditor:wxGridCellEditor()
+%% @spec (This::wxGrid(), C::{R::integer(), C::integer()}) -> wxGridCellEditor:wxGridCellEditor()
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxgrid.html#wxgridgetdefaulteditorforcell">external documentation</a>.
getDefaultEditorForCell(#wx_ref{type=ThisT,ref=ThisRef},{CR,CC})
when is_integer(CR),is_integer(CC) ->
@@ -869,7 +869,7 @@ getRowMinimalAcceptableHeight(#wx_ref{type=ThisT,ref=ThisRef}) ->
wxe_util:call(?wxGrid_GetRowMinimalAcceptableHeight,
<<ThisRef:32/?UI>>).
-%% @spec (This::wxGrid()) -> {Horiz::integer(),Vert::integer()}
+%% @spec (This::wxGrid()) -> {Horiz::integer(), Vert::integer()}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxgrid.html#wxgridgetrowlabelalignment">external documentation</a>.
getRowLabelAlignment(#wx_ref{type=ThisT,ref=ThisRef}) ->
?CLASS(ThisT,wxGrid),
@@ -913,7 +913,7 @@ getScrollLineY(#wx_ref{type=ThisT,ref=ThisRef}) ->
wxe_util:call(?wxGrid_GetScrollLineY,
<<ThisRef:32/?UI>>).
-%% @spec (This::wxGrid()) -> [{R::integer(),C::integer()}]
+%% @spec (This::wxGrid()) -> [{R::integer(), C::integer()}]
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxgrid.html#wxgridgetselectedcells">external documentation</a>.
getSelectedCells(#wx_ref{type=ThisT,ref=ThisRef}) ->
?CLASS(ThisT,wxGrid),
@@ -941,14 +941,14 @@ getSelectionBackground(#wx_ref{type=ThisT,ref=ThisRef}) ->
wxe_util:call(?wxGrid_GetSelectionBackground,
<<ThisRef:32/?UI>>).
-%% @spec (This::wxGrid()) -> [{R::integer(),C::integer()}]
+%% @spec (This::wxGrid()) -> [{R::integer(), C::integer()}]
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxgrid.html#wxgridgetselectionblocktopleft">external documentation</a>.
getSelectionBlockTopLeft(#wx_ref{type=ThisT,ref=ThisRef}) ->
?CLASS(ThisT,wxGrid),
wxe_util:call(?wxGrid_GetSelectionBlockTopLeft,
<<ThisRef:32/?UI>>).
-%% @spec (This::wxGrid()) -> [{R::integer(),C::integer()}]
+%% @spec (This::wxGrid()) -> [{R::integer(), C::integer()}]
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxgrid.html#wxgridgetselectionblockbottomright">external documentation</a>.
getSelectionBlockBottomRight(#wx_ref{type=ThisT,ref=ThisRef}) ->
?CLASS(ThisT,wxGrid),
@@ -1065,7 +1065,7 @@ isEditable(#wx_ref{type=ThisT,ref=ThisRef}) ->
wxe_util:call(?wxGrid_IsEditable,
<<ThisRef:32/?UI>>).
-%% @spec (This::wxGrid(), Coords::{R::integer(),C::integer()}) -> bool()
+%% @spec (This::wxGrid(), Coords::{R::integer(), C::integer()}) -> bool()
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxgrid.html#wxgridisinselection">external documentation</a>.
isInSelection(#wx_ref{type=ThisT,ref=ThisRef},{CoordsR,CoordsC})
when is_integer(CoordsR),is_integer(CoordsC) ->
@@ -1096,7 +1096,7 @@ isSelection(#wx_ref{type=ThisT,ref=ThisRef}) ->
wxe_util:call(?wxGrid_IsSelection,
<<ThisRef:32/?UI>>).
-%% @spec (This::wxGrid(), Coords::{R::integer(),C::integer()}) -> bool()
+%% @spec (This::wxGrid(), Coords::{R::integer(), C::integer()}) -> bool()
%% @equiv isVisible(This,Coords, [])
isVisible(This,Coords={CoordsR,CoordsC})
when is_record(This, wx_ref),is_integer(CoordsR),is_integer(CoordsC) ->
@@ -1108,7 +1108,7 @@ isVisible(This,Coords={CoordsR,CoordsC})
%% <p><c>
%% isVisible(This::wxGrid(), Row::integer(), Col::integer()) -> isVisible(This,Row,Col, []) </c></p>
%% <p><c>
-%% isVisible(This::wxGrid(), Coords::{R::integer(),C::integer()}, [Option]) -> bool() </c>
+%% isVisible(This::wxGrid(), Coords::{R::integer(), C::integer()}, [Option]) -> bool() </c>
%%<br /> Option = {wholeCellVisible, bool()}
%% </p>
@@ -1136,7 +1136,7 @@ isVisible(#wx_ref{type=ThisT,ref=ThisRef},Row,Col, Options)
wxe_util:call(?wxGrid_IsVisible_3,
<<ThisRef:32/?UI,Row:32/?UI,Col:32/?UI, 0:32,BinOpt/binary>>).
-%% @spec (This::wxGrid(), Coords::{R::integer(),C::integer()}) -> ok
+%% @spec (This::wxGrid(), Coords::{R::integer(), C::integer()}) -> ok
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxgrid.html#wxgridmakecellvisible">external documentation</a>.
makeCellVisible(#wx_ref{type=ThisT,ref=ThisRef},{CoordsR,CoordsC})
when is_integer(CoordsR),is_integer(CoordsC) ->
@@ -1255,13 +1255,13 @@ selectAll(#wx_ref{type=ThisT,ref=ThisRef}) ->
wxe_util:cast(?wxGrid_SelectAll,
<<ThisRef:32/?UI>>).
-%% @spec (This::wxGrid(), TopLeft::{R::integer(),C::integer()}, BottomRight::{R::integer(),C::integer()}) -> ok
+%% @spec (This::wxGrid(), TopLeft::{R::integer(), C::integer()}, BottomRight::{R::integer(), C::integer()}) -> ok
%% @equiv selectBlock(This,TopLeft,BottomRight, [])
selectBlock(This,TopLeft={TopLeftR,TopLeftC},BottomRight={BottomRightR,BottomRightC})
when is_record(This, wx_ref),is_integer(TopLeftR),is_integer(TopLeftC),is_integer(BottomRightR),is_integer(BottomRightC) ->
selectBlock(This,TopLeft,BottomRight, []).
-%% @spec (This::wxGrid(), TopLeft::{R::integer(),C::integer()}, BottomRight::{R::integer(),C::integer()}, [Option]) -> ok
+%% @spec (This::wxGrid(), TopLeft::{R::integer(), C::integer()}, BottomRight::{R::integer(), C::integer()}, [Option]) -> ok
%% Option = {addToSelected, bool()}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxgrid.html#wxgridselectblock">external documentation</a>.
selectBlock(#wx_ref{type=ThisT,ref=ThisRef},{TopLeftR,TopLeftC},{BottomRightR,BottomRightC}, Options)
@@ -1434,7 +1434,7 @@ setCellTextColour(#wx_ref{type=ThisT,ref=ThisRef},Val,Row,Col)
wxe_util:cast(?wxGrid_SetCellTextColour_3_1,
<<ThisRef:32/?UI,(wxe_util:colour_bin(Val)):16/binary,Row:32/?UI,Col:32/?UI>>).
-%% @spec (This::wxGrid(), Coords::{R::integer(),C::integer()}, S::string()) -> ok
+%% @spec (This::wxGrid(), Coords::{R::integer(), C::integer()}, S::string()) -> ok
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxgrid.html#wxgridsetcellvalue">external documentation</a>.
setCellValue(#wx_ref{type=ThisT,ref=ThisRef},{CoordsR,CoordsC},S)
when is_integer(CoordsR),is_integer(CoordsC),is_list(S) ->
diff --git a/lib/wx/src/gen/wxGridBagSizer.erl b/lib/wx/src/gen/wxGridBagSizer.erl
index cfc182cf89..d2b8a2b045 100644
--- a/lib/wx/src/gen/wxGridBagSizer.erl
+++ b/lib/wx/src/gen/wxGridBagSizer.erl
@@ -90,7 +90,7 @@ add(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=ItemT,ref=ItemRef}) ->
%% <p><c>
%% add(This::wxGridBagSizer(), Width::integer(), Height::integer()) -> add(This,Width,Height, []) </c></p>
%% <p><c>
-%% add(This::wxGridBagSizer(), Window::wxWindow:wxWindow() | wxSizer:wxSizer(), Pos::{R::integer(),C::integer()}) -> add(This,Window,Pos, []) </c></p>
+%% add(This::wxGridBagSizer(), Window::wxWindow:wxWindow() | wxSizer:wxSizer(), Pos::{R::integer(), C::integer()}) -> add(This,Window,Pos, []) </c></p>
%% <p><c>
%% add(This::wxGridBagSizer(), Window::wxWindow:wxWindow() | wxSizer:wxSizer(), [Option]) -> wxSizerItem:wxSizerItem() </c>
%%<br /> Option = {proportion, integer()} | {flag, integer()} | {border, integer()} | {userData, wx:wx()}
@@ -125,14 +125,14 @@ add(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=WindowT,ref=WindowRef}, Options
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxgridbagsizer.html#wxgridbagsizeradd">external documentation</a>.
%% <br /> Alternatives:
%% <p><c>
-%% add(This::wxGridBagSizer(), Width::integer(), Height::integer(), Pos::{R::integer(),C::integer()}) -> add(This,Width,Height,Pos, []) </c></p>
+%% add(This::wxGridBagSizer(), Width::integer(), Height::integer(), Pos::{R::integer(), C::integer()}) -> add(This,Width,Height,Pos, []) </c></p>
%% <p><c>
%% add(This::wxGridBagSizer(), Width::integer(), Height::integer(), [Option]) -> wxSizerItem:wxSizerItem() </c>
%%<br /> Option = {proportion, integer()} | {flag, integer()} | {border, integer()} | {userData, wx:wx()}
%% </p>
%% <p><c>
-%% add(This::wxGridBagSizer(), Window::wxWindow:wxWindow() | wxSizer:wxSizer(), Pos::{R::integer(),C::integer()}, [Option]) -> wxSizerItem:wxSizerItem() </c>
-%%<br /> Option = {span, {RS::integer(),CS::integer()}} | {flag, integer()} | {border, integer()} | {userData, wx:wx()}
+%% add(This::wxGridBagSizer(), Window::wxWindow:wxWindow() | wxSizer:wxSizer(), Pos::{R::integer(), C::integer()}, [Option]) -> wxSizerItem:wxSizerItem() </c>
+%%<br /> Option = {span, {RS::integer(), CS::integer()}} | {flag, integer()} | {border, integer()} | {userData, wx:wx()}
%% </p>
add(This,Width,Height,Pos={PosR,PosC})
@@ -167,8 +167,8 @@ add(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=WindowT,ref=WindowRef},{PosR,Po
wxe_util:call(WindowOP,
<<ThisRef:32/?UI,WindowRef:32/?UI,PosR:32/?UI,PosC:32/?UI, BinOpt/binary>>).
-%% @spec (This::wxGridBagSizer(), Width::integer(), Height::integer(), Pos::{R::integer(),C::integer()}, [Option]) -> wxSizerItem:wxSizerItem()
-%% Option = {span, {RS::integer(),CS::integer()}} | {flag, integer()} | {border, integer()} | {userData, wx:wx()}
+%% @spec (This::wxGridBagSizer(), Width::integer(), Height::integer(), Pos::{R::integer(), C::integer()}, [Option]) -> wxSizerItem:wxSizerItem()
+%% Option = {span, {RS::integer(), CS::integer()}} | {flag, integer()} | {border, integer()} | {userData, wx:wx()}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxgridbagsizer.html#wxgridbagsizeradd">external documentation</a>.
add(#wx_ref{type=ThisT,ref=ThisRef},Width,Height,{PosR,PosC}, Options)
when is_integer(Width),is_integer(Height),is_integer(PosR),is_integer(PosC),is_list(Options) ->
@@ -182,7 +182,7 @@ add(#wx_ref{type=ThisT,ref=ThisRef},Width,Height,{PosR,PosC}, Options)
wxe_util:call(?wxGridBagSizer_Add_4,
<<ThisRef:32/?UI,Width:32/?UI,Height:32/?UI,PosR:32/?UI,PosC:32/?UI, 0:32,BinOpt/binary>>).
-%% @spec (This::wxGridBagSizer()) -> {W::integer(),H::integer()}
+%% @spec (This::wxGridBagSizer()) -> {W::integer(), H::integer()}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxgridbagsizer.html#wxgridbagsizercalcmin">external documentation</a>.
calcMin(#wx_ref{type=ThisT,ref=ThisRef}) ->
?CLASS(ThisT,wxGridBagSizer),
@@ -199,7 +199,7 @@ checkForIntersection(This,Item)
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxgridbagsizer.html#wxgridbagsizercheckforintersection">external documentation</a>.
%% <br /> Alternatives:
%% <p><c>
-%% checkForIntersection(This::wxGridBagSizer(), Pos::{R::integer(),C::integer()}, Span::{RS::integer(),CS::integer()}) -> checkForIntersection(This,Pos,Span, []) </c></p>
+%% checkForIntersection(This::wxGridBagSizer(), Pos::{R::integer(), C::integer()}, Span::{RS::integer(), CS::integer()}) -> checkForIntersection(This,Pos,Span, []) </c></p>
%% <p><c>
%% checkForIntersection(This::wxGridBagSizer(), Item::wxGBSizerItem:wxGBSizerItem(), [Option]) -> bool() </c>
%%<br /> Option = {excludeItem, wxGBSizerItem:wxGBSizerItem()}
@@ -218,7 +218,7 @@ checkForIntersection(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=ItemT,ref=Item
wxe_util:call(?wxGridBagSizer_CheckForIntersection_2,
<<ThisRef:32/?UI,ItemRef:32/?UI, BinOpt/binary>>).
-%% @spec (This::wxGridBagSizer(), Pos::{R::integer(),C::integer()}, Span::{RS::integer(),CS::integer()}, [Option]) -> bool()
+%% @spec (This::wxGridBagSizer(), Pos::{R::integer(), C::integer()}, Span::{RS::integer(), CS::integer()}, [Option]) -> bool()
%% Option = {excludeItem, wxGBSizerItem:wxGBSizerItem()}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxgridbagsizer.html#wxgridbagsizercheckforintersection">external documentation</a>.
checkForIntersection(#wx_ref{type=ThisT,ref=ThisRef},{PosR,PosC},{SpanRS,SpanCS}, Options)
@@ -243,7 +243,7 @@ findItem(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=WindowT,ref=WindowRef}) ->
wxe_util:call(WindowOP,
<<ThisRef:32/?UI,WindowRef:32/?UI>>).
-%% @spec (This::wxGridBagSizer(), Pt::{X::integer(),Y::integer()}) -> wxGBSizerItem:wxGBSizerItem()
+%% @spec (This::wxGridBagSizer(), Pt::{X::integer(), Y::integer()}) -> wxGBSizerItem:wxGBSizerItem()
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxgridbagsizer.html#wxgridbagsizerfinditematpoint">external documentation</a>.
findItemAtPoint(#wx_ref{type=ThisT,ref=ThisRef},{PtX,PtY})
when is_integer(PtX),is_integer(PtY) ->
@@ -251,7 +251,7 @@ findItemAtPoint(#wx_ref{type=ThisT,ref=ThisRef},{PtX,PtY})
wxe_util:call(?wxGridBagSizer_FindItemAtPoint,
<<ThisRef:32/?UI,PtX:32/?UI,PtY:32/?UI>>).
-%% @spec (This::wxGridBagSizer(), Pos::{R::integer(),C::integer()}) -> wxGBSizerItem:wxGBSizerItem()
+%% @spec (This::wxGridBagSizer(), Pos::{R::integer(), C::integer()}) -> wxGBSizerItem:wxGBSizerItem()
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxgridbagsizer.html#wxgridbagsizerfinditematposition">external documentation</a>.
findItemAtPosition(#wx_ref{type=ThisT,ref=ThisRef},{PosR,PosC})
when is_integer(PosR),is_integer(PosC) ->
@@ -267,7 +267,7 @@ findItemWithData(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=UserDataT,ref=User
wxe_util:call(?wxGridBagSizer_FindItemWithData,
<<ThisRef:32/?UI,UserDataRef:32/?UI>>).
-%% @spec (This::wxGridBagSizer(), Row::integer(), Col::integer()) -> {W::integer(),H::integer()}
+%% @spec (This::wxGridBagSizer(), Row::integer(), Col::integer()) -> {W::integer(), H::integer()}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxgridbagsizer.html#wxgridbagsizergetcellsize">external documentation</a>.
getCellSize(#wx_ref{type=ThisT,ref=ThisRef},Row,Col)
when is_integer(Row),is_integer(Col) ->
@@ -275,21 +275,21 @@ getCellSize(#wx_ref{type=ThisT,ref=ThisRef},Row,Col)
wxe_util:call(?wxGridBagSizer_GetCellSize,
<<ThisRef:32/?UI,Row:32/?UI,Col:32/?UI>>).
-%% @spec (This::wxGridBagSizer()) -> {W::integer(),H::integer()}
+%% @spec (This::wxGridBagSizer()) -> {W::integer(), H::integer()}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxgridbagsizer.html#wxgridbagsizergetemptycellsize">external documentation</a>.
getEmptyCellSize(#wx_ref{type=ThisT,ref=ThisRef}) ->
?CLASS(ThisT,wxGridBagSizer),
wxe_util:call(?wxGridBagSizer_GetEmptyCellSize,
<<ThisRef:32/?UI>>).
-%% @spec (This::wxGridBagSizer(),X::integer()|term()) -> {R::integer(),C::integer()}
+%% @spec (This::wxGridBagSizer(),X::integer()|term()) -> {R::integer(), C::integer()}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxgridbagsizer.html#wxgridbagsizergetitemposition">external documentation</a>.
%% <br /> Alternatives:
%% <p><c>
-%% getItemPosition(This::wxGridBagSizer(), Index::integer()) -> {R::integer(),C::integer()} </c>
+%% getItemPosition(This::wxGridBagSizer(), Index::integer()) -> {R::integer(), C::integer()} </c>
%% </p>
%% <p><c>
-%% getItemPosition(This::wxGridBagSizer(), Window::wxWindow:wxWindow() | wxSizer:wxSizer()) -> {R::integer(),C::integer()} </c>
+%% getItemPosition(This::wxGridBagSizer(), Window::wxWindow:wxWindow() | wxSizer:wxSizer()) -> {R::integer(), C::integer()} </c>
%% </p>
getItemPosition(#wx_ref{type=ThisT,ref=ThisRef},Index)
when is_integer(Index) ->
@@ -307,14 +307,14 @@ getItemPosition(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=WindowT,ref=WindowR
wxe_util:call(WindowOP,
<<ThisRef:32/?UI,WindowRef:32/?UI>>).
-%% @spec (This::wxGridBagSizer(),X::integer()|term()) -> {RS::integer(),CS::integer()}
+%% @spec (This::wxGridBagSizer(),X::integer()|term()) -> {RS::integer(), CS::integer()}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxgridbagsizer.html#wxgridbagsizergetitemspan">external documentation</a>.
%% <br /> Alternatives:
%% <p><c>
-%% getItemSpan(This::wxGridBagSizer(), Index::integer()) -> {RS::integer(),CS::integer()} </c>
+%% getItemSpan(This::wxGridBagSizer(), Index::integer()) -> {RS::integer(), CS::integer()} </c>
%% </p>
%% <p><c>
-%% getItemSpan(This::wxGridBagSizer(), Window::wxWindow:wxWindow() | wxSizer:wxSizer()) -> {RS::integer(),CS::integer()} </c>
+%% getItemSpan(This::wxGridBagSizer(), Window::wxWindow:wxWindow() | wxSizer:wxSizer()) -> {RS::integer(), CS::integer()} </c>
%% </p>
getItemSpan(#wx_ref{type=ThisT,ref=ThisRef},Index)
when is_integer(Index) ->
@@ -332,7 +332,7 @@ getItemSpan(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=WindowT,ref=WindowRef})
wxe_util:call(WindowOP,
<<ThisRef:32/?UI,WindowRef:32/?UI>>).
-%% @spec (This::wxGridBagSizer(), Sz::{W::integer(),H::integer()}) -> ok
+%% @spec (This::wxGridBagSizer(), Sz::{W::integer(), H::integer()}) -> ok
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxgridbagsizer.html#wxgridbagsizersetemptycellsize">external documentation</a>.
setEmptyCellSize(#wx_ref{type=ThisT,ref=ThisRef},{SzW,SzH})
when is_integer(SzW),is_integer(SzH) ->
@@ -340,14 +340,14 @@ setEmptyCellSize(#wx_ref{type=ThisT,ref=ThisRef},{SzW,SzH})
wxe_util:cast(?wxGridBagSizer_SetEmptyCellSize,
<<ThisRef:32/?UI,SzW:32/?UI,SzH:32/?UI>>).
-%% @spec (This::wxGridBagSizer(),X::integer()|term(),Pos::{R::integer(),C::integer()}) -> bool()
+%% @spec (This::wxGridBagSizer(),X::integer()|term(),Pos::{R::integer(), C::integer()}) -> bool()
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxgridbagsizer.html#wxgridbagsizersetitemposition">external documentation</a>.
%% <br /> Alternatives:
%% <p><c>
-%% setItemPosition(This::wxGridBagSizer(), Index::integer(), Pos::{R::integer(),C::integer()}) -> bool() </c>
+%% setItemPosition(This::wxGridBagSizer(), Index::integer(), Pos::{R::integer(), C::integer()}) -> bool() </c>
%% </p>
%% <p><c>
-%% setItemPosition(This::wxGridBagSizer(), Window::wxWindow:wxWindow() | wxSizer:wxSizer(), Pos::{R::integer(),C::integer()}) -> bool() </c>
+%% setItemPosition(This::wxGridBagSizer(), Window::wxWindow:wxWindow() | wxSizer:wxSizer(), Pos::{R::integer(), C::integer()}) -> bool() </c>
%% </p>
setItemPosition(#wx_ref{type=ThisT,ref=ThisRef},Index,{PosR,PosC})
when is_integer(Index),is_integer(PosR),is_integer(PosC) ->
@@ -366,14 +366,14 @@ setItemPosition(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=WindowT,ref=WindowR
wxe_util:call(WindowOP,
<<ThisRef:32/?UI,WindowRef:32/?UI,PosR:32/?UI,PosC:32/?UI>>).
-%% @spec (This::wxGridBagSizer(),X::integer()|term(),Span::{RS::integer(),CS::integer()}) -> bool()
+%% @spec (This::wxGridBagSizer(),X::integer()|term(),Span::{RS::integer(), CS::integer()}) -> bool()
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxgridbagsizer.html#wxgridbagsizersetitemspan">external documentation</a>.
%% <br /> Alternatives:
%% <p><c>
-%% setItemSpan(This::wxGridBagSizer(), Index::integer(), Span::{RS::integer(),CS::integer()}) -> bool() </c>
+%% setItemSpan(This::wxGridBagSizer(), Index::integer(), Span::{RS::integer(), CS::integer()}) -> bool() </c>
%% </p>
%% <p><c>
-%% setItemSpan(This::wxGridBagSizer(), Window::wxWindow:wxWindow() | wxSizer:wxSizer(), Span::{RS::integer(),CS::integer()}) -> bool() </c>
+%% setItemSpan(This::wxGridBagSizer(), Window::wxWindow:wxWindow() | wxSizer:wxSizer(), Span::{RS::integer(), CS::integer()}) -> bool() </c>
%% </p>
setItemSpan(#wx_ref{type=ThisT,ref=ThisRef},Index,{SpanRS,SpanCS})
when is_integer(Index),is_integer(SpanRS),is_integer(SpanCS) ->
diff --git a/lib/wx/src/gen/wxGridCellAttr.erl b/lib/wx/src/gen/wxGridCellAttr.erl
index 3d23c2acfc..a9a0c1fb79 100644
--- a/lib/wx/src/gen/wxGridCellAttr.erl
+++ b/lib/wx/src/gen/wxGridCellAttr.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2010. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2011. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -165,7 +165,7 @@ getFont(#wx_ref{type=ThisT,ref=ThisRef}) ->
wxe_util:call(?wxGridCellAttr_GetFont,
<<ThisRef:32/?UI>>).
-%% @spec (This::wxGridCellAttr()) -> {HAlign::integer(),VAlign::integer()}
+%% @spec (This::wxGridCellAttr()) -> {HAlign::integer(), VAlign::integer()}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxgridcellattr.html#wxgridcellattrgetalignment">external documentation</a>.
getAlignment(#wx_ref{type=ThisT,ref=ThisRef}) ->
?CLASS(ThisT,wxGridCellAttr),
diff --git a/lib/wx/src/gen/wxGridCellEditor.erl b/lib/wx/src/gen/wxGridCellEditor.erl
index a27ba7bd0f..de1ebc5a4c 100644
--- a/lib/wx/src/gen/wxGridCellEditor.erl
+++ b/lib/wx/src/gen/wxGridCellEditor.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2010. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2011. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -50,7 +50,7 @@ isCreated(#wx_ref{type=ThisT,ref=ThisRef}) ->
wxe_util:call(?wxGridCellEditor_IsCreated,
<<ThisRef:32/?UI>>).
-%% @spec (This::wxGridCellEditor(), Rect::{X::integer(),Y::integer(),W::integer(),H::integer()}) -> ok
+%% @spec (This::wxGridCellEditor(), Rect::{X::integer(), Y::integer(), W::integer(), H::integer()}) -> ok
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxgridcelleditor.html#wxgridcelleditorsetsize">external documentation</a>.
setSize(#wx_ref{type=ThisT,ref=ThisRef},{RectX,RectY,RectW,RectH})
when is_integer(RectX),is_integer(RectY),is_integer(RectW),is_integer(RectH) ->
@@ -76,7 +76,7 @@ show(#wx_ref{type=ThisT,ref=ThisRef},Show, Options)
wxe_util:cast(?wxGridCellEditor_Show,
<<ThisRef:32/?UI,(wxe_util:from_bool(Show)):32/?UI, BinOpt/binary>>).
-%% @spec (This::wxGridCellEditor(), RectCell::{X::integer(),Y::integer(),W::integer(),H::integer()}, Attr::wxGridCellAttr:wxGridCellAttr()) -> ok
+%% @spec (This::wxGridCellEditor(), RectCell::{X::integer(), Y::integer(), W::integer(), H::integer()}, Attr::wxGridCellAttr:wxGridCellAttr()) -> ok
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxgridcelleditor.html#wxgridcelleditorpaintbackground">external documentation</a>.
paintBackground(#wx_ref{type=ThisT,ref=ThisRef},{RectCellX,RectCellY,RectCellW,RectCellH},#wx_ref{type=AttrT,ref=AttrRef})
when is_integer(RectCellX),is_integer(RectCellY),is_integer(RectCellW),is_integer(RectCellH) ->
diff --git a/lib/wx/src/gen/wxGridCellRenderer.erl b/lib/wx/src/gen/wxGridCellRenderer.erl
index d9520c478f..765c116a48 100644
--- a/lib/wx/src/gen/wxGridCellRenderer.erl
+++ b/lib/wx/src/gen/wxGridCellRenderer.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2010. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2011. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -32,7 +32,7 @@
%% @hidden
parent_class(_Class) -> erlang:error({badtype, ?MODULE}).
-%% @spec (This::wxGridCellRenderer(), Grid::wxGrid:wxGrid(), Attr::wxGridCellAttr:wxGridCellAttr(), Dc::wxDC:wxDC(), Rect::{X::integer(),Y::integer(),W::integer(),H::integer()}, Row::integer(), Col::integer(), IsSelected::bool()) -> ok
+%% @spec (This::wxGridCellRenderer(), Grid::wxGrid:wxGrid(), Attr::wxGridCellAttr:wxGridCellAttr(), Dc::wxDC:wxDC(), Rect::{X::integer(), Y::integer(), W::integer(), H::integer()}, Row::integer(), Col::integer(), IsSelected::bool()) -> ok
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxgridcellrenderer.html#wxgridcellrendererdraw">external documentation</a>.
draw(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=GridT,ref=GridRef},#wx_ref{type=AttrT,ref=AttrRef},#wx_ref{type=DcT,ref=DcRef},{RectX,RectY,RectW,RectH},Row,Col,IsSelected)
when is_integer(RectX),is_integer(RectY),is_integer(RectW),is_integer(RectH),is_integer(Row),is_integer(Col),is_boolean(IsSelected) ->
@@ -43,7 +43,7 @@ draw(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=GridT,ref=GridRef},#wx_ref{typ
wxe_util:cast(?wxGridCellRenderer_Draw,
<<ThisRef:32/?UI,GridRef:32/?UI,AttrRef:32/?UI,DcRef:32/?UI,RectX:32/?UI,RectY:32/?UI,RectW:32/?UI,RectH:32/?UI,Row:32/?UI,Col:32/?UI,(wxe_util:from_bool(IsSelected)):32/?UI>>).
-%% @spec (This::wxGridCellRenderer(), Grid::wxGrid:wxGrid(), Attr::wxGridCellAttr:wxGridCellAttr(), Dc::wxDC:wxDC(), Row::integer(), Col::integer()) -> {W::integer(),H::integer()}
+%% @spec (This::wxGridCellRenderer(), Grid::wxGrid:wxGrid(), Attr::wxGridCellAttr:wxGridCellAttr(), Dc::wxDC:wxDC(), Row::integer(), Col::integer()) -> {W::integer(), H::integer()}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxgridcellrenderer.html#wxgridcellrenderergetbestsize">external documentation</a>.
getBestSize(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=GridT,ref=GridRef},#wx_ref{type=AttrT,ref=AttrRef},#wx_ref{type=DcT,ref=DcRef},Row,Col)
when is_integer(Row),is_integer(Col) ->
diff --git a/lib/wx/src/gen/wxGridEvent.erl b/lib/wx/src/gen/wxGridEvent.erl
index 9b7e0012ca..123088afb5 100644
--- a/lib/wx/src/gen/wxGridEvent.erl
+++ b/lib/wx/src/gen/wxGridEvent.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2010. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2011. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -69,7 +69,7 @@ getCol(#wx_ref{type=ThisT,ref=ThisRef}) ->
wxe_util:call(?wxGridEvent_GetCol,
<<ThisRef:32/?UI>>).
-%% @spec (This::wxGridEvent()) -> {X::integer(),Y::integer()}
+%% @spec (This::wxGridEvent()) -> {X::integer(), Y::integer()}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxgridevent.html#wxgrideventgetposition">external documentation</a>.
getPosition(#wx_ref{type=ThisT,ref=ThisRef}) ->
?CLASS(ThisT,wxGridEvent),
diff --git a/lib/wx/src/gen/wxHelpEvent.erl b/lib/wx/src/gen/wxHelpEvent.erl
index ef3c666ab7..b80903c314 100644
--- a/lib/wx/src/gen/wxHelpEvent.erl
+++ b/lib/wx/src/gen/wxHelpEvent.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2010. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2011. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -50,7 +50,7 @@ getOrigin(#wx_ref{type=ThisT,ref=ThisRef}) ->
wxe_util:call(?wxHelpEvent_GetOrigin,
<<ThisRef:32/?UI>>).
-%% @spec (This::wxHelpEvent()) -> {X::integer(),Y::integer()}
+%% @spec (This::wxHelpEvent()) -> {X::integer(), Y::integer()}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxhelpevent.html#wxhelpeventgetposition">external documentation</a>.
getPosition(#wx_ref{type=ThisT,ref=ThisRef}) ->
?CLASS(ThisT,wxHelpEvent),
@@ -67,7 +67,7 @@ setOrigin(#wx_ref{type=ThisT,ref=ThisRef},Origin)
wxe_util:cast(?wxHelpEvent_SetOrigin,
<<ThisRef:32/?UI,Origin:32/?UI>>).
-%% @spec (This::wxHelpEvent(), Pos::{X::integer(),Y::integer()}) -> ok
+%% @spec (This::wxHelpEvent(), Pos::{X::integer(), Y::integer()}) -> ok
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxhelpevent.html#wxhelpeventsetposition">external documentation</a>.
setPosition(#wx_ref{type=ThisT,ref=ThisRef},{PosX,PosY})
when is_integer(PosX),is_integer(PosY) ->
diff --git a/lib/wx/src/gen/wxHtmlWindow.erl b/lib/wx/src/gen/wxHtmlWindow.erl
index ba8278ff56..891e5481fb 100644
--- a/lib/wx/src/gen/wxHtmlWindow.erl
+++ b/lib/wx/src/gen/wxHtmlWindow.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2009-2010. All Rights Reserved.
+%% Copyright Ericsson AB 2009-2011. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -99,7 +99,7 @@ new(Parent)
new(Parent, []).
%% @spec (Parent::wxWindow:wxWindow(), [Option]) -> wxHtmlWindow()
-%% Option = {id, integer()} | {pos, {X::integer(),Y::integer()}} | {size, {W::integer(),H::integer()}} | {style, integer()}
+%% Option = {id, integer()} | {pos, {X::integer(), Y::integer()}} | {size, {W::integer(), H::integer()}} | {style, integer()}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxhtmlwindow.html#wxhtmlwindowwxhtmlwindow">external documentation</a>.
new(#wx_ref{type=ParentT,ref=ParentRef}, Options)
when is_list(Options) ->
@@ -217,7 +217,7 @@ selectionToText(#wx_ref{type=ThisT,ref=ThisRef}) ->
wxe_util:call(?wxHtmlWindow_SelectionToText,
<<ThisRef:32/?UI>>).
-%% @spec (This::wxHtmlWindow(), Pos::{X::integer(),Y::integer()}) -> ok
+%% @spec (This::wxHtmlWindow(), Pos::{X::integer(), Y::integer()}) -> ok
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxhtmlwindow.html#wxhtmlwindowselectline">external documentation</a>.
selectLine(#wx_ref{type=ThisT,ref=ThisRef},{PosX,PosY})
when is_integer(PosX),is_integer(PosY) ->
@@ -225,7 +225,7 @@ selectLine(#wx_ref{type=ThisT,ref=ThisRef},{PosX,PosY})
wxe_util:cast(?wxHtmlWindow_SelectLine,
<<ThisRef:32/?UI,PosX:32/?UI,PosY:32/?UI>>).
-%% @spec (This::wxHtmlWindow(), Pos::{X::integer(),Y::integer()}) -> ok
+%% @spec (This::wxHtmlWindow(), Pos::{X::integer(), Y::integer()}) -> ok
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxhtmlwindow.html#wxhtmlwindowselectword">external documentation</a>.
selectWord(#wx_ref{type=ThisT,ref=ThisRef},{PosX,PosY})
when is_integer(PosX),is_integer(PosY) ->
diff --git a/lib/wx/src/gen/wxIconBundle.erl b/lib/wx/src/gen/wxIconBundle.erl
index ee133cbcb9..011b2dd1ac 100644
--- a/lib/wx/src/gen/wxIconBundle.erl
+++ b/lib/wx/src/gen/wxIconBundle.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2010. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2011. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -89,7 +89,7 @@ getIcon(This)
%%<br /> Option = {size, integer()}
%% </p>
%% <p><c>
-%% getIcon(This::wxIconBundle(), Size::{W::integer(),H::integer()}) -> wxIcon:wxIcon() </c>
+%% getIcon(This::wxIconBundle(), Size::{W::integer(), H::integer()}) -> wxIcon:wxIcon() </c>
%% </p>
getIcon(#wx_ref{type=ThisT,ref=ThisRef}, Options)
when is_list(Options) ->
diff --git a/lib/wx/src/gen/wxImage.erl b/lib/wx/src/gen/wxImage.erl
index 5fe105fbb2..ea41a78a40 100644
--- a/lib/wx/src/gen/wxImage.erl
+++ b/lib/wx/src/gen/wxImage.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2010. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2011. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -303,13 +303,13 @@ create(#wx_ref{type=ThisT,ref=ThisRef},Width,Height,Data,Alpha, Options)
wxe_util:cast(?wxImage_Destroy,
<<ThisRef:32/?UI>>).
-%% @spec (This::wxImage()) -> {bool(),R::integer(),G::integer(),B::integer()}
+%% @spec (This::wxImage()) -> {bool(), R::integer(), G::integer(), B::integer()}
%% @equiv findFirstUnusedColour(This, [])
findFirstUnusedColour(This)
when is_record(This, wx_ref) ->
findFirstUnusedColour(This, []).
-%% @spec (This::wxImage(), [Option]) -> {bool(),R::integer(),G::integer(),B::integer()}
+%% @spec (This::wxImage(), [Option]) -> {bool(), R::integer(), G::integer(), B::integer()}
%% Option = {startR, integer()} | {startG, integer()} | {startB, integer()}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wximage.html#wximagefindfirstunusedcolour">external documentation</a>.
findFirstUnusedColour(#wx_ref{type=ThisT,ref=ThisRef}, Options)
@@ -413,7 +413,7 @@ getMaskRed(#wx_ref{type=ThisT,ref=ThisRef}) ->
wxe_util:call(?wxImage_GetMaskRed,
<<ThisRef:32/?UI>>).
-%% @spec (This::wxImage()) -> {bool(),R::integer(),G::integer(),B::integer()}
+%% @spec (This::wxImage()) -> {bool(), R::integer(), G::integer(), B::integer()}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wximage.html#wximagegetorfindmaskcolour">external documentation</a>.
getOrFindMaskColour(#wx_ref{type=ThisT,ref=ThisRef}) ->
?CLASS(ThisT,wxImage),
@@ -435,7 +435,7 @@ getRed(#wx_ref{type=ThisT,ref=ThisRef},X,Y)
wxe_util:call(?wxImage_GetRed,
<<ThisRef:32/?UI,X:32/?UI,Y:32/?UI>>).
-%% @spec (This::wxImage(), Rect::{X::integer(),Y::integer(),W::integer(),H::integer()}) -> wxImage()
+%% @spec (This::wxImage(), Rect::{X::integer(), Y::integer(), W::integer(), H::integer()}) -> wxImage()
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wximage.html#wximagegetsubimage">external documentation</a>.
getSubImage(#wx_ref{type=ThisT,ref=ThisRef},{RectX,RectY,RectW,RectH})
when is_integer(RectX),is_integer(RectY),is_integer(RectW),is_integer(RectH) ->
@@ -615,13 +615,13 @@ rescale(#wx_ref{type=ThisT,ref=ThisRef},Width,Height, Options)
wxe_util:call(?wxImage_Rescale,
<<ThisRef:32/?UI,Width:32/?UI,Height:32/?UI, 0:32,BinOpt/binary>>).
-%% @spec (This::wxImage(), Size::{W::integer(),H::integer()}, Pos::{X::integer(),Y::integer()}) -> wxImage()
+%% @spec (This::wxImage(), Size::{W::integer(), H::integer()}, Pos::{X::integer(), Y::integer()}) -> wxImage()
%% @equiv resize(This,Size,Pos, [])
resize(This,Size={SizeW,SizeH},Pos={PosX,PosY})
when is_record(This, wx_ref),is_integer(SizeW),is_integer(SizeH),is_integer(PosX),is_integer(PosY) ->
resize(This,Size,Pos, []).
-%% @spec (This::wxImage(), Size::{W::integer(),H::integer()}, Pos::{X::integer(),Y::integer()}, [Option]) -> wxImage()
+%% @spec (This::wxImage(), Size::{W::integer(), H::integer()}, Pos::{X::integer(), Y::integer()}, [Option]) -> wxImage()
%% Option = {r, integer()} | {g, integer()} | {b, integer()}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wximage.html#wximageresize">external documentation</a>.
resize(#wx_ref{type=ThisT,ref=ThisRef},{SizeW,SizeH},{PosX,PosY}, Options)
@@ -635,14 +635,14 @@ resize(#wx_ref{type=ThisT,ref=ThisRef},{SizeW,SizeH},{PosX,PosY}, Options)
wxe_util:call(?wxImage_Resize,
<<ThisRef:32/?UI,SizeW:32/?UI,SizeH:32/?UI,PosX:32/?UI,PosY:32/?UI, 0:32,BinOpt/binary>>).
-%% @spec (This::wxImage(), Angle::float(), Centre_of_rotation::{X::integer(),Y::integer()}) -> wxImage()
+%% @spec (This::wxImage(), Angle::float(), Centre_of_rotation::{X::integer(), Y::integer()}) -> wxImage()
%% @equiv rotate(This,Angle,Centre_of_rotation, [])
rotate(This,Angle,Centre_of_rotation={Centre_of_rotationX,Centre_of_rotationY})
when is_record(This, wx_ref),is_float(Angle),is_integer(Centre_of_rotationX),is_integer(Centre_of_rotationY) ->
rotate(This,Angle,Centre_of_rotation, []).
-%% @spec (This::wxImage(), Angle::float(), Centre_of_rotation::{X::integer(),Y::integer()}, [Option]) -> wxImage()
-%% Option = {interpolating, bool()} | {offset_after_rotation, {X::integer(),Y::integer()}}
+%% @spec (This::wxImage(), Angle::float(), Centre_of_rotation::{X::integer(), Y::integer()}, [Option]) -> wxImage()
+%% Option = {interpolating, bool()} | {offset_after_rotation, {X::integer(), Y::integer()}}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wximage.html#wximagerotate">external documentation</a>.
rotate(#wx_ref{type=ThisT,ref=ThisRef},Angle,{Centre_of_rotationX,Centre_of_rotationY}, Options)
when is_float(Angle),is_integer(Centre_of_rotationX),is_integer(Centre_of_rotationY),is_list(Options) ->
@@ -730,13 +730,13 @@ scale(#wx_ref{type=ThisT,ref=ThisRef},Width,Height, Options)
wxe_util:call(?wxImage_Scale,
<<ThisRef:32/?UI,Width:32/?UI,Height:32/?UI, 0:32,BinOpt/binary>>).
-%% @spec (This::wxImage(), Size::{W::integer(),H::integer()}, Pos::{X::integer(),Y::integer()}) -> wxImage()
+%% @spec (This::wxImage(), Size::{W::integer(), H::integer()}, Pos::{X::integer(), Y::integer()}) -> wxImage()
%% @equiv size(This,Size,Pos, [])
size(This,Size={SizeW,SizeH},Pos={PosX,PosY})
when is_record(This, wx_ref),is_integer(SizeW),is_integer(SizeH),is_integer(PosX),is_integer(PosY) ->
size(This,Size,Pos, []).
-%% @spec (This::wxImage(), Size::{W::integer(),H::integer()}, Pos::{X::integer(),Y::integer()}, [Option]) -> wxImage()
+%% @spec (This::wxImage(), Size::{W::integer(), H::integer()}, Pos::{X::integer(), Y::integer()}, [Option]) -> wxImage()
%% Option = {r, integer()} | {g, integer()} | {b, integer()}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wximage.html#wximagesize">external documentation</a>.
size(#wx_ref{type=ThisT,ref=ThisRef},{SizeW,SizeH},{PosX,PosY}, Options)
@@ -881,7 +881,7 @@ setPalette(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=PaletteT,ref=PaletteRef}
wxe_util:cast(?wxImage_SetPalette,
<<ThisRef:32/?UI,PaletteRef:32/?UI>>).
-%% @spec (This::wxImage(), Rect::{X::integer(),Y::integer(),W::integer(),H::integer()}, R::integer(), G::integer(), B::integer()) -> ok
+%% @spec (This::wxImage(), Rect::{X::integer(), Y::integer(), W::integer(), H::integer()}, R::integer(), G::integer(), B::integer()) -> ok
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wximage.html#wximagesetrgb">external documentation</a>.
setRGB(#wx_ref{type=ThisT,ref=ThisRef},{RectX,RectY,RectW,RectH},R,G,B)
when is_integer(RectX),is_integer(RectY),is_integer(RectW),is_integer(RectH),is_integer(R),is_integer(G),is_integer(B) ->
diff --git a/lib/wx/src/gen/wxImageList.erl b/lib/wx/src/gen/wxImageList.erl
index dbd51bc47b..f805a234df 100644
--- a/lib/wx/src/gen/wxImageList.erl
+++ b/lib/wx/src/gen/wxImageList.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2010. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2011. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -150,7 +150,7 @@ getImageCount(#wx_ref{type=ThisT,ref=ThisRef}) ->
wxe_util:call(?wxImageList_GetImageCount,
<<ThisRef:32/?UI>>).
-%% @spec (This::wxImageList(), Index::integer()) -> {bool(),Width::integer(),Height::integer()}
+%% @spec (This::wxImageList(), Index::integer()) -> {bool(), Width::integer(), Height::integer()}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wximagelist.html#wximagelistgetsize">external documentation</a>.
getSize(#wx_ref{type=ThisT,ref=ThisRef},Index)
when is_integer(Index) ->
diff --git a/lib/wx/src/gen/wxJoystickEvent.erl b/lib/wx/src/gen/wxJoystickEvent.erl
index 2c2d7f3968..2f149a50f8 100644
--- a/lib/wx/src/gen/wxJoystickEvent.erl
+++ b/lib/wx/src/gen/wxJoystickEvent.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2010. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2011. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -118,7 +118,7 @@ getJoystick(#wx_ref{type=ThisT,ref=ThisRef}) ->
wxe_util:call(?wxJoystickEvent_GetJoystick,
<<ThisRef:32/?UI>>).
-%% @spec (This::wxJoystickEvent()) -> {X::integer(),Y::integer()}
+%% @spec (This::wxJoystickEvent()) -> {X::integer(), Y::integer()}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxjoystickevent.html#wxjoystickeventgetposition">external documentation</a>.
getPosition(#wx_ref{type=ThisT,ref=ThisRef}) ->
?CLASS(ThisT,wxJoystickEvent),
diff --git a/lib/wx/src/gen/wxKeyEvent.erl b/lib/wx/src/gen/wxKeyEvent.erl
index 00d1e2033a..edda5ee0a6 100644
--- a/lib/wx/src/gen/wxKeyEvent.erl
+++ b/lib/wx/src/gen/wxKeyEvent.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2010. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2011. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -78,7 +78,7 @@ getModifiers(#wx_ref{type=ThisT,ref=ThisRef}) ->
wxe_util:call(?wxKeyEvent_GetModifiers,
<<ThisRef:32/?UI>>).
-%% @spec (This::wxKeyEvent()) -> {X::integer(),Y::integer()}
+%% @spec (This::wxKeyEvent()) -> {X::integer(), Y::integer()}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxkeyevent.html#wxkeyeventgetposition">external documentation</a>.
getPosition(#wx_ref{type=ThisT,ref=ThisRef}) ->
?CLASS(ThisT,wxKeyEvent),
diff --git a/lib/wx/src/gen/wxLayoutAlgorithm.erl b/lib/wx/src/gen/wxLayoutAlgorithm.erl
index 402d116338..c17abeaed1 100644
--- a/lib/wx/src/gen/wxLayoutAlgorithm.erl
+++ b/lib/wx/src/gen/wxLayoutAlgorithm.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2010. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2011. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -65,7 +65,7 @@ layoutMDIFrame(This,Frame)
layoutMDIFrame(This,Frame, []).
%% @spec (This::wxLayoutAlgorithm(), Frame::wxMDIParentFrame:wxMDIParentFrame(), [Option]) -> bool()
-%% Option = {rect, {X::integer(),Y::integer(),W::integer(),H::integer()}}
+%% Option = {rect, {X::integer(), Y::integer(), W::integer(), H::integer()}}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxlayoutalgorithm.html#wxlayoutalgorithmlayoutmdiframe">external documentation</a>.
layoutMDIFrame(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=FrameT,ref=FrameRef}, Options)
when is_list(Options) ->
diff --git a/lib/wx/src/gen/wxListBox.erl b/lib/wx/src/gen/wxListBox.erl
index 731209c586..cc30bf95e4 100644
--- a/lib/wx/src/gen/wxListBox.erl
+++ b/lib/wx/src/gen/wxListBox.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2010. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2011. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -94,7 +94,7 @@ new(Parent,Id)
new(Parent,Id, []).
%% @spec (Parent::wxWindow:wxWindow(), Id::integer(), [Option]) -> wxListBox()
-%% Option = {pos, {X::integer(),Y::integer()}} | {size, {W::integer(),H::integer()}} | {choices, [[string()]]} | {style, integer()} | {validator, wx:wx()}
+%% Option = {pos, {X::integer(), Y::integer()}} | {size, {W::integer(), H::integer()}} | {choices, [[string()]]} | {style, integer()} | {validator, wx:wx()}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxlistbox.html#wxlistboxwxlistbox">external documentation</a>.
new(#wx_ref{type=ParentT,ref=ParentRef},Id, Options)
when is_integer(Id),is_list(Options) ->
@@ -109,13 +109,13 @@ new(#wx_ref{type=ParentT,ref=ParentRef},Id, Options)
wxe_util:construct(?wxListBox_new_3,
<<ParentRef:32/?UI,Id:32/?UI, BinOpt/binary>>).
-%% @spec (This::wxListBox(), Parent::wxWindow:wxWindow(), Id::integer(), Pos::{X::integer(),Y::integer()}, Size::{W::integer(),H::integer()}, Choices::[[string()]]) -> bool()
+%% @spec (This::wxListBox(), Parent::wxWindow:wxWindow(), Id::integer(), Pos::{X::integer(), Y::integer()}, Size::{W::integer(), H::integer()}, Choices::[[string()]]) -> bool()
%% @equiv create(This,Parent,Id,Pos,Size,Choices, [])
create(This,Parent,Id,Pos={PosX,PosY},Size={SizeW,SizeH},Choices)
when is_record(This, wx_ref),is_record(Parent, wx_ref),is_integer(Id),is_integer(PosX),is_integer(PosY),is_integer(SizeW),is_integer(SizeH),is_list(Choices) ->
create(This,Parent,Id,Pos,Size,Choices, []).
-%% @spec (This::wxListBox(), Parent::wxWindow:wxWindow(), Id::integer(), Pos::{X::integer(),Y::integer()}, Size::{W::integer(),H::integer()}, Choices::[[string()]], [Option]) -> bool()
+%% @spec (This::wxListBox(), Parent::wxWindow:wxWindow(), Id::integer(), Pos::{X::integer(), Y::integer()}, Size::{W::integer(), H::integer()}, Choices::[[string()]], [Option]) -> bool()
%% Option = {style, integer()} | {validator, wx:wx()}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxlistbox.html#wxlistboxcreate">external documentation</a>.
create(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=ParentT,ref=ParentRef},Id,{PosX,PosY},{SizeW,SizeH},Choices, Options)
@@ -139,7 +139,7 @@ deselect(#wx_ref{type=ThisT,ref=ThisRef},N)
wxe_util:cast(?wxListBox_Deselect,
<<ThisRef:32/?UI,N:32/?UI>>).
-%% @spec (This::wxListBox()) -> {integer(),ASelections::[integer()]}
+%% @spec (This::wxListBox()) -> {integer(), ASelections::[integer()]}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxlistbox.html#wxlistboxgetselections">external documentation</a>.
getSelections(#wx_ref{type=ThisT,ref=ThisRef}) ->
?CLASS(ThisT,wxListBox),
@@ -174,7 +174,7 @@ set(#wx_ref{type=ThisT,ref=ThisRef},Items)
wxe_util:cast(?wxListBox_Set,
<<ThisRef:32/?UI,(length(Items_UCA)):32/?UI, (<< <<(byte_size(UC_Str)):32/?UI, UC_Str/binary>>|| UC_Str <- Items_UCA>>)/binary, 0:(((8- ((0 + lists:sum([byte_size(S)+4||S<-Items_UCA])) band 16#7)) band 16#7))/unit:8>>).
-%% @spec (This::wxListBox(), Point::{X::integer(),Y::integer()}) -> integer()
+%% @spec (This::wxListBox(), Point::{X::integer(), Y::integer()}) -> integer()
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxlistbox.html#wxlistboxhittest">external documentation</a>.
hitTest(#wx_ref{type=ThisT,ref=ThisRef},{PointX,PointY})
when is_integer(PointX),is_integer(PointY) ->
diff --git a/lib/wx/src/gen/wxListCtrl.erl b/lib/wx/src/gen/wxListCtrl.erl
index 5799206b87..fa99897171 100644
--- a/lib/wx/src/gen/wxListCtrl.erl
+++ b/lib/wx/src/gen/wxListCtrl.erl
@@ -263,7 +263,7 @@ findItem(This,Start,Str)
%%<br /> Option = {partial, bool()}
%% </p>
%% <p><c>
-%% findItem(This::wxListCtrl(), Start::integer(), Pt::{X::integer(),Y::integer()}, Direction::integer()) -> integer() </c>
+%% findItem(This::wxListCtrl(), Start::integer(), Pt::{X::integer(), Y::integer()}, Direction::integer()) -> integer() </c>
%% </p>
findItem(#wx_ref{type=ThisT,ref=ThisRef},Start,Str, Options)
when is_integer(Start),is_list(Str),is_list(Options) ->
@@ -365,7 +365,7 @@ getItemFont(#wx_ref{type=ThisT,ref=ThisRef},Item)
wxe_util:call(?wxListCtrl_GetItemFont,
<<ThisRef:32/?UI,Item:32/?UI>>).
-%% @spec (This::wxListCtrl(), Item::integer(), Pos::{X::integer(),Y::integer()}) -> bool()
+%% @spec (This::wxListCtrl(), Item::integer(), Pos::{X::integer(), Y::integer()}) -> bool()
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxlistctrl.html#wxlistctrlgetitemposition">external documentation</a>.
getItemPosition(#wx_ref{type=ThisT,ref=ThisRef},Item,{PosX,PosY})
when is_integer(Item),is_integer(PosX),is_integer(PosY) ->
@@ -373,13 +373,13 @@ getItemPosition(#wx_ref{type=ThisT,ref=ThisRef},Item,{PosX,PosY})
wxe_util:call(?wxListCtrl_GetItemPosition,
<<ThisRef:32/?UI,Item:32/?UI,PosX:32/?UI,PosY:32/?UI>>).
-%% @spec (This::wxListCtrl(), Item::integer(), Rect::{X::integer(),Y::integer(),W::integer(),H::integer()}) -> bool()
+%% @spec (This::wxListCtrl(), Item::integer(), Rect::{X::integer(), Y::integer(), W::integer(), H::integer()}) -> bool()
%% @equiv getItemRect(This,Item,Rect, [])
getItemRect(This,Item,Rect={RectX,RectY,RectW,RectH})
when is_record(This, wx_ref),is_integer(Item),is_integer(RectX),is_integer(RectY),is_integer(RectW),is_integer(RectH) ->
getItemRect(This,Item,Rect, []).
-%% @spec (This::wxListCtrl(), Item::integer(), Rect::{X::integer(),Y::integer(),W::integer(),H::integer()}, [Option]) -> bool()
+%% @spec (This::wxListCtrl(), Item::integer(), Rect::{X::integer(), Y::integer(), W::integer(), H::integer()}, [Option]) -> bool()
%% Option = {code, integer()}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxlistctrl.html#wxlistctrlgetitemrect">external documentation</a>.
getItemRect(#wx_ref{type=ThisT,ref=ThisRef},Item,{RectX,RectY,RectW,RectH}, Options)
@@ -391,7 +391,7 @@ getItemRect(#wx_ref{type=ThisT,ref=ThisRef},Item,{RectX,RectY,RectW,RectH}, Opti
wxe_util:call(?wxListCtrl_GetItemRect,
<<ThisRef:32/?UI,Item:32/?UI,RectX:32/?UI,RectY:32/?UI,RectW:32/?UI,RectH:32/?UI, BinOpt/binary>>).
-%% @spec (This::wxListCtrl()) -> {W::integer(),H::integer()}
+%% @spec (This::wxListCtrl()) -> {W::integer(), H::integer()}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxlistctrl.html#wxlistctrlgetitemspacing">external documentation</a>.
getItemSpacing(#wx_ref{type=ThisT,ref=ThisRef}) ->
?CLASS(ThisT,wxListCtrl),
@@ -462,14 +462,14 @@ getTopItem(#wx_ref{type=ThisT,ref=ThisRef}) ->
wxe_util:call(?wxListCtrl_GetTopItem,
<<ThisRef:32/?UI>>).
-%% @spec (This::wxListCtrl()) -> {X::integer(),Y::integer(),W::integer(),H::integer()}
+%% @spec (This::wxListCtrl()) -> {X::integer(), Y::integer(), W::integer(), H::integer()}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxlistctrl.html#wxlistctrlgetviewrect">external documentation</a>.
getViewRect(#wx_ref{type=ThisT,ref=ThisRef}) ->
?CLASS(ThisT,wxListCtrl),
wxe_util:call(?wxListCtrl_GetViewRect,
<<ThisRef:32/?UI>>).
-%% @spec (This::wxListCtrl(), Point::{X::integer(),Y::integer()}) -> {integer(),Flags::integer()}
+%% @spec (This::wxListCtrl(), Point::{X::integer(), Y::integer()}) -> {integer(), Flags::integer()}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxlistctrl.html#wxlistctrlhittest">external documentation</a>.
hitTest(#wx_ref{type=ThisT,ref=ThisRef},{PointX,PointY})
when is_integer(PointX),is_integer(PointY) ->
@@ -692,7 +692,7 @@ setItemColumnImage(#wx_ref{type=ThisT,ref=ThisRef},Item,Column,Image)
wxe_util:call(?wxListCtrl_SetItemColumnImage,
<<ThisRef:32/?UI,Item:32/?UI,Column:32/?UI,Image:32/?UI>>).
-%% @spec (This::wxListCtrl(), Item::integer(), Pos::{X::integer(),Y::integer()}) -> bool()
+%% @spec (This::wxListCtrl(), Item::integer(), Pos::{X::integer(), Y::integer()}) -> bool()
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxlistctrl.html#wxlistctrlsetitemposition">external documentation</a>.
setItemPosition(#wx_ref{type=ThisT,ref=ThisRef},Item,{PosX,PosY})
when is_integer(Item),is_integer(PosX),is_integer(PosY) ->
diff --git a/lib/wx/src/gen/wxListEvent.erl b/lib/wx/src/gen/wxListEvent.erl
index 74f9e6095c..f7d8658acc 100644
--- a/lib/wx/src/gen/wxListEvent.erl
+++ b/lib/wx/src/gen/wxListEvent.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2010. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2011. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -83,7 +83,7 @@ getColumn(#wx_ref{type=ThisT,ref=ThisRef}) ->
wxe_util:call(?wxListEvent_GetColumn,
<<ThisRef:32/?UI>>).
-%% @spec (This::wxListEvent()) -> {X::integer(),Y::integer()}
+%% @spec (This::wxListEvent()) -> {X::integer(), Y::integer()}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxlistevent.html#wxlisteventgetpoint">external documentation</a>.
getPoint(#wx_ref{type=ThisT,ref=ThisRef}) ->
?CLASS(ThisT,wxListEvent),
diff --git a/lib/wx/src/gen/wxListbook.erl b/lib/wx/src/gen/wxListbook.erl
index b1f0e3d9a4..c204dc87a1 100644
--- a/lib/wx/src/gen/wxListbook.erl
+++ b/lib/wx/src/gen/wxListbook.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2009-2010. All Rights Reserved.
+%% Copyright Ericsson AB 2009-2011. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -93,7 +93,7 @@ new(Parent,Id)
new(Parent,Id, []).
%% @spec (Parent::wxWindow:wxWindow(), Id::integer(), [Option]) -> wxListbook()
-%% Option = {pos, {X::integer(),Y::integer()}} | {size, {W::integer(),H::integer()}} | {style, integer()}
+%% Option = {pos, {X::integer(), Y::integer()}} | {size, {W::integer(), H::integer()}} | {style, integer()}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxlistbook.html#wxlistbookwxlistbook">external documentation</a>.
new(#wx_ref{type=ParentT,ref=ParentRef},Id, Options)
when is_integer(Id),is_list(Options) ->
@@ -160,7 +160,7 @@ create(This,Parent,Id)
create(This,Parent,Id, []).
%% @spec (This::wxListbook(), Parent::wxWindow:wxWindow(), Id::integer(), [Option]) -> bool()
-%% Option = {pos, {X::integer(),Y::integer()}} | {size, {W::integer(),H::integer()}} | {style, integer()}
+%% Option = {pos, {X::integer(), Y::integer()}} | {size, {W::integer(), H::integer()}} | {style, integer()}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxlistbook.html#wxlistbookcreate">external documentation</a>.
create(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=ParentT,ref=ParentRef},Id, Options)
when is_integer(Id),is_list(Options) ->
@@ -249,7 +249,7 @@ getSelection(#wx_ref{type=ThisT,ref=ThisRef}) ->
wxe_util:call(?wxListbook_GetSelection,
<<ThisRef:32/?UI>>).
-%% @spec (This::wxListbook(), Pt::{X::integer(),Y::integer()}) -> {integer(),Flags::integer()}
+%% @spec (This::wxListbook(), Pt::{X::integer(), Y::integer()}) -> {integer(), Flags::integer()}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxlistbook.html#wxlistbookhittest">external documentation</a>.
hitTest(#wx_ref{type=ThisT,ref=ThisRef},{PtX,PtY})
when is_integer(PtX),is_integer(PtY) ->
@@ -286,7 +286,7 @@ setImageList(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=ImageListT,ref=ImageLi
wxe_util:cast(?wxListbook_SetImageList,
<<ThisRef:32/?UI,ImageListRef:32/?UI>>).
-%% @spec (This::wxListbook(), Size::{W::integer(),H::integer()}) -> ok
+%% @spec (This::wxListbook(), Size::{W::integer(), H::integer()}) -> ok
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxlistbook.html#wxlistbooksetpagesize">external documentation</a>.
setPageSize(#wx_ref{type=ThisT,ref=ThisRef},{SizeW,SizeH})
when is_integer(SizeW),is_integer(SizeH) ->
diff --git a/lib/wx/src/gen/wxMDIChildFrame.erl b/lib/wx/src/gen/wxMDIChildFrame.erl
index 34edac4213..d3e1edda55 100644
--- a/lib/wx/src/gen/wxMDIChildFrame.erl
+++ b/lib/wx/src/gen/wxMDIChildFrame.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2010. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2011. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -100,7 +100,7 @@ new(Parent,Id,Title)
new(Parent,Id,Title, []).
%% @spec (Parent::wxMDIParentFrame:wxMDIParentFrame(), Id::integer(), Title::string(), [Option]) -> wxMDIChildFrame()
-%% Option = {pos, {X::integer(),Y::integer()}} | {size, {W::integer(),H::integer()}} | {style, integer()}
+%% Option = {pos, {X::integer(), Y::integer()}} | {size, {W::integer(), H::integer()}} | {style, integer()}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxmdichildframe.html#wxmdichildframewxmdichildframe">external documentation</a>.
new(#wx_ref{type=ParentT,ref=ParentRef},Id,Title, Options)
when is_integer(Id),is_list(Title),is_list(Options) ->
@@ -128,7 +128,7 @@ create(This,Parent,Id,Title)
create(This,Parent,Id,Title, []).
%% @spec (This::wxMDIChildFrame(), Parent::wxMDIParentFrame:wxMDIParentFrame(), Id::integer(), Title::string(), [Option]) -> bool()
-%% Option = {pos, {X::integer(),Y::integer()}} | {size, {W::integer(),H::integer()}} | {style, integer()}
+%% Option = {pos, {X::integer(), Y::integer()}} | {size, {W::integer(), H::integer()}} | {style, integer()}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxmdichildframe.html#wxmdichildframecreate">external documentation</a>.
create(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=ParentT,ref=ParentRef},Id,Title, Options)
when is_integer(Id),is_list(Title),is_list(Options) ->
diff --git a/lib/wx/src/gen/wxMDIParentFrame.erl b/lib/wx/src/gen/wxMDIParentFrame.erl
index db47e7ac74..7f8a305876 100644
--- a/lib/wx/src/gen/wxMDIParentFrame.erl
+++ b/lib/wx/src/gen/wxMDIParentFrame.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2010. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2011. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -102,7 +102,7 @@ new(Parent,Id,Title)
new(Parent,Id,Title, []).
%% @spec (Parent::wxWindow:wxWindow(), Id::integer(), Title::string(), [Option]) -> wxMDIParentFrame()
-%% Option = {pos, {X::integer(),Y::integer()}} | {size, {W::integer(),H::integer()}} | {style, integer()}
+%% Option = {pos, {X::integer(), Y::integer()}} | {size, {W::integer(), H::integer()}} | {style, integer()}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxmdiparentframe.html#wxmdiparentframewxmdiparentframe">external documentation</a>.
new(#wx_ref{type=ParentT,ref=ParentRef},Id,Title, Options)
when is_integer(Id),is_list(Title),is_list(Options) ->
@@ -151,7 +151,7 @@ create(This,Parent,Id,Title)
create(This,Parent,Id,Title, []).
%% @spec (This::wxMDIParentFrame(), Parent::wxWindow:wxWindow(), Id::integer(), Title::string(), [Option]) -> bool()
-%% Option = {pos, {X::integer(),Y::integer()}} | {size, {W::integer(),H::integer()}} | {style, integer()}
+%% Option = {pos, {X::integer(), Y::integer()}} | {size, {W::integer(), H::integer()}} | {style, integer()}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxmdiparentframe.html#wxmdiparentframecreate">external documentation</a>.
create(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=ParentT,ref=ParentRef},Id,Title, Options)
when is_integer(Id),is_list(Title),is_list(Options) ->
diff --git a/lib/wx/src/gen/wxMessageDialog.erl b/lib/wx/src/gen/wxMessageDialog.erl
index 916b201d3f..d13bb7cb6e 100644
--- a/lib/wx/src/gen/wxMessageDialog.erl
+++ b/lib/wx/src/gen/wxMessageDialog.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2010. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2011. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -91,7 +91,7 @@ new(Parent,Message)
new(Parent,Message, []).
%% @spec (Parent::wxWindow:wxWindow(), Message::string(), [Option]) -> wxMessageDialog()
-%% Option = {caption, string()} | {style, integer()} | {pos, {X::integer(),Y::integer()}}
+%% Option = {caption, string()} | {style, integer()} | {pos, {X::integer(), Y::integer()}}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxmessagedialog.html#wxmessagedialogwxmessagedialog">external documentation</a>.
new(#wx_ref{type=ParentT,ref=ParentRef},Message, Options)
when is_list(Message),is_list(Options) ->
diff --git a/lib/wx/src/gen/wxMiniFrame.erl b/lib/wx/src/gen/wxMiniFrame.erl
index b86f1d7cfa..108ebcfb0e 100644
--- a/lib/wx/src/gen/wxMiniFrame.erl
+++ b/lib/wx/src/gen/wxMiniFrame.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2010. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2011. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -100,7 +100,7 @@ new(Parent,Id,Title)
new(Parent,Id,Title, []).
%% @spec (Parent::wxWindow:wxWindow(), Id::integer(), Title::string(), [Option]) -> wxMiniFrame()
-%% Option = {pos, {X::integer(),Y::integer()}} | {size, {W::integer(),H::integer()}} | {style, integer()}
+%% Option = {pos, {X::integer(), Y::integer()}} | {size, {W::integer(), H::integer()}} | {style, integer()}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxminiframe.html#wxminiframewxminiframe">external documentation</a>.
new(#wx_ref{type=ParentT,ref=ParentRef},Id,Title, Options)
when is_integer(Id),is_list(Title),is_list(Options) ->
@@ -121,7 +121,7 @@ create(This,Parent,Id,Title)
create(This,Parent,Id,Title, []).
%% @spec (This::wxMiniFrame(), Parent::wxWindow:wxWindow(), Id::integer(), Title::string(), [Option]) -> bool()
-%% Option = {pos, {X::integer(),Y::integer()}} | {size, {W::integer(),H::integer()}} | {style, integer()}
+%% Option = {pos, {X::integer(), Y::integer()}} | {size, {W::integer(), H::integer()}} | {style, integer()}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxminiframe.html#wxminiframecreate">external documentation</a>.
create(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=ParentT,ref=ParentRef},Id,Title, Options)
when is_integer(Id),is_list(Title),is_list(Options) ->
diff --git a/lib/wx/src/gen/wxMouseEvent.erl b/lib/wx/src/gen/wxMouseEvent.erl
index fed9a33db7..a91d2a2e99 100644
--- a/lib/wx/src/gen/wxMouseEvent.erl
+++ b/lib/wx/src/gen/wxMouseEvent.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2010. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2011. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -151,14 +151,14 @@ getButton(#wx_ref{type=ThisT,ref=ThisRef}) ->
wxe_util:call(?wxMouseEvent_GetButton,
<<ThisRef:32/?UI>>).
-%% @spec (This::wxMouseEvent()) -> {X::integer(),Y::integer()}
+%% @spec (This::wxMouseEvent()) -> {X::integer(), Y::integer()}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxmouseevent.html#wxmouseeventgetposition">external documentation</a>.
getPosition(#wx_ref{type=ThisT,ref=ThisRef}) ->
?CLASS(ThisT,wxMouseEvent),
wxe_util:call(?wxMouseEvent_GetPosition,
<<ThisRef:32/?UI>>).
-%% @spec (This::wxMouseEvent(), Dc::wxDC:wxDC()) -> {X::integer(),Y::integer()}
+%% @spec (This::wxMouseEvent(), Dc::wxDC:wxDC()) -> {X::integer(), Y::integer()}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxmouseevent.html#wxmouseeventgetlogicalposition">external documentation</a>.
getLogicalPosition(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=DcT,ref=DcRef}) ->
?CLASS(ThisT,wxMouseEvent),
diff --git a/lib/wx/src/gen/wxMoveEvent.erl b/lib/wx/src/gen/wxMoveEvent.erl
index 80bf59074a..97cf803310 100644
--- a/lib/wx/src/gen/wxMoveEvent.erl
+++ b/lib/wx/src/gen/wxMoveEvent.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2010. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2011. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -41,7 +41,7 @@
parent_class(wxEvent) -> true;
parent_class(_Class) -> erlang:error({badtype, ?MODULE}).
-%% @spec (This::wxMoveEvent()) -> {X::integer(),Y::integer()}
+%% @spec (This::wxMoveEvent()) -> {X::integer(), Y::integer()}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxmoveevent.html#wxmoveeventgetposition">external documentation</a>.
getPosition(#wx_ref{type=ThisT,ref=ThisRef}) ->
?CLASS(ThisT,wxMoveEvent),
diff --git a/lib/wx/src/gen/wxMultiChoiceDialog.erl b/lib/wx/src/gen/wxMultiChoiceDialog.erl
index e69889a1e0..6fae0c4860 100644
--- a/lib/wx/src/gen/wxMultiChoiceDialog.erl
+++ b/lib/wx/src/gen/wxMultiChoiceDialog.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2010. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2011. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -97,7 +97,7 @@ new(Parent,Message,Caption,Choices)
new(Parent,Message,Caption,Choices, []).
%% @spec (Parent::wxWindow:wxWindow(), Message::string(), Caption::string(), Choices::[[string()]], [Option]) -> wxMultiChoiceDialog()
-%% Option = {style, integer()} | {pos, {X::integer(),Y::integer()}}
+%% Option = {style, integer()} | {pos, {X::integer(), Y::integer()}}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxmultichoicedialog.html#wxmultichoicedialogwxmultichoicedialog">external documentation</a>.
new(#wx_ref{type=ParentT,ref=ParentRef},Message,Caption,Choices, Options)
when is_list(Message),is_list(Caption),is_list(Choices),is_list(Options) ->
diff --git a/lib/wx/src/gen/wxNotebook.erl b/lib/wx/src/gen/wxNotebook.erl
index da543d7ac6..b918de5bb4 100644
--- a/lib/wx/src/gen/wxNotebook.erl
+++ b/lib/wx/src/gen/wxNotebook.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2010. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2011. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -93,7 +93,7 @@ new(Parent,Winid)
new(Parent,Winid, []).
%% @spec (Parent::wxWindow:wxWindow(), Winid::integer(), [Option]) -> wxNotebook()
-%% Option = {pos, {X::integer(),Y::integer()}} | {size, {W::integer(),H::integer()}} | {style, integer()}
+%% Option = {pos, {X::integer(), Y::integer()}} | {size, {W::integer(), H::integer()}} | {style, integer()}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxnotebook.html#wxnotebookwxnotebook">external documentation</a>.
new(#wx_ref{type=ParentT,ref=ParentRef},Winid, Options)
when is_integer(Winid),is_list(Options) ->
@@ -160,7 +160,7 @@ create(This,Parent,Id)
create(This,Parent,Id, []).
%% @spec (This::wxNotebook(), Parent::wxWindow:wxWindow(), Id::integer(), [Option]) -> bool()
-%% Option = {pos, {X::integer(),Y::integer()}} | {size, {W::integer(),H::integer()}} | {style, integer()}
+%% Option = {pos, {X::integer(), Y::integer()}} | {size, {W::integer(), H::integer()}} | {style, integer()}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxnotebook.html#wxnotebookcreate">external documentation</a>.
create(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=ParentT,ref=ParentRef},Id, Options)
when is_integer(Id),is_list(Options) ->
@@ -263,7 +263,7 @@ getThemeBackgroundColour(#wx_ref{type=ThisT,ref=ThisRef}) ->
wxe_util:call(?wxNotebook_GetThemeBackgroundColour,
<<ThisRef:32/?UI>>).
-%% @spec (This::wxNotebook(), Pt::{X::integer(),Y::integer()}) -> {integer(),Flags::integer()}
+%% @spec (This::wxNotebook(), Pt::{X::integer(), Y::integer()}) -> {integer(), Flags::integer()}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxnotebook.html#wxnotebookhittest">external documentation</a>.
hitTest(#wx_ref{type=ThisT,ref=ThisRef},{PtX,PtY})
when is_integer(PtX),is_integer(PtY) ->
@@ -300,7 +300,7 @@ setImageList(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=ImageListT,ref=ImageLi
wxe_util:cast(?wxNotebook_SetImageList,
<<ThisRef:32/?UI,ImageListRef:32/?UI>>).
-%% @spec (This::wxNotebook(), Padding::{W::integer(),H::integer()}) -> ok
+%% @spec (This::wxNotebook(), Padding::{W::integer(), H::integer()}) -> ok
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxnotebook.html#wxnotebooksetpadding">external documentation</a>.
setPadding(#wx_ref{type=ThisT,ref=ThisRef},{PaddingW,PaddingH})
when is_integer(PaddingW),is_integer(PaddingH) ->
@@ -308,7 +308,7 @@ setPadding(#wx_ref{type=ThisT,ref=ThisRef},{PaddingW,PaddingH})
wxe_util:cast(?wxNotebook_SetPadding,
<<ThisRef:32/?UI,PaddingW:32/?UI,PaddingH:32/?UI>>).
-%% @spec (This::wxNotebook(), Size::{W::integer(),H::integer()}) -> ok
+%% @spec (This::wxNotebook(), Size::{W::integer(), H::integer()}) -> ok
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxnotebook.html#wxnotebooksetpagesize">external documentation</a>.
setPageSize(#wx_ref{type=ThisT,ref=ThisRef},{SizeW,SizeH})
when is_integer(SizeW),is_integer(SizeH) ->
diff --git a/lib/wx/src/gen/wxPageSetupDialogData.erl b/lib/wx/src/gen/wxPageSetupDialogData.erl
index 672ec7c083..00b4ca2a36 100644
--- a/lib/wx/src/gen/wxPageSetupDialogData.erl
+++ b/lib/wx/src/gen/wxPageSetupDialogData.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2010. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2011. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -146,28 +146,28 @@ getDefaultInfo(#wx_ref{type=ThisT,ref=ThisRef}) ->
wxe_util:call(?wxPageSetupDialogData_GetDefaultInfo,
<<ThisRef:32/?UI>>).
-%% @spec (This::wxPageSetupDialogData()) -> {X::integer(),Y::integer()}
+%% @spec (This::wxPageSetupDialogData()) -> {X::integer(), Y::integer()}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxpagesetupdialogdata.html#wxpagesetupdialogdatagetmargintopleft">external documentation</a>.
getMarginTopLeft(#wx_ref{type=ThisT,ref=ThisRef}) ->
?CLASS(ThisT,wxPageSetupDialogData),
wxe_util:call(?wxPageSetupDialogData_GetMarginTopLeft,
<<ThisRef:32/?UI>>).
-%% @spec (This::wxPageSetupDialogData()) -> {X::integer(),Y::integer()}
+%% @spec (This::wxPageSetupDialogData()) -> {X::integer(), Y::integer()}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxpagesetupdialogdata.html#wxpagesetupdialogdatagetmarginbottomright">external documentation</a>.
getMarginBottomRight(#wx_ref{type=ThisT,ref=ThisRef}) ->
?CLASS(ThisT,wxPageSetupDialogData),
wxe_util:call(?wxPageSetupDialogData_GetMarginBottomRight,
<<ThisRef:32/?UI>>).
-%% @spec (This::wxPageSetupDialogData()) -> {X::integer(),Y::integer()}
+%% @spec (This::wxPageSetupDialogData()) -> {X::integer(), Y::integer()}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxpagesetupdialogdata.html#wxpagesetupdialogdatagetminmargintopleft">external documentation</a>.
getMinMarginTopLeft(#wx_ref{type=ThisT,ref=ThisRef}) ->
?CLASS(ThisT,wxPageSetupDialogData),
wxe_util:call(?wxPageSetupDialogData_GetMinMarginTopLeft,
<<ThisRef:32/?UI>>).
-%% @spec (This::wxPageSetupDialogData()) -> {X::integer(),Y::integer()}
+%% @spec (This::wxPageSetupDialogData()) -> {X::integer(), Y::integer()}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxpagesetupdialogdata.html#wxpagesetupdialogdatagetminmarginbottomright">external documentation</a>.
getMinMarginBottomRight(#wx_ref{type=ThisT,ref=ThisRef}) ->
?CLASS(ThisT,wxPageSetupDialogData),
@@ -181,7 +181,7 @@ getPaperId(#wx_ref{type=ThisT,ref=ThisRef}) ->
wxe_util:call(?wxPageSetupDialogData_GetPaperId,
<<ThisRef:32/?UI>>).
-%% @spec (This::wxPageSetupDialogData()) -> {W::integer(),H::integer()}
+%% @spec (This::wxPageSetupDialogData()) -> {W::integer(), H::integer()}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxpagesetupdialogdata.html#wxpagesetupdialogdatagetpapersize">external documentation</a>.
getPaperSize(#wx_ref{type=ThisT,ref=ThisRef}) ->
?CLASS(ThisT,wxPageSetupDialogData),
@@ -218,7 +218,7 @@ setDefaultMinMargins(#wx_ref{type=ThisT,ref=ThisRef},Flag)
wxe_util:cast(?wxPageSetupDialogData_SetDefaultMinMargins,
<<ThisRef:32/?UI,(wxe_util:from_bool(Flag)):32/?UI>>).
-%% @spec (This::wxPageSetupDialogData(), Pt::{X::integer(),Y::integer()}) -> ok
+%% @spec (This::wxPageSetupDialogData(), Pt::{X::integer(), Y::integer()}) -> ok
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxpagesetupdialogdata.html#wxpagesetupdialogdatasetmargintopleft">external documentation</a>.
setMarginTopLeft(#wx_ref{type=ThisT,ref=ThisRef},{PtX,PtY})
when is_integer(PtX),is_integer(PtY) ->
@@ -226,7 +226,7 @@ setMarginTopLeft(#wx_ref{type=ThisT,ref=ThisRef},{PtX,PtY})
wxe_util:cast(?wxPageSetupDialogData_SetMarginTopLeft,
<<ThisRef:32/?UI,PtX:32/?UI,PtY:32/?UI>>).
-%% @spec (This::wxPageSetupDialogData(), Pt::{X::integer(),Y::integer()}) -> ok
+%% @spec (This::wxPageSetupDialogData(), Pt::{X::integer(), Y::integer()}) -> ok
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxpagesetupdialogdata.html#wxpagesetupdialogdatasetmarginbottomright">external documentation</a>.
setMarginBottomRight(#wx_ref{type=ThisT,ref=ThisRef},{PtX,PtY})
when is_integer(PtX),is_integer(PtY) ->
@@ -234,7 +234,7 @@ setMarginBottomRight(#wx_ref{type=ThisT,ref=ThisRef},{PtX,PtY})
wxe_util:cast(?wxPageSetupDialogData_SetMarginBottomRight,
<<ThisRef:32/?UI,PtX:32/?UI,PtY:32/?UI>>).
-%% @spec (This::wxPageSetupDialogData(), Pt::{X::integer(),Y::integer()}) -> ok
+%% @spec (This::wxPageSetupDialogData(), Pt::{X::integer(), Y::integer()}) -> ok
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxpagesetupdialogdata.html#wxpagesetupdialogdatasetminmargintopleft">external documentation</a>.
setMinMarginTopLeft(#wx_ref{type=ThisT,ref=ThisRef},{PtX,PtY})
when is_integer(PtX),is_integer(PtY) ->
@@ -242,7 +242,7 @@ setMinMarginTopLeft(#wx_ref{type=ThisT,ref=ThisRef},{PtX,PtY})
wxe_util:cast(?wxPageSetupDialogData_SetMinMarginTopLeft,
<<ThisRef:32/?UI,PtX:32/?UI,PtY:32/?UI>>).
-%% @spec (This::wxPageSetupDialogData(), Pt::{X::integer(),Y::integer()}) -> ok
+%% @spec (This::wxPageSetupDialogData(), Pt::{X::integer(), Y::integer()}) -> ok
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxpagesetupdialogdata.html#wxpagesetupdialogdatasetminmarginbottomright">external documentation</a>.
setMinMarginBottomRight(#wx_ref{type=ThisT,ref=ThisRef},{PtX,PtY})
when is_integer(PtX),is_integer(PtY) ->
@@ -265,7 +265,7 @@ setPaperId(#wx_ref{type=ThisT,ref=ThisRef},Id)
%% setPaperSize(This::wxPageSetupDialogData(), Id::integer()) -> ok </c>
%% </p>
%% <p><c>
-%% setPaperSize(This::wxPageSetupDialogData(), Sz::{W::integer(),H::integer()}) -> ok </c>
+%% setPaperSize(This::wxPageSetupDialogData(), Sz::{W::integer(), H::integer()}) -> ok </c>
%% </p>
setPaperSize(#wx_ref{type=ThisT,ref=ThisRef},Id)
when is_integer(Id) ->
diff --git a/lib/wx/src/gen/wxPalette.erl b/lib/wx/src/gen/wxPalette.erl
index ee1fd0016d..3d8e811988 100644
--- a/lib/wx/src/gen/wxPalette.erl
+++ b/lib/wx/src/gen/wxPalette.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2010. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2011. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -75,7 +75,7 @@ getPixel(#wx_ref{type=ThisT,ref=ThisRef},Red,Green,Blue)
wxe_util:call(?wxPalette_GetPixel,
<<ThisRef:32/?UI,Red:32/?UI,Green:32/?UI,Blue:32/?UI>>).
-%% @spec (This::wxPalette(), Pixel::integer()) -> {bool(),Red::integer(),Green::integer(),Blue::integer()}
+%% @spec (This::wxPalette(), Pixel::integer()) -> {bool(), Red::integer(), Green::integer(), Blue::integer()}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxpalette.html#wxpalettegetrgb">external documentation</a>.
getRGB(#wx_ref{type=ThisT,ref=ThisRef},Pixel)
when is_integer(Pixel) ->
diff --git a/lib/wx/src/gen/wxPanel.erl b/lib/wx/src/gen/wxPanel.erl
index 55eaa9f404..59fba03102 100644
--- a/lib/wx/src/gen/wxPanel.erl
+++ b/lib/wx/src/gen/wxPanel.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2010. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2011. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -86,7 +86,7 @@ new(Parent)
new(Parent, []).
%% @spec (Parent::wxWindow:wxWindow(), [Option]) -> wxPanel()
-%% Option = {winid, integer()} | {pos, {X::integer(),Y::integer()}} | {size, {W::integer(),H::integer()}} | {style, integer()}
+%% Option = {winid, integer()} | {pos, {X::integer(), Y::integer()}} | {size, {W::integer(), H::integer()}} | {style, integer()}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxpanel.html#wxpanelwxpanel">external documentation</a>.
new(#wx_ref{type=ParentT,ref=ParentRef}, Options)
when is_list(Options) ->
diff --git a/lib/wx/src/gen/wxPasswordEntryDialog.erl b/lib/wx/src/gen/wxPasswordEntryDialog.erl
index f79734ab46..07a0bcef56 100644
--- a/lib/wx/src/gen/wxPasswordEntryDialog.erl
+++ b/lib/wx/src/gen/wxPasswordEntryDialog.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2010. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2011. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -94,7 +94,7 @@ new(Parent,Message)
new(Parent,Message, []).
%% @spec (Parent::wxWindow:wxWindow(), Message::string(), [Option]) -> wxPasswordEntryDialog()
-%% Option = {caption, string()} | {value, string()} | {style, integer()} | {pos, {X::integer(),Y::integer()}}
+%% Option = {caption, string()} | {value, string()} | {style, integer()} | {pos, {X::integer(), Y::integer()}}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxpasswordentrydialog.html#wxpasswordentrydialogwxpasswordentrydialog">external documentation</a>.
new(#wx_ref{type=ParentT,ref=ParentRef},Message, Options)
when is_list(Message),is_list(Options) ->
diff --git a/lib/wx/src/gen/wxPreviewControlBar.erl b/lib/wx/src/gen/wxPreviewControlBar.erl
index 78d46d1b95..e85af625e2 100644
--- a/lib/wx/src/gen/wxPreviewControlBar.erl
+++ b/lib/wx/src/gen/wxPreviewControlBar.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2010. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2011. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -83,7 +83,7 @@ new(Preview,Buttons,Parent)
new(Preview,Buttons,Parent, []).
%% @spec (Preview::wxPrintPreview:wxPrintPreview(), Buttons::integer(), Parent::wxWindow:wxWindow(), [Option]) -> wxPreviewControlBar()
-%% Option = {pos, {X::integer(),Y::integer()}} | {size, {W::integer(),H::integer()}} | {style, integer()}
+%% Option = {pos, {X::integer(), Y::integer()}} | {size, {W::integer(), H::integer()}} | {style, integer()}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxpreviewcontrolbar.html#wxpreviewcontrolbarwxpreviewcontrolbar">external documentation</a>.
new(#wx_ref{type=PreviewT,ref=PreviewRef},Buttons,#wx_ref{type=ParentT,ref=ParentRef}, Options)
when is_integer(Buttons),is_list(Options) ->
diff --git a/lib/wx/src/gen/wxPreviewFrame.erl b/lib/wx/src/gen/wxPreviewFrame.erl
index 91a32e9889..da43f86030 100644
--- a/lib/wx/src/gen/wxPreviewFrame.erl
+++ b/lib/wx/src/gen/wxPreviewFrame.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2010. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2011. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -95,7 +95,7 @@ new(Preview,Parent)
new(Preview,Parent, []).
%% @spec (Preview::wxPrintPreview:wxPrintPreview(), Parent::wxWindow:wxWindow(), [Option]) -> wxPreviewFrame()
-%% Option = {title, string()} | {pos, {X::integer(),Y::integer()}} | {size, {W::integer(),H::integer()}} | {style, integer()}
+%% Option = {title, string()} | {pos, {X::integer(), Y::integer()}} | {size, {W::integer(), H::integer()}} | {style, integer()}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxpreviewframe.html#wxpreviewframewxpreviewframe">external documentation</a>.
new(#wx_ref{type=PreviewT,ref=PreviewRef},#wx_ref{type=ParentT,ref=ParentRef}, Options)
when is_list(Options) ->
diff --git a/lib/wx/src/gen/wxPrintout.erl b/lib/wx/src/gen/wxPrintout.erl
index b5b93921e6..a34c030275 100644
--- a/lib/wx/src/gen/wxPrintout.erl
+++ b/lib/wx/src/gen/wxPrintout.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2010. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2011. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -125,35 +125,35 @@ getDC(#wx_ref{type=ThisT,ref=ThisRef}) ->
wxe_util:call(?wxPrintout_GetDC,
<<ThisRef:32/?UI>>).
-%% @spec (This::wxPrintout()) -> {W::integer(),H::integer()}
+%% @spec (This::wxPrintout()) -> {W::integer(), H::integer()}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxprintout.html#wxprintoutgetpagesizemm">external documentation</a>.
getPageSizeMM(#wx_ref{type=ThisT,ref=ThisRef}) ->
?CLASS(ThisT,wxPrintout),
wxe_util:call(?wxPrintout_GetPageSizeMM,
<<ThisRef:32/?UI>>).
-%% @spec (This::wxPrintout()) -> {W::integer(),H::integer()}
+%% @spec (This::wxPrintout()) -> {W::integer(), H::integer()}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxprintout.html#wxprintoutgetpagesizepixels">external documentation</a>.
getPageSizePixels(#wx_ref{type=ThisT,ref=ThisRef}) ->
?CLASS(ThisT,wxPrintout),
wxe_util:call(?wxPrintout_GetPageSizePixels,
<<ThisRef:32/?UI>>).
-%% @spec (This::wxPrintout()) -> {X::integer(),Y::integer(),W::integer(),H::integer()}
+%% @spec (This::wxPrintout()) -> {X::integer(), Y::integer(), W::integer(), H::integer()}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxprintout.html#wxprintoutgetpaperrectpixels">external documentation</a>.
getPaperRectPixels(#wx_ref{type=ThisT,ref=ThisRef}) ->
?CLASS(ThisT,wxPrintout),
wxe_util:call(?wxPrintout_GetPaperRectPixels,
<<ThisRef:32/?UI>>).
-%% @spec (This::wxPrintout()) -> {X::integer(),Y::integer()}
+%% @spec (This::wxPrintout()) -> {X::integer(), Y::integer()}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxprintout.html#wxprintoutgetppiprinter">external documentation</a>.
getPPIPrinter(#wx_ref{type=ThisT,ref=ThisRef}) ->
?CLASS(ThisT,wxPrintout),
wxe_util:call(?wxPrintout_GetPPIPrinter,
<<ThisRef:32/?UI>>).
-%% @spec (This::wxPrintout()) -> {X::integer(),Y::integer()}
+%% @spec (This::wxPrintout()) -> {X::integer(), Y::integer()}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxprintout.html#wxprintoutgetppiscreen">external documentation</a>.
getPPIScreen(#wx_ref{type=ThisT,ref=ThisRef}) ->
?CLASS(ThisT,wxPrintout),
@@ -174,7 +174,7 @@ isPreview(#wx_ref{type=ThisT,ref=ThisRef}) ->
wxe_util:call(?wxPrintout_IsPreview,
<<ThisRef:32/?UI>>).
-%% @spec (This::wxPrintout(), ImageSize::{W::integer(),H::integer()}) -> ok
+%% @spec (This::wxPrintout(), ImageSize::{W::integer(), H::integer()}) -> ok
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxprintout.html#wxprintoutfitthissizetopaper">external documentation</a>.
fitThisSizeToPaper(#wx_ref{type=ThisT,ref=ThisRef},{ImageSizeW,ImageSizeH})
when is_integer(ImageSizeW),is_integer(ImageSizeH) ->
@@ -182,7 +182,7 @@ fitThisSizeToPaper(#wx_ref{type=ThisT,ref=ThisRef},{ImageSizeW,ImageSizeH})
wxe_util:cast(?wxPrintout_FitThisSizeToPaper,
<<ThisRef:32/?UI,ImageSizeW:32/?UI,ImageSizeH:32/?UI>>).
-%% @spec (This::wxPrintout(), ImageSize::{W::integer(),H::integer()}) -> ok
+%% @spec (This::wxPrintout(), ImageSize::{W::integer(), H::integer()}) -> ok
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxprintout.html#wxprintoutfitthissizetopage">external documentation</a>.
fitThisSizeToPage(#wx_ref{type=ThisT,ref=ThisRef},{ImageSizeW,ImageSizeH})
when is_integer(ImageSizeW),is_integer(ImageSizeH) ->
@@ -190,7 +190,7 @@ fitThisSizeToPage(#wx_ref{type=ThisT,ref=ThisRef},{ImageSizeW,ImageSizeH})
wxe_util:cast(?wxPrintout_FitThisSizeToPage,
<<ThisRef:32/?UI,ImageSizeW:32/?UI,ImageSizeH:32/?UI>>).
-%% @spec (This::wxPrintout(), ImageSize::{W::integer(),H::integer()}, PageSetupData::wxPageSetupDialogData:wxPageSetupDialogData()) -> ok
+%% @spec (This::wxPrintout(), ImageSize::{W::integer(), H::integer()}, PageSetupData::wxPageSetupDialogData:wxPageSetupDialogData()) -> ok
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxprintout.html#wxprintoutfitthissizetopagemargins">external documentation</a>.
fitThisSizeToPageMargins(#wx_ref{type=ThisT,ref=ThisRef},{ImageSizeW,ImageSizeH},#wx_ref{type=PageSetupDataT,ref=PageSetupDataRef})
when is_integer(ImageSizeW),is_integer(ImageSizeH) ->
@@ -228,21 +228,21 @@ mapScreenSizeToDevice(#wx_ref{type=ThisT,ref=ThisRef}) ->
wxe_util:cast(?wxPrintout_MapScreenSizeToDevice,
<<ThisRef:32/?UI>>).
-%% @spec (This::wxPrintout()) -> {X::integer(),Y::integer(),W::integer(),H::integer()}
+%% @spec (This::wxPrintout()) -> {X::integer(), Y::integer(), W::integer(), H::integer()}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxprintout.html#wxprintoutgetlogicalpaperrect">external documentation</a>.
getLogicalPaperRect(#wx_ref{type=ThisT,ref=ThisRef}) ->
?CLASS(ThisT,wxPrintout),
wxe_util:call(?wxPrintout_GetLogicalPaperRect,
<<ThisRef:32/?UI>>).
-%% @spec (This::wxPrintout()) -> {X::integer(),Y::integer(),W::integer(),H::integer()}
+%% @spec (This::wxPrintout()) -> {X::integer(), Y::integer(), W::integer(), H::integer()}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxprintout.html#wxprintoutgetlogicalpagerect">external documentation</a>.
getLogicalPageRect(#wx_ref{type=ThisT,ref=ThisRef}) ->
?CLASS(ThisT,wxPrintout),
wxe_util:call(?wxPrintout_GetLogicalPageRect,
<<ThisRef:32/?UI>>).
-%% @spec (This::wxPrintout(), PageSetupData::wxPageSetupDialogData:wxPageSetupDialogData()) -> {X::integer(),Y::integer(),W::integer(),H::integer()}
+%% @spec (This::wxPrintout(), PageSetupData::wxPageSetupDialogData:wxPageSetupDialogData()) -> {X::integer(), Y::integer(), W::integer(), H::integer()}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxprintout.html#wxprintoutgetlogicalpagemarginsrect">external documentation</a>.
getLogicalPageMarginsRect(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=PageSetupDataT,ref=PageSetupDataRef}) ->
?CLASS(ThisT,wxPrintout),
diff --git a/lib/wx/src/gen/wxRadioBox.erl b/lib/wx/src/gen/wxRadioBox.erl
index 06e8833972..766a691108 100644
--- a/lib/wx/src/gen/wxRadioBox.erl
+++ b/lib/wx/src/gen/wxRadioBox.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2010. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2011. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -78,13 +78,13 @@ parent_class(wxWindow) -> true;
parent_class(wxEvtHandler) -> true;
parent_class(_Class) -> erlang:error({badtype, ?MODULE}).
-%% @spec (Parent::wxWindow:wxWindow(), Id::integer(), Title::string(), Pos::{X::integer(),Y::integer()}, Size::{W::integer(),H::integer()}, Choices::[[string()]]) -> wxRadioBox()
+%% @spec (Parent::wxWindow:wxWindow(), Id::integer(), Title::string(), Pos::{X::integer(), Y::integer()}, Size::{W::integer(), H::integer()}, Choices::[[string()]]) -> wxRadioBox()
%% @equiv new(Parent,Id,Title,Pos,Size,Choices, [])
new(Parent,Id,Title,Pos={PosX,PosY},Size={SizeW,SizeH},Choices)
when is_record(Parent, wx_ref),is_integer(Id),is_list(Title),is_integer(PosX),is_integer(PosY),is_integer(SizeW),is_integer(SizeH),is_list(Choices) ->
new(Parent,Id,Title,Pos,Size,Choices, []).
-%% @spec (Parent::wxWindow:wxWindow(), Id::integer(), Title::string(), Pos::{X::integer(),Y::integer()}, Size::{W::integer(),H::integer()}, Choices::[[string()]], [Option]) -> wxRadioBox()
+%% @spec (Parent::wxWindow:wxWindow(), Id::integer(), Title::string(), Pos::{X::integer(), Y::integer()}, Size::{W::integer(), H::integer()}, Choices::[[string()]], [Option]) -> wxRadioBox()
%% Option = {majorDim, integer()} | {style, integer()} | {val, wx:wx()}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxradiobox.html#wxradioboxwxradiobox">external documentation</a>.
new(#wx_ref{type=ParentT,ref=ParentRef},Id,Title,{PosX,PosY},{SizeW,SizeH},Choices, Options)
@@ -101,13 +101,13 @@ new(#wx_ref{type=ParentT,ref=ParentRef},Id,Title,{PosX,PosY},{SizeW,SizeH},Choic
wxe_util:construct(?wxRadioBox_new,
<<ParentRef:32/?UI,Id:32/?UI,(byte_size(Title_UC)):32/?UI,(Title_UC)/binary, 0:(((8- ((4+byte_size(Title_UC)) band 16#7)) band 16#7))/unit:8,PosX:32/?UI,PosY:32/?UI,SizeW:32/?UI,SizeH:32/?UI,(length(Choices_UCA)):32/?UI, (<< <<(byte_size(UC_Str)):32/?UI, UC_Str/binary>>|| UC_Str <- Choices_UCA>>)/binary, 0:(((8- ((4 + lists:sum([byte_size(S)+4||S<-Choices_UCA])) band 16#7)) band 16#7))/unit:8, BinOpt/binary>>).
-%% @spec (This::wxRadioBox(), Parent::wxWindow:wxWindow(), Id::integer(), Title::string(), Pos::{X::integer(),Y::integer()}, Size::{W::integer(),H::integer()}, Choices::[[string()]]) -> bool()
+%% @spec (This::wxRadioBox(), Parent::wxWindow:wxWindow(), Id::integer(), Title::string(), Pos::{X::integer(), Y::integer()}, Size::{W::integer(), H::integer()}, Choices::[[string()]]) -> bool()
%% @equiv create(This,Parent,Id,Title,Pos,Size,Choices, [])
create(This,Parent,Id,Title,Pos={PosX,PosY},Size={SizeW,SizeH},Choices)
when is_record(This, wx_ref),is_record(Parent, wx_ref),is_integer(Id),is_list(Title),is_integer(PosX),is_integer(PosY),is_integer(SizeW),is_integer(SizeH),is_list(Choices) ->
create(This,Parent,Id,Title,Pos,Size,Choices, []).
-%% @spec (This::wxRadioBox(), Parent::wxWindow:wxWindow(), Id::integer(), Title::string(), Pos::{X::integer(),Y::integer()}, Size::{W::integer(),H::integer()}, Choices::[[string()]], [Option]) -> bool()
+%% @spec (This::wxRadioBox(), Parent::wxWindow:wxWindow(), Id::integer(), Title::string(), Pos::{X::integer(), Y::integer()}, Size::{W::integer(), H::integer()}, Choices::[[string()]], [Option]) -> bool()
%% Option = {majorDim, integer()} | {style, integer()} | {val, wx:wx()}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxradiobox.html#wxradioboxcreate">external documentation</a>.
create(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=ParentT,ref=ParentRef},Id,Title,{PosX,PosY},{SizeW,SizeH},Choices, Options)
@@ -251,7 +251,7 @@ getItemToolTip(#wx_ref{type=ThisT,ref=ThisRef},Item)
wxe_util:call(?wxRadioBox_GetItemToolTip,
<<ThisRef:32/?UI,Item:32/?UI>>).
-%% @spec (This::wxRadioBox(), Pt::{X::integer(),Y::integer()}) -> integer()
+%% @spec (This::wxRadioBox(), Pt::{X::integer(), Y::integer()}) -> integer()
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxradiobox.html#wxradioboxgetitemfrompoint">external documentation</a>.
getItemFromPoint(#wx_ref{type=ThisT,ref=ThisRef},{PtX,PtY})
when is_integer(PtX),is_integer(PtY) ->
diff --git a/lib/wx/src/gen/wxRadioButton.erl b/lib/wx/src/gen/wxRadioButton.erl
index c2c5a00be6..c4665837b5 100644
--- a/lib/wx/src/gen/wxRadioButton.erl
+++ b/lib/wx/src/gen/wxRadioButton.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2010. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2011. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -88,7 +88,7 @@ new(Parent,Id,Label)
new(Parent,Id,Label, []).
%% @spec (Parent::wxWindow:wxWindow(), Id::integer(), Label::string(), [Option]) -> wxRadioButton()
-%% Option = {pos, {X::integer(),Y::integer()}} | {size, {W::integer(),H::integer()}} | {style, integer()} | {validator, wx:wx()}
+%% Option = {pos, {X::integer(), Y::integer()}} | {size, {W::integer(), H::integer()}} | {style, integer()} | {validator, wx:wx()}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxradiobutton.html#wxradiobuttonwxradiobutton">external documentation</a>.
new(#wx_ref{type=ParentT,ref=ParentRef},Id,Label, Options)
when is_integer(Id),is_list(Label),is_list(Options) ->
@@ -110,7 +110,7 @@ create(This,Parent,Id,Label)
create(This,Parent,Id,Label, []).
%% @spec (This::wxRadioButton(), Parent::wxWindow:wxWindow(), Id::integer(), Label::string(), [Option]) -> bool()
-%% Option = {pos, {X::integer(),Y::integer()}} | {size, {W::integer(),H::integer()}} | {style, integer()} | {validator, wx:wx()}
+%% Option = {pos, {X::integer(), Y::integer()}} | {size, {W::integer(), H::integer()}} | {style, integer()} | {validator, wx:wx()}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxradiobutton.html#wxradiobuttoncreate">external documentation</a>.
create(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=ParentT,ref=ParentRef},Id,Label, Options)
when is_integer(Id),is_list(Label),is_list(Options) ->
diff --git a/lib/wx/src/gen/wxRegion.erl b/lib/wx/src/gen/wxRegion.erl
index 4e8d98a54f..9107a4d6b1 100644
--- a/lib/wx/src/gen/wxRegion.erl
+++ b/lib/wx/src/gen/wxRegion.erl
@@ -59,7 +59,7 @@ new({RectX,RectY,RectW,RectH})
wxe_util:construct(?wxRegion_new_1_1,
<<RectX:32/?UI,RectY:32/?UI,RectW:32/?UI,RectH:32/?UI>>).
-%% @spec (TopLeft::{X::integer(),Y::integer()}, BottomRight::{X::integer(),Y::integer()}) -> wxRegion()
+%% @spec (TopLeft::{X::integer(), Y::integer()}, BottomRight::{X::integer(), Y::integer()}) -> wxRegion()
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxregion.html#wxregionwxregion">external documentation</a>.
new({TopLeftX,TopLeftY},{BottomRightX,BottomRightY})
when is_integer(TopLeftX),is_integer(TopLeftY),is_integer(BottomRightX),is_integer(BottomRightY) ->
@@ -84,12 +84,12 @@ clear(#wx_ref{type=ThisT,ref=ThisRef}) ->
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxregion.html#wxregioncontains">external documentation</a>.
%% <br /> Alternatives:
%% <p><c>
-%% contains(This::wxRegion(), Pt::{X::integer(),Y::integer()}) -> WxRegionContain </c>
+%% contains(This::wxRegion(), Pt::{X::integer(), Y::integer()}) -> WxRegionContain </c>
%%<br /> WxRegionContain = integer()
%%<br /> WxRegionContain is one of ?wxOutRegion | ?wxPartRegion | ?wxInRegion
%% </p>
%% <p><c>
-%% contains(This::wxRegion(), Rect::{X::integer(),Y::integer(),W::integer(),H::integer()}) -> WxRegionContain </c>
+%% contains(This::wxRegion(), Rect::{X::integer(), Y::integer(), W::integer(), H::integer()}) -> WxRegionContain </c>
%%<br /> WxRegionContain = integer()
%%<br /> WxRegionContain is one of ?wxOutRegion | ?wxPartRegion | ?wxInRegion
%% </p>
@@ -131,7 +131,7 @@ convertToBitmap(#wx_ref{type=ThisT,ref=ThisRef}) ->
wxe_util:call(?wxRegion_ConvertToBitmap,
<<ThisRef:32/?UI>>).
-%% @spec (This::wxRegion()) -> {X::integer(),Y::integer(),W::integer(),H::integer()}
+%% @spec (This::wxRegion()) -> {X::integer(), Y::integer(), W::integer(), H::integer()}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxregion.html#wxregiongetbox">external documentation</a>.
getBox(#wx_ref{type=ThisT,ref=ThisRef}) ->
?CLASS(ThisT,wxRegion),
@@ -145,7 +145,7 @@ getBox(#wx_ref{type=ThisT,ref=ThisRef}) ->
%% intersect(This::wxRegion(), Region::wxRegion()) -> bool() </c>
%% </p>
%% <p><c>
-%% intersect(This::wxRegion(), Rect::{X::integer(),Y::integer(),W::integer(),H::integer()}) -> bool() </c>
+%% intersect(This::wxRegion(), Rect::{X::integer(), Y::integer(), W::integer(), H::integer()}) -> bool() </c>
%% </p>
intersect(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=RegionT,ref=RegionRef}) ->
?CLASS(ThisT,wxRegion),
@@ -180,7 +180,7 @@ isEmpty(#wx_ref{type=ThisT,ref=ThisRef}) ->
%% subtract(This::wxRegion(), Region::wxRegion()) -> bool() </c>
%% </p>
%% <p><c>
-%% subtract(This::wxRegion(), Rect::{X::integer(),Y::integer(),W::integer(),H::integer()}) -> bool() </c>
+%% subtract(This::wxRegion(), Rect::{X::integer(), Y::integer(), W::integer(), H::integer()}) -> bool() </c>
%% </p>
subtract(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=RegionT,ref=RegionRef}) ->
?CLASS(ThisT,wxRegion),
@@ -201,7 +201,7 @@ subtract(#wx_ref{type=ThisT,ref=ThisRef},X,Y,W,H)
wxe_util:call(?wxRegion_Subtract_4,
<<ThisRef:32/?UI,X:32/?UI,Y:32/?UI,W:32/?UI,H:32/?UI>>).
-%% @spec (This::wxRegion(), Pt::{X::integer(),Y::integer()}) -> bool()
+%% @spec (This::wxRegion(), Pt::{X::integer(), Y::integer()}) -> bool()
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxregion.html#wxregionoffset">external documentation</a>.
offset(#wx_ref{type=ThisT,ref=ThisRef},{PtX,PtY})
when is_integer(PtX),is_integer(PtY) ->
@@ -224,7 +224,7 @@ offset(#wx_ref{type=ThisT,ref=ThisRef},X,Y)
%% union(This::wxRegion(), Region::wxRegion() | wxBitmap:wxBitmap()) -> bool() </c>
%% </p>
%% <p><c>
-%% union(This::wxRegion(), Rect::{X::integer(),Y::integer(),W::integer(),H::integer()}) -> bool() </c>
+%% union(This::wxRegion(), Rect::{X::integer(), Y::integer(), W::integer(), H::integer()}) -> bool() </c>
%% </p>
union(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=RegionT,ref=RegionRef}) ->
?CLASS(ThisT,wxRegion),
@@ -276,7 +276,7 @@ union(#wx_ref{type=ThisT,ref=ThisRef},X,Y,W,H)
%% 'Xor'(This::wxRegion(), Region::wxRegion()) -> bool() </c>
%% </p>
%% <p><c>
-%% 'Xor'(This::wxRegion(), Rect::{X::integer(),Y::integer(),W::integer(),H::integer()}) -> bool() </c>
+%% 'Xor'(This::wxRegion(), Rect::{X::integer(), Y::integer(), W::integer(), H::integer()}) -> bool() </c>
%% </p>
'Xor'(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=RegionT,ref=RegionRef}) ->
?CLASS(ThisT,wxRegion),
diff --git a/lib/wx/src/gen/wxSashEvent.erl b/lib/wx/src/gen/wxSashEvent.erl
index 480e241807..f9c58a04b1 100644
--- a/lib/wx/src/gen/wxSashEvent.erl
+++ b/lib/wx/src/gen/wxSashEvent.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2010. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2011. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -54,7 +54,7 @@ getEdge(#wx_ref{type=ThisT,ref=ThisRef}) ->
wxe_util:call(?wxSashEvent_GetEdge,
<<ThisRef:32/?UI>>).
-%% @spec (This::wxSashEvent()) -> {X::integer(),Y::integer(),W::integer(),H::integer()}
+%% @spec (This::wxSashEvent()) -> {X::integer(), Y::integer(), W::integer(), H::integer()}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxsashevent.html#wxsasheventgetdragrect">external documentation</a>.
getDragRect(#wx_ref{type=ThisT,ref=ThisRef}) ->
?CLASS(ThisT,wxSashEvent),
diff --git a/lib/wx/src/gen/wxSashLayoutWindow.erl b/lib/wx/src/gen/wxSashLayoutWindow.erl
index 9bc5a185ba..eb8eb38011 100644
--- a/lib/wx/src/gen/wxSashLayoutWindow.erl
+++ b/lib/wx/src/gen/wxSashLayoutWindow.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2010. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2011. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -93,7 +93,7 @@ new(Parent)
new(Parent, []).
%% @spec (Parent::wxWindow:wxWindow(), [Option]) -> wxSashLayoutWindow()
-%% Option = {id, integer()} | {pos, {X::integer(),Y::integer()}} | {size, {W::integer(),H::integer()}} | {style, integer()}
+%% Option = {id, integer()} | {pos, {X::integer(), Y::integer()}} | {size, {W::integer(), H::integer()}} | {style, integer()}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxsashlayoutwindow.html#wxsashlayoutwindowwxsashlayoutwindow">external documentation</a>.
new(#wx_ref{type=ParentT,ref=ParentRef}, Options)
when is_list(Options) ->
@@ -114,7 +114,7 @@ create(This,Parent)
create(This,Parent, []).
%% @spec (This::wxSashLayoutWindow(), Parent::wxWindow:wxWindow(), [Option]) -> bool()
-%% Option = {id, integer()} | {pos, {X::integer(),Y::integer()}} | {size, {W::integer(),H::integer()}} | {style, integer()}
+%% Option = {id, integer()} | {pos, {X::integer(), Y::integer()}} | {size, {W::integer(), H::integer()}} | {style, integer()}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxsashlayoutwindow.html#wxsashlayoutwindowcreate">external documentation</a>.
create(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=ParentT,ref=ParentRef}, Options)
when is_list(Options) ->
@@ -157,7 +157,7 @@ setAlignment(#wx_ref{type=ThisT,ref=ThisRef},Align)
wxe_util:cast(?wxSashLayoutWindow_SetAlignment,
<<ThisRef:32/?UI,Align:32/?UI>>).
-%% @spec (This::wxSashLayoutWindow(), Size::{W::integer(),H::integer()}) -> ok
+%% @spec (This::wxSashLayoutWindow(), Size::{W::integer(), H::integer()}) -> ok
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxsashlayoutwindow.html#wxsashlayoutwindowsetdefaultsize">external documentation</a>.
setDefaultSize(#wx_ref{type=ThisT,ref=ThisRef},{SizeW,SizeH})
when is_integer(SizeW),is_integer(SizeH) ->
diff --git a/lib/wx/src/gen/wxSashWindow.erl b/lib/wx/src/gen/wxSashWindow.erl
index 49fb82f828..698cfb8fb6 100644
--- a/lib/wx/src/gen/wxSashWindow.erl
+++ b/lib/wx/src/gen/wxSashWindow.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2010. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2011. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -88,7 +88,7 @@ new(Parent)
new(Parent, []).
%% @spec (Parent::wxWindow:wxWindow(), [Option]) -> wxSashWindow()
-%% Option = {id, integer()} | {pos, {X::integer(),Y::integer()}} | {size, {W::integer(),H::integer()}} | {style, integer()}
+%% Option = {id, integer()} | {pos, {X::integer(), Y::integer()}} | {size, {W::integer(), H::integer()}} | {style, integer()}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxsashwindow.html#wxsashwindowwxsashwindow">external documentation</a>.
new(#wx_ref{type=ParentT,ref=ParentRef}, Options)
when is_list(Options) ->
diff --git a/lib/wx/src/gen/wxScrollBar.erl b/lib/wx/src/gen/wxScrollBar.erl
index 41ca8d867f..5c7890009f 100644
--- a/lib/wx/src/gen/wxScrollBar.erl
+++ b/lib/wx/src/gen/wxScrollBar.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2010. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2011. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -89,7 +89,7 @@ new(Parent,Id)
new(Parent,Id, []).
%% @spec (Parent::wxWindow:wxWindow(), Id::integer(), [Option]) -> wxScrollBar()
-%% Option = {pos, {X::integer(),Y::integer()}} | {size, {W::integer(),H::integer()}} | {style, integer()} | {validator, wx:wx()}
+%% Option = {pos, {X::integer(), Y::integer()}} | {size, {W::integer(), H::integer()}} | {style, integer()} | {validator, wx:wx()}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxscrollbar.html#wxscrollbarwxscrollbar">external documentation</a>.
new(#wx_ref{type=ParentT,ref=ParentRef},Id, Options)
when is_integer(Id),is_list(Options) ->
@@ -110,7 +110,7 @@ create(This,Parent,Id)
create(This,Parent,Id, []).
%% @spec (This::wxScrollBar(), Parent::wxWindow:wxWindow(), Id::integer(), [Option]) -> bool()
-%% Option = {pos, {X::integer(),Y::integer()}} | {size, {W::integer(),H::integer()}} | {style, integer()} | {validator, wx:wx()}
+%% Option = {pos, {X::integer(), Y::integer()}} | {size, {W::integer(), H::integer()}} | {style, integer()} | {validator, wx:wx()}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxscrollbar.html#wxscrollbarcreate">external documentation</a>.
create(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=ParentT,ref=ParentRef},Id, Options)
when is_integer(Id),is_list(Options) ->
diff --git a/lib/wx/src/gen/wxScrolledWindow.erl b/lib/wx/src/gen/wxScrolledWindow.erl
index a6f813d1a2..0693a79760 100644
--- a/lib/wx/src/gen/wxScrolledWindow.erl
+++ b/lib/wx/src/gen/wxScrolledWindow.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2010. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2011. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -91,7 +91,7 @@ new(Parent)
new(Parent, []).
%% @spec (Parent::wxWindow:wxWindow(), [Option]) -> wxScrolledWindow()
-%% Option = {winid, integer()} | {pos, {X::integer(),Y::integer()}} | {size, {W::integer(),H::integer()}} | {style, integer()}
+%% Option = {winid, integer()} | {pos, {X::integer(), Y::integer()}} | {size, {W::integer(), H::integer()}} | {style, integer()}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxscrolledwindow.html#wxscrolledwindowwxscrolledwindow">external documentation</a>.
new(#wx_ref{type=ParentT,ref=ParentRef}, Options)
when is_list(Options) ->
@@ -105,7 +105,7 @@ new(#wx_ref{type=ParentT,ref=ParentRef}, Options)
wxe_util:construct(?wxScrolledWindow_new_2,
<<ParentRef:32/?UI, 0:32,BinOpt/binary>>).
-%% @spec (This::wxScrolledWindow(), Pt::{X::integer(),Y::integer()}) -> {X::integer(),Y::integer()}
+%% @spec (This::wxScrolledWindow(), Pt::{X::integer(), Y::integer()}) -> {X::integer(), Y::integer()}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxscrolledwindow.html#wxscrolledwindowcalcscrolledposition">external documentation</a>.
calcScrolledPosition(#wx_ref{type=ThisT,ref=ThisRef},{PtX,PtY})
when is_integer(PtX),is_integer(PtY) ->
@@ -113,7 +113,7 @@ calcScrolledPosition(#wx_ref{type=ThisT,ref=ThisRef},{PtX,PtY})
wxe_util:call(?wxScrolledWindow_CalcScrolledPosition_1,
<<ThisRef:32/?UI,PtX:32/?UI,PtY:32/?UI>>).
-%% @spec (This::wxScrolledWindow(), X::integer(), Y::integer()) -> {Xx::integer(),Yy::integer()}
+%% @spec (This::wxScrolledWindow(), X::integer(), Y::integer()) -> {Xx::integer(), Yy::integer()}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxscrolledwindow.html#wxscrolledwindowcalcscrolledposition">external documentation</a>.
calcScrolledPosition(#wx_ref{type=ThisT,ref=ThisRef},X,Y)
when is_integer(X),is_integer(Y) ->
@@ -121,7 +121,7 @@ calcScrolledPosition(#wx_ref{type=ThisT,ref=ThisRef},X,Y)
wxe_util:call(?wxScrolledWindow_CalcScrolledPosition_4,
<<ThisRef:32/?UI,X:32/?UI,Y:32/?UI>>).
-%% @spec (This::wxScrolledWindow(), Pt::{X::integer(),Y::integer()}) -> {X::integer(),Y::integer()}
+%% @spec (This::wxScrolledWindow(), Pt::{X::integer(), Y::integer()}) -> {X::integer(), Y::integer()}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxscrolledwindow.html#wxscrolledwindowcalcunscrolledposition">external documentation</a>.
calcUnscrolledPosition(#wx_ref{type=ThisT,ref=ThisRef},{PtX,PtY})
when is_integer(PtX),is_integer(PtY) ->
@@ -129,7 +129,7 @@ calcUnscrolledPosition(#wx_ref{type=ThisT,ref=ThisRef},{PtX,PtY})
wxe_util:call(?wxScrolledWindow_CalcUnscrolledPosition_1,
<<ThisRef:32/?UI,PtX:32/?UI,PtY:32/?UI>>).
-%% @spec (This::wxScrolledWindow(), X::integer(), Y::integer()) -> {Xx::integer(),Yy::integer()}
+%% @spec (This::wxScrolledWindow(), X::integer(), Y::integer()) -> {Xx::integer(), Yy::integer()}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxscrolledwindow.html#wxscrolledwindowcalcunscrolledposition">external documentation</a>.
calcUnscrolledPosition(#wx_ref{type=ThisT,ref=ThisRef},X,Y)
when is_integer(X),is_integer(Y) ->
@@ -145,14 +145,14 @@ enableScrolling(#wx_ref{type=ThisT,ref=ThisRef},X_scrolling,Y_scrolling)
wxe_util:cast(?wxScrolledWindow_EnableScrolling,
<<ThisRef:32/?UI,(wxe_util:from_bool(X_scrolling)):32/?UI,(wxe_util:from_bool(Y_scrolling)):32/?UI>>).
-%% @spec (This::wxScrolledWindow()) -> {PixelsPerUnitX::integer(),PixelsPerUnitY::integer()}
+%% @spec (This::wxScrolledWindow()) -> {PixelsPerUnitX::integer(), PixelsPerUnitY::integer()}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxscrolledwindow.html#wxscrolledwindowgetscrollpixelsperunit">external documentation</a>.
getScrollPixelsPerUnit(#wx_ref{type=ThisT,ref=ThisRef}) ->
?CLASS(ThisT,wxScrolledWindow),
wxe_util:call(?wxScrolledWindow_GetScrollPixelsPerUnit,
<<ThisRef:32/?UI>>).
-%% @spec (This::wxScrolledWindow()) -> {X::integer(),Y::integer()}
+%% @spec (This::wxScrolledWindow()) -> {X::integer(), Y::integer()}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxscrolledwindow.html#wxscrolledwindowgetviewstart">external documentation</a>.
getViewStart(#wx_ref{type=ThisT,ref=ThisRef}) ->
?CLASS(ThisT,wxScrolledWindow),
diff --git a/lib/wx/src/gen/wxSingleChoiceDialog.erl b/lib/wx/src/gen/wxSingleChoiceDialog.erl
index 16e0c3d8ce..e2b835917e 100644
--- a/lib/wx/src/gen/wxSingleChoiceDialog.erl
+++ b/lib/wx/src/gen/wxSingleChoiceDialog.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2010. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2011. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -97,7 +97,7 @@ new(Parent,Message,Caption,Choices)
new(Parent,Message,Caption,Choices, []).
%% @spec (Parent::wxWindow:wxWindow(), Message::string(), Caption::string(), Choices::[[string()]], [Option]) -> wxSingleChoiceDialog()
-%% Option = {style, integer()} | {pos, {X::integer(),Y::integer()}}
+%% Option = {style, integer()} | {pos, {X::integer(), Y::integer()}}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxsinglechoicedialog.html#wxsinglechoicedialogwxsinglechoicedialog">external documentation</a>.
new(#wx_ref{type=ParentT,ref=ParentRef},Message,Caption,Choices, Options)
when is_list(Message),is_list(Caption),is_list(Choices),is_list(Options) ->
diff --git a/lib/wx/src/gen/wxSizeEvent.erl b/lib/wx/src/gen/wxSizeEvent.erl
index 9e7619ebbd..0898f4aed9 100644
--- a/lib/wx/src/gen/wxSizeEvent.erl
+++ b/lib/wx/src/gen/wxSizeEvent.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2010. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2011. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -41,7 +41,7 @@
parent_class(wxEvent) -> true;
parent_class(_Class) -> erlang:error({badtype, ?MODULE}).
-%% @spec (This::wxSizeEvent()) -> {W::integer(),H::integer()}
+%% @spec (This::wxSizeEvent()) -> {W::integer(), H::integer()}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxsizeevent.html#wxsizeeventgetsize">external documentation</a>.
getSize(#wx_ref{type=ThisT,ref=ThisRef}) ->
?CLASS(ThisT,wxSizeEvent),
diff --git a/lib/wx/src/gen/wxSizer.erl b/lib/wx/src/gen/wxSizer.erl
index e9b83a7333..0f1a92f379 100644
--- a/lib/wx/src/gen/wxSizer.erl
+++ b/lib/wx/src/gen/wxSizer.erl
@@ -132,7 +132,7 @@ addStretchSpacer(#wx_ref{type=ThisT,ref=ThisRef}, Options)
wxe_util:call(?wxSizer_AddStretchSpacer,
<<ThisRef:32/?UI, 0:32,BinOpt/binary>>).
-%% @spec (This::wxSizer()) -> {W::integer(),H::integer()}
+%% @spec (This::wxSizer()) -> {W::integer(), H::integer()}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxsizer.html#wxsizercalcmin">external documentation</a>.
calcMin(#wx_ref{type=ThisT,ref=ThisRef}) ->
?CLASS(ThisT,wxSizer),
@@ -182,7 +182,7 @@ detach(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=WindowT,ref=WindowRef}) ->
wxe_util:call(WindowOP,
<<ThisRef:32/?UI,WindowRef:32/?UI>>).
-%% @spec (This::wxSizer(), Window::wxWindow:wxWindow()) -> {W::integer(),H::integer()}
+%% @spec (This::wxSizer(), Window::wxWindow:wxWindow()) -> {W::integer(), H::integer()}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxsizer.html#wxsizerfit">external documentation</a>.
fit(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=WindowT,ref=WindowRef}) ->
?CLASS(ThisT,wxSizer),
@@ -241,21 +241,21 @@ getItem(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=WindowT,ref=WindowRef}, Opt
wxe_util:call(WindowOP,
<<ThisRef:32/?UI,WindowRef:32/?UI, BinOpt/binary>>).
-%% @spec (This::wxSizer()) -> {W::integer(),H::integer()}
+%% @spec (This::wxSizer()) -> {W::integer(), H::integer()}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxsizer.html#wxsizergetsize">external documentation</a>.
getSize(#wx_ref{type=ThisT,ref=ThisRef}) ->
?CLASS(ThisT,wxSizer),
wxe_util:call(?wxSizer_GetSize,
<<ThisRef:32/?UI>>).
-%% @spec (This::wxSizer()) -> {X::integer(),Y::integer()}
+%% @spec (This::wxSizer()) -> {X::integer(), Y::integer()}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxsizer.html#wxsizergetposition">external documentation</a>.
getPosition(#wx_ref{type=ThisT,ref=ThisRef}) ->
?CLASS(ThisT,wxSizer),
wxe_util:call(?wxSizer_GetPosition,
<<ThisRef:32/?UI>>).
-%% @spec (This::wxSizer()) -> {W::integer(),H::integer()}
+%% @spec (This::wxSizer()) -> {W::integer(), H::integer()}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxsizer.html#wxsizergetminsize">external documentation</a>.
getMinSize(#wx_ref{type=ThisT,ref=ThisRef}) ->
?CLASS(ThisT,wxSizer),
@@ -596,7 +596,7 @@ setDimension(#wx_ref{type=ThisT,ref=ThisRef},X,Y,Width,Height)
wxe_util:cast(?wxSizer_SetDimension,
<<ThisRef:32/?UI,X:32/?UI,Y:32/?UI,Width:32/?UI,Height:32/?UI>>).
-%% @spec (This::wxSizer(), Size::{W::integer(),H::integer()}) -> ok
+%% @spec (This::wxSizer(), Size::{W::integer(), H::integer()}) -> ok
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxsizer.html#wxsizersetminsize">external documentation</a>.
setMinSize(#wx_ref{type=ThisT,ref=ThisRef},{SizeW,SizeH})
when is_integer(SizeW),is_integer(SizeH) ->
@@ -612,14 +612,14 @@ setMinSize(#wx_ref{type=ThisT,ref=ThisRef},Width,Height)
wxe_util:cast(?wxSizer_SetMinSize_2,
<<ThisRef:32/?UI,Width:32/?UI,Height:32/?UI>>).
-%% @spec (This::wxSizer(),X::integer()|term(),Size::{W::integer(),H::integer()}) -> bool()
+%% @spec (This::wxSizer(),X::integer()|term(),Size::{W::integer(), H::integer()}) -> bool()
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxsizer.html#wxsizersetitemminsize">external documentation</a>.
%% <br /> Alternatives:
%% <p><c>
-%% setItemMinSize(This::wxSizer(), Index::integer(), Size::{W::integer(),H::integer()}) -> bool() </c>
+%% setItemMinSize(This::wxSizer(), Index::integer(), Size::{W::integer(), H::integer()}) -> bool() </c>
%% </p>
%% <p><c>
-%% setItemMinSize(This::wxSizer(), Window::wxWindow:wxWindow() | wxSizer(), Size::{W::integer(),H::integer()}) -> bool() </c>
+%% setItemMinSize(This::wxSizer(), Window::wxWindow:wxWindow() | wxSizer(), Size::{W::integer(), H::integer()}) -> bool() </c>
%% </p>
setItemMinSize(#wx_ref{type=ThisT,ref=ThisRef},Index,{SizeW,SizeH})
when is_integer(Index),is_integer(SizeW),is_integer(SizeH) ->
diff --git a/lib/wx/src/gen/wxSizerItem.erl b/lib/wx/src/gen/wxSizerItem.erl
index 1e9f05d53c..41cb86eae2 100644
--- a/lib/wx/src/gen/wxSizerItem.erl
+++ b/lib/wx/src/gen/wxSizerItem.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2010. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2011. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -89,7 +89,7 @@ new(Width,Height,Proportion,Flag,Border,#wx_ref{type=UserDataT,ref=UserDataRef})
wxe_util:construct(?wxSizerItem_new_6,
<<Width:32/?UI,Height:32/?UI,Proportion:32/?UI,Flag:32/?UI,Border:32/?UI,UserDataRef:32/?UI>>).
-%% @spec (This::wxSizerItem()) -> {W::integer(),H::integer()}
+%% @spec (This::wxSizerItem()) -> {W::integer(), H::integer()}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxsizeritem.html#wxsizeritemcalcmin">external documentation</a>.
calcMin(#wx_ref{type=ThisT,ref=ThisRef}) ->
?CLASS(ThisT,wxSizerItem),
@@ -124,14 +124,14 @@ getFlag(#wx_ref{type=ThisT,ref=ThisRef}) ->
wxe_util:call(?wxSizerItem_GetFlag,
<<ThisRef:32/?UI>>).
-%% @spec (This::wxSizerItem()) -> {W::integer(),H::integer()}
+%% @spec (This::wxSizerItem()) -> {W::integer(), H::integer()}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxsizeritem.html#wxsizeritemgetminsize">external documentation</a>.
getMinSize(#wx_ref{type=ThisT,ref=ThisRef}) ->
?CLASS(ThisT,wxSizerItem),
wxe_util:call(?wxSizerItem_GetMinSize,
<<ThisRef:32/?UI>>).
-%% @spec (This::wxSizerItem()) -> {X::integer(),Y::integer()}
+%% @spec (This::wxSizerItem()) -> {X::integer(), Y::integer()}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxsizeritem.html#wxsizeritemgetposition">external documentation</a>.
getPosition(#wx_ref{type=ThisT,ref=ThisRef}) ->
?CLASS(ThisT,wxSizerItem),
@@ -152,14 +152,14 @@ getRatio(#wx_ref{type=ThisT,ref=ThisRef}) ->
wxe_util:call(?wxSizerItem_GetRatio,
<<ThisRef:32/?UI>>).
-%% @spec (This::wxSizerItem()) -> {X::integer(),Y::integer(),W::integer(),H::integer()}
+%% @spec (This::wxSizerItem()) -> {X::integer(), Y::integer(), W::integer(), H::integer()}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxsizeritem.html#wxsizeritemgetrect">external documentation</a>.
getRect(#wx_ref{type=ThisT,ref=ThisRef}) ->
?CLASS(ThisT,wxSizerItem),
wxe_util:call(?wxSizerItem_GetRect,
<<ThisRef:32/?UI>>).
-%% @spec (This::wxSizerItem()) -> {W::integer(),H::integer()}
+%% @spec (This::wxSizerItem()) -> {W::integer(), H::integer()}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxsizeritem.html#wxsizeritemgetsize">external documentation</a>.
getSize(#wx_ref{type=ThisT,ref=ThisRef}) ->
?CLASS(ThisT,wxSizerItem),
@@ -173,7 +173,7 @@ getSizer(#wx_ref{type=ThisT,ref=ThisRef}) ->
wxe_util:call(?wxSizerItem_GetSizer,
<<ThisRef:32/?UI>>).
-%% @spec (This::wxSizerItem()) -> {W::integer(),H::integer()}
+%% @spec (This::wxSizerItem()) -> {W::integer(), H::integer()}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxsizeritem.html#wxsizeritemgetspacer">external documentation</a>.
getSpacer(#wx_ref{type=ThisT,ref=ThisRef}) ->
?CLASS(ThisT,wxSizerItem),
@@ -230,7 +230,7 @@ setBorder(#wx_ref{type=ThisT,ref=ThisRef},Border)
wxe_util:cast(?wxSizerItem_SetBorder,
<<ThisRef:32/?UI,Border:32/?UI>>).
-%% @spec (This::wxSizerItem(), Pos::{X::integer(),Y::integer()}, Size::{W::integer(),H::integer()}) -> ok
+%% @spec (This::wxSizerItem(), Pos::{X::integer(), Y::integer()}, Size::{W::integer(), H::integer()}) -> ok
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxsizeritem.html#wxsizeritemsetdimension">external documentation</a>.
setDimension(#wx_ref{type=ThisT,ref=ThisRef},{PosX,PosY},{SizeW,SizeH})
when is_integer(PosX),is_integer(PosY),is_integer(SizeW),is_integer(SizeH) ->
@@ -254,7 +254,7 @@ setInitSize(#wx_ref{type=ThisT,ref=ThisRef},X,Y)
wxe_util:cast(?wxSizerItem_SetInitSize,
<<ThisRef:32/?UI,X:32/?UI,Y:32/?UI>>).
-%% @spec (This::wxSizerItem(), Size::{W::integer(),H::integer()}) -> ok
+%% @spec (This::wxSizerItem(), Size::{W::integer(), H::integer()}) -> ok
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxsizeritem.html#wxsizeritemsetminsize">external documentation</a>.
setMinSize(#wx_ref{type=ThisT,ref=ThisRef},{SizeW,SizeH})
when is_integer(SizeW),is_integer(SizeH) ->
@@ -285,7 +285,7 @@ setProportion(#wx_ref{type=ThisT,ref=ThisRef},Proportion)
%% setRatio(This::wxSizerItem(), Ratio::float()) -> ok </c>
%% </p>
%% <p><c>
-%% setRatio(This::wxSizerItem(), Size::{W::integer(),H::integer()}) -> ok </c>
+%% setRatio(This::wxSizerItem(), Size::{W::integer(), H::integer()}) -> ok </c>
%% </p>
setRatio(#wx_ref{type=ThisT,ref=ThisRef},Ratio)
when is_float(Ratio) ->
@@ -314,7 +314,7 @@ setSizer(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=SizerT,ref=SizerRef}) ->
wxe_util:cast(?wxSizerItem_SetSizer,
<<ThisRef:32/?UI,SizerRef:32/?UI>>).
-%% @spec (This::wxSizerItem(), Size::{W::integer(),H::integer()}) -> ok
+%% @spec (This::wxSizerItem(), Size::{W::integer(), H::integer()}) -> ok
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxsizeritem.html#wxsizeritemsetspacer">external documentation</a>.
setSpacer(#wx_ref{type=ThisT,ref=ThisRef},{SizeW,SizeH})
when is_integer(SizeW),is_integer(SizeH) ->
diff --git a/lib/wx/src/gen/wxSlider.erl b/lib/wx/src/gen/wxSlider.erl
index c70f127a5b..c7a3d6f5c0 100644
--- a/lib/wx/src/gen/wxSlider.erl
+++ b/lib/wx/src/gen/wxSlider.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2010. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2011. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -90,7 +90,7 @@ new(Parent,Id,Value,MinValue,MaxValue)
new(Parent,Id,Value,MinValue,MaxValue, []).
%% @spec (Parent::wxWindow:wxWindow(), Id::integer(), Value::integer(), MinValue::integer(), MaxValue::integer(), [Option]) -> wxSlider()
-%% Option = {pos, {X::integer(),Y::integer()}} | {size, {W::integer(),H::integer()}} | {style, integer()} | {validator, wx:wx()}
+%% Option = {pos, {X::integer(), Y::integer()}} | {size, {W::integer(), H::integer()}} | {style, integer()} | {validator, wx:wx()}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxslider.html#wxsliderwxslider">external documentation</a>.
new(#wx_ref{type=ParentT,ref=ParentRef},Id,Value,MinValue,MaxValue, Options)
when is_integer(Id),is_integer(Value),is_integer(MinValue),is_integer(MaxValue),is_list(Options) ->
@@ -111,7 +111,7 @@ create(This,Parent,Id,Value,MinValue,MaxValue)
create(This,Parent,Id,Value,MinValue,MaxValue, []).
%% @spec (This::wxSlider(), Parent::wxWindow:wxWindow(), Id::integer(), Value::integer(), MinValue::integer(), MaxValue::integer(), [Option]) -> bool()
-%% Option = {pos, {X::integer(),Y::integer()}} | {size, {W::integer(),H::integer()}} | {style, integer()} | {validator, wx:wx()}
+%% Option = {pos, {X::integer(), Y::integer()}} | {size, {W::integer(), H::integer()}} | {style, integer()} | {validator, wx:wx()}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxslider.html#wxslidercreate">external documentation</a>.
create(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=ParentT,ref=ParentRef},Id,Value,MinValue,MaxValue, Options)
when is_integer(Id),is_integer(Value),is_integer(MinValue),is_integer(MaxValue),is_list(Options) ->
diff --git a/lib/wx/src/gen/wxSpinButton.erl b/lib/wx/src/gen/wxSpinButton.erl
index 027699e295..e269dbe329 100644
--- a/lib/wx/src/gen/wxSpinButton.erl
+++ b/lib/wx/src/gen/wxSpinButton.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2010. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2011. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -89,7 +89,7 @@ new(Parent)
new(Parent, []).
%% @spec (Parent::wxWindow:wxWindow(), [Option]) -> wxSpinButton()
-%% Option = {id, integer()} | {pos, {X::integer(),Y::integer()}} | {size, {W::integer(),H::integer()}} | {style, integer()}
+%% Option = {id, integer()} | {pos, {X::integer(), Y::integer()}} | {size, {W::integer(), H::integer()}} | {style, integer()}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxspinbutton.html#wxspinbuttonwxspinbutton">external documentation</a>.
new(#wx_ref{type=ParentT,ref=ParentRef}, Options)
when is_list(Options) ->
@@ -110,7 +110,7 @@ create(This,Parent)
create(This,Parent, []).
%% @spec (This::wxSpinButton(), Parent::wxWindow:wxWindow(), [Option]) -> bool()
-%% Option = {id, integer()} | {pos, {X::integer(),Y::integer()}} | {size, {W::integer(),H::integer()}} | {style, integer()}
+%% Option = {id, integer()} | {pos, {X::integer(), Y::integer()}} | {size, {W::integer(), H::integer()}} | {style, integer()}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxspinbutton.html#wxspinbuttoncreate">external documentation</a>.
create(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=ParentT,ref=ParentRef}, Options)
when is_list(Options) ->
diff --git a/lib/wx/src/gen/wxSpinCtrl.erl b/lib/wx/src/gen/wxSpinCtrl.erl
index 6b77376b40..c6e8ad2238 100644
--- a/lib/wx/src/gen/wxSpinCtrl.erl
+++ b/lib/wx/src/gen/wxSpinCtrl.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2010. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2011. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -89,7 +89,7 @@ new(Parent)
new(Parent, []).
%% @spec (Parent::wxWindow:wxWindow(), [Option]) -> wxSpinCtrl()
-%% Option = {id, integer()} | {value, string()} | {pos, {X::integer(),Y::integer()}} | {size, {W::integer(),H::integer()}} | {style, integer()} | {min, integer()} | {max, integer()} | {initial, integer()}
+%% Option = {id, integer()} | {value, string()} | {pos, {X::integer(), Y::integer()}} | {size, {W::integer(), H::integer()}} | {style, integer()} | {min, integer()} | {max, integer()} | {initial, integer()}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxspinctrl.html#wxspinctrlwxspinctrl">external documentation</a>.
new(#wx_ref{type=ParentT,ref=ParentRef}, Options)
when is_list(Options) ->
@@ -114,7 +114,7 @@ create(This,Parent)
create(This,Parent, []).
%% @spec (This::wxSpinCtrl(), Parent::wxWindow:wxWindow(), [Option]) -> bool()
-%% Option = {id, integer()} | {value, string()} | {pos, {X::integer(),Y::integer()}} | {size, {W::integer(),H::integer()}} | {style, integer()} | {min, integer()} | {max, integer()} | {initial, integer()}
+%% Option = {id, integer()} | {value, string()} | {pos, {X::integer(), Y::integer()}} | {size, {W::integer(), H::integer()}} | {style, integer()} | {min, integer()} | {max, integer()} | {initial, integer()}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxspinctrl.html#wxspinctrlcreate">external documentation</a>.
create(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=ParentT,ref=ParentRef}, Options)
when is_list(Options) ->
diff --git a/lib/wx/src/gen/wxSplashScreen.erl b/lib/wx/src/gen/wxSplashScreen.erl
index 8806d07018..79ef8e413a 100644
--- a/lib/wx/src/gen/wxSplashScreen.erl
+++ b/lib/wx/src/gen/wxSplashScreen.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2010. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2011. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -100,7 +100,7 @@ new(Bitmap,SplashStyle,Milliseconds,Parent,Id)
new(Bitmap,SplashStyle,Milliseconds,Parent,Id, []).
%% @spec (Bitmap::wxBitmap:wxBitmap(), SplashStyle::integer(), Milliseconds::integer(), Parent::wxWindow:wxWindow(), Id::integer(), [Option]) -> wxSplashScreen()
-%% Option = {pos, {X::integer(),Y::integer()}} | {size, {W::integer(),H::integer()}} | {style, integer()}
+%% Option = {pos, {X::integer(), Y::integer()}} | {size, {W::integer(), H::integer()}} | {style, integer()}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxsplashscreen.html#wxsplashscreenwxsplashscreen">external documentation</a>.
new(#wx_ref{type=BitmapT,ref=BitmapRef},SplashStyle,Milliseconds,#wx_ref{type=ParentT,ref=ParentRef},Id, Options)
when is_integer(SplashStyle),is_integer(Milliseconds),is_integer(Id),is_list(Options) ->
diff --git a/lib/wx/src/gen/wxSplitterWindow.erl b/lib/wx/src/gen/wxSplitterWindow.erl
index 9e27be7475..b17fed3151 100644
--- a/lib/wx/src/gen/wxSplitterWindow.erl
+++ b/lib/wx/src/gen/wxSplitterWindow.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2009-2010. All Rights Reserved.
+%% Copyright Ericsson AB 2009-2011. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -91,7 +91,7 @@ new(Parent)
new(Parent, []).
%% @spec (Parent::wxWindow:wxWindow(), [Option]) -> wxSplitterWindow()
-%% Option = {id, integer()} | {pos, {X::integer(),Y::integer()}} | {size, {W::integer(),H::integer()}} | {style, integer()}
+%% Option = {id, integer()} | {pos, {X::integer(), Y::integer()}} | {size, {W::integer(), H::integer()}} | {style, integer()}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxsplitterwindow.html#wxsplitterwindowwxsplitterwindow">external documentation</a>.
new(#wx_ref{type=ParentT,ref=ParentRef}, Options)
when is_list(Options) ->
@@ -112,7 +112,7 @@ create(This,Parent)
create(This,Parent, []).
%% @spec (This::wxSplitterWindow(), Parent::wxWindow:wxWindow(), [Option]) -> bool()
-%% Option = {id, integer()} | {pos, {X::integer(),Y::integer()}} | {size, {W::integer(),H::integer()}} | {style, integer()}
+%% Option = {id, integer()} | {pos, {X::integer(), Y::integer()}} | {size, {W::integer(), H::integer()}} | {style, integer()}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxsplitterwindow.html#wxsplitterwindowcreate">external documentation</a>.
create(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=ParentT,ref=ParentRef}, Options)
when is_list(Options) ->
diff --git a/lib/wx/src/gen/wxStaticBitmap.erl b/lib/wx/src/gen/wxStaticBitmap.erl
index 6fbc59236d..31e39b3a6c 100644
--- a/lib/wx/src/gen/wxStaticBitmap.erl
+++ b/lib/wx/src/gen/wxStaticBitmap.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2010. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2011. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -88,7 +88,7 @@ new(Parent,Id,Label)
new(Parent,Id,Label, []).
%% @spec (Parent::wxWindow:wxWindow(), Id::integer(), Label::wxBitmap:wxBitmap(), [Option]) -> wxStaticBitmap()
-%% Option = {pos, {X::integer(),Y::integer()}} | {size, {W::integer(),H::integer()}} | {style, integer()}
+%% Option = {pos, {X::integer(), Y::integer()}} | {size, {W::integer(), H::integer()}} | {style, integer()}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxstaticbitmap.html#wxstaticbitmapwxstaticbitmap">external documentation</a>.
new(#wx_ref{type=ParentT,ref=ParentRef},Id,#wx_ref{type=LabelT,ref=LabelRef}, Options)
when is_integer(Id),is_list(Options) ->
@@ -109,7 +109,7 @@ create(This,Parent,Id,Label)
create(This,Parent,Id,Label, []).
%% @spec (This::wxStaticBitmap(), Parent::wxWindow:wxWindow(), Id::integer(), Label::wxBitmap:wxBitmap(), [Option]) -> bool()
-%% Option = {pos, {X::integer(),Y::integer()}} | {size, {W::integer(),H::integer()}} | {style, integer()}
+%% Option = {pos, {X::integer(), Y::integer()}} | {size, {W::integer(), H::integer()}} | {style, integer()}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxstaticbitmap.html#wxstaticbitmapcreate">external documentation</a>.
create(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=ParentT,ref=ParentRef},Id,#wx_ref{type=LabelT,ref=LabelRef}, Options)
when is_integer(Id),is_list(Options) ->
diff --git a/lib/wx/src/gen/wxStaticBox.erl b/lib/wx/src/gen/wxStaticBox.erl
index ad54184867..ec83ff5fd9 100644
--- a/lib/wx/src/gen/wxStaticBox.erl
+++ b/lib/wx/src/gen/wxStaticBox.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2010. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2011. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -88,7 +88,7 @@ new(Parent,Id,Label)
new(Parent,Id,Label, []).
%% @spec (Parent::wxWindow:wxWindow(), Id::integer(), Label::string(), [Option]) -> wxStaticBox()
-%% Option = {pos, {X::integer(),Y::integer()}} | {size, {W::integer(),H::integer()}} | {style, integer()}
+%% Option = {pos, {X::integer(), Y::integer()}} | {size, {W::integer(), H::integer()}} | {style, integer()}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxstaticbox.html#wxstaticboxwxstaticbox">external documentation</a>.
new(#wx_ref{type=ParentT,ref=ParentRef},Id,Label, Options)
when is_integer(Id),is_list(Label),is_list(Options) ->
@@ -109,7 +109,7 @@ create(This,Parent,Id,Label)
create(This,Parent,Id,Label, []).
%% @spec (This::wxStaticBox(), Parent::wxWindow:wxWindow(), Id::integer(), Label::string(), [Option]) -> bool()
-%% Option = {pos, {X::integer(),Y::integer()}} | {size, {W::integer(),H::integer()}} | {style, integer()}
+%% Option = {pos, {X::integer(), Y::integer()}} | {size, {W::integer(), H::integer()}} | {style, integer()}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxstaticbox.html#wxstaticboxcreate">external documentation</a>.
create(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=ParentT,ref=ParentRef},Id,Label, Options)
when is_integer(Id),is_list(Label),is_list(Options) ->
diff --git a/lib/wx/src/gen/wxStaticLine.erl b/lib/wx/src/gen/wxStaticLine.erl
index e3a1bedbdc..a850065ba0 100644
--- a/lib/wx/src/gen/wxStaticLine.erl
+++ b/lib/wx/src/gen/wxStaticLine.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2010. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2011. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -89,7 +89,7 @@ new(Parent)
new(Parent, []).
%% @spec (Parent::wxWindow:wxWindow(), [Option]) -> wxStaticLine()
-%% Option = {id, integer()} | {pos, {X::integer(),Y::integer()}} | {size, {W::integer(),H::integer()}} | {style, integer()}
+%% Option = {id, integer()} | {pos, {X::integer(), Y::integer()}} | {size, {W::integer(), H::integer()}} | {style, integer()}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxstaticline.html#wxstaticlinewxstaticline">external documentation</a>.
new(#wx_ref{type=ParentT,ref=ParentRef}, Options)
when is_list(Options) ->
@@ -110,7 +110,7 @@ create(This,Parent)
create(This,Parent, []).
%% @spec (This::wxStaticLine(), Parent::wxWindow:wxWindow(), [Option]) -> bool()
-%% Option = {id, integer()} | {pos, {X::integer(),Y::integer()}} | {size, {W::integer(),H::integer()}} | {style, integer()}
+%% Option = {id, integer()} | {pos, {X::integer(), Y::integer()}} | {size, {W::integer(), H::integer()}} | {style, integer()}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxstaticline.html#wxstaticlinecreate">external documentation</a>.
create(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=ParentT,ref=ParentRef}, Options)
when is_list(Options) ->
diff --git a/lib/wx/src/gen/wxStaticText.erl b/lib/wx/src/gen/wxStaticText.erl
index 46c73a5998..301999d49a 100644
--- a/lib/wx/src/gen/wxStaticText.erl
+++ b/lib/wx/src/gen/wxStaticText.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2010. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2011. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -88,7 +88,7 @@ new(Parent,Id,Label)
new(Parent,Id,Label, []).
%% @spec (Parent::wxWindow:wxWindow(), Id::integer(), Label::string(), [Option]) -> wxStaticText()
-%% Option = {pos, {X::integer(),Y::integer()}} | {size, {W::integer(),H::integer()}} | {style, integer()}
+%% Option = {pos, {X::integer(), Y::integer()}} | {size, {W::integer(), H::integer()}} | {style, integer()}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxstatictext.html#wxstatictextwxstatictext">external documentation</a>.
new(#wx_ref{type=ParentT,ref=ParentRef},Id,Label, Options)
when is_integer(Id),is_list(Label),is_list(Options) ->
@@ -109,7 +109,7 @@ create(This,Parent,Id,Label)
create(This,Parent,Id,Label, []).
%% @spec (This::wxStaticText(), Parent::wxWindow:wxWindow(), Id::integer(), Label::string(), [Option]) -> bool()
-%% Option = {pos, {X::integer(),Y::integer()}} | {size, {W::integer(),H::integer()}} | {style, integer()}
+%% Option = {pos, {X::integer(), Y::integer()}} | {size, {W::integer(), H::integer()}} | {style, integer()}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxstatictext.html#wxstatictextcreate">external documentation</a>.
create(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=ParentT,ref=ParentRef},Id,Label, Options)
when is_integer(Id),is_list(Label),is_list(Options) ->
diff --git a/lib/wx/src/gen/wxStatusBar.erl b/lib/wx/src/gen/wxStatusBar.erl
index 52467117d7..6e77761f1d 100644
--- a/lib/wx/src/gen/wxStatusBar.erl
+++ b/lib/wx/src/gen/wxStatusBar.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2010. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2011. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -121,7 +121,7 @@ create(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=ParentT,ref=ParentRef}, Opti
wxe_util:call(?wxStatusBar_Create,
<<ThisRef:32/?UI,ParentRef:32/?UI, BinOpt/binary>>).
-%% @spec (This::wxStatusBar(), I::integer(), Rect::{X::integer(),Y::integer(),W::integer(),H::integer()}) -> bool()
+%% @spec (This::wxStatusBar(), I::integer(), Rect::{X::integer(), Y::integer(), W::integer(), H::integer()}) -> bool()
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxstatusbar.html#wxstatusbargetfieldrect">external documentation</a>.
getFieldRect(#wx_ref{type=ThisT,ref=ThisRef},I,{RectX,RectY,RectW,RectH})
when is_integer(I),is_integer(RectX),is_integer(RectY),is_integer(RectW),is_integer(RectH) ->
diff --git a/lib/wx/src/gen/wxStyledTextCtrl.erl b/lib/wx/src/gen/wxStyledTextCtrl.erl
index 71d1bd0d53..61f0e5afef 100644
--- a/lib/wx/src/gen/wxStyledTextCtrl.erl
+++ b/lib/wx/src/gen/wxStyledTextCtrl.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2010. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2011. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -190,7 +190,7 @@ new(Parent)
new(Parent, []).
%% @spec (Parent::wxWindow:wxWindow(), [Option]) -> wxStyledTextCtrl()
-%% Option = {id, integer()} | {pos, {X::integer(),Y::integer()}} | {size, {W::integer(),H::integer()}} | {style, integer()}
+%% Option = {id, integer()} | {pos, {X::integer(), Y::integer()}} | {size, {W::integer(), H::integer()}} | {style, integer()}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxstyledtextctrl.html#wxstyledtextctrlwxstyledtextctrl">external documentation</a>.
new(#wx_ref{type=ParentT,ref=ParentRef}, Options)
when is_list(Options) ->
@@ -211,7 +211,7 @@ create(This,Parent)
create(This,Parent, []).
%% @spec (This::wxStyledTextCtrl(), Parent::wxWindow:wxWindow(), [Option]) -> bool()
-%% Option = {id, integer()} | {pos, {X::integer(),Y::integer()}} | {size, {W::integer(),H::integer()}} | {style, integer()}
+%% Option = {id, integer()} | {pos, {X::integer(), Y::integer()}} | {size, {W::integer(), H::integer()}} | {style, integer()}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxstyledtextctrl.html#wxstyledtextctrlcreate">external documentation</a>.
create(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=ParentT,ref=ParentRef}, Options)
when is_list(Options) ->
@@ -385,7 +385,7 @@ setViewWhiteSpace(#wx_ref{type=ThisT,ref=ThisRef},ViewWS)
wxe_util:cast(?wxStyledTextCtrl_SetViewWhiteSpace,
<<ThisRef:32/?UI,ViewWS:32/?UI>>).
-%% @spec (This::wxStyledTextCtrl(), Pt::{X::integer(),Y::integer()}) -> integer()
+%% @spec (This::wxStyledTextCtrl(), Pt::{X::integer(), Y::integer()}) -> integer()
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxstyledtextctrl.html#wxstyledtextctrlpositionfrompoint">external documentation</a>.
positionFromPoint(#wx_ref{type=ThisT,ref=ThisRef},{PtX,PtY})
when is_integer(PtX),is_integer(PtY) ->
@@ -425,7 +425,7 @@ setAnchor(#wx_ref{type=ThisT,ref=ThisRef},PosAnchor)
wxe_util:cast(?wxStyledTextCtrl_SetAnchor,
<<ThisRef:32/?UI,PosAnchor:32/?UI>>).
-%% @spec (This::wxStyledTextCtrl()) -> {string(),LinePos::integer()}
+%% @spec (This::wxStyledTextCtrl()) -> {string(), LinePos::integer()}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxstyledtextctrl.html#wxstyledtextctrlgetcurline">external documentation</a>.
getCurLine(#wx_ref{type=ThisT,ref=ThisRef}) ->
?CLASS(ThisT,wxStyledTextCtrl),
@@ -1454,7 +1454,7 @@ findText(#wx_ref{type=ThisT,ref=ThisRef},MinPos,MaxPos,Text, Options)
wxe_util:call(?wxStyledTextCtrl_FindText,
<<ThisRef:32/?UI,MinPos:32/?UI,MaxPos:32/?UI,(byte_size(Text_UC)):32/?UI,(Text_UC)/binary, 0:(((8- ((0+byte_size(Text_UC)) band 16#7)) band 16#7))/unit:8, BinOpt/binary>>).
-%% @spec (This::wxStyledTextCtrl(), DoDraw::bool(), StartPos::integer(), EndPos::integer(), Draw::wxDC:wxDC(), Target::wxDC:wxDC(), RenderRect::{X::integer(),Y::integer(),W::integer(),H::integer()}, PageRect::{X::integer(),Y::integer(),W::integer(),H::integer()}) -> integer()
+%% @spec (This::wxStyledTextCtrl(), DoDraw::bool(), StartPos::integer(), EndPos::integer(), Draw::wxDC:wxDC(), Target::wxDC:wxDC(), RenderRect::{X::integer(), Y::integer(), W::integer(), H::integer()}, PageRect::{X::integer(), Y::integer(), W::integer(), H::integer()}) -> integer()
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxstyledtextctrl.html#wxstyledtextctrlformatrange">external documentation</a>.
formatRange(#wx_ref{type=ThisT,ref=ThisRef},DoDraw,StartPos,EndPos,#wx_ref{type=DrawT,ref=DrawRef},#wx_ref{type=TargetT,ref=TargetRef},{RenderRectX,RenderRectY,RenderRectW,RenderRectH},{PageRectX,PageRectY,PageRectW,PageRectH})
when is_boolean(DoDraw),is_integer(StartPos),is_integer(EndPos),is_integer(RenderRectX),is_integer(RenderRectY),is_integer(RenderRectW),is_integer(RenderRectH),is_integer(PageRectX),is_integer(PageRectY),is_integer(PageRectW),is_integer(PageRectH) ->
@@ -3417,14 +3417,14 @@ setMargins(#wx_ref{type=ThisT,ref=ThisRef},Left,Right)
wxe_util:cast(?wxStyledTextCtrl_SetMargins,
<<ThisRef:32/?UI,Left:32/?UI,Right:32/?UI>>).
-%% @spec (This::wxStyledTextCtrl()) -> {StartPos::integer(),EndPos::integer()}
+%% @spec (This::wxStyledTextCtrl()) -> {StartPos::integer(), EndPos::integer()}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxstyledtextctrl.html#wxstyledtextctrlgetselection">external documentation</a>.
getSelection(#wx_ref{type=ThisT,ref=ThisRef}) ->
?CLASS(ThisT,wxStyledTextCtrl),
wxe_util:call(?wxStyledTextCtrl_GetSelection,
<<ThisRef:32/?UI>>).
-%% @spec (This::wxStyledTextCtrl(), Pos::integer()) -> {X::integer(),Y::integer()}
+%% @spec (This::wxStyledTextCtrl(), Pos::integer()) -> {X::integer(), Y::integer()}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxstyledtextctrl.html#wxstyledtextctrlpointfromposition">external documentation</a>.
pointFromPosition(#wx_ref{type=ThisT,ref=ThisRef},Pos)
when is_integer(Pos) ->
@@ -3562,7 +3562,7 @@ insertTextRaw(#wx_ref{type=ThisT,ref=ThisRef},Pos,Text)
wxe_util:cast(?wxStyledTextCtrl_InsertTextRaw,
<<ThisRef:32/?UI,Pos:32/?UI>>).
-%% @spec (This::wxStyledTextCtrl()) -> {binary(),LinePos::integer()}
+%% @spec (This::wxStyledTextCtrl()) -> {binary(), LinePos::integer()}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxstyledtextctrl.html#wxstyledtextctrlgetcurlineraw">external documentation</a>.
getCurLineRaw(#wx_ref{type=ThisT,ref=ThisRef}) ->
?CLASS(ThisT,wxStyledTextCtrl),
diff --git a/lib/wx/src/gen/wxSystemOptions.erl b/lib/wx/src/gen/wxSystemOptions.erl
new file mode 100644
index 0000000000..d5e504632b
--- /dev/null
+++ b/lib/wx/src/gen/wxSystemOptions.erl
@@ -0,0 +1,87 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2008-2011. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%% This file is generated DO NOT EDIT
+
+%% @doc See external documentation: <a href="http://www.wxwidgets.org/manuals/stable/wx_wxsystemoptions.html">wxSystemOptions</a>.
+%% @type wxSystemOptions(). An object reference, The representation is internal
+%% and can be changed without notice. It can't be used for comparsion
+%% stored on disc or distributed for use on other nodes.
+
+-module(wxSystemOptions).
+-include("wxe.hrl").
+-export([getOption/1,getOptionInt/1,hasOption/1,isFalse/1,setOption/2]).
+
+%% inherited exports
+-export([parent_class/1]).
+
+%% @hidden
+parent_class(_Class) -> erlang:error({badtype, ?MODULE}).
+
+%% @spec (Name::string()) -> string()
+%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxsystemoptions.html#wxsystemoptionsgetoption">external documentation</a>.
+getOption(Name)
+ when is_list(Name) ->
+ Name_UC = unicode:characters_to_binary([Name,0]),
+ wxe_util:call(?wxSystemOptions_GetOption,
+ <<(byte_size(Name_UC)):32/?UI,(Name_UC)/binary, 0:(((8- ((4+byte_size(Name_UC)) band 16#7)) band 16#7))/unit:8>>).
+
+%% @spec (Name::string()) -> integer()
+%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxsystemoptions.html#wxsystemoptionsgetoptionint">external documentation</a>.
+getOptionInt(Name)
+ when is_list(Name) ->
+ Name_UC = unicode:characters_to_binary([Name,0]),
+ wxe_util:call(?wxSystemOptions_GetOptionInt,
+ <<(byte_size(Name_UC)):32/?UI,(Name_UC)/binary, 0:(((8- ((4+byte_size(Name_UC)) band 16#7)) band 16#7))/unit:8>>).
+
+%% @spec (Name::string()) -> bool()
+%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxsystemoptions.html#wxsystemoptionshasoption">external documentation</a>.
+hasOption(Name)
+ when is_list(Name) ->
+ Name_UC = unicode:characters_to_binary([Name,0]),
+ wxe_util:call(?wxSystemOptions_HasOption,
+ <<(byte_size(Name_UC)):32/?UI,(Name_UC)/binary, 0:(((8- ((4+byte_size(Name_UC)) band 16#7)) band 16#7))/unit:8>>).
+
+%% @spec (Name::string()) -> bool()
+%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxsystemoptions.html#wxsystemoptionsisfalse">external documentation</a>.
+isFalse(Name)
+ when is_list(Name) ->
+ Name_UC = unicode:characters_to_binary([Name,0]),
+ wxe_util:call(?wxSystemOptions_IsFalse,
+ <<(byte_size(Name_UC)):32/?UI,(Name_UC)/binary, 0:(((8- ((4+byte_size(Name_UC)) band 16#7)) band 16#7))/unit:8>>).
+
+%% @spec (Name::string(),X::integer()|string()) -> ok
+%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxsystemoptions.html#wxsystemoptionssetoption">external documentation</a>.
+%% <br /> Alternatives:
+%% <p><c>
+%% setOption(Name::string(), Value::integer()) -> ok </c>
+%% </p>
+%% <p><c>
+%% setOption(Name::string(), Value::string()) -> ok </c>
+%% </p>
+setOption(Name,Value)
+ when is_list(Name),is_integer(Value) ->
+ Name_UC = unicode:characters_to_binary([Name,0]),
+ wxe_util:cast(?wxSystemOptions_SetOption_2_0,
+ <<(byte_size(Name_UC)):32/?UI,(Name_UC)/binary, 0:(((8- ((4+byte_size(Name_UC)) band 16#7)) band 16#7))/unit:8,Value:32/?UI>>);
+setOption(Name,Value)
+ when is_list(Name),is_list(Value) ->
+ Name_UC = unicode:characters_to_binary([Name,0]),
+ Value_UC = unicode:characters_to_binary([Value,0]),
+ wxe_util:cast(?wxSystemOptions_SetOption_2_1,
+ <<(byte_size(Name_UC)):32/?UI,(Name_UC)/binary, 0:(((8- ((4+byte_size(Name_UC)) band 16#7)) band 16#7))/unit:8,(byte_size(Value_UC)):32/?UI,(Value_UC)/binary, 0:(((8- ((4+byte_size(Value_UC)) band 16#7)) band 16#7))/unit:8>>).
+
diff --git a/lib/wx/src/gen/wxTextCtrl.erl b/lib/wx/src/gen/wxTextCtrl.erl
index b4af23bdd9..b32f45b83b 100644
--- a/lib/wx/src/gen/wxTextCtrl.erl
+++ b/lib/wx/src/gen/wxTextCtrl.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2010. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2011. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -96,7 +96,7 @@ new(Parent,Id)
new(Parent,Id, []).
%% @spec (Parent::wxWindow:wxWindow(), Id::integer(), [Option]) -> wxTextCtrl()
-%% Option = {value, string()} | {pos, {X::integer(),Y::integer()}} | {size, {W::integer(),H::integer()}} | {style, integer()} | {validator, wx:wx()}
+%% Option = {value, string()} | {pos, {X::integer(), Y::integer()}} | {size, {W::integer(), H::integer()}} | {style, integer()} | {validator, wx:wx()}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxtextctrl.html#wxtextctrlwxtextctrl">external documentation</a>.
new(#wx_ref{type=ParentT,ref=ParentRef},Id, Options)
when is_integer(Id),is_list(Options) ->
@@ -176,7 +176,7 @@ create(This,Parent,Id)
create(This,Parent,Id, []).
%% @spec (This::wxTextCtrl(), Parent::wxWindow:wxWindow(), Id::integer(), [Option]) -> bool()
-%% Option = {value, string()} | {pos, {X::integer(),Y::integer()}} | {size, {W::integer(),H::integer()}} | {style, integer()} | {validator, wx:wx()}
+%% Option = {value, string()} | {pos, {X::integer(), Y::integer()}} | {size, {W::integer(), H::integer()}} | {style, integer()} | {validator, wx:wx()}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxtextctrl.html#wxtextctrlcreate">external documentation</a>.
create(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=ParentT,ref=ParentRef},Id, Options)
when is_integer(Id),is_list(Options) ->
@@ -266,7 +266,7 @@ getRange(#wx_ref{type=ThisT,ref=ThisRef},From,To)
wxe_util:call(?wxTextCtrl_GetRange,
<<ThisRef:32/?UI,From:32/?UI,To:32/?UI>>).
-%% @spec (This::wxTextCtrl()) -> {From::integer(),To::integer()}
+%% @spec (This::wxTextCtrl()) -> {From::integer(), To::integer()}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxtextctrl.html#wxtextctrlgetselection">external documentation</a>.
getSelection(#wx_ref{type=ThisT,ref=ThisRef}) ->
?CLASS(ThisT,wxTextCtrl),
@@ -357,7 +357,7 @@ paste(#wx_ref{type=ThisT,ref=ThisRef}) ->
wxe_util:cast(?wxTextCtrl_Paste,
<<ThisRef:32/?UI>>).
-%% @spec (This::wxTextCtrl(), Pos::integer()) -> {bool(),X::integer(),Y::integer()}
+%% @spec (This::wxTextCtrl(), Pos::integer()) -> {bool(), X::integer(), Y::integer()}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxtextctrl.html#wxtextctrlpositiontoxy">external documentation</a>.
positionToXY(#wx_ref{type=ThisT,ref=ThisRef},Pos)
when is_integer(Pos) ->
diff --git a/lib/wx/src/gen/wxTextEntryDialog.erl b/lib/wx/src/gen/wxTextEntryDialog.erl
index a30c32dd53..53694a47e6 100644
--- a/lib/wx/src/gen/wxTextEntryDialog.erl
+++ b/lib/wx/src/gen/wxTextEntryDialog.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2010. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2011. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -91,7 +91,7 @@ new(Parent,Message)
new(Parent,Message, []).
%% @spec (Parent::wxWindow:wxWindow(), Message::string(), [Option]) -> wxTextEntryDialog()
-%% Option = {caption, string()} | {value, string()} | {style, integer()} | {pos, {X::integer(),Y::integer()}}
+%% Option = {caption, string()} | {value, string()} | {style, integer()} | {pos, {X::integer(), Y::integer()}}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxtextentrydialog.html#wxtextentrydialogwxtextentrydialog">external documentation</a>.
new(#wx_ref{type=ParentT,ref=ParentRef},Message, Options)
when is_list(Message),is_list(Options) ->
diff --git a/lib/wx/src/gen/wxToggleButton.erl b/lib/wx/src/gen/wxToggleButton.erl
index ab595c1906..d7755cc50b 100644
--- a/lib/wx/src/gen/wxToggleButton.erl
+++ b/lib/wx/src/gen/wxToggleButton.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2010. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2011. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -88,7 +88,7 @@ new(Parent,Id,Label)
new(Parent,Id,Label, []).
%% @spec (Parent::wxWindow:wxWindow(), Id::integer(), Label::string(), [Option]) -> wxToggleButton()
-%% Option = {pos, {X::integer(),Y::integer()}} | {size, {W::integer(),H::integer()}} | {style, integer()} | {validator, wx:wx()}
+%% Option = {pos, {X::integer(), Y::integer()}} | {size, {W::integer(), H::integer()}} | {style, integer()} | {validator, wx:wx()}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxtogglebutton.html#wxtogglebuttonwxtogglebutton">external documentation</a>.
new(#wx_ref{type=ParentT,ref=ParentRef},Id,Label, Options)
when is_integer(Id),is_list(Label),is_list(Options) ->
@@ -110,7 +110,7 @@ create(This,Parent,Id,Label)
create(This,Parent,Id,Label, []).
%% @spec (This::wxToggleButton(), Parent::wxWindow:wxWindow(), Id::integer(), Label::string(), [Option]) -> bool()
-%% Option = {pos, {X::integer(),Y::integer()}} | {size, {W::integer(),H::integer()}} | {style, integer()} | {validator, wx:wx()}
+%% Option = {pos, {X::integer(), Y::integer()}} | {size, {W::integer(), H::integer()}} | {style, integer()} | {validator, wx:wx()}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxtogglebutton.html#wxtogglebuttoncreate">external documentation</a>.
create(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=ParentT,ref=ParentRef},Id,Label, Options)
when is_integer(Id),is_list(Label),is_list(Options) ->
diff --git a/lib/wx/src/gen/wxToolBar.erl b/lib/wx/src/gen/wxToolBar.erl
index c68936d493..59369368f0 100644
--- a/lib/wx/src/gen/wxToolBar.erl
+++ b/lib/wx/src/gen/wxToolBar.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2010. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2011. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -327,21 +327,21 @@ findToolForPosition(#wx_ref{type=ThisT,ref=ThisRef},X,Y)
wxe_util:call(?wxToolBar_FindToolForPosition,
<<ThisRef:32/?UI,X:32/?UI,Y:32/?UI>>).
-%% @spec (This::wxToolBar()) -> {W::integer(),H::integer()}
+%% @spec (This::wxToolBar()) -> {W::integer(), H::integer()}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxtoolbar.html#wxtoolbargettoolsize">external documentation</a>.
getToolSize(#wx_ref{type=ThisT,ref=ThisRef}) ->
?CLASS(ThisT,wxToolBar),
wxe_util:call(?wxToolBar_GetToolSize,
<<ThisRef:32/?UI>>).
-%% @spec (This::wxToolBar()) -> {W::integer(),H::integer()}
+%% @spec (This::wxToolBar()) -> {W::integer(), H::integer()}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxtoolbar.html#wxtoolbargettoolbitmapsize">external documentation</a>.
getToolBitmapSize(#wx_ref{type=ThisT,ref=ThisRef}) ->
?CLASS(ThisT,wxToolBar),
wxe_util:call(?wxToolBar_GetToolBitmapSize,
<<ThisRef:32/?UI>>).
-%% @spec (This::wxToolBar()) -> {W::integer(),H::integer()}
+%% @spec (This::wxToolBar()) -> {W::integer(), H::integer()}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxtoolbar.html#wxtoolbargetmargins">external documentation</a>.
getMargins(#wx_ref{type=ThisT,ref=ThisRef}) ->
?CLASS(ThisT,wxToolBar),
@@ -504,7 +504,7 @@ setMargins(#wx_ref{type=ThisT,ref=ThisRef},X,Y)
wxe_util:cast(?wxToolBar_SetMargins,
<<ThisRef:32/?UI,X:32/?UI,Y:32/?UI>>).
-%% @spec (This::wxToolBar(), Size::{W::integer(),H::integer()}) -> ok
+%% @spec (This::wxToolBar(), Size::{W::integer(), H::integer()}) -> ok
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxtoolbar.html#wxtoolbarsettoolbitmapsize">external documentation</a>.
setToolBitmapSize(#wx_ref{type=ThisT,ref=ThisRef},{SizeW,SizeH})
when is_integer(SizeW),is_integer(SizeH) ->
diff --git a/lib/wx/src/gen/wxToolbook.erl b/lib/wx/src/gen/wxToolbook.erl
index 4d188e979d..764f66c2e5 100644
--- a/lib/wx/src/gen/wxToolbook.erl
+++ b/lib/wx/src/gen/wxToolbook.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2009-2010. All Rights Reserved.
+%% Copyright Ericsson AB 2009-2011. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -93,7 +93,7 @@ new(Parent,Id)
new(Parent,Id, []).
%% @spec (Parent::wxWindow:wxWindow(), Id::integer(), [Option]) -> wxToolbook()
-%% Option = {pos, {X::integer(),Y::integer()}} | {size, {W::integer(),H::integer()}} | {style, integer()}
+%% Option = {pos, {X::integer(), Y::integer()}} | {size, {W::integer(), H::integer()}} | {style, integer()}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxtoolbook.html#wxtoolbookwxtoolbook">external documentation</a>.
new(#wx_ref{type=ParentT,ref=ParentRef},Id, Options)
when is_integer(Id),is_list(Options) ->
@@ -160,7 +160,7 @@ create(This,Parent,Id)
create(This,Parent,Id, []).
%% @spec (This::wxToolbook(), Parent::wxWindow:wxWindow(), Id::integer(), [Option]) -> bool()
-%% Option = {pos, {X::integer(),Y::integer()}} | {size, {W::integer(),H::integer()}} | {style, integer()}
+%% Option = {pos, {X::integer(), Y::integer()}} | {size, {W::integer(), H::integer()}} | {style, integer()}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxtoolbook.html#wxtoolbookcreate">external documentation</a>.
create(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=ParentT,ref=ParentRef},Id, Options)
when is_integer(Id),is_list(Options) ->
@@ -249,7 +249,7 @@ getSelection(#wx_ref{type=ThisT,ref=ThisRef}) ->
wxe_util:call(?wxToolbook_GetSelection,
<<ThisRef:32/?UI>>).
-%% @spec (This::wxToolbook(), Pt::{X::integer(),Y::integer()}) -> {integer(),Flags::integer()}
+%% @spec (This::wxToolbook(), Pt::{X::integer(), Y::integer()}) -> {integer(), Flags::integer()}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxtoolbook.html#wxtoolbookhittest">external documentation</a>.
hitTest(#wx_ref{type=ThisT,ref=ThisRef},{PtX,PtY})
when is_integer(PtX),is_integer(PtY) ->
@@ -286,7 +286,7 @@ setImageList(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=ImageListT,ref=ImageLi
wxe_util:cast(?wxToolbook_SetImageList,
<<ThisRef:32/?UI,ImageListRef:32/?UI>>).
-%% @spec (This::wxToolbook(), Size::{W::integer(),H::integer()}) -> ok
+%% @spec (This::wxToolbook(), Size::{W::integer(), H::integer()}) -> ok
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxtoolbook.html#wxtoolbooksetpagesize">external documentation</a>.
setPageSize(#wx_ref{type=ThisT,ref=ThisRef},{SizeW,SizeH})
when is_integer(SizeW),is_integer(SizeH) ->
diff --git a/lib/wx/src/gen/wxTreeCtrl.erl b/lib/wx/src/gen/wxTreeCtrl.erl
index e3fe4c9612..77705ec76e 100644
--- a/lib/wx/src/gen/wxTreeCtrl.erl
+++ b/lib/wx/src/gen/wxTreeCtrl.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2010. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2011. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -108,7 +108,7 @@ new(Parent)
new(Parent, []).
%% @spec (Parent::wxWindow:wxWindow(), [Option]) -> wxTreeCtrl()
-%% Option = {id, integer()} | {pos, {X::integer(),Y::integer()}} | {size, {W::integer(),H::integer()}} | {style, integer()} | {validator, wx:wx()}
+%% Option = {id, integer()} | {pos, {X::integer(), Y::integer()}} | {size, {W::integer(), H::integer()}} | {style, integer()} | {validator, wx:wx()}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxtreectrl.html#wxtreectrlwxtreectrl">external documentation</a>.
new(#wx_ref{type=ParentT,ref=ParentRef}, Options)
when is_list(Options) ->
@@ -204,7 +204,7 @@ create(This,Parent)
create(This,Parent, []).
%% @spec (This::wxTreeCtrl(), Parent::wxWindow:wxWindow(), [Option]) -> bool()
-%% Option = {id, integer()} | {pos, {X::integer(),Y::integer()}} | {size, {W::integer(),H::integer()}} | {style, integer()} | {validator, wx:wx()}
+%% Option = {id, integer()} | {pos, {X::integer(), Y::integer()}} | {size, {W::integer(), H::integer()}} | {style, integer()} | {validator, wx:wx()}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxtreectrl.html#wxtreectrlcreate">external documentation</a>.
create(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=ParentT,ref=ParentRef}, Options)
when is_list(Options) ->
@@ -267,13 +267,13 @@ expand(#wx_ref{type=ThisT,ref=ThisRef},Item)
wxe_util:cast(?wxTreeCtrl_Expand,
<<ThisRef:32/?UI,0:32,Item:64/?UI>>).
-%% @spec (This::wxTreeCtrl(), Item::integer(), Rect::{X::integer(),Y::integer(),W::integer(),H::integer()}) -> bool()
+%% @spec (This::wxTreeCtrl(), Item::integer(), Rect::{X::integer(), Y::integer(), W::integer(), H::integer()}) -> bool()
%% @equiv getBoundingRect(This,Item,Rect, [])
getBoundingRect(This,Item,Rect={RectX,RectY,RectW,RectH})
when is_record(This, wx_ref),is_integer(Item),is_integer(RectX),is_integer(RectY),is_integer(RectW),is_integer(RectH) ->
getBoundingRect(This,Item,Rect, []).
-%% @spec (This::wxTreeCtrl(), Item::integer(), Rect::{X::integer(),Y::integer(),W::integer(),H::integer()}, [Option]) -> bool()
+%% @spec (This::wxTreeCtrl(), Item::integer(), Rect::{X::integer(), Y::integer(), W::integer(), H::integer()}, [Option]) -> bool()
%% Option = {textOnly, bool()}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxtreectrl.html#wxtreectrlgetboundingrect">external documentation</a>.
getBoundingRect(#wx_ref{type=ThisT,ref=ThisRef},Item,{RectX,RectY,RectW,RectH}, Options)
@@ -317,7 +317,7 @@ getEditControl(#wx_ref{type=ThisT,ref=ThisRef}) ->
wxe_util:call(?wxTreeCtrl_GetEditControl,
<<ThisRef:32/?UI>>).
-%% @spec (This::wxTreeCtrl(), Item::integer()) -> {integer(),Cookie::integer()}
+%% @spec (This::wxTreeCtrl(), Item::integer()) -> {integer(), Cookie::integer()}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxtreectrl.html#wxtreectrlgetfirstchild">external documentation</a>.
getFirstChild(#wx_ref{type=ThisT,ref=ThisRef},Item)
when is_integer(Item) ->
@@ -325,7 +325,7 @@ getFirstChild(#wx_ref{type=ThisT,ref=ThisRef},Item)
wxe_util:call(?wxTreeCtrl_GetFirstChild,
<<ThisRef:32/?UI,0:32,Item:64/?UI>>).
-%% @spec (This::wxTreeCtrl(), Item::integer(), Cookie::integer()) -> {integer(),Cookie::integer()}
+%% @spec (This::wxTreeCtrl(), Item::integer(), Cookie::integer()) -> {integer(), Cookie::integer()}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxtreectrl.html#wxtreectrlgetnextchild">external documentation</a>.
getNextChild(#wx_ref{type=ThisT,ref=ThisRef},Item,Cookie)
when is_integer(Item),is_integer(Cookie) ->
@@ -478,7 +478,7 @@ getSelection(#wx_ref{type=ThisT,ref=ThisRef}) ->
wxe_util:call(?wxTreeCtrl_GetSelection,
<<ThisRef:32/?UI>>).
-%% @spec (This::wxTreeCtrl()) -> {integer(),Val::[integer()]}
+%% @spec (This::wxTreeCtrl()) -> {integer(), Val::[integer()]}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxtreectrl.html#wxtreectrlgetselections">external documentation</a>.
getSelections(#wx_ref{type=ThisT,ref=ThisRef}) ->
?CLASS(ThisT,wxTreeCtrl),
@@ -492,7 +492,7 @@ getStateImageList(#wx_ref{type=ThisT,ref=ThisRef}) ->
wxe_util:call(?wxTreeCtrl_GetStateImageList,
<<ThisRef:32/?UI>>).
-%% @spec (This::wxTreeCtrl(), Point::{X::integer(),Y::integer()}) -> integer()
+%% @spec (This::wxTreeCtrl(), Point::{X::integer(), Y::integer()}) -> integer()
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxtreectrl.html#wxtreectrlhittest">external documentation</a>.
hitTest(#wx_ref{type=ThisT,ref=ThisRef},{PointX,PointY})
when is_integer(PointX),is_integer(PointY) ->
diff --git a/lib/wx/src/gen/wxTreeEvent.erl b/lib/wx/src/gen/wxTreeEvent.erl
index d5379b7abe..0264d43568 100644
--- a/lib/wx/src/gen/wxTreeEvent.erl
+++ b/lib/wx/src/gen/wxTreeEvent.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2010. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2011. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -83,7 +83,7 @@ getOldItem(#wx_ref{type=ThisT,ref=ThisRef}) ->
wxe_util:call(?wxTreeEvent_GetOldItem,
<<ThisRef:32/?UI>>).
-%% @spec (This::wxTreeEvent()) -> {X::integer(),Y::integer()}
+%% @spec (This::wxTreeEvent()) -> {X::integer(), Y::integer()}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxtreeevent.html#wxtreeeventgetpoint">external documentation</a>.
getPoint(#wx_ref{type=ThisT,ref=ThisRef}) ->
?CLASS(ThisT,wxTreeEvent),
diff --git a/lib/wx/src/gen/wxTreebook.erl b/lib/wx/src/gen/wxTreebook.erl
index a515ec9639..24f5d72c43 100644
--- a/lib/wx/src/gen/wxTreebook.erl
+++ b/lib/wx/src/gen/wxTreebook.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2009-2010. All Rights Reserved.
+%% Copyright Ericsson AB 2009-2011. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -94,7 +94,7 @@ new(Parent,Id)
new(Parent,Id, []).
%% @spec (Parent::wxWindow:wxWindow(), Id::integer(), [Option]) -> wxTreebook()
-%% Option = {pos, {X::integer(),Y::integer()}} | {size, {W::integer(),H::integer()}} | {style, integer()}
+%% Option = {pos, {X::integer(), Y::integer()}} | {size, {W::integer(), H::integer()}} | {style, integer()}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxtreebook.html#wxtreebookwxtreebook">external documentation</a>.
new(#wx_ref{type=ParentT,ref=ParentRef},Id, Options)
when is_integer(Id),is_list(Options) ->
@@ -161,7 +161,7 @@ create(This,Parent,Id)
create(This,Parent,Id, []).
%% @spec (This::wxTreebook(), Parent::wxWindow:wxWindow(), Id::integer(), [Option]) -> bool()
-%% Option = {pos, {X::integer(),Y::integer()}} | {size, {W::integer(),H::integer()}} | {style, integer()}
+%% Option = {pos, {X::integer(), Y::integer()}} | {size, {W::integer(), H::integer()}} | {style, integer()}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxtreebook.html#wxtreebookcreate">external documentation</a>.
create(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=ParentT,ref=ParentRef},Id, Options)
when is_integer(Id),is_list(Options) ->
@@ -276,7 +276,7 @@ isNodeExpanded(#wx_ref{type=ThisT,ref=ThisRef},Pos)
wxe_util:call(?wxTreebook_IsNodeExpanded,
<<ThisRef:32/?UI,Pos:32/?UI>>).
-%% @spec (This::wxTreebook(), Pt::{X::integer(),Y::integer()}) -> {integer(),Flags::integer()}
+%% @spec (This::wxTreebook(), Pt::{X::integer(), Y::integer()}) -> {integer(), Flags::integer()}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxtreebook.html#wxtreebookhittest">external documentation</a>.
hitTest(#wx_ref{type=ThisT,ref=ThisRef},{PtX,PtY})
when is_integer(PtX),is_integer(PtY) ->
@@ -334,7 +334,7 @@ setImageList(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=ImageListT,ref=ImageLi
wxe_util:cast(?wxTreebook_SetImageList,
<<ThisRef:32/?UI,ImageListRef:32/?UI>>).
-%% @spec (This::wxTreebook(), Size::{W::integer(),H::integer()}) -> ok
+%% @spec (This::wxTreebook(), Size::{W::integer(), H::integer()}) -> ok
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxtreebook.html#wxtreebooksetpagesize">external documentation</a>.
setPageSize(#wx_ref{type=ThisT,ref=ThisRef},{SizeW,SizeH})
when is_integer(SizeW),is_integer(SizeH) ->
diff --git a/lib/wx/src/gen/wxWindow.erl b/lib/wx/src/gen/wxWindow.erl
index 031314bfe2..6b57cf508e 100644
--- a/lib/wx/src/gen/wxWindow.erl
+++ b/lib/wx/src/gen/wxWindow.erl
@@ -86,7 +86,7 @@ new(Parent,Id)
new(Parent,Id, []).
%% @spec (Parent::wxWindow(), Id::integer(), [Option]) -> wxWindow()
-%% Option = {pos, {X::integer(),Y::integer()}} | {size, {W::integer(),H::integer()}} | {style, integer()}
+%% Option = {pos, {X::integer(), Y::integer()}} | {size, {W::integer(), H::integer()}} | {style, integer()}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxwindow.html#wxwindowwxwindow">external documentation</a>.
new(#wx_ref{type=ParentT,ref=ParentRef},Id, Options)
when is_integer(Id),is_list(Options) ->
@@ -99,7 +99,7 @@ new(#wx_ref{type=ParentT,ref=ParentRef},Id, Options)
wxe_util:construct(?wxWindow_new_3,
<<ParentRef:32/?UI,Id:32/?UI, BinOpt/binary>>).
-%% @spec (This::wxWindow(), Size::{W::integer(),H::integer()}) -> ok
+%% @spec (This::wxWindow(), Size::{W::integer(), H::integer()}) -> ok
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxwindow.html#wxwindowcachebestsize">external documentation</a>.
cacheBestSize(#wx_ref{type=ThisT,ref=ThisRef},{SizeW,SizeH})
when is_integer(SizeW),is_integer(SizeH) ->
@@ -193,7 +193,7 @@ clearBackground(#wx_ref{type=ThisT,ref=ThisRef}) ->
wxe_util:cast(?wxWindow_ClearBackground,
<<ThisRef:32/?UI>>).
-%% @spec (This::wxWindow(), Pt::{X::integer(),Y::integer()}) -> {X::integer(),Y::integer()}
+%% @spec (This::wxWindow(), Pt::{X::integer(), Y::integer()}) -> {X::integer(), Y::integer()}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxwindow.html#wxwindowclienttoscreen">external documentation</a>.
clientToScreen(#wx_ref{type=ThisT,ref=ThisRef},{PtX,PtY})
when is_integer(PtX),is_integer(PtY) ->
@@ -201,7 +201,7 @@ clientToScreen(#wx_ref{type=ThisT,ref=ThisRef},{PtX,PtY})
wxe_util:call(?wxWindow_ClientToScreen_1,
<<ThisRef:32/?UI,PtX:32/?UI,PtY:32/?UI>>).
-%% @spec (This::wxWindow(), X::integer(), Y::integer()) -> {X::integer(),Y::integer()}
+%% @spec (This::wxWindow(), X::integer(), Y::integer()) -> {X::integer(), Y::integer()}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxwindow.html#wxwindowclienttoscreen">external documentation</a>.
clientToScreen(#wx_ref{type=ThisT,ref=ThisRef},X,Y)
when is_integer(X),is_integer(Y) ->
@@ -227,7 +227,7 @@ close(#wx_ref{type=ThisT,ref=ThisRef}, Options)
wxe_util:call(?wxWindow_Close,
<<ThisRef:32/?UI, 0:32,BinOpt/binary>>).
-%% @spec (This::wxWindow(), Sz::{W::integer(),H::integer()}) -> {W::integer(),H::integer()}
+%% @spec (This::wxWindow(), Sz::{W::integer(), H::integer()}) -> {W::integer(), H::integer()}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxwindow.html#wxwindowconvertdialogtopixels">external documentation</a>.
convertDialogToPixels(#wx_ref{type=ThisT,ref=ThisRef},{SzW,SzH})
when is_integer(SzW),is_integer(SzH) ->
@@ -235,7 +235,7 @@ convertDialogToPixels(#wx_ref{type=ThisT,ref=ThisRef},{SzW,SzH})
wxe_util:call(?wxWindow_ConvertDialogToPixels,
<<ThisRef:32/?UI,SzW:32/?UI,SzH:32/?UI>>).
-%% @spec (This::wxWindow(), Sz::{W::integer(),H::integer()}) -> {W::integer(),H::integer()}
+%% @spec (This::wxWindow(), Sz::{W::integer(), H::integer()}) -> {W::integer(), H::integer()}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxwindow.html#wxwindowconvertpixelstodialog">external documentation</a>.
convertPixelsToDialog(#wx_ref{type=ThisT,ref=ThisRef},{SzW,SzH})
when is_integer(SzW),is_integer(SzH) ->
@@ -406,7 +406,7 @@ getBackgroundStyle(#wx_ref{type=ThisT,ref=ThisRef}) ->
wxe_util:call(?wxWindow_GetBackgroundStyle,
<<ThisRef:32/?UI>>).
-%% @spec (This::wxWindow()) -> {W::integer(),H::integer()}
+%% @spec (This::wxWindow()) -> {W::integer(), H::integer()}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxwindow.html#wxwindowgetbestsize">external documentation</a>.
getBestSize(#wx_ref{type=ThisT,ref=ThisRef}) ->
?CLASS(ThisT,wxWindow),
@@ -447,7 +447,7 @@ getChildren(#wx_ref{type=ThisT,ref=ThisRef}) ->
wxe_util:call(?wxWindow_GetChildren,
<<ThisRef:32/?UI>>).
-%% @spec (This::wxWindow()) -> {W::integer(),H::integer()}
+%% @spec (This::wxWindow()) -> {W::integer(), H::integer()}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxwindow.html#wxwindowgetclientsize">external documentation</a>.
getClientSize(#wx_ref{type=ThisT,ref=ThisRef}) ->
?CLASS(ThisT,wxWindow),
@@ -538,14 +538,14 @@ getLabel(#wx_ref{type=ThisT,ref=ThisRef}) ->
wxe_util:call(?wxWindow_GetLabel,
<<ThisRef:32/?UI>>).
-%% @spec (This::wxWindow()) -> {W::integer(),H::integer()}
+%% @spec (This::wxWindow()) -> {W::integer(), H::integer()}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxwindow.html#wxwindowgetmaxsize">external documentation</a>.
getMaxSize(#wx_ref{type=ThisT,ref=ThisRef}) ->
?CLASS(ThisT,wxWindow),
wxe_util:call(?wxWindow_GetMaxSize,
<<ThisRef:32/?UI>>).
-%% @spec (This::wxWindow()) -> {W::integer(),H::integer()}
+%% @spec (This::wxWindow()) -> {W::integer(), H::integer()}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxwindow.html#wxwindowgetminsize">external documentation</a>.
getMinSize(#wx_ref{type=ThisT,ref=ThisRef}) ->
?CLASS(ThisT,wxWindow),
@@ -566,28 +566,28 @@ getParent(#wx_ref{type=ThisT,ref=ThisRef}) ->
wxe_util:call(?wxWindow_GetParent,
<<ThisRef:32/?UI>>).
-%% @spec (This::wxWindow()) -> {X::integer(),Y::integer()}
+%% @spec (This::wxWindow()) -> {X::integer(), Y::integer()}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxwindow.html#wxwindowgetposition">external documentation</a>.
getPosition(#wx_ref{type=ThisT,ref=ThisRef}) ->
?CLASS(ThisT,wxWindow),
wxe_util:call(?wxWindow_GetPosition,
<<ThisRef:32/?UI>>).
-%% @spec (This::wxWindow()) -> {X::integer(),Y::integer(),W::integer(),H::integer()}
+%% @spec (This::wxWindow()) -> {X::integer(), Y::integer(), W::integer(), H::integer()}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxwindow.html#wxwindowgetrect">external documentation</a>.
getRect(#wx_ref{type=ThisT,ref=ThisRef}) ->
?CLASS(ThisT,wxWindow),
wxe_util:call(?wxWindow_GetRect,
<<ThisRef:32/?UI>>).
-%% @spec (This::wxWindow()) -> {X::integer(),Y::integer()}
+%% @spec (This::wxWindow()) -> {X::integer(), Y::integer()}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxwindow.html#wxwindowgetscreenposition">external documentation</a>.
getScreenPosition(#wx_ref{type=ThisT,ref=ThisRef}) ->
?CLASS(ThisT,wxWindow),
wxe_util:call(?wxWindow_GetScreenPosition,
<<ThisRef:32/?UI>>).
-%% @spec (This::wxWindow()) -> {X::integer(),Y::integer(),W::integer(),H::integer()}
+%% @spec (This::wxWindow()) -> {X::integer(), Y::integer(), W::integer(), H::integer()}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxwindow.html#wxwindowgetscreenrect">external documentation</a>.
getScreenRect(#wx_ref{type=ThisT,ref=ThisRef}) ->
?CLASS(ThisT,wxWindow),
@@ -618,7 +618,7 @@ getScrollThumb(#wx_ref{type=ThisT,ref=ThisRef},Orient)
wxe_util:call(?wxWindow_GetScrollThumb,
<<ThisRef:32/?UI,Orient:32/?UI>>).
-%% @spec (This::wxWindow()) -> {W::integer(),H::integer()}
+%% @spec (This::wxWindow()) -> {W::integer(), H::integer()}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxwindow.html#wxwindowgetsize">external documentation</a>.
getSize(#wx_ref{type=ThisT,ref=ThisRef}) ->
?CLASS(ThisT,wxWindow),
@@ -632,13 +632,13 @@ getSizer(#wx_ref{type=ThisT,ref=ThisRef}) ->
wxe_util:call(?wxWindow_GetSizer,
<<ThisRef:32/?UI>>).
-%% @spec (This::wxWindow(), String::string()) -> {X::integer(),Y::integer(),Descent::integer(),ExternalLeading::integer()}
+%% @spec (This::wxWindow(), String::string()) -> {X::integer(), Y::integer(), Descent::integer(), ExternalLeading::integer()}
%% @equiv getTextExtent(This,String, [])
getTextExtent(This,String)
when is_record(This, wx_ref),is_list(String) ->
getTextExtent(This,String, []).
-%% @spec (This::wxWindow(), String::string(), [Option]) -> {X::integer(),Y::integer(),Descent::integer(),ExternalLeading::integer()}
+%% @spec (This::wxWindow(), String::string(), [Option]) -> {X::integer(), Y::integer(), Descent::integer(), ExternalLeading::integer()}
%% Option = {theFont, wxFont:wxFont()}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxwindow.html#wxwindowgettextextent">external documentation</a>.
getTextExtent(#wx_ref{type=ThisT,ref=ThisRef},String, Options)
@@ -665,7 +665,7 @@ getUpdateRegion(#wx_ref{type=ThisT,ref=ThisRef}) ->
wxe_util:call(?wxWindow_GetUpdateRegion,
<<ThisRef:32/?UI>>).
-%% @spec (This::wxWindow()) -> {W::integer(),H::integer()}
+%% @spec (This::wxWindow()) -> {W::integer(), H::integer()}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxwindow.html#wxwindowgetvirtualsize">external documentation</a>.
getVirtualSize(#wx_ref{type=ThisT,ref=ThisRef}) ->
?CLASS(ThisT,wxWindow),
@@ -749,10 +749,10 @@ isEnabled(#wx_ref{type=ThisT,ref=ThisRef}) ->
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxwindow.html#wxwindowisexposed">external documentation</a>.
%% <br /> Alternatives:
%% <p><c>
-%% isExposed(This::wxWindow(), Pt::{X::integer(),Y::integer()}) -> bool() </c>
+%% isExposed(This::wxWindow(), Pt::{X::integer(), Y::integer()}) -> bool() </c>
%% </p>
%% <p><c>
-%% isExposed(This::wxWindow(), Rect::{X::integer(),Y::integer(),W::integer(),H::integer()}) -> bool() </c>
+%% isExposed(This::wxWindow(), Rect::{X::integer(), Y::integer(), W::integer(), H::integer()}) -> bool() </c>
%% </p>
isExposed(#wx_ref{type=ThisT,ref=ThisRef},{PtX,PtY})
when is_integer(PtX),is_integer(PtY) ->
@@ -848,7 +848,7 @@ makeModal(#wx_ref{type=ThisT,ref=ThisRef}, Options)
wxe_util:cast(?wxWindow_MakeModal,
<<ThisRef:32/?UI, 0:32,BinOpt/binary>>).
-%% @spec (This::wxWindow(), Pt::{X::integer(),Y::integer()}) -> ok
+%% @spec (This::wxWindow(), Pt::{X::integer(), Y::integer()}) -> ok
%% @equiv move(This,Pt, [])
move(This,Pt={PtX,PtY})
when is_record(This, wx_ref),is_integer(PtX),is_integer(PtY) ->
@@ -860,7 +860,7 @@ move(This,Pt={PtX,PtY})
%% <p><c>
%% move(This::wxWindow(), X::integer(), Y::integer()) -> move(This,X,Y, []) </c></p>
%% <p><c>
-%% move(This::wxWindow(), Pt::{X::integer(),Y::integer()}, [Option]) -> ok </c>
+%% move(This::wxWindow(), Pt::{X::integer(), Y::integer()}, [Option]) -> ok </c>
%%<br /> Option = {flags, integer()}
%% </p>
@@ -961,7 +961,7 @@ popupMenu(This,Menu)
popupMenu(This,Menu, []).
%% @spec (This::wxWindow(), Menu::wxMenu:wxMenu(), [Option]) -> bool()
-%% Option = {pos, {X::integer(),Y::integer()}}
+%% Option = {pos, {X::integer(), Y::integer()}}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxwindow.html#wxwindowpopupmenu">external documentation</a>.
popupMenu(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=MenuT,ref=MenuRef}, Options)
when is_list(Options) ->
@@ -996,7 +996,7 @@ refresh(This)
refresh(This, []).
%% @spec (This::wxWindow(), [Option]) -> ok
-%% Option = {eraseBackground, bool()} | {rect, {X::integer(),Y::integer(),W::integer(),H::integer()}}
+%% Option = {eraseBackground, bool()} | {rect, {X::integer(), Y::integer(), W::integer(), H::integer()}}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxwindow.html#wxwindowrefresh">external documentation</a>.
refresh(#wx_ref{type=ThisT,ref=ThisRef}, Options)
when is_list(Options) ->
@@ -1008,13 +1008,13 @@ refresh(#wx_ref{type=ThisT,ref=ThisRef}, Options)
wxe_util:cast(?wxWindow_Refresh,
<<ThisRef:32/?UI, 0:32,BinOpt/binary>>).
-%% @spec (This::wxWindow(), Rect::{X::integer(),Y::integer(),W::integer(),H::integer()}) -> ok
+%% @spec (This::wxWindow(), Rect::{X::integer(), Y::integer(), W::integer(), H::integer()}) -> ok
%% @equiv refreshRect(This,Rect, [])
refreshRect(This,Rect={RectX,RectY,RectW,RectH})
when is_record(This, wx_ref),is_integer(RectX),is_integer(RectY),is_integer(RectW),is_integer(RectH) ->
refreshRect(This,Rect, []).
-%% @spec (This::wxWindow(), Rect::{X::integer(),Y::integer(),W::integer(),H::integer()}, [Option]) -> ok
+%% @spec (This::wxWindow(), Rect::{X::integer(), Y::integer(), W::integer(), H::integer()}, [Option]) -> ok
%% Option = {eraseBackground, bool()}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxwindow.html#wxwindowrefreshrect">external documentation</a>.
refreshRect(#wx_ref{type=ThisT,ref=ThisRef},{RectX,RectY,RectW,RectH}, Options)
@@ -1049,14 +1049,14 @@ reparent(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=NewParentT,ref=NewParentRe
wxe_util:call(?wxWindow_Reparent,
<<ThisRef:32/?UI,NewParentRef:32/?UI>>).
-%% @spec (This::wxWindow()) -> {X::integer(),Y::integer()}
+%% @spec (This::wxWindow()) -> {X::integer(), Y::integer()}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxwindow.html#wxwindowscreentoclient">external documentation</a>.
screenToClient(#wx_ref{type=ThisT,ref=ThisRef}) ->
?CLASS(ThisT,wxWindow),
wxe_util:call(?wxWindow_ScreenToClient_2,
<<ThisRef:32/?UI>>).
-%% @spec (This::wxWindow(), Pt::{X::integer(),Y::integer()}) -> {X::integer(),Y::integer()}
+%% @spec (This::wxWindow(), Pt::{X::integer(), Y::integer()}) -> {X::integer(), Y::integer()}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxwindow.html#wxwindowscreentoclient">external documentation</a>.
screenToClient(#wx_ref{type=ThisT,ref=ThisRef},{PtX,PtY})
when is_integer(PtX),is_integer(PtY) ->
@@ -1087,7 +1087,7 @@ scrollWindow(This,Dx,Dy)
scrollWindow(This,Dx,Dy, []).
%% @spec (This::wxWindow(), Dx::integer(), Dy::integer(), [Option]) -> ok
-%% Option = {rect, {X::integer(),Y::integer(),W::integer(),H::integer()}}
+%% Option = {rect, {X::integer(), Y::integer(), W::integer(), H::integer()}}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxwindow.html#wxwindowscrollwindow">external documentation</a>.
scrollWindow(#wx_ref{type=ThisT,ref=ThisRef},Dx,Dy, Options)
when is_integer(Dx),is_integer(Dy),is_list(Options) ->
@@ -1184,7 +1184,7 @@ setCursor(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=CursorT,ref=CursorRef}) -
wxe_util:call(?wxWindow_SetCursor,
<<ThisRef:32/?UI,CursorRef:32/?UI>>).
-%% @spec (This::wxWindow(), MaxSize::{W::integer(),H::integer()}) -> ok
+%% @spec (This::wxWindow(), MaxSize::{W::integer(), H::integer()}) -> ok
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxwindow.html#wxwindowsetmaxsize">external documentation</a>.
setMaxSize(#wx_ref{type=ThisT,ref=ThisRef},{MaxSizeW,MaxSizeH})
when is_integer(MaxSizeW),is_integer(MaxSizeH) ->
@@ -1192,7 +1192,7 @@ setMaxSize(#wx_ref{type=ThisT,ref=ThisRef},{MaxSizeW,MaxSizeH})
wxe_util:cast(?wxWindow_SetMaxSize,
<<ThisRef:32/?UI,MaxSizeW:32/?UI,MaxSizeH:32/?UI>>).
-%% @spec (This::wxWindow(), MinSize::{W::integer(),H::integer()}) -> ok
+%% @spec (This::wxWindow(), MinSize::{W::integer(), H::integer()}) -> ok
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxwindow.html#wxwindowsetminsize">external documentation</a>.
setMinSize(#wx_ref{type=ThisT,ref=ThisRef},{MinSizeW,MinSizeH})
when is_integer(MinSizeW),is_integer(MinSizeH) ->
@@ -1353,9 +1353,9 @@ setScrollPos(#wx_ref{type=ThisT,ref=ThisRef},Orient,Pos, Options)
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxwindow.html#wxwindowsetsize">external documentation</a>.
%% <br /> Alternatives:
%% <p><c>
-%% setSize(This::wxWindow(), Rect::{X::integer(),Y::integer(),W::integer(),H::integer()}) -> setSize(This,Rect, []) </c></p>
+%% setSize(This::wxWindow(), Rect::{X::integer(), Y::integer(), W::integer(), H::integer()}) -> setSize(This,Rect, []) </c></p>
%% <p><c>
-%% setSize(This::wxWindow(), Size::{W::integer(),H::integer()}) -> ok </c>
+%% setSize(This::wxWindow(), Size::{W::integer(), H::integer()}) -> ok </c>
%% </p>
setSize(This,Rect={RectX,RectY,RectW,RectH})
@@ -1374,7 +1374,7 @@ setSize(#wx_ref{type=ThisT,ref=ThisRef},{SizeW,SizeH})
%% setSize(This::wxWindow(), Width::integer(), Height::integer()) -> ok </c>
%% </p>
%% <p><c>
-%% setSize(This::wxWindow(), Rect::{X::integer(),Y::integer(),W::integer(),H::integer()}, [Option]) -> ok </c>
+%% setSize(This::wxWindow(), Rect::{X::integer(), Y::integer(), W::integer(), H::integer()}, [Option]) -> ok </c>
%%<br /> Option = {sizeFlags, integer()}
%% </p>
setSize(#wx_ref{type=ThisT,ref=ThisRef},Width,Height)
@@ -1409,7 +1409,7 @@ setSize(#wx_ref{type=ThisT,ref=ThisRef},X,Y,Width,Height, Options)
wxe_util:cast(?wxWindow_SetSize_5,
<<ThisRef:32/?UI,X:32/?UI,Y:32/?UI,Width:32/?UI,Height:32/?UI, 0:32,BinOpt/binary>>).
-%% @spec (This::wxWindow(), MinSize::{W::integer(),H::integer()}) -> ok
+%% @spec (This::wxWindow(), MinSize::{W::integer(), H::integer()}) -> ok
%% @equiv setSizeHints(This,MinSize, [])
setSizeHints(This,MinSize={MinSizeW,MinSizeH})
when is_record(This, wx_ref),is_integer(MinSizeW),is_integer(MinSizeH) ->
@@ -1421,8 +1421,8 @@ setSizeHints(This,MinSize={MinSizeW,MinSizeH})
%% <p><c>
%% setSizeHints(This::wxWindow(), MinW::integer(), MinH::integer()) -> setSizeHints(This,MinW,MinH, []) </c></p>
%% <p><c>
-%% setSizeHints(This::wxWindow(), MinSize::{W::integer(),H::integer()}, [Option]) -> ok </c>
-%%<br /> Option = {maxSize, {W::integer(),H::integer()}} | {incSize, {W::integer(),H::integer()}}
+%% setSizeHints(This::wxWindow(), MinSize::{W::integer(), H::integer()}, [Option]) -> ok </c>
+%%<br /> Option = {maxSize, {W::integer(), H::integer()}} | {incSize, {W::integer(), H::integer()}}
%% </p>
setSizeHints(This,MinW,MinH)
@@ -1520,7 +1520,7 @@ setToolTip(#wx_ref{type=ThisT,ref=ThisRef},#wx_ref{type=TipT,ref=TipRef}) ->
wxe_util:cast(?wxWindow_SetToolTip_1_1,
<<ThisRef:32/?UI,TipRef:32/?UI>>).
-%% @spec (This::wxWindow(), Size::{W::integer(),H::integer()}) -> ok
+%% @spec (This::wxWindow(), Size::{W::integer(), H::integer()}) -> ok
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_wxwindow.html#wxwindowsetvirtualsize">external documentation</a>.
setVirtualSize(#wx_ref{type=ThisT,ref=ThisRef},{SizeW,SizeH})
when is_integer(SizeW),is_integer(SizeH) ->
@@ -1536,7 +1536,7 @@ setVirtualSize(#wx_ref{type=ThisT,ref=ThisRef},X,Y)
wxe_util:cast(?wxWindow_SetVirtualSize_2,
<<ThisRef:32/?UI,X:32/?UI,Y:32/?UI>>).
-%% @spec (This::wxWindow(), MinSize::{W::integer(),H::integer()}) -> ok
+%% @spec (This::wxWindow(), MinSize::{W::integer(), H::integer()}) -> ok
%% @equiv setVirtualSizeHints(This,MinSize, [])
setVirtualSizeHints(This,MinSize={MinSizeW,MinSizeH})
when is_record(This, wx_ref),is_integer(MinSizeW),is_integer(MinSizeH) ->
@@ -1548,8 +1548,8 @@ setVirtualSizeHints(This,MinSize={MinSizeW,MinSizeH})
%% <p><c>
%% setVirtualSizeHints(This::wxWindow(), MinW::integer(), MinH::integer()) -> setVirtualSizeHints(This,MinW,MinH, []) </c></p>
%% <p><c>
-%% setVirtualSizeHints(This::wxWindow(), MinSize::{W::integer(),H::integer()}, [Option]) -> ok </c>
-%%<br /> Option = {maxSize, {W::integer(),H::integer()}}
+%% setVirtualSizeHints(This::wxWindow(), MinSize::{W::integer(), H::integer()}, [Option]) -> ok </c>
+%%<br /> Option = {maxSize, {W::integer(), H::integer()}}
%% </p>
setVirtualSizeHints(This,MinW,MinH)
diff --git a/lib/wx/src/gen/wx_misc.erl b/lib/wx/src/gen/wx_misc.erl
index cf23d4cf8b..3382d898e4 100644
--- a/lib/wx/src/gen/wx_misc.erl
+++ b/lib/wx/src/gen/wx_misc.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2010. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2011. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -39,7 +39,7 @@ getKeyState(Key)
wxe_util:call(?utils_wxGetKeyState,
<<Key:32/?UI>>).
-%% @spec () -> {X::integer(),Y::integer()}
+%% @spec () -> {X::integer(), Y::integer()}
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_miscellany.html#wxgetmouseposition">external documentation</a>.
getMousePosition() ->
wxe_util:call(?utils_wxGetMousePosition,
@@ -74,14 +74,14 @@ findMenuItemId(#wx_ref{type=FrameT,ref=FrameRef},MenuString,ItemString)
wxe_util:call(?utils_wxFindMenuItemId,
<<FrameRef:32/?UI,(byte_size(MenuString_UC)):32/?UI,(MenuString_UC)/binary, 0:(((8- ((0+byte_size(MenuString_UC)) band 16#7)) band 16#7))/unit:8,(byte_size(ItemString_UC)):32/?UI,(ItemString_UC)/binary, 0:(((8- ((4+byte_size(ItemString_UC)) band 16#7)) band 16#7))/unit:8>>).
-%% @spec (Pt::{X::integer(),Y::integer()}) -> wxWindow:wxWindow()
+%% @spec (Pt::{X::integer(), Y::integer()}) -> wxWindow:wxWindow()
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_miscellany.html#wxgenericfindwindowatpoint">external documentation</a>.
genericFindWindowAtPoint({PtX,PtY})
when is_integer(PtX),is_integer(PtY) ->
wxe_util:call(?utils_wxGenericFindWindowAtPoint,
<<PtX:32/?UI,PtY:32/?UI>>).
-%% @spec (Pt::{X::integer(),Y::integer()}) -> wxWindow:wxWindow()
+%% @spec (Pt::{X::integer(), Y::integer()}) -> wxWindow:wxWindow()
%% @doc See <a href="http://www.wxwidgets.org/manuals/stable/wx_miscellany.html#wxfindwindowatpoint">external documentation</a>.
findWindowAtPoint({PtX,PtY})
when is_integer(PtX),is_integer(PtY) ->
diff --git a/lib/wx/src/gen/wxe_debug.hrl b/lib/wx/src/gen/wxe_debug.hrl
index 960f67a1f6..4224c54200 100644
--- a/lib/wx/src/gen/wxe_debug.hrl
+++ b/lib/wx/src/gen/wxe_debug.hrl
@@ -3273,26 +3273,32 @@ wxdebug_table() ->
{3489, {wxSystemSettings, getFont, 1}},
{3490, {wxSystemSettings, getMetric, 2}},
{3491, {wxSystemSettings, getScreenType, 0}},
- {3492, {wxAuiNotebookEvent, setSelection, 1}},
- {3493, {wxAuiNotebookEvent, getSelection, 0}},
- {3494, {wxAuiNotebookEvent, setOldSelection, 1}},
- {3495, {wxAuiNotebookEvent, getOldSelection, 0}},
- {3496, {wxAuiNotebookEvent, setDragSource, 1}},
- {3497, {wxAuiNotebookEvent, getDragSource, 0}},
- {3498, {wxAuiManagerEvent, setManager, 1}},
- {3499, {wxAuiManagerEvent, getManager, 0}},
- {3500, {wxAuiManagerEvent, setPane, 1}},
- {3501, {wxAuiManagerEvent, getPane, 0}},
- {3502, {wxAuiManagerEvent, setButton, 1}},
- {3503, {wxAuiManagerEvent, getButton, 0}},
- {3504, {wxAuiManagerEvent, setDC, 1}},
- {3505, {wxAuiManagerEvent, getDC, 0}},
- {3506, {wxAuiManagerEvent, veto, 1}},
- {3507, {wxAuiManagerEvent, getVeto, 0}},
- {3508, {wxAuiManagerEvent, setCanVeto, 1}},
- {3509, {wxAuiManagerEvent, canVeto, 0}},
- {3510, {wxLogNull, new, 0}},
- {3511, {wxLogNull, 'Destroy', undefined}},
+ {3492, {wxSystemOptions, getOption, 1}},
+ {3493, {wxSystemOptions, getOptionInt, 1}},
+ {3494, {wxSystemOptions, hasOption, 1}},
+ {3495, {wxSystemOptions, isFalse, 1}},
+ {3496, {wxSystemOptions, setOption_2_1, 2}},
+ {3497, {wxSystemOptions, setOption_2_0, 2}},
+ {3498, {wxAuiNotebookEvent, setSelection, 1}},
+ {3499, {wxAuiNotebookEvent, getSelection, 0}},
+ {3500, {wxAuiNotebookEvent, setOldSelection, 1}},
+ {3501, {wxAuiNotebookEvent, getOldSelection, 0}},
+ {3502, {wxAuiNotebookEvent, setDragSource, 1}},
+ {3503, {wxAuiNotebookEvent, getDragSource, 0}},
+ {3504, {wxAuiManagerEvent, setManager, 1}},
+ {3505, {wxAuiManagerEvent, getManager, 0}},
+ {3506, {wxAuiManagerEvent, setPane, 1}},
+ {3507, {wxAuiManagerEvent, getPane, 0}},
+ {3508, {wxAuiManagerEvent, setButton, 1}},
+ {3509, {wxAuiManagerEvent, getButton, 0}},
+ {3510, {wxAuiManagerEvent, setDC, 1}},
+ {3511, {wxAuiManagerEvent, getDC, 0}},
+ {3512, {wxAuiManagerEvent, veto, 1}},
+ {3513, {wxAuiManagerEvent, getVeto, 0}},
+ {3514, {wxAuiManagerEvent, setCanVeto, 1}},
+ {3515, {wxAuiManagerEvent, canVeto, 0}},
+ {3516, {wxLogNull, new, 0}},
+ {3517, {wxLogNull, 'Destroy', undefined}},
{-1, {mod, func, -1}}
].
diff --git a/lib/wx/src/gen/wxe_funcs.hrl b/lib/wx/src/gen/wxe_funcs.hrl
index af74caaa25..55cbee5572 100644
--- a/lib/wx/src/gen/wxe_funcs.hrl
+++ b/lib/wx/src/gen/wxe_funcs.hrl
@@ -3270,23 +3270,29 @@
-define(wxSystemSettings_GetFont, 3489).
-define(wxSystemSettings_GetMetric, 3490).
-define(wxSystemSettings_GetScreenType, 3491).
--define(wxAuiNotebookEvent_SetSelection, 3492).
--define(wxAuiNotebookEvent_GetSelection, 3493).
--define(wxAuiNotebookEvent_SetOldSelection, 3494).
--define(wxAuiNotebookEvent_GetOldSelection, 3495).
--define(wxAuiNotebookEvent_SetDragSource, 3496).
--define(wxAuiNotebookEvent_GetDragSource, 3497).
--define(wxAuiManagerEvent_SetManager, 3498).
--define(wxAuiManagerEvent_GetManager, 3499).
--define(wxAuiManagerEvent_SetPane, 3500).
--define(wxAuiManagerEvent_GetPane, 3501).
--define(wxAuiManagerEvent_SetButton, 3502).
--define(wxAuiManagerEvent_GetButton, 3503).
--define(wxAuiManagerEvent_SetDC, 3504).
--define(wxAuiManagerEvent_GetDC, 3505).
--define(wxAuiManagerEvent_Veto, 3506).
--define(wxAuiManagerEvent_GetVeto, 3507).
--define(wxAuiManagerEvent_SetCanVeto, 3508).
--define(wxAuiManagerEvent_CanVeto, 3509).
--define(wxLogNull_new, 3510).
--define(wxLogNull_destroy, 3511).
+-define(wxSystemOptions_GetOption, 3492).
+-define(wxSystemOptions_GetOptionInt, 3493).
+-define(wxSystemOptions_HasOption, 3494).
+-define(wxSystemOptions_IsFalse, 3495).
+-define(wxSystemOptions_SetOption_2_1, 3496).
+-define(wxSystemOptions_SetOption_2_0, 3497).
+-define(wxAuiNotebookEvent_SetSelection, 3498).
+-define(wxAuiNotebookEvent_GetSelection, 3499).
+-define(wxAuiNotebookEvent_SetOldSelection, 3500).
+-define(wxAuiNotebookEvent_GetOldSelection, 3501).
+-define(wxAuiNotebookEvent_SetDragSource, 3502).
+-define(wxAuiNotebookEvent_GetDragSource, 3503).
+-define(wxAuiManagerEvent_SetManager, 3504).
+-define(wxAuiManagerEvent_GetManager, 3505).
+-define(wxAuiManagerEvent_SetPane, 3506).
+-define(wxAuiManagerEvent_GetPane, 3507).
+-define(wxAuiManagerEvent_SetButton, 3508).
+-define(wxAuiManagerEvent_GetButton, 3509).
+-define(wxAuiManagerEvent_SetDC, 3510).
+-define(wxAuiManagerEvent_GetDC, 3511).
+-define(wxAuiManagerEvent_Veto, 3512).
+-define(wxAuiManagerEvent_GetVeto, 3513).
+-define(wxAuiManagerEvent_SetCanVeto, 3514).
+-define(wxAuiManagerEvent_CanVeto, 3515).
+-define(wxLogNull_new, 3516).
+-define(wxLogNull_destroy, 3517).
diff --git a/lib/wx/src/wx_object.erl b/lib/wx/src/wx_object.erl
index bfd38960dd..82c4cfbad5 100644
--- a/lib/wx/src/wx_object.erl
+++ b/lib/wx/src/wx_object.erl
@@ -537,16 +537,16 @@ error_info(_Reason, application_controller, _Msg, _State, _Debug) ->
error_info(Reason, Name, Msg, State, Debug) ->
Reason1 =
case Reason of
- {undef,[{M,F,A}|MFAs]} ->
+ {undef,[{M,F,A,L}|MFAs]} ->
case code:is_loaded(M) of
false ->
- {'module could not be loaded',[{M,F,A}|MFAs]};
+ {'module could not be loaded',[{M,F,A,L}|MFAs]};
_ ->
case erlang:function_exported(M, F, length(A)) of
true ->
Reason;
false ->
- {'function not exported',[{M,F,A}|MFAs]}
+ {'function not exported',[{M,F,A,L}|MFAs]}
end
end;
_ ->
diff --git a/lib/wx/test/wx_event_SUITE.erl b/lib/wx/test/wx_event_SUITE.erl
index 0d8dd4852e..8f364049b4 100644
--- a/lib/wx/test/wx_event_SUITE.erl
+++ b/lib/wx/test/wx_event_SUITE.erl
@@ -47,7 +47,7 @@ suite() -> [{ct_hooks,[ts_install_cth]}].
all() ->
[connect, disconnect, connect_msg_20, connect_cb_20,
- mouse_on_grid, spin_event, connect_in_callback].
+ mouse_on_grid, spin_event, connect_in_callback, recursive].
groups() ->
[].
@@ -331,3 +331,35 @@ connect_in_callback(Config) ->
wx_test_lib:flush(),
wx_test_lib:wx_destroy(Frame, Config).
+
+%% Test that event callback which triggers another callback works
+%% i.e. the callback invoker in driver will recurse
+recursive(TestInfo) when is_atom(TestInfo) -> wx_test_lib:tc_info(TestInfo);
+recursive(Config) ->
+ Wx = wx:new(),
+ Frame = wxFrame:new(Wx, ?wxID_ANY, "Connect in callback"),
+ Panel = wxPanel:new(Frame, []),
+ Sz = wxBoxSizer:new(?wxVERTICAL),
+ ListBox = wxListBox:new(Panel, ?wxID_ANY, [{choices, ["foo", "bar", "baz"]}]),
+ wxSizer:add(Sz, ListBox, [{proportion, 1},{flag, ?wxEXPAND}]),
+ wxWindow:setSizer(Panel, Sz),
+ wxListBox:connect(ListBox, command_listbox_selected,
+ [{callback,
+ fun(#wx{event=#wxCommand{commandInt=Id}}, _) ->
+ io:format("Selected ~p~n",[Id])
+ end}]),
+ wxListBox:setSelection(ListBox, 0),
+ wxListBox:connect(ListBox, size,
+ [{callback,
+ fun(#wx{event=#wxSize{}}, _) ->
+ io:format("Size init ~n",[]),
+ case wxListBox:getCount(ListBox) > 0 of
+ true -> wxListBox:delete(ListBox, 0);
+ false -> ok
+ end,
+ io:format("Size done ~n",[])
+ end}]),
+ wxFrame:show(Frame),
+ wx_test_lib:flush(),
+
+ wx_test_lib:wx_destroy(Frame, Config).
diff --git a/lib/xmerl/doc/examples/test_html.erl b/lib/xmerl/doc/examples/test_html.erl
index 3ca15f30f8..3ca15f30f8 100755..100644
--- a/lib/xmerl/doc/examples/test_html.erl
+++ b/lib/xmerl/doc/examples/test_html.erl
diff --git a/lib/xmerl/doc/examples/xml/test.xml b/lib/xmerl/doc/examples/xml/test.xml
index e803a83560..e803a83560 100755..100644
--- a/lib/xmerl/doc/examples/xml/test.xml
+++ b/lib/xmerl/doc/examples/xml/test.xml
diff --git a/lib/xmerl/doc/examples/xml/test2.xml b/lib/xmerl/doc/examples/xml/test2.xml
index 0cb11194fc..0cb11194fc 100755..100644
--- a/lib/xmerl/doc/examples/xml/test2.xml
+++ b/lib/xmerl/doc/examples/xml/test2.xml
diff --git a/lib/xmerl/doc/examples/xml/test3.xml b/lib/xmerl/doc/examples/xml/test3.xml
index dbdc1e62c2..dbdc1e62c2 100755..100644
--- a/lib/xmerl/doc/examples/xml/test3.xml
+++ b/lib/xmerl/doc/examples/xml/test3.xml
diff --git a/lib/xmerl/doc/examples/xml/test4.xml b/lib/xmerl/doc/examples/xml/test4.xml
index e9d85b8d8f..e9d85b8d8f 100755..100644
--- a/lib/xmerl/doc/examples/xml/test4.xml
+++ b/lib/xmerl/doc/examples/xml/test4.xml
diff --git a/lib/xmerl/doc/examples/xml/test5.xml b/lib/xmerl/doc/examples/xml/test5.xml
index e9d85b8d8f..e9d85b8d8f 100755..100644
--- a/lib/xmerl/doc/examples/xml/test5.xml
+++ b/lib/xmerl/doc/examples/xml/test5.xml
diff --git a/lib/xmerl/doc/examples/xml/testdtd.dtd b/lib/xmerl/doc/examples/xml/testdtd.dtd
index 2ce1c513a6..2ce1c513a6 100755..100644
--- a/lib/xmerl/doc/examples/xml/testdtd.dtd
+++ b/lib/xmerl/doc/examples/xml/testdtd.dtd
diff --git a/lib/xmerl/doc/examples/xml/xmerl.xml b/lib/xmerl/doc/examples/xml/xmerl.xml
index f02282dbef..f02282dbef 100755..100644
--- a/lib/xmerl/doc/examples/xml/xmerl.xml
+++ b/lib/xmerl/doc/examples/xml/xmerl.xml
diff --git a/lib/xmerl/doc/src/make.dep b/lib/xmerl/doc/src/make.dep
deleted file mode 100644
index 9c303fc41c..0000000000
--- a/lib/xmerl/doc/src/make.dep
+++ /dev/null
@@ -1,24 +0,0 @@
-# ----------------------------------------------------
-# >>>> Do not edit this file <<<<
-# This file was automaticly generated by
-# /home/otp/bin/docdepend
-# ----------------------------------------------------
-
-
-# ----------------------------------------------------
-# TeX files that the DVI file depend on
-# ----------------------------------------------------
-
-book.dvi: book.tex part.tex ref_man.tex xmerl.tex xmerl_eventp.tex \
- xmerl_scan.tex xmerl_ug.tex xmerl_xpath.tex \
- xmerl_xs.tex xmerl_xsd.tex xmerl_sax_parser.tex
-
-# ----------------------------------------------------
-# Source inlined when transforming from source to LaTeX
-# ----------------------------------------------------
-
-book.tex: ref_man.xml
-
-xmerl_ug.tex: motorcycles.txt motorcycles2html.erl motorcycles_dtd.txt \
- new_motorcycles.txt new_motorcycles2.txt
-
diff --git a/lib/xmerl/doc/src/part_notes.xml b/lib/xmerl/doc/src/part_notes.xml
index 827ffd90e9..827ffd90e9 100755..100644
--- a/lib/xmerl/doc/src/part_notes.xml
+++ b/lib/xmerl/doc/src/part_notes.xml
diff --git a/lib/xmerl/include/xmerl.hrl b/lib/xmerl/include/xmerl.hrl
index 7bb3f4de9b..3760a5cce0 100755..100644
--- a/lib/xmerl/include/xmerl.hrl
+++ b/lib/xmerl/include/xmerl.hrl
@@ -61,10 +61,11 @@
}).
%% namespace node - i.e. a {Prefix, URI} pair
-%% TODO: these are not currently used?? /RC
-record(xmlNsNode,{
- prefix,
- uri = []
+ parents = [], % [{atom(),integer()}]
+ pos, % integer()
+ prefix, % string()
+ uri = [] % [] | atom()
}).
%% XML Element
@@ -103,9 +104,10 @@
%% processing instruction
-record(xmlPI,{
- name, % atom()
- pos, % integer()
- value % IOlist()
+ name, % atom()
+ parents = [], % [{atom(),integer()}]
+ pos, % integer()
+ value % IOlist()
}).
-record(xmlDocument,{
@@ -154,6 +156,9 @@
declarations = [], % [{Name, Attrs}]
doctype_name,
doctype_DTD = internal, % internal | DTDId
+ comments = true,
+ document = false,
+ default_attrs = false,
rules,
keep_rules = false, % delete (ets) tab if false
namespace_conformant = false, % true | false
diff --git a/lib/xmerl/include/xmerl_xlink.hrl b/lib/xmerl/include/xmerl_xlink.hrl
index 375e244c23..375e244c23 100755..100644
--- a/lib/xmerl/include/xmerl_xlink.hrl
+++ b/lib/xmerl/include/xmerl_xlink.hrl
diff --git a/lib/xmerl/src/xmerl.erl b/lib/xmerl/src/xmerl.erl
index cf78f7bdf7..2332517988 100644
--- a/lib/xmerl/src/xmerl.erl
+++ b/lib/xmerl/src/xmerl.erl
@@ -307,7 +307,7 @@ apply_cb(Ms, F, Df, Args) ->
apply_cb([M|Ms], F, Df, Args, Ms0) ->
case catch apply(M, F, Args) of
- {'EXIT', {undef,[{M,F,_}|_]}} ->
+ {'EXIT', {undef,[{M,F,_,_}|_]}} ->
apply_cb(Ms, F, Df, Args, Ms0);
{'EXIT', Reason} ->
exit(Reason);
diff --git a/lib/xmerl/src/xmerl_lib.erl b/lib/xmerl/src/xmerl_lib.erl
index 6402f1cbeb..aeb821f411 100644
--- a/lib/xmerl/src/xmerl_lib.erl
+++ b/lib/xmerl/src/xmerl_lib.erl
@@ -160,8 +160,9 @@ expand_element(E = #xmlText{}, Pos, Parents, Norm) ->
E#xmlText{pos = Pos,
parents = Parents,
value = expand_text(E#xmlText.value, Norm)};
-expand_element(E = #xmlPI{}, Pos, _Parents, Norm) ->
+expand_element(E = #xmlPI{}, Pos, Parents, Norm) ->
E#xmlPI{pos = Pos,
+ parents = Parents,
value = expand_text(E#xmlPI.value, Norm)};
expand_element(E = #xmlComment{}, Pos, Parents, Norm) ->
E#xmlComment{pos = Pos,
diff --git a/lib/xmerl/src/xmerl_sax_parser_base.erlsrc b/lib/xmerl/src/xmerl_sax_parser_base.erlsrc
index 3b9eaa309c..ec9178ea25 100644
--- a/lib/xmerl/src/xmerl_sax_parser_base.erlsrc
+++ b/lib/xmerl/src/xmerl_sax_parser_base.erlsrc
@@ -944,14 +944,19 @@ parse_att_value(?STRING_REST("&", Rest), State, Stop, Acc) ->
{unparsed, Name, _} ->
?fatal_error(State1, "Unparsed entity reference in attribute value: " ++ Name)
end;
-parse_att_value(?STRING_UNBOUND_REST(Stop, Rest), State, Stop, Acc) ->
+parse_att_value(?STRING_UNBOUND_REST(Stop, Rest), State, Stop, Acc) ->
{lists:reverse(Acc), Rest, State};
-parse_att_value(?STRING_UNBOUND_REST($<, _Rest), State, _Stop, _Acc) ->
+parse_att_value(?STRING_UNBOUND_REST($<, _Rest), State, _Stop, _Acc) ->
?fatal_error(State, "< not allowed in attribute value");
-parse_att_value(?STRING_UNBOUND_REST(C, Rest), State, Stop, Acc) ->
- parse_att_value(Rest, State, Stop, [C|Acc]);
-parse_att_value(Bytes, State, Stop, Acc) ->
- unicode_incomplete_check([Bytes, State, Stop, Acc, fun parse_att_value/4],
+parse_att_value(?STRING_UNBOUND_REST(C, Rest), State, Stop, Acc) ->
+ if
+ ?is_char(C) ->
+ parse_att_value(Rest, State, Stop, [C|Acc]);
+ true ->
+ ?fatal_error(State, lists:flatten(io_lib:format("Bad character in attribute value: ~p", [C])))
+ end;
+parse_att_value(Bytes, State, Stop, Acc) ->
+ unicode_incomplete_check([Bytes, State, Stop, Acc, fun parse_att_value/4],
undefined).
@@ -1120,10 +1125,10 @@ parse_content(?STRING_UNBOUND_REST(C, Rest), State, Acc, _IgnorableWS) ->
?is_char(C) ->
parse_content(Rest, State, [C|Acc], false);
true ->
- ?fatal_error(State, "Bad character in content: " ++ C)
- end;
-parse_content(Bytes, State, Acc, IgnorableWS) ->
- unicode_incomplete_check([Bytes, State, Acc, IgnorableWS, fun parse_content/4],
+ ?fatal_error(State, lists:flatten(io_lib:format("Bad character in content: ~p", [C])))
+ end;
+parse_content(Bytes, State, Acc, IgnorableWS) ->
+ unicode_incomplete_check([Bytes, State, Acc, IgnorableWS, fun parse_content/4],
undefined).
@@ -2522,11 +2527,16 @@ parse_entity_value(?STRING_REST("%", Rest), #xmerl_sax_parser_state{file_type=Ty
end
end;
-parse_entity_value(?STRING_UNBOUND_REST(Stop, Rest), State, Stop, Acc) ->
+parse_entity_value(?STRING_UNBOUND_REST(Stop, Rest), State, Stop, Acc) ->
{lists:reverse(Acc), Rest, State};
-parse_entity_value(?STRING_UNBOUND_REST(C, Rest), State, Stop, Acc) ->
- parse_entity_value(Rest, State, Stop, [C|Acc]);
-parse_entity_value(Bytes, State, Stop, Acc) ->
+parse_entity_value(?STRING_UNBOUND_REST(C, Rest), State, Stop, Acc) ->
+ if
+ ?is_char(C) ->
+ parse_entity_value(Rest, State, Stop, [C|Acc]);
+ true ->
+ ?fatal_error(State, lists:flatten(io_lib:format("Bad character in entity value: ~p", [C])))
+ end;
+parse_entity_value(Bytes, State, Stop, Acc) ->
unicode_incomplete_check([Bytes, State, Stop, Acc, fun parse_entity_value/4],
undefined).
diff --git a/lib/xmerl/src/xmerl_scan.erl b/lib/xmerl/src/xmerl_scan.erl
index 25c6547497..ec7ea534d6 100644
--- a/lib/xmerl/src/xmerl_scan.erl
+++ b/lib/xmerl/src/xmerl_scan.erl
@@ -100,7 +100,21 @@
%% <dd>Set default character set used (default UTF-8).
%% This character set is used only if not explicitly given by the XML
%% declaration. </dd>
+%% <dt><code>{document, Flag}</code></dt>
+%% <dd>Set to 'true' if xmerl should return a complete XML document
+%% as an xmlDocument record (default 'false').</dd>
+%% <dt><code>{comments, Flag}</code></dt>
+%% <dd>Set to 'false' if xmerl should skip comments otherwise they will
+%% be returned as xmlComment records (default 'true').</dd>
+%% <dt><code>{default_attrs, Flag}</code></dt>
+%% <dd>Set to 'true' if xmerl should add to elements missing attributes
+%% with a defined default value (default 'false').</dd>
%% </dl>
+%% @type document() = xmlElement() | xmlDocument(). <p>
+%% The document returned by <tt>xmerl_scan:string/[1,2]</tt> and
+%% <tt>xmerl_scan:file/[1,2]</tt>. The type of the returned record depends on
+%% the value of the document option passed to the function.
+%% </p>
-module(xmerl_scan).
@@ -224,7 +238,7 @@ cont_state(X, S=#xmerl_scanner{fun_states = FS}) ->
file(F) ->
file(F, []).
-%% @spec file(Filename::string(), Options::option_list()) -> {xmlElement(),Rest}
+%% @spec file(Filename::string(), Options::option_list()) -> {document(),Rest}
%% Rest = list()
%%% @doc Parse file containing an XML document
file(F, Options) ->
@@ -264,7 +278,7 @@ int_file_decl(F, Options,_ExtCharset) ->
string(Str) ->
string(Str, []).
-%% @spec string(Text::list(),Options::option_list()) -> {xmlElement(),Rest}
+%% @spec string(Text::list(),Options::option_list()) -> {document(),Rest}
%% Rest = list()
%%% @doc Parse string containing an XML document
string(Str, Options) ->
@@ -381,6 +395,12 @@ initial_state([{quiet, F}|T], S) when F==true; F==false ->
initial_state(T, S#xmerl_scanner{quiet = F});
initial_state([{doctype_DTD,DTD}|T], S) ->
initial_state(T,S#xmerl_scanner{doctype_DTD = DTD});
+initial_state([{document, F}|T], S) when is_boolean(F) ->
+ initial_state(T,S#xmerl_scanner{document = F});
+initial_state([{comments, F}|T], S) when is_boolean(F) ->
+ initial_state(T,S#xmerl_scanner{comments = F});
+initial_state([{default_attrs, F}|T], S) when is_boolean(F) ->
+ initial_state(T,S#xmerl_scanner{default_attrs = F});
initial_state([{text_decl,Bool}|T], S) ->
initial_state(T,S#xmerl_scanner{text_decl=Bool});
initial_state([{environment,Env}|T], S) ->
@@ -518,6 +538,7 @@ scan_document(Str0, S=#xmerl_scanner{event_fun = Event,
line = L, col = C,
environment=Env,
encoding=Charset,
+ document=Document,
validation=ValidateResult}) ->
S1 = Event(#xmerl_event{event = started,
line = L,
@@ -530,8 +551,8 @@ scan_document(Str0, S=#xmerl_scanner{event_fun = Event,
Str=if
Charset == "utf-8" ->
Str0;
- Charset=/=undefined -> % Default character set is UTF-8
- xmerl_ucs:to_unicode(Str0,list_to_atom(Charset));
+ Charset =/= undefined -> % Default character set is UTF-8
+ xmerl_ucs:to_unicode(Str0, list_to_atom(Charset));
true -> %% Charset is undefined if no external input is
%% given, and no auto detection of character
%% encoding was made.
@@ -539,17 +560,17 @@ scan_document(Str0, S=#xmerl_scanner{event_fun = Event,
end,
%% M1 = erlang:memory(),
%% io:format("Memory status before prolog: ~p~n",[M1]),
- {T1, S2} = scan_prolog(Str, S1, _StartPos = 1),
+ {Prolog, Pos, T1, S2} = scan_prolog(Str, S1, _StartPos = 1),
%% M2 = erlang:memory(),
%% io:format("Memory status after prolog: ~p~n",[M2]),
%%io:format("scan_document 2, prolog parsed~n",[]),
- T2 = scan_mandatory("<",T1,1,S2,expected_element_start_tag),
+ T2 = scan_mandatory("<", T1, 1, S2, expected_element_start_tag),
%% M3 = erlang:memory(),
%% io:format("Memory status before element: ~p~n",[M3]),
- {Res, T3, S3} =scan_element(T2,S2,_StartPos = 1),
+ {Res, T3, S3} = scan_element(T2,S2,Pos),
%% M4 = erlang:memory(),
%% io:format("Memory status after element: ~p~n",[M4]),
- {Tail, S4}=scan_misc(T3, S3, _StartPos = 1),
+ {Misc, _Pos1, Tail, S4}=scan_misc(T3, S3, Pos + 1),
%% M5 = erlang:memory(),
%% io:format("Memory status after misc: ~p~n",[M5]),
@@ -558,44 +579,52 @@ scan_document(Str0, S=#xmerl_scanner{event_fun = Event,
col = S4#xmerl_scanner.col,
data = document}, S4),
- {Res2,S6} = case validation_mode(ValidateResult) of
+ {Res2, S6} = case validation_mode(ValidateResult) of
off ->
- {Res,cleanup(S5)};
+ {Res, cleanup(S5)};
dtd when Env == element; Env == prolog ->
check_decl2(S5),
- case xmerl_validate:validate(S5,Res) of
- {'EXIT',{error,Reason}} ->
- S5b=cleanup(S5),
- ?fatal({failed_validation,Reason}, S5b);
- {'EXIT',Reason} ->
- S5b=cleanup(S5),
- ?fatal({failed_validation,Reason}, S5b);
- {error,Reason} ->
- S5b=cleanup(S5),
- ?fatal({failed_validation,Reason}, S5b);
- {error,Reason,_Next} ->
- S5b=cleanup(S5),
- ?fatal({failed_validation,Reason}, S5b);
+ case xmerl_validate:validate(S5, Res) of
+ {'EXIT', {error, Reason}} ->
+ S5b = cleanup(S5),
+ ?fatal({failed_validation, Reason}, S5b);
+ {'EXIT', Reason} ->
+ S5b = cleanup(S5),
+ ?fatal({failed_validation, Reason}, S5b);
+ {error, Reason} ->
+ S5b = cleanup(S5),
+ ?fatal({failed_validation, Reason}, S5b);
+ {error, Reason, _Next} ->
+ S5b = cleanup(S5),
+ ?fatal({failed_validation, Reason}, S5b);
_XML ->
- {Res,cleanup(S5)}
+ {Res, cleanup(S5)}
end;
schema ->
- case schemaLocations(Res,S5) of
- {ok,Schemas} ->
+ case schemaLocations(Res, S5) of
+ {ok, Schemas} ->
cleanup(S5),
%%io:format("Schemas: ~p~nRes: ~p~ninhertih_options(S): ~p~n",
%% [Schemas,Res,inherit_options(S5)]),
- XSDRes = xmerl_xsd:process_validate(Schemas,Res,
+ XSDRes = xmerl_xsd:process_validate(Schemas, Res,
inherit_options(S5)),
- handle_schema_result(XSDRes,S5);
+ handle_schema_result(XSDRes, S5);
_ ->
- {Res,cleanup(S5)}
+ {Res, cleanup(S5)}
end;
_ ->
- {Res,cleanup(S5)}
+ {Res, cleanup(S5)}
end,
- {Res2, Tail, S6}.
+ Res3 =
+ case Document of
+ true ->
+ Content = lists:reverse(Prolog, [Res2 | lists:reverse(Misc)]),
+ #xmlDocument{content = Content};
+ false ->
+ Res2
+ end,
+ {Res3, Tail, S6}.
scan_decl(Str, S=#xmerl_scanner{event_fun = Event,
@@ -609,11 +638,11 @@ scan_decl(Str, S=#xmerl_scanner{event_fun = Event,
data = document}, S),
case scan_prolog(Str, S1, _StartPos = 1) of
- {T2="<"++_, S2} ->
+ {_,_,T2="<"++_, S2} ->
{{S2#xmerl_scanner.user_state,T2},[],S2};
- {[], S2}->
+ {_,_,[], S2}->
{[],[],S2};
- {T2, S2} ->
+ {_,_,T2, S2} ->
{_,_,S3} = scan_content(T2,S2,[],_Attrs=[],S2#xmerl_scanner.space,
_Lang=[],_Parents=[],#xmlNamespace{}),
{T2,[],S3}
@@ -624,14 +653,17 @@ scan_decl(Str, S=#xmerl_scanner{event_fun = Event,
%%% prolog ::= XMLDecl? Misc* (doctypedecl Misc*)?
%%%
%% empty text declarations are handled by the first function clause.
-scan_prolog([], S=#xmerl_scanner{continuation_fun = F}, Pos) ->
+scan_prolog(T, S, Pos) ->
+ scan_prolog(T, S, Pos, []).
+scan_prolog([], S=#xmerl_scanner{continuation_fun = F}, Pos, Acc) ->
?dbg("cont()...~n", []),
- F(fun(MoreBytes, S1) -> scan_prolog(MoreBytes, S1, Pos) end,
- fun(S1) -> {[], S1} end,
+ F(fun(MoreBytes, S1) -> scan_prolog(MoreBytes, S1, Pos, Acc) end,
+ fun(S1) -> {Acc, Pos, [], S1} end,
S);
-scan_prolog("<?xml"++T,S0=#xmerl_scanner{encoding=Charset0,col=Col,line=L},Pos)
- when ?whitespace(hd(T)) ->
- {Charset,T3, S3}=
+scan_prolog("<?xml"++T,
+ S0=#xmerl_scanner{encoding=Charset0,col=Col,line=L},
+ Pos,Acc) when ?whitespace(hd(T)) ->
+ {Charset, T3, S3} =
if
Col==1,L==1,S0#xmerl_scanner.text_decl==true ->
?dbg("prolog(\"<?xml\")~n", []),
@@ -639,13 +671,13 @@ scan_prolog("<?xml"++T,S0=#xmerl_scanner{encoding=Charset0,col=Col,line=L},Pos)
{_,T1,S1} = mandatory_strip(T,S),
{Decl,T2, S2}=scan_text_decl(T1,S1),
Encoding=Decl#xmlDecl.encoding,
- {Encoding,T2, S2#xmerl_scanner{encoding=Encoding}};
+ {Encoding, T2, S2#xmerl_scanner{encoding=Encoding}};
Col==1,L==1 ->
?dbg("prolog(\"<?xml\")~n", []),
?bump_col(5),
{Decl,T2, S2}=scan_xml_decl(T, S),
Encoding=Decl#xmlDecl.encoding,
- {Encoding,T2, S2#xmerl_scanner{encoding=Encoding}};
+ {Encoding, T2, S2#xmerl_scanner{encoding=Encoding}};
true ->
?fatal({xml_declaration_must_be_first_in_doc,Col,L},S0)
end,
@@ -659,7 +691,7 @@ scan_prolog("<?xml"++T,S0=#xmerl_scanner{encoding=Charset0,col=Col,line=L},Pos)
%% Now transform to declared character set.
if
Charset==Charset0 -> % Document already transformed to this charset!
- scan_prolog(T3, S3, Pos);
+ scan_prolog(T3, S3, Pos, Acc);
Charset0=/=undefined ->
%% For example may an external entity
%% have the BOM for utf-16 and the internal
@@ -668,17 +700,18 @@ scan_prolog("<?xml"++T,S0=#xmerl_scanner{encoding=Charset0,col=Col,line=L},Pos)
%% 'iso-10646-utf-1', and Charset will be 'utf-16', all
%% legal.
%%
- scan_prolog(T3,S3#xmerl_scanner{encoding=Charset0},Pos);
+ scan_prolog(T3,S3#xmerl_scanner{encoding=Charset0},Pos,Acc);
Charset == "utf-8" ->
- scan_prolog(T3, S3, Pos);
+ scan_prolog(T3, S3, Pos, Acc);
Charset=/=undefined -> % Document not previously transformed
T4=xmerl_ucs:to_unicode(T3,list_to_atom(Charset)),
- scan_prolog(T4, S3, Pos);
+ scan_prolog(T4, S3, Pos, Acc);
true -> % No encoding info given
- scan_prolog(T3, S3, Pos)
+ scan_prolog(T3, S3, Pos, Acc)
end;
-scan_prolog("<!DOCTYPE" ++ T, S0=#xmerl_scanner{environment=prolog,
- encoding=_Charset}, Pos) ->
+scan_prolog("<!DOCTYPE" ++ T,
+ S0=#xmerl_scanner{environment=prolog,encoding=_Charset},
+ Pos, Acc) ->
?dbg("prolog(\"<!DOCTYPE\")~n", []),
?bump_col(9),
%% If no known character set assume it is UTF-8
@@ -687,10 +720,13 @@ scan_prolog("<!DOCTYPE" ++ T, S0=#xmerl_scanner{environment=prolog,
true -> T
end,
{T2, S1} = scan_doctype(T1, S),
- scan_misc(T2, S1, Pos);
-scan_prolog(Str="%"++_T,S=#xmerl_scanner{environment={external,_}},_Pos) ->
- scan_ext_subset(Str,S);
-scan_prolog(Str, S0 = #xmerl_scanner{user_state=_US,encoding=_Charset},Pos) ->
+ scan_misc(T2, S1, Pos, Acc);
+scan_prolog(Str="%"++_T,S=#xmerl_scanner{environment={external,_}},
+ Pos,Acc) ->
+ {T, S1} = scan_ext_subset(Str,S),
+ {Acc, Pos, T, S1};
+scan_prolog(Str, S0 = #xmerl_scanner{user_state=_US,encoding=_Charset},
+ Pos,Acc) ->
?dbg("prolog(\"<\")~n", []),
%% Check for Comments, PI before possible DOCTYPE declaration
@@ -700,26 +736,28 @@ scan_prolog(Str, S0 = #xmerl_scanner{user_state=_US,encoding=_Charset},Pos) ->
%% Charset==undefined -> xmerl_ucs:to_unicode(Str,'utf-8');
true -> Str
end,
- {T1, S1}=scan_misc(T, S, Pos),
- scan_prolog2(T1,S1,Pos).
+ {Acc1, Pos1, T1, S1}=scan_misc(T, S, Pos, Acc),
+ scan_prolog2(T1,S1,Pos1,Acc1).
-scan_prolog2([], S=#xmerl_scanner{continuation_fun = F}, Pos) ->
+scan_prolog2([], S=#xmerl_scanner{continuation_fun = F}, Pos, Acc) ->
?dbg("cont()...~n", []),
- F(fun(MoreBytes, S1) -> scan_prolog2(MoreBytes, S1, Pos) end,
- fun(S1) -> {[], S1} end,
+ F(fun(MoreBytes, S1) -> scan_prolog2(MoreBytes, S1, Pos, Acc) end,
+ fun(S1) -> {Acc, Pos, [], S1} end,
S);
-scan_prolog2("<!DOCTYPE" ++ T, S0=#xmerl_scanner{environment=prolog}, Pos) ->
+scan_prolog2("<!DOCTYPE" ++ T, S0=#xmerl_scanner{environment=prolog},
+ Pos, Acc) ->
?dbg("prolog(\"<!DOCTYPE\")~n", []),
?bump_col(9),
{T1, S1} = scan_doctype(T, S),
- scan_misc(T1, S1, Pos);
-scan_prolog2(Str = "<!" ++ _, S, _Pos) ->
+ scan_misc(T1, S1, Pos, Acc);
+scan_prolog2(Str = "<!" ++ _, S, Pos, Acc) ->
?dbg("prolog(\"<!\")~n", []),
%% In e.g. a DTD, we jump directly to markup declarations
- scan_ext_subset(Str, S);
-scan_prolog2(Str, S0 = #xmerl_scanner{user_state=_US},Pos) ->
+ {T, S1} = scan_ext_subset(Str, S),
+ {Acc, Pos, T, S1};
+scan_prolog2(Str, S0 = #xmerl_scanner{user_state=_US},Pos,Acc) ->
?dbg("prolog(\"<\")~n", []),
%% Here we consider the DTD provided by doctype_DTD option,
@@ -733,7 +771,7 @@ scan_prolog2(Str, S0 = #xmerl_scanner{user_state=_US},Pos) ->
end,
%% Check for more Comments and PI after DOCTYPE declaration
% ?bump_col(1),
- scan_misc(Str, S1, Pos).
+ scan_misc(Str, S1, Pos, Acc).
@@ -743,26 +781,46 @@ scan_prolog2(Str, S0 = #xmerl_scanner{user_state=_US},Pos) ->
%% - Neither of Comment and PI are returned in the resulting parsed
%% structure.
%% - scan_misc/3 implements Misc* as that is how the rule is always used
-scan_misc([], S=#xmerl_scanner{continuation_fun = F}, Pos) ->
+scan_misc(T, S, Pos) ->
+ scan_misc(T, S, Pos, []).
+scan_misc([], S=#xmerl_scanner{continuation_fun = F}, Pos, Acc) ->
?dbg("cont()...~n", []),
- F(fun(MoreBytes, S1) -> scan_misc(MoreBytes, S1, Pos) end,
- fun(S1) -> {[], S1} end,
+ F(fun(MoreBytes, S1) -> scan_misc(MoreBytes, S1, Pos, Acc) end,
+ fun(S1) -> {Acc, Pos, [], S1} end,
S);
-scan_misc("<!--" ++ T, S0, Pos) -> % Comment
+scan_misc("<!--" ++ T, S0=#xmerl_scanner{acc_fun = F, comments=CF}, Pos, Acc) -> % Comment
?bump_col(4),
- {_, T1, S1} = scan_comment(T, S, Pos, _Parents = [], _Lang = []),
- scan_misc(T1,S1,Pos);
-scan_misc("<?" ++ T, S0, Pos) -> % PI
+ {C, T1, S1} = scan_comment(T, S, Pos, _Parents = [], _Lang = []),
+ case CF of
+ true ->
+ {Acc2, Pos2, S3} =
+ case F(C, Acc, S1) of
+ {Acc1, S2} ->
+ {Acc1, Pos + 1, S2};
+ {Acc1, Pos1, S2} ->
+ {Acc1, Pos1, S2}
+ end,
+ scan_misc(T1, S3, Pos2, Acc2);
+ false ->
+ scan_misc(T1, S1, Pos, Acc)
+ end;
+scan_misc("<?" ++ T, S0=#xmerl_scanner{acc_fun = F}, Pos, Acc) -> % PI
?dbg("prolog(\"<?\")~n", []),
?bump_col(2),
- {_PI, T1, S1} = scan_pi(T, S, Pos),
- scan_misc(T1,S1,Pos);
-scan_misc(T=[H|_T], S, Pos) when ?whitespace(H) ->
+ {PI, T1, S1} = scan_pi(T, S, Pos, []),
+ {Acc2, Pos2, S3} = case F(PI, Acc, S1) of
+ {Acc1, S2} ->
+ {Acc1, Pos + 1, S2};
+ {Acc1, Pos1, S2} ->
+ {Acc1, Pos1, S2}
+ end,
+ scan_misc(T1,S3,Pos2,Acc2);
+scan_misc(T=[H|_T], S, Pos, Acc) when ?whitespace(H) ->
?dbg("prolog(whitespace)~n", []),
{_,T1,S1}=strip(T,S),
- scan_misc(T1,S1,Pos);
-scan_misc(T,S,_Pos) ->
- {T,S}.
+ scan_misc(T1,S1,Pos,Acc);
+scan_misc(T,S,Pos,Acc) ->
+ {Acc,Pos,T,S}.
cleanup(S=#xmerl_scanner{keep_rules = false,
@@ -789,7 +847,8 @@ scan_xml_decl(T, S) ->
Attr = #xmlAttribute{name = version,
parents = [{xml, _XMLPos = 1}],
value = Vsn},
- scan_xml_decl(T4, S4, #xmlDecl{attributes = [Attr]}).
+ scan_xml_decl(T4, S4, #xmlDecl{vsn = Vsn,
+ attributes = [Attr]}).
scan_xml_decl([], S=#xmerl_scanner{continuation_fun = F}, Decl) ->
?dbg("cont()...~n", []),
@@ -1025,50 +1084,53 @@ xml_vsn([H|T], S=#xmerl_scanner{col = C}, Delim, Acc) ->
%%%%%%% [16] PI ::= '<?' PITarget (S (Char* - (Char* '?>' Char*)))? '?>'
-scan_pi([], S=#xmerl_scanner{continuation_fun = F}, Pos) ->
+scan_pi([], S=#xmerl_scanner{continuation_fun = F}, Pos, Ps) ->
?dbg("cont()...~n", []),
- F(fun(MoreBytes, S1) -> scan_pi(MoreBytes, S1, Pos) end,
+ F(fun(MoreBytes, S1) -> scan_pi(MoreBytes, S1, Pos, Ps) end,
fun(S1) -> ?fatal(unexpected_end, S1) end,
S);
-scan_pi(Str = [H1,H2,H3 | T],S0=#xmerl_scanner{line = L, col = C}, Pos)
+scan_pi(Str = [H1,H2,H3 | T],S0=#xmerl_scanner{line = L, col = C}, Pos, Ps)
when H1==$x;H1==$X ->
%% names beginning with [xX][mM][lL] are reserved for future use.
?bump_col(3),
if
((H2==$m) or (H2==$M)) and
((H3==$l) or (H3==$L)) ->
- scan_wellknown_pi(T,S,Pos);
+ scan_wellknown_pi(T,S,Pos,Ps);
true ->
{Target, _NamespaceInfo, T1, S1} = scan_name(Str, S),
- scan_pi(T1, S1, Target, L, C, Pos, [])
+ scan_pi(T1, S1, Target, L, C, Pos, Ps, [])
end;
-scan_pi(Str, S=#xmerl_scanner{line = L, col = C}, Pos) ->
+scan_pi(Str, S=#xmerl_scanner{line = L, col = C}, Pos, Ps) ->
{Target, _NamespaceInfo, T1, S1} = scan_name(Str, S),
- scan_pi(T1, S1, Target, L, C, Pos,[]).
+ scan_pi(T1, S1, Target, L, C, Pos, Ps, []).
%%% More info on xml-stylesheet can be found at:
%%% "Associating Style Sheets with XML documents", Version 1.0,
%%% W3C Recommendation 29 June 1999 (http://www.w3.org/TR/xml-stylesheet/)
-scan_wellknown_pi("-stylesheet"++T, S0=#xmerl_scanner{line=L,col=C},Pos) ->
+scan_wellknown_pi("-stylesheet"++T, S0=#xmerl_scanner{line=L,col=C},Pos,Ps) ->
?dbg("prolog(\"<?xml-stylesheet\")~n", []),
?bump_col(16),
- scan_pi(T, S, "xml-stylesheet",L,C,Pos,[]);
-scan_wellknown_pi(Str,S,_Pos) ->
+ scan_pi(T, S, "xml-stylesheet",L,C,Pos,Ps,[]);
+scan_wellknown_pi(Str,S,_Pos,_Ps) ->
?fatal({invalid_target_name, lists:sublist(Str, 1, 10)}, S).
-scan_pi([], S=#xmerl_scanner{continuation_fun = F}, Target,L, C, Pos, Acc) ->
+scan_pi([], S=#xmerl_scanner{continuation_fun = F}, Target,
+ L, C, Pos, Ps, Acc) ->
?dbg("cont()...~n", []),
- F(fun(MoreBytes, S1) -> scan_pi(MoreBytes, S1, Target, L, C, Pos, Acc) end,
+ F(fun(MoreBytes, S1) -> scan_pi(MoreBytes, S1, Target,
+ L, C, Pos, Ps, Acc) end,
fun(S1) -> ?fatal(unexpected_end, S1) end,
S);
scan_pi("?>" ++ T, S0 = #xmerl_scanner{hook_fun = Hook,
event_fun = Event},
- Target, L, C, Pos, Acc) ->
+ Target, L, C, Pos, Ps, Acc) ->
?bump_col(2),
PI = #xmlPI{name = Target,
+ parents = Ps,
pos = Pos,
value = lists:reverse(Acc)},
S1 = #xmerl_scanner{} = Event(#xmerl_event{event = ended,
@@ -1077,22 +1139,25 @@ scan_pi("?>" ++ T, S0 = #xmerl_scanner{hook_fun = Hook,
data = PI}, S),
{Ret, S2} = Hook(PI, S1),
{Ret, T, S2};
-scan_pi([H|T], S, Target, L, C, Pos, Acc) when ?whitespace(H) ->
+scan_pi([H|T], S, Target, L, C, Pos, Ps, Acc) when ?whitespace(H) ->
?strip1,
- scan_pi2(T1, S1, Target, L, C, Pos, Acc);
-scan_pi([H|_T],S,_Target, _L, _C, _Pos, _Acc) ->
+ scan_pi2(T1, S1, Target, L, C, Pos, Ps, Acc);
+scan_pi([H|_T],S,_Target, _L, _C, _Pos, _Ps, _Acc) ->
?fatal({expected_whitespace_OR_end_of_PI,{char,H}}, S).
-scan_pi2([], S=#xmerl_scanner{continuation_fun = F}, Target,L, C, Pos, Acc) ->
+scan_pi2([], S=#xmerl_scanner{continuation_fun = F}, Target,
+ L, C, Pos, Ps, Acc) ->
?dbg("cont()...~n", []),
- F(fun(MoreBytes, S1) -> scan_pi2(MoreBytes, S1, Target, L, C, Pos, Acc) end,
+ F(fun(MoreBytes, S1) -> scan_pi2(MoreBytes, S1, Target,
+ L, C, Pos, Ps, Acc) end,
fun(S1) -> ?fatal(unexpected_end, S1) end,
S);
scan_pi2("?>" ++ T, S0 = #xmerl_scanner{hook_fun = Hook,
event_fun = Event},
- Target, L, C, Pos, Acc) ->
+ Target, L, C, Pos, Ps, Acc) ->
?bump_col(2),
PI = #xmlPI{name = Target,
+ parents = Ps,
pos = Pos,
value = lists:reverse(Acc)},
S1 = #xmerl_scanner{} = Event(#xmerl_event{event = ended,
@@ -1101,10 +1166,10 @@ scan_pi2("?>" ++ T, S0 = #xmerl_scanner{hook_fun = Hook,
data = PI}, S),
{Ret, S2} = Hook(PI, S1),
{Ret, T, S2};
-scan_pi2(Str, S0, Target, L, C, Pos, Acc) ->
+scan_pi2(Str, S0, Target, L, C, Pos, Ps, Acc) ->
?bump_col(1),
{Ch,T} = wfc_legal_char(Str,S),
- scan_pi2(T, S, Target, L, C, Pos, [Ch|Acc]).
+ scan_pi2(T, S, Target, L, C, Pos, Ps, [Ch|Acc]).
@@ -1575,7 +1640,7 @@ scan_markup_decl("<!--" ++ T, S0) ->
scan_comment(T, S);
scan_markup_decl("<?" ++ T, S0) ->
?bump_col(2),
- {_PI, T1, S1} = scan_pi(T, S,_Pos=markup),
+ {_PI, T1, S1} = scan_pi(T, S,_Pos=markup,[]),
strip(T1, S1);
scan_markup_decl("<!ELEMENT" ++ T,
#xmerl_scanner{rules_read_fun = Read,
@@ -1981,7 +2046,7 @@ scan_element(T, S, Pos) ->
scan_element(T, S=#xmerl_scanner{line=L,col=C},
Pos, SpaceDefault,Lang, Parents, NS) ->
{Name, NamespaceInfo, T1, S1} = scan_name(T, S),
- vc_Element_valid(Name,S),
+ vc_Element_valid(Name,NamespaceInfo,S),
?strip2,
scan_element(T2, S2, Pos, Name, L, C, _Attrs = [],
Lang, Parents, NamespaceInfo, NS,
@@ -2016,7 +2081,8 @@ scan_element("/>" ++ T, S0 = #xmerl_scanner{hook_fun = Hook,
Attrs = lists:reverse(Attrs0),
E=processed_whole_element(S, Pos, Name, Attrs, Lang, Parents,NSI,Namespace),
- wfc_unique_att_spec(Attrs,S),
+ #xmlElement{attributes = Attrs1} = E,
+ wfc_unique_att_spec(Attrs1,S),
S1 = #xmerl_scanner{} = Event(#xmerl_event{event = ended,
line = L,
col = C,
@@ -2086,9 +2152,10 @@ scan_element(T, S, Pos, Name, StartL, StartC, Attrs, Lang, Parents,
P+1
end,
Attr = #xmlAttribute{name = AttName,
+ parents = [{Name, Pos}|Parents],
pos = AttrPos,
language = Lang,
- namespace = NamespaceInfo,
+ nsinfo = NamespaceInfo,
value = AttValue,
normalized = IsNorm},
XMLBase=if
@@ -2110,6 +2177,14 @@ scan_element(T, S, Pos, Name, StartL, StartC, Attrs, Lang, Parents,
scan_element(T4, S5, Pos, Name, StartL, StartC, [Attr|Attrs],
Lang, Parents, NSI, NewNS, SpaceDefault).
+get_default_attrs(S = #xmerl_scanner{rules_read_fun = Read}, ElemName) ->
+ case Read(elem_def, ElemName, S) of
+ #xmlElement{attributes = Attrs} ->
+ [ {AttName, AttValue} ||
+ {AttName, _, AttValue, _, _} <- Attrs, AttValue =/= no_value ];
+ _ -> []
+ end.
+
get_att_type(S=#xmerl_scanner{rules_read_fun=Read},AttName,ElemName) ->
case Read(elem_def,ElemName,S) of
#xmlElement{attributes = Attrs} ->
@@ -2139,6 +2214,23 @@ processed_whole_element(S=#xmerl_scanner{hook_fun = _Hook,
Pos, Name, Attrs, Lang, Parents, NSI, Namespace) ->
Language = check_language(Attrs, Lang),
+ AllAttrs =
+ case S#xmerl_scanner.default_attrs of
+ true ->
+ [ #xmlAttribute{name = AttName,
+ parents = [{Name, Pos} | Parents],
+ language = Lang,
+ nsinfo = NSI,
+ namespace = Namespace,
+ value = AttValue,
+ normalized = true} ||
+ {AttName, AttValue} <- get_default_attrs(S, Name),
+ AttValue =/= no_value,
+ not lists:keymember(AttName, #xmlAttribute.name, Attrs) ];
+ false ->
+ Attrs
+ end,
+
{ExpName, ExpAttrs} =
case S#xmerl_scanner.namespace_conformant of
true ->
@@ -2153,14 +2245,15 @@ processed_whole_element(S=#xmerl_scanner{hook_fun = _Hook,
TempNamespace = Namespace#xmlNamespace{default = []},
ExpAttrsX =
[A#xmlAttribute{
+ namespace=Namespace,
expanded_name=expanded_name(
A#xmlAttribute.name,
- A#xmlAttribute.namespace,
+ A#xmlAttribute.nsinfo,
% NSI,
- TempNamespace, S)} || A <- Attrs],
+ TempNamespace, S)} || A <- AllAttrs],
{expanded_name(Name, NSI, Namespace, S), ExpAttrsX};
false ->
- {Name, Attrs}
+ {Name, AllAttrs}
end,
#xmlElement{name = Name,
@@ -2194,10 +2287,32 @@ check_namespace(_, _, _, NS) ->
expanded_name(Name, [], #xmlNamespace{default = []}, _S) ->
Name;
-expanded_name(Name, [], #xmlNamespace{default = URI}, _S) ->
- {URI, Name};
-expanded_name(_Name, {"xmlns", Local}, _NS, _S) -> % CHECK THIS /JB
- {"xmlns",Local};
+expanded_name(Name, [], #xmlNamespace{default = URI}, S) ->
+ case URI of
+ 'http://www.w3.org/XML/1998/namespace' ->
+ ?fatal(cannot_bind_default_namespace_to_xml_namespace_name, S);
+ 'http://www.w3.org/2000/xmlns/' ->
+ ?fatal(cannot_bind_default_namespace_to_xmlns_namespace_name, S);
+ _ ->
+ {URI, Name}
+ end;
+expanded_name(Name, N = {"xmlns", Local}, #xmlNamespace{nodes = Ns}, S) ->
+ {_, Value} = lists:keyfind(Local, 1, Ns),
+ case Name of
+ 'xmlns:xml' when Value =/= 'http://www.w3.org/XML/1998/namespace' ->
+ ?fatal({xml_prefix_cannot_be_redeclared, Value}, S);
+ 'xmlns:xmlns' ->
+ ?fatal({xmlns_prefix_cannot_be_declared, Value}, S);
+ _ ->
+ case Value of
+ 'http://www.w3.org/XML/1998/namespace' ->
+ ?fatal({cannot_bind_prefix_to_xml_namespace, Local}, S);
+ 'http://www.w3.org/2000/xmlns/' ->
+ ?fatal({cannot_bind_prefix_to_xmlns_namespace, Local}, S);
+ _ ->
+ N
+ end
+ end;
expanded_name(_Name, {Prefix, Local}, #xmlNamespace{nodes = Ns}, S) ->
case lists:keysearch(Prefix, 1, Ns) of
{value, {_, URI}} ->
@@ -2449,9 +2564,23 @@ scan_content("&" ++ T, S0, Pos, Name, Attrs, Space, Lang, Parents, NS, Acc,[]) -
_ ->
scan_content(string_to_char_set(S1#xmerl_scanner.encoding,ExpRef)++T1,S1,Pos,Name,Attrs,Space,Lang,Parents,NS,Acc,[])
end;
-scan_content("<!--" ++ T, S, Pos, Name, Attrs, Space, Lang, Parents, NS, Acc,[]) ->
- {_, T1, S1} = scan_comment(T, S, Pos, Parents, Lang),
- scan_content(T1, S1, Pos+1, Name, Attrs, Space, Lang, Parents, NS, Acc,[]);
+scan_content("<!--" ++ T, S0=#xmerl_scanner{acc_fun = F, comments=CF}, Pos, Name, Attrs, Space,
+ Lang, Parents, NS, Acc,[]) ->
+ ?bump_col(4),
+ {C, T1, S1} = scan_comment(T, S, Pos, Parents, Lang),
+ case CF of
+ true ->
+ {Acc2, Pos2, S3} =
+ case F(C, Acc, S1) of
+ {Acc1, S2} ->
+ {Acc1, Pos + 1, S2};
+ {Acc1, Pos1, S2} ->
+ {Acc1, Pos1, S2}
+ end,
+ scan_content(T1, S3, Pos2, Name, Attrs, Space, Lang, Parents, NS, Acc2,[]);
+ false ->
+ scan_content(T1, S1, Pos, Name, Attrs, Space, Lang, Parents, NS, Acc,[])
+ end;
scan_content("<" ++ T, S0, Pos, Name, Attrs, Space, Lang, Parents, NS, Acc,[]) ->
?bump_col(1),
{Markup, T1, S1} =
@@ -2508,9 +2637,9 @@ scan_content_markup("![CDATA[" ++ T, S0, Pos, _Name, _Attrs,
_Space, _Lang, Parents, _NS) ->
?bump_col(8),
scan_cdata(T, S, Pos, Parents);
-scan_content_markup("?"++T,S0,Pos,_Name,_Attrs,_Space,_Lang,_Parents,_NS) ->
+scan_content_markup("?"++T,S0,Pos,_Name,_Attrs,_Space,_Lang,Parents,_NS) ->
?bump_col(1),
- scan_pi(T, S, Pos);
+ scan_pi(T, S, Pos, Parents);
scan_content_markup(T, S, Pos, _Name, _Attrs, Space, Lang, Parents, NS) ->
scan_element(T, S, Pos, Space, Lang, Parents, NS).
@@ -3259,12 +3388,18 @@ mandatory_delimeter_wfc(T,S) ->
wfc_unique_att_spec([],_S) ->
ok;
-wfc_unique_att_spec([#xmlAttribute{name=N}|Atts],S) ->
+wfc_unique_att_spec([#xmlAttribute{name=N,expanded_name=EN}|Atts],S) ->
case lists:keymember(N,#xmlAttribute.name,Atts) of
true ->
?fatal({error,{unique_att_spec_required,N}},S);
_ ->
- wfc_unique_att_spec(Atts,S)
+ case S#xmerl_scanner.namespace_conformant andalso
+ lists:keymember(EN, #xmlAttribute.expanded_name, Atts) of
+ true ->
+ ?fatal({error,{unique_att_spec_required,EN}},S);
+ _ ->
+ wfc_unique_att_spec(Atts,S)
+ end
end.
wfc_legal_char(Chars,S) when is_list(Chars)->
@@ -3313,6 +3448,11 @@ wfc_Internal_parsed_entity(internal,Value,S) ->
wfc_Internal_parsed_entity(_,_,_) ->
ok.
+vc_Element_valid(_Name, {"xmlns", _},
+ S = #xmerl_scanner{namespace_conformant = true}) ->
+ ?fatal({error,{illegal_element_prefix,xmlns}},S);
+vc_Element_valid(Name, _, S) ->
+ vc_Element_valid(Name, S).
vc_Element_valid(_Name,#xmerl_scanner{environment=internal_parsed_entity}) ->
ok;
@@ -3917,7 +4057,7 @@ schemaLocations(El,#xmerl_scanner{schemaLocation=SL}) ->
schemaLocations(#xmlElement{attributes=Atts,xmlbase=_Base}) ->
Pred = fun(#xmlAttribute{name=schemaLocation}) -> false;
- (#xmlAttribute{namespace={_,"schemaLocation"}}) -> false;
+ (#xmlAttribute{nsinfo={_,"schemaLocation"}}) -> false;
(_) -> true
end,
case lists:dropwhile(Pred,Atts) of
diff --git a/lib/xmerl/src/xmerl_validate.erl b/lib/xmerl/src/xmerl_validate.erl
index 893e23ca34..4028fef2b9 100644
--- a/lib/xmerl/src/xmerl_validate.erl
+++ b/lib/xmerl/src/xmerl_validate.erl
@@ -399,25 +399,28 @@ test_attribute_value(_Rule,Attr,_,_) ->
%% +type valid_contents([rule()],[xmlElement()])->
%% [xmlElement() | {error,???}.
-valid_contents(Rule,XMLS,Rules,S,WSActionMode)->
- case parse(Rule,XMLS,Rules,WSActionMode,S) of
- {XML_N,[]}->
- lists:flatten(XML_N);
- {_,[#xmlElement{name=Name}|_T]} ->
- exit({error,{element,Name,isnt_comprise_in_the_rule,Rule}});
- {_,[#xmlText{}=Txt|_T]} ->
- exit({error,{element,text,Txt,isnt_comprise_in_the_rule,Rule}});
- {error,Reason} ->
- {error,Reason};
- {error,Reason,N} ->
- {error,Reason,N}
+valid_contents(Rule, XMLS, Rules, S, WSActionMode)->
+ case parse(Rule, XMLS, Rules, WSActionMode, S) of
+ {error, Reason} ->
+ {error, Reason};
+ {error, Reason, N} ->
+ {error, Reason, N};
+ {XML_N, Rest} -> %The list may consist of xmlComment{} records
+ case lists:dropwhile(fun(X) when is_record(X, xmlComment) -> true; (_) -> false end, Rest) of
+ [] ->
+ lists:flatten(XML_N);
+ [#xmlElement{name=Name} |_T] ->
+ exit({error, {element, Name, isnt_comprise_in_the_rule, Rule}});
+ [#xmlText{} = Txt |_T] ->
+ exit({error, {element, text, Txt, isnt_comprise_in_the_rule, Rule}})
+ end
end.
-parse({'*',SubRule},XMLS,Rules,WSaction,S)->
- star(SubRule,XMLS,Rules,WSaction,[],S);
-parse({'+',SubRule},XMLS,Rules,WSaction,S) ->
- plus(SubRule,XMLS,Rules,WSaction,S);
-parse({choice,CHOICE},XMLS,Rules,WSaction,S)->
+parse({'*', SubRule}, XMLS, Rules, WSaction, S)->
+ star(SubRule, XMLS, Rules, WSaction, [], S);
+parse({'+',SubRule}, XMLS, Rules, WSaction, S) ->
+ plus(SubRule, XMLS, Rules, WSaction, S);
+parse({choice,CHOICE}, XMLS, Rules, WSaction, S)->
% case XMLS of
% [] ->
% io:format("~p~n",[{choice,CHOICE,[]}]);
@@ -426,47 +429,49 @@ parse({choice,CHOICE},XMLS,Rules,WSaction,S)->
% [#xmlText{value=V}|_] ->
% io:format("~p~n",[{choice,CHOICE,{text,V}}])
% end,
- choice(CHOICE,XMLS,Rules,WSaction,S);
-parse(empty,[],_Rules,_WSaction,_S) ->
- {[],[]};
-parse({'?',SubRule},XMLS,Rules,_WSaction,S)->
- question(SubRule,XMLS,Rules,S);
-parse({seq,List},XMLS,Rules,WSaction,S) ->
- seq(List,XMLS,Rules,WSaction,S);
-parse(El_Name,[#xmlElement{name=El_Name}=XML|T],Rules,_WSaction,S)
+ choice(CHOICE, XMLS, Rules, WSaction, S);
+parse(empty, [], _Rules, _WSaction, _S) ->
+ {[], []};
+parse({'?', SubRule}, XMLS, Rules, _WSaction, S)->
+ question(SubRule, XMLS, Rules, S);
+parse({seq,List}, XMLS, Rules, WSaction, S) ->
+ seq(List, XMLS, Rules, WSaction, S);
+parse(El_Name, [#xmlElement{name=El_Name} = XML |T], Rules, _WSaction, S)
when is_atom(El_Name)->
- case do_validation(read_rules(Rules,El_Name),XML,Rules,S) of
- {error,R} ->
+ case do_validation(read_rules(Rules, El_Name), XML, Rules, S) of
+ {error, R} ->
% {error,R};
exit(R);
- {error,R,_N}->
+ {error, R, _N}->
% {error,R,N};
exit(R);
XML_->
- {[XML_],T}
+ {[XML_], T}
end;
-parse(any,Cont,Rules,_WSaction,S) ->
- case catch parse_any(Cont,Rules,S) of
- Err = {error,_} -> Err;
- ValidContents -> {ValidContents,[]}
+parse(any, Cont, Rules, _WSaction, S) ->
+ case catch parse_any(Cont, Rules, S) of
+ Err = {error, _} -> Err;
+ ValidContents -> {ValidContents, []}
end;
-parse(El_Name,[#xmlElement{name=Name}|_T]=S,_Rules,_WSa,_S) when is_atom(El_Name)->
+parse(El_Name, [#xmlElement{name=Name} |_T] = XMLS, _Rules, _WSa, _S) when is_atom(El_Name) ->
{error,
- {element_seq_not_conform,{wait,El_Name},{is,Name}},
- {{next,S},{act,[]}} };
-parse(_El_Name,[#xmlPI{}=H|T],_Rules,_WSa,_S) ->
- {[H],T};
-parse('#PCDATA',XML,_Rules,_WSa,_S)->
+ {element_seq_not_conform,{wait, El_Name}, {is, Name}},
+ {{next, XMLS}, {act, []}}};
+parse(El_Name, [#xmlComment{} |T], Rules, WSa, S) ->
+ parse(El_Name, T, Rules, WSa, S);
+parse(_El_Name, [#xmlPI{} = H |T], _Rules, _WSa, _S) ->
+ {[H], T};
+parse('#PCDATA', XMLS, _Rules, _WSa, _S)->
%%% PCDATA it is 0 , 1 or more #xmlText{}.
- parse_pcdata(XML);
-parse(El_Name,[#xmlText{}|_T]=S,_Rules,_WSa,_S)->
+ parse_pcdata(XMLS);
+parse(El_Name, [#xmlText{}|_T] = XMLS, _Rules, _WSa, _S)->
{error,
- {text_in_place_of,El_Name},
- {{next,S},{act,[]}}};
-parse([],_,_,_,_) ->
- {error,no_rule};
-parse(Rule,[],_,_,_) ->
- {error,{no_xml_element,Rule}}.
+ {text_in_place_of, El_Name},
+ {{next, XMLS}, {act, []}}};
+parse([], _, _, _, _) ->
+ {error, no_rule};
+parse(Rule, [], _, _, _) ->
+ {error, {no_xml_element, Rule}}.
parse_any([],_Rules,_S) ->
[];
@@ -618,11 +623,15 @@ el_name(#xmlElement{name=Name})->
parse_pcdata([#xmlText{}=H|T])->
parse_pcdata(T,[H]);
+parse_pcdata([#xmlComment{}|T])->
+ parse_pcdata(T,[]);
parse_pcdata(H) ->
{[],H}.
parse_pcdata([#xmlText{}=H|T],Acc)->
parse_pcdata(T,Acc++[H]);
+parse_pcdata([#xmlComment{}|T],Acc)->
+ parse_pcdata(T,Acc);
parse_pcdata(H,Acc) ->
{Acc,H}.
diff --git a/lib/xmerl/src/xmerl_xpath.erl b/lib/xmerl/src/xmerl_xpath.erl
index db3d3ac2d6..b3301f2faf 100644
--- a/lib/xmerl/src/xmerl_xpath.erl
+++ b/lib/xmerl/src/xmerl_xpath.erl
@@ -41,18 +41,13 @@
% xmerl_xpath_parse:parse(xmerl_xpath_scan:tokens("parent::processing-instruction('foo')")).
%% </pre>
%%
-%% @type docEntity() =
+%% @type nodeEntity() =
%% xmlElement()
%% | xmlAttribute()
%% | xmlText()
%% | xmlPI()
%% | xmlComment()
-%% @type nodeEntity() =
-%% xmlElement()
-%% | xmlAttribute()
-%% | xmlText()
-%% | xmlPI()
-%% | xmlNamespace()
+%% | xmlNsNode()
%% | xmlDocument()
%% @type option_list(). <p>Options allows to customize the behaviour of the
%% XPath scanner.
@@ -303,6 +298,17 @@ write_node(#xmlNode{pos = Pos,
node = #xmlText{value = Txt,
parents = Ps}}) ->
{text, Pos, Txt, Ps};
+write_node(#xmlNode{pos = Pos,
+ node = #xmlComment{parents = Ps}}) ->
+ {comment, Pos, '', Ps};
+write_node(#xmlNode{pos = Pos,
+ node = #xmlPI{name = Name,
+ parents = Ps}}) ->
+ {processing_instruction, Pos, Name, Ps};
+write_node(#xmlNode{pos = Pos,
+ node = #xmlNsNode{parents = Ps,
+ prefix = Prefix}}) ->
+ {namespace, Pos, Prefix, Ps};
write_node(_) ->
other.
@@ -330,18 +336,16 @@ eval_path(rel, PathExpr, C = #xmlContext{}) ->
Context = C#xmlContext{nodeset = NodeSet},
S = #state{context = Context},
path_expr(PathExpr, S);
-eval_path(filter, {PathExpr, PredExpr}, C = #xmlContext{}) ->
+eval_path(filter, {PathExpr, {pred, Pred}}, C = #xmlContext{}) ->
S = #state{context = C},
- S1 = path_expr(PathExpr, S),
- pred_expr(PredExpr, S1).
+ S1 = match_expr(PathExpr, S),
+ eval_pred(Pred, S1).
-eval_primary_expr(FC = {function_call,_,_},S = #state{context = Context}) ->
+eval_primary_expr(PrimExpr, S = #state{context = Context}) ->
%% NewNodeSet = xmerl_xpath_pred:eval(FC, Context),
- NewNodeSet = xmerl_xpath_lib:eval(primary_expr, FC, Context),
+ NewNodeSet = xmerl_xpath_lib:eval(primary_expr, PrimExpr, Context),
NewContext = Context#xmlContext{nodeset = NewNodeSet},
- S#state{context = NewContext};
-eval_primary_expr(PrimExpr,_S) ->
- exit({primary_expression,{not_implemented, PrimExpr}}).
+ S#state{context = NewContext}.
%% axis(Axis,NodeTest,Context::xmlContext()) -> xmlContext()
@@ -384,8 +388,8 @@ axis1(preceding, Tok, N, Acc, Context) ->
match_preceding(Tok, N, Acc, Context);
axis1(attribute, Tok, N, Acc, Context) ->
match_attribute(Tok, N, Acc, Context);
-%axis1(namespace, Tok, N, Acc, Context) ->
-% match_namespace(Tok, N, Acc, Context);
+axis1(namespace, Tok, N, Acc, Context) ->
+ match_namespace(Tok, N, Acc, Context);
axis1(ancestor_or_self, Tok, N, Acc, Context) ->
match_ancestor_or_self(Tok, N, Acc, Context);
axis1(descendant_or_self, Tok, N, Acc, Context) ->
@@ -627,14 +631,58 @@ node_type(#xmlAttribute{}) -> attribute;
node_type(#xmlElement{}) -> element;
node_type(#xmlText{}) -> text;
node_type(#xmlPI{}) -> processing_instruction;
-node_type(#xmlNamespace{}) -> namespace;
+node_type(#xmlNsNode{}) -> namespace;
+node_type(#xmlComment{}) -> comment;
node_type(#xmlDocument{}) -> root_node.
%% "The namespace axis contains the namespace nodes of the context node;
%% the axis will be empty unless the context node is an element."
-%match_namespace(_Tok, _N, _Acc, _Context) ->
- %% TODO: IMPLEMENT NAMESPACE AXIS
-% erlang:fault(not_yet_implemented).
+match_namespace(Tok, N, Acc, Context) ->
+ case N#xmlNode.type of
+ element ->
+ #xmlNode{parents = Ps, node = E} = N,
+ #xmlElement{name = Name,
+ namespace = NS,
+ parents = EPs,
+ pos = Pos} = E,
+ #xmlNamespace{default = Default, nodes = NSPairs} = NS,
+ ThisEPs = [{Name, Pos}|EPs],
+ ThisPs = [N|Ps],
+ Acc0 =
+ case Default of
+ D when D =:= []; D =:= '' ->
+ {[], 1};
+ URI ->
+ DefaultNSNode = #xmlNsNode{parents = ThisEPs,
+ pos = 1,
+ prefix = [],
+ uri = URI},
+ Node = #xmlNode{type = namespace,
+ node = DefaultNSNode,
+ parents = ThisPs},
+ {[Node], 2}
+ end,
+ {Nodes, _I} =
+ lists:foldr(
+ fun ({Prefix, URI}, {AccX, I}) ->
+ NSNode = #xmlNsNode{parents = ThisEPs,
+ pos = I,
+ prefix = Prefix,
+ uri = URI},
+ ThisN = #xmlNode{pos = I,
+ type = namespace,
+ node = NSNode,
+ parents = ThisPs},
+ {[ThisN | AccX], I + 1}
+ end, Acc0, NSPairs),
+ lists:foldr(
+ fun (ThisN, AccX) ->
+ match_self(Tok, ThisN, AccX, Context)
+ end, Acc, Nodes);
+ _Other ->
+ %%[]
+ Acc
+ end.
update_nodeset(Context = #xmlContext{axis_type = AxisType}, NodeSet) ->
@@ -655,8 +703,15 @@ update_nodeset(Context = #xmlContext{axis_type = AxisType}, NodeSet) ->
node_test(F, N, Context) when is_function(F) ->
F(N, Context);
+node_test(_Test, #xmlNode{type=attribute,node=#xmlAttribute{name=xmlns}},
+ _Context) ->
+ false;
+node_test(_Test,
+ #xmlNode{type=attribute,node=#xmlAttribute{nsinfo={"xmlns",_Local}}},
+ _Context) ->
+ false;
node_test({wildcard, _}, #xmlNode{type=ElAt}, _Context)
- when ElAt==element; ElAt==attribute ->
+ when ElAt==element; ElAt==attribute; ElAt==namespace ->
true;
node_test({prefix_test, Prefix}, #xmlNode{node = N}, _Context) ->
case N of
@@ -720,6 +775,9 @@ node_test({name, {_Tag, Prefix, Local}},
[{_Tag, Prefix, Local}, write_node(NSNodes)]),
false
end;
+node_test({name, {_Tag, [], Local}},
+ #xmlNode{node = #xmlNsNode{prefix = Local}}, _Context) ->
+ true;
node_test({node_type, NT}, #xmlNode{node = N}, _Context) ->
case {NT, N} of
{text, #xmlText{}} ->
@@ -728,14 +786,18 @@ node_test({node_type, NT}, #xmlNode{node = N}, _Context) ->
true;
{attribute, #xmlAttribute{}} ->
true;
- {namespace, #xmlNamespace{}} ->
+ {namespace, #xmlNsNode{}} ->
+ true;
+ {comment, #xmlComment{}} ->
+ true;
+ {processing_instruction, #xmlPI{}} ->
true;
_ ->
false
end;
-node_test({processing_instruction, {literal, _, Name}},
- #xmlNode{node = {processing_instruction, Name, _Data}}, _Context) ->
- true;
+node_test({processing_instruction, Name1},
+ #xmlNode{node = #xmlPI{name = Name2}}, _Context) ->
+ Name1 == atom_to_list(Name2);
node_test(_Other, _N, _Context) ->
%io:format("node_test(~p, ~p) -> false.~n", [_Other, write_node(_N)]),
false.
diff --git a/lib/xmerl/src/xmerl_xpath_lib.erl b/lib/xmerl/src/xmerl_xpath_lib.erl
index cfd0e36667..096f54ec30 100644
--- a/lib/xmerl/src/xmerl_xpath_lib.erl
+++ b/lib/xmerl/src/xmerl_xpath_lib.erl
@@ -49,5 +49,7 @@ primary_expr({function_call, F, Args}, C) ->
%% here, we should look up the function in the context provided
%% by the caller, but we haven't figured this out yet.
exit({not_a_core_function, F})
- end.
+ end;
+primary_expr(PrimExpr, _C) ->
+ exit({primary_expression, {not_implemented, PrimExpr}}).
diff --git a/lib/xmerl/src/xmerl_xpath_parse.yrl b/lib/xmerl/src/xmerl_xpath_parse.yrl
index 37576b9e61..f60cea0a2e 100644
--- a/lib/xmerl/src/xmerl_xpath_parse.yrl
+++ b/lib/xmerl/src/xmerl_xpath_parse.yrl
@@ -144,6 +144,7 @@ Expect 2.
%% [7]
'NodeTest' -> 'NameTest' : '$1' .
'NodeTest' -> 'node_type' '(' ')' : {node_type, value('$1')} .
+'NodeTest' -> 'processing-instruction' '(' ')' : {node_type, value('$1')} .
'NodeTest' -> 'processing-instruction' '(' 'literal' ')'
: {processing_instruction, value('$3')} .
diff --git a/lib/xmerl/src/xmerl_xpath_pred.erl b/lib/xmerl/src/xmerl_xpath_pred.erl
index 451a09bee3..855b8599fe 100644
--- a/lib/xmerl/src/xmerl_xpath_pred.erl
+++ b/lib/xmerl/src/xmerl_xpath_pred.erl
@@ -337,6 +337,9 @@ local_name1([#xmlNode{type=element,node=El}|_]) ->
local_name1([#xmlNode{type=attribute,node=Att}|_]) ->
#xmlAttribute{name=Name,nsinfo=NSI} = Att,
local_name2(Name,NSI);
+local_name1([#xmlNode{type=namespace,node=N}|_]) ->
+ #xmlNsNode{prefix=Prefix} = N,
+ ?string(Prefix);
local_name1([#xmlElement{name = Name, nsinfo = NSI}|_]) ->
local_name2(Name,NSI).
local_name2(Name, NSI) ->
@@ -431,6 +434,9 @@ string_value(N=#xmlObj{}) ->
string_value(A=#xmlNode{type=attribute}) ->
#xmlAttribute{value=AttVal}=A#xmlNode.node,
?string(AttVal);
+string_value(N=#xmlNode{type=namespace}) ->
+ #xmlNsNode{uri=URI}=N#xmlNode.node,
+ ?string(atom_to_list(URI));
string_value(El=#xmlNode{type=element}) ->
#xmlElement{content=C} = El#xmlNode.node,
TextValue = fun(#xmlText{value=T},_Fun) -> T;
@@ -442,6 +448,9 @@ string_value(El=#xmlNode{type=element}) ->
string_value(T=#xmlNode{type=text}) ->
#xmlText{value=Txt} = T#xmlNode.node,
?string(Txt);
+string_value(T=#xmlNode{type=comment}) ->
+ #xmlComment{value=Txt} = T#xmlNode.node,
+ ?string(Txt);
string_value(infinity) -> ?string("Infinity");
string_value(neg_infinity) -> ?string("-Infinity");
string_value(A) when is_atom(A) ->
diff --git a/lib/xmerl/src/xmerl_xpath_scan.erl b/lib/xmerl/src/xmerl_xpath_scan.erl
index 10e2756e74..a3240a1311 100644
--- a/lib/xmerl/src/xmerl_xpath_scan.erl
+++ b/lib/xmerl/src/xmerl_xpath_scan.erl
@@ -287,6 +287,7 @@ strip_ws(T) ->
special_token('@') -> true;
special_token('::') -> true;
+special_token(',') -> true;
special_token('(') -> true;
special_token('[') -> true;
special_token('/') -> true;
diff --git a/lib/xmerl/src/xmerl_xsd.erl b/lib/xmerl/src/xmerl_xsd.erl
index dfdc6138ef..ed0890f0d0 100644
--- a/lib/xmerl/src/xmerl_xsd.erl
+++ b/lib/xmerl/src/xmerl_xsd.erl
@@ -245,21 +245,27 @@ process_validate2({SE,_},Schema,Xml,Opts) ->
S4 = validation_options(S3,Opts),
validate3(Schema,Xml,S4).
-validate3(Schema,Xml,S=#xsd_state{errors=[]}) ->
- Ret = {_,S2} =
- case catch validate_xml(Xml,S) of
- {[XML2],[],Sx} ->
- {XML2,Sx};
- {XML2,[],Sx} ->
- {XML2,Sx};
- {_,UnValidated,Sx} ->
- {Xml,acc_errs(Sx,{error_path(UnValidated,Xml#xmlElement.name),?MODULE,
- {unvalidated_rest,UnValidated}})};
- _Err = {error,Reason} ->
- {Xml,acc_errs(S,Reason)};
- {'EXIT',Reason} ->
- {Xml,acc_errs(S,{error_path(Xml,Xml#xmlElement.name),?MODULE,
- {undefined,{internal_error,Reason}}})}
+validate3(Schema, Xml,S =#xsd_state{errors=[]}) ->
+ Ret = {_, S2} =
+ case catch validate_xml(Xml, S) of
+ _Err = {error, Reason} ->
+ {Xml, acc_errs(S, Reason)};
+ {'EXIT', Reason} ->
+ {Xml, acc_errs(S, {error_path(Xml, Xml#xmlElement.name), ?MODULE,
+ {undefined, {internal_error, Reason}}})};
+ {XML2, Rest, Sx} ->
+ case lists:dropwhile(fun(X) when is_record(X, xmlComment) -> true; (_) -> false end, Rest) of
+ [] ->
+ case XML2 of
+ [XML3] ->
+ {XML3,Sx};
+ XML3 ->
+ {XML3,Sx}
+ end;
+ UnValidated ->
+ {Xml,acc_errs(Sx,{error_path(UnValidated,Xml#xmlElement.name),?MODULE,
+ {unvalidated_rest,UnValidated}})}
+ end
end,
save_to_file(S2,filename:rootname(Schema)++".tab2"),
case S2#xsd_state.errors of
@@ -1950,7 +1956,7 @@ fetch_external_schema(Path,S) when is_list(Path) ->
{EXSD,S#xsd_state{schema_name=File}}
end;
{_,{string,String},_} -> %% this is for a user defined fetch fun that returns an xml document on string format.
- ?debug("scanning string: ~p~n",[File]),
+ ?debug("scanning string: ~p~n",[String]),
case xmerl_scan:string(String,S#xsd_state.xml_options) of
{error,Reason} ->
{error,acc_errs(S,{[],?MODULE,{parsing_external_schema_failed,Path,Reason}})};
@@ -2520,9 +2526,9 @@ check_element_type([],#schema_complex_type{name=_Name,block=_Bl,content=C},
{error,{error_path(Checked,undefined),?MODULE,
{empty_content_not_allowed,C}}}
end;
-check_element_type(C,{anyType,_},_Env,_Block,S,_Checked) ->
+check_element_type(C, {anyType, _}, _Env, _Block, S, _Checked) ->
%% permitt anything
- {C,[],S};
+ {lists:reverse(C), [], S};
check_element_type(XML=[#xmlText{}|_],Type=#schema_simple_type{},
_Env,_Block,S,_Checked) ->
@@ -2585,7 +2591,7 @@ check_element_type(XML=[XMLEl=#xmlElement{name=Name}|RestXML],
S6 = check_form(ElName,Name,XMLEl,
actual_form_value(CMEl#schema_element.form,
S5#xsd_state.elementFormDefault),
- S5),
+ S5),
%Step into content of XML element.
{Content,_,S7} =
case
@@ -2605,12 +2611,12 @@ check_element_type(XML=[XMLEl=#xmlElement{name=Name}|RestXML],
RestXML,
set_scope(S5#xsd_state.scope,set_num_el(S7,S6))};
true ->
- {error,{error_path(XMLEl,Name),?MODULE,
- {element_not_suitable_with_schema,ElName,S}}};
+ {error,{error_path(XMLEl, Name), ?MODULE,
+ {element_not_suitable_with_schema, ElName, S}}};
_ when S#xsd_state.num_el >= Min ->
%% it may be a match error or an optional element not
%% present
- {[],XML,S#xsd_state{num_el=0}};
+ {[], XML, S#xsd_state{num_el=0}};
_ ->
{error,{error_path(XMLEl,Name),?MODULE,
{element_not_suitable_with_schema,ElName,CMName,CMEl,S}}}
@@ -2645,7 +2651,7 @@ check_element_type(XML=[#xmlElement{}|_Rest],
check_element_type(XML=[E=#xmlElement{name=Name}|Rest],
Any={any,{Namespace,_Occ={Min,_},ProcessorContents}},Env,
_Block,S,_Checked) ->
- ?debug("check any: {any,{~p,~p,~p}}~n",[Namespace,Occ,ProcessorContents]),
+ ?debug("check any: {any,{~p,~p,~p}}~n",[Namespace,_Occ,ProcessorContents]),
%% ProcessorContents any of lax | strict | skip
%% lax: may validate if schema is found
%% strict: must validate
@@ -2710,8 +2716,11 @@ check_element_type([],CM,_Env,_Block,S,Checked) ->
{error,{error_path(Checked,undefined),?MODULE,
{empty_content_not_allowed,CM}}}
end;
+check_element_type([C = #xmlComment{} |Rest],CM,Env,Block,S,Checked) ->
+ check_element_type(Rest,CM,Env,Block,S,[C |Checked]);
check_element_type(XML,CM,_Env,_Block,S,_Checked) ->
{error,{error_path(XML,undefined),?MODULE,{match_failure,XML,CM,S}}}.
+
%% single xml content object and single schema object
check_text_type(XML=[#xmlText{}|_],optional_text,S) ->
% {XMLTxt,optional_text};
@@ -2730,7 +2739,7 @@ check_text_type([XMLTxt=#xmlText{}|_],CMEl,_S) ->
{cannot_contain_text,XMLTxt,CMEl}}}.
split_xmlText(XML) ->
- splitwith(fun(#xmlText{}) -> true;(_) -> false end,XML).
+ splitwith(fun(#xmlText{}) -> true;(#xmlComment{}) -> true;(_) -> false end,XML).
%% Sequence
check_sequence([T=#xmlText{}|Rest],Els,Occ,Env,S,Checked) ->
@@ -2773,6 +2782,8 @@ check_sequence(Seq=[_InstEl=#xmlElement{}|_],[El|Els],Occ={_Min,_Max},Env,S,Chec
count_num_el(set_num_el(S3,S2)),
Ret++Checked)
end;
+check_sequence([C = #xmlComment{} |Rest], Els, Occ, Env, S, Checked) ->
+ check_sequence(Rest,Els,Occ,Env,S,[C |Checked]);
check_sequence(Rest,[],_Occ,_Env,S,Checked) ->
{Checked,Rest,set_num_el(S,0)};
check_sequence([],Els,_Occ,_Env,S,Checked) ->
@@ -2869,6 +2880,8 @@ check_all(XML=[E=#xmlElement{name=Name}|RestXML],CM,Occ,Env,S,
{element_not_in_all,ElName,E,CM}},
check_all(RestXML,CM,Occ,Env,acc_errs(S,Err),[E|Checked],PrevXML)
end;
+check_all([C=#xmlComment{} |RestXML], CM, Occ, Env, S, Checked, XML) ->
+ check_all(RestXML, CM, Occ, Env, S, [C |Checked], XML);
check_all(XML,[],_,_,S,Checked,_) ->
{Checked,XML,S};
check_all([],CM,_Occ,_,S,Checked,_PrevXML) ->
@@ -2920,7 +2933,7 @@ check_target_namespace(XMLEl,S) ->
schemaLocations(El=#xmlElement{attributes=Atts},S) ->
Pred = fun(#xmlAttribute{name=schemaLocation}) -> false;
- (#xmlAttribute{namespace={_,"schemaLocation"}}) -> false;
+ (#xmlAttribute{nsinfo={_,"schemaLocation"}}) -> false;
(_) -> true
end,
case lists:dropwhile(Pred,Atts) of
diff --git a/lib/xmerl/test/xmerl_SUITE.erl b/lib/xmerl/test/xmerl_SUITE.erl
index 94c38d4d48..55b6d1844c 100644
--- a/lib/xmerl/test/xmerl_SUITE.erl
+++ b/lib/xmerl/test/xmerl_SUITE.erl
@@ -58,7 +58,7 @@ groups() ->
{ticket_tests, [],
[ticket_5998, ticket_7211, ticket_7214, ticket_7430,
ticket_6873, ticket_7496, ticket_8156, ticket_8697,
- ticket_9411, ticket_9457]},
+ ticket_9411, ticket_9457, ticket_9664_schema, ticket_9664_dtd]},
{app_test, [], [{xmerl_app_test, all}]},
{appup_test, [], [{xmerl_appup_test, all}]}].
@@ -284,7 +284,7 @@ export(Config) ->
?line {E,_} = xmerl_scan:file(TestFile),
?line Exported = xmerl:export([E],xmerl_xml,[{prolog,Prolog}]),
B = list_to_binary(Exported++"\n"),
- ?line {ok,B} = file:read_file(TestFile),
+ ?line {ok, B} = file:read_file(TestFile),
ok.
%%----------------------------------------------------------------------
@@ -609,6 +609,38 @@ ticket_9457_cont(Continue, Exception, GlobalState) ->
Exception(GlobalState)
end.
+
+ticket_9664_schema(suite) -> [];
+ticket_9664_schema(doc) ->
+ ["Test that comments are handled correct whith"];
+ticket_9664_schema(Config) ->
+
+ ?line {E, _} = xmerl_scan:file(filename:join([?config(data_dir, Config), misc,
+ "ticket_9664_schema.xml"]),[]),
+ ?line {ok, S} = xmerl_xsd:process_schema(filename:join([?config(data_dir, Config), misc,
+ "motorcycles.xsd"])),
+ ?line {E1, _} = xmerl_xsd:validate(E, S),
+
+ ?line {E1,_} = xmerl_xsd:process_validate(filename:join([?config(data_dir,Config), misc,
+ "motorcycles.xsd"]),E,[]),
+
+ ?line {E1,_} = xmerl_scan:file(filename:join([?config(data_dir,Config), misc,
+ "ticket_9664_schema.xml"]),
+ [{schemaLocation, [{"mc", "motorcycles.xsd"}]},
+ {validation, schema}]),
+ ok.
+
+ticket_9664_dtd(suite) -> [];
+ticket_9664_dtd(doc) ->
+ ["Test that comments are handled correct whith"];
+ticket_9664_dtd(Config) ->
+ ?line {E, _} = xmerl_scan:file(filename:join([?config(data_dir, Config), misc,
+ "ticket_9664_dtd.xml"]),[]),
+ ?line {E, _} = xmerl_scan:file(filename:join([?config(data_dir, Config), misc,
+ "ticket_9664_dtd.xml"]),[{validation, true}]),
+ ok.
+
+
%%======================================================================
%% Support Functions
%%======================================================================
diff --git a/lib/xmerl/test/xmerl_SUITE_data/misc.tar.gz b/lib/xmerl/test/xmerl_SUITE_data/misc.tar.gz
index fef7431845..ffc1d327a5 100644
--- a/lib/xmerl/test/xmerl_SUITE_data/misc.tar.gz
+++ b/lib/xmerl/test/xmerl_SUITE_data/misc.tar.gz
Binary files differ
diff --git a/lib/xmerl/test/xmerl_SUITE_data/xpath/xpath_abbrev.erl b/lib/xmerl/test/xmerl_SUITE_data/xpath/xpath_abbrev.erl
index 850b7f8135..7b6f1e95b3 100644
--- a/lib/xmerl/test/xmerl_SUITE_data/xpath/xpath_abbrev.erl
+++ b/lib/xmerl/test/xmerl_SUITE_data/xpath/xpath_abbrev.erl
@@ -210,7 +210,7 @@ ticket_7496() ->
?line {Doc3,_} = xmerl_scan:file("documentRoot.xml"),
?line ok = Test(Doc3,"//child",[child,child,child]),
?line ok = Test(Doc3,"//child[@name='beta']",[child]),
- ?line [{xmlAttribute,id,[],[],[],[],1,[],"2",false}] =
+ ?line [{xmlAttribute,id,[],[],[],_,1,[],"2",false}] =
xmerl_xpath:string("/documentRoot/parent/child[@name='beta']/@id",Doc3),
?line ok = Test(Doc3,"/documentRoot/parent/child|/documentRoot/parent/pet",
[child,child,child,pet,pet]),
diff --git a/lib/xmerl/test/xmerl_test_lib.erl b/lib/xmerl/test/xmerl_test_lib.erl
index a83956c076..e82ad283b2 100644
--- a/lib/xmerl/test/xmerl_test_lib.erl
+++ b/lib/xmerl/test/xmerl_test_lib.erl
@@ -87,6 +87,6 @@ keysearch_delete(Key,N,List) ->
%% the original data directory.
get_data_dir(Config) ->
- Data0 = ?config(data_dir, Config),
- {ok,Data,_} = regexp:sub(Data0, "xmerl_sax_std_SUITE", "xmerl_std_SUITE"),
- Data.
+ Data = ?config(data_dir, Config),
+ Opts = [{return,list}],
+ re:replace(Data, "xmerl_sax_std_SUITE", "xmerl_std_SUITE", Opts).
diff --git a/lib/xmerl/test/xmerl_xsd_SUITE_data/mim.xsd b/lib/xmerl/test/xmerl_xsd_SUITE_data/mim.xsd
index 057344cde8..057344cde8 100755..100644
--- a/lib/xmerl/test/xmerl_xsd_SUITE_data/mim.xsd
+++ b/lib/xmerl/test/xmerl_xsd_SUITE_data/mim.xsd
diff --git a/lib/xmerl/vsn.mk b/lib/xmerl/vsn.mk
index 82df8fdeef..de47e3418b 100644
--- a/lib/xmerl/vsn.mk
+++ b/lib/xmerl/vsn.mk
@@ -1 +1 @@
-XMERL_VSN = 1.2.10
+XMERL_VSN = 1.3
diff --git a/lib/xmerl/xmerl.pub b/lib/xmerl/xmerl.pub
index 29a81bbde2..29a81bbde2 100755..100644
--- a/lib/xmerl/xmerl.pub
+++ b/lib/xmerl/xmerl.pub