aboutsummaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/asn1/doc/src/asn1_ug.xml796
-rw-r--r--lib/asn1/doc/src/asn1ct.xml9
-rw-r--r--lib/asn1/src/asn1.app.src3
-rw-r--r--lib/asn1/src/asn1ct.erl2
-rw-r--r--lib/asn1/src/asn1ct_check.erl219
-rw-r--r--lib/asn1/src/asn1ct_gen.erl19
-rw-r--r--lib/asn1/test/asn1_SUITE.erl8
-rw-r--r--lib/asn1/test/asn1_SUITE_data/INSTANCEOF.asn14
-rw-r--r--lib/asn1/test/asn1_SUITE_data/ImportsFrom.asn114
-rw-r--r--lib/asn1/test/asn1_SUITE_data/ImportsFrom2.asn17
-rw-r--r--lib/asn1/test/asn1_SUITE_data/ImportsFrom3.asn14
-rw-r--r--lib/asn1/test/error_SUITE.erl81
-rw-r--r--lib/asn1/vsn.mk2
-rw-r--r--lib/common_test/doc/src/run_test_chapter.xml4
-rw-r--r--lib/common_test/src/common_test.app.src7
-rw-r--r--lib/common_test/src/ct_conn_log_h.erl9
-rw-r--r--lib/common_test/src/ct_framework.erl9
-rw-r--r--lib/common_test/src/ct_gen_conn.erl7
-rw-r--r--lib/common_test/src/ct_hooks.erl36
-rw-r--r--lib/common_test/src/ct_netconfc.erl17
-rw-r--r--lib/common_test/src/ct_telnet.erl195
-rw-r--r--lib/common_test/src/ct_telnet_client.erl137
-rw-r--r--lib/common_test/src/cth_conn_log.erl1
-rw-r--r--lib/common_test/src/cth_surefire.erl4
-rw-r--r--lib/common_test/src/unix_telnet.erl6
-rw-r--r--lib/common_test/test/ct_master_SUITE.erl3
-rw-r--r--lib/common_test/test/ct_telnet_SUITE.erl34
-rw-r--r--lib/common_test/test/ct_telnet_SUITE_data/ct_telnet_own_server_SUITE.erl65
-rw-r--r--lib/common_test/test/telnet_server.erl100
-rw-r--r--lib/common_test/vsn.mk2
-rw-r--r--lib/compiler/src/beam_disasm.erl9
-rw-r--r--lib/compiler/src/cerl.erl94
-rw-r--r--lib/compiler/src/cerl_clauses.erl11
-rw-r--r--lib/compiler/src/cerl_inline.erl8
-rw-r--r--lib/compiler/src/cerl_trees.erl8
-rw-r--r--lib/compiler/src/compile.erl59
-rw-r--r--lib/compiler/src/compiler.app.src4
-rw-r--r--lib/compiler/src/core_lib.erl2
-rw-r--r--lib/compiler/src/core_parse.hrl20
-rw-r--r--lib/compiler/src/core_parse.yrl8
-rw-r--r--lib/compiler/src/core_pp.erl14
-rw-r--r--lib/compiler/src/erl_bifs.erl1
-rw-r--r--lib/compiler/src/sys_core_fold.erl51
-rw-r--r--lib/compiler/src/v3_codegen.erl4
-rw-r--r--lib/compiler/src/v3_core.erl84
-rw-r--r--lib/compiler/src/v3_kernel.erl37
-rw-r--r--lib/compiler/src/v3_kernel_pp.erl18
-rw-r--r--lib/compiler/src/v3_life.erl3
-rw-r--r--lib/compiler/test/core_SUITE_data/map_core_test.core4
-rw-r--r--lib/compiler/test/core_fold_SUITE.erl14
-rw-r--r--lib/compiler/test/error_SUITE.erl28
-rw-r--r--lib/compiler/test/map_SUITE.erl48
-rw-r--r--lib/compiler/test/warnings_SUITE.erl81
-rw-r--r--lib/compiler/vsn.mk2
-rw-r--r--lib/cosEvent/src/cosEvent.app.src3
-rw-r--r--lib/cosEvent/vsn.mk2
-rw-r--r--lib/cosEventDomain/src/cosEventDomain.app.src4
-rw-r--r--lib/cosEventDomain/vsn.mk2
-rw-r--r--lib/cosFileTransfer/src/cosFileTransfer.app.src4
-rw-r--r--lib/cosFileTransfer/vsn.mk2
-rw-r--r--lib/cosNotification/src/cosNotification.app.src4
-rw-r--r--lib/cosNotification/vsn.mk2
-rw-r--r--lib/cosProperty/src/cosProperty.app.src4
-rw-r--r--lib/cosProperty/vsn.mk2
-rw-r--r--lib/cosTime/src/cosTime.app.src4
-rw-r--r--lib/cosTime/vsn.mk3
-rw-r--r--lib/cosTransactions/src/cosTransactions.app.src3
-rw-r--r--lib/cosTransactions/vsn.mk2
-rw-r--r--lib/crypto/doc/src/crypto_app.xml4
-rw-r--r--lib/crypto/src/crypto.app.src3
-rw-r--r--lib/crypto/vsn.mk2
-rw-r--r--lib/debugger/src/dbg_ieval.erl16
-rw-r--r--lib/debugger/src/dbg_iload.erl13
-rw-r--r--lib/debugger/src/debugger.app.src4
-rw-r--r--lib/debugger/src/debugger.erl6
-rw-r--r--lib/debugger/test/int_eval_SUITE.erl9
-rw-r--r--lib/debugger/test/int_eval_SUITE_data/my_int_eval_module.erl3
-rw-r--r--lib/debugger/test/map_SUITE.erl6
-rw-r--r--lib/debugger/vsn.mk2
-rw-r--r--lib/dialyzer/src/dialyzer.app.src5
-rw-r--r--lib/dialyzer/src/dialyzer.erl16
-rw-r--r--lib/dialyzer/src/dialyzer.hrl15
-rw-r--r--lib/dialyzer/src/dialyzer_analysis_callgraph.erl10
-rw-r--r--lib/dialyzer/src/dialyzer_cl.erl48
-rw-r--r--lib/dialyzer/src/dialyzer_contracts.erl78
-rw-r--r--lib/dialyzer/src/dialyzer_dataflow.erl51
-rw-r--r--lib/dialyzer/src/dialyzer_dep.erl10
-rw-r--r--lib/dialyzer/src/dialyzer_gui_wx.erl2
-rw-r--r--lib/dialyzer/src/dialyzer_options.erl7
-rw-r--r--lib/dialyzer/src/dialyzer_races.erl12
-rw-r--r--lib/dialyzer/test/opaque_SUITE_data/dialyzer_options2
-rw-r--r--lib/dialyzer/test/opaque_SUITE_data/src/modules/opaque_erl_scan.erl2
-rw-r--r--lib/dialyzer/test/options1_SUITE_data/dialyzer_options2
-rw-r--r--lib/dialyzer/test/r9c_SUITE_data/dialyzer_options2
-rw-r--r--lib/dialyzer/test/race_SUITE_data/dialyzer_options2
-rw-r--r--lib/dialyzer/test/small_SUITE_data/dialyzer_options2
-rw-r--r--lib/dialyzer/test/small_SUITE_data/results/contracts_with_subtypes39
-rw-r--r--lib/dialyzer/test/small_SUITE_data/results/contracts_with_subtypes23
-rw-r--r--lib/dialyzer/test/small_SUITE_data/results/funs_from_outside7
-rw-r--r--lib/dialyzer/test/small_SUITE_data/results/invalid_spec_22
-rw-r--r--lib/dialyzer/test/small_SUITE_data/src/contracts_with_subtypes.erl47
-rw-r--r--lib/dialyzer/test/small_SUITE_data/src/contracts_with_subtypes2.erl40
-rw-r--r--lib/dialyzer/test/small_SUITE_data/src/funs_from_outside.erl83
-rw-r--r--lib/dialyzer/test/small_SUITE_data/src/invalid_spec_2/scala_data.erl5
-rw-r--r--lib/dialyzer/test/small_SUITE_data/src/invalid_spec_2/scala_user.erl8
-rw-r--r--lib/dialyzer/test/small_SUITE_data/src/maps_redef.erl12
-rw-r--r--lib/dialyzer/test/underspecs_SUITE_data/dialyzer_options2
-rw-r--r--lib/dialyzer/test/user_SUITE_data/dialyzer_options2
-rw-r--r--lib/diameter/doc/src/diameter_make.xml2
-rw-r--r--lib/diameter/doc/src/notes.xml8
-rw-r--r--lib/diameter/src/Makefile19
-rw-r--r--lib/diameter/src/base/diameter_service.erl2
-rw-r--r--lib/diameter/src/compiler/diameter_codegen.erl8
-rw-r--r--lib/diameter/src/compiler/diameter_forms.hrl6
-rw-r--r--lib/diameter/src/compiler/diameter_make.erl32
-rw-r--r--lib/diameter/src/diameter.app.src19
-rw-r--r--lib/diameter/src/info/diameter_dbg.erl (renamed from lib/diameter/src/base/diameter_dbg.erl)15
-rw-r--r--lib/diameter/src/info/diameter_info.erl (renamed from lib/diameter/src/base/diameter_info.erl)14
-rw-r--r--lib/diameter/src/modules.mk12
-rw-r--r--lib/diameter/test/diameter_codec_test.erl3
-rw-r--r--lib/diameter/test/diameter_compiler_SUITE.erl10
-rw-r--r--lib/edoc/src/edoc.app.src4
-rw-r--r--lib/edoc/vsn.mk2
-rw-r--r--lib/eldap/src/Makefile2
-rw-r--r--lib/eldap/src/eldap.app.src4
-rw-r--r--lib/eldap/test/eldap_misc_SUITE.erl51
-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/aclocal.m46
-rw-r--r--lib/erl_interface/src/connect/ei_connect.c4
-rw-r--r--lib/erl_interface/src/connect/ei_resolve.c2
-rw-r--r--lib/erl_interface/vsn.mk3
-rw-r--r--lib/et/src/et.app.src4
-rw-r--r--lib/et/vsn.mk2
-rw-r--r--lib/eunit/src/eunit.app.src3
-rw-r--r--lib/eunit/vsn.mk2
-rw-r--r--lib/gs/src/gs.app.src3
-rw-r--r--lib/gs/vsn.mk2
-rw-r--r--lib/hipe/Makefile2
-rw-r--r--lib/hipe/arm/hipe_arm_assemble.erl48
-rw-r--r--lib/hipe/cerl/Makefile11
-rw-r--r--lib/hipe/cerl/cerl_to_icode.erl38
-rw-r--r--lib/hipe/cerl/erl_types.erl74
-rw-r--r--lib/hipe/icode/hipe_beam_to_icode.erl4
-rw-r--r--lib/hipe/icode/hipe_icode.erl13
-rw-r--r--lib/hipe/icode/hipe_icode.hrl8
-rw-r--r--lib/hipe/icode/hipe_icode_fp.erl2
-rw-r--r--lib/hipe/icode/hipe_icode_mulret.erl16
-rw-r--r--lib/hipe/icode/hipe_icode_type.erl47
-rw-r--r--lib/hipe/llvm/Makefile109
-rw-r--r--lib/hipe/llvm/elf32_format.hrl59
-rw-r--r--lib/hipe/llvm/elf64_format.hrl58
-rw-r--r--lib/hipe/llvm/elf_format.erl790
-rw-r--r--lib/hipe/llvm/elf_format.hrl488
-rw-r--r--lib/hipe/llvm/hipe_llvm.erl1131
-rw-r--r--lib/hipe/llvm/hipe_llvm_arch.hrl11
-rw-r--r--lib/hipe/llvm/hipe_llvm_liveness.erl112
-rw-r--r--lib/hipe/llvm/hipe_llvm_main.erl514
-rw-r--r--lib/hipe/llvm/hipe_llvm_merge.erl114
-rw-r--r--lib/hipe/llvm/hipe_rtl_to_llvm.erl1612
-rw-r--r--lib/hipe/main/hipe.app.src10
-rw-r--r--lib/hipe/main/hipe.erl53
-rw-r--r--lib/hipe/main/hipe_main.erl42
-rw-r--r--lib/hipe/misc/hipe_gensym.erl2
-rw-r--r--lib/hipe/misc/hipe_pack_constants.erl100
-rw-r--r--lib/hipe/ppc/hipe_ppc_assemble.erl48
-rw-r--r--lib/hipe/regalloc/hipe_ls_regalloc.erl4
-rw-r--r--lib/hipe/regalloc/hipe_optimistic_regalloc.erl4
-rw-r--r--lib/hipe/rtl/hipe_icode2rtl.erl4
-rw-r--r--lib/hipe/rtl/hipe_rtl.erl174
-rw-r--r--lib/hipe/rtl/hipe_rtl.hrl3
-rw-r--r--lib/hipe/rtl/hipe_rtl_liveness.erl3
-rw-r--r--lib/hipe/rtl/hipe_tagscheme.erl37
-rw-r--r--lib/hipe/sparc/hipe_sparc_assemble.erl48
-rw-r--r--lib/hipe/test/Makefile6
-rw-r--r--lib/hipe/test/hipe_testsuite_driver.erl25
-rw-r--r--lib/hipe/vsn.mk2
-rw-r--r--lib/hipe/x86/hipe_x86_assemble.erl51
-rw-r--r--lib/ic/src/ic.app.src3
-rw-r--r--lib/ic/src/ic.erl2
-rw-r--r--lib/ic/src/ic_codegen.erl3
-rw-r--r--lib/ic/src/ic_pp.erl8
-rw-r--r--lib/ic/test/java_client_erl_server_SUITE.erl2
-rw-r--r--lib/ic/vsn.mk2
-rw-r--r--lib/inets/src/http_client/httpc_cookie.erl3
-rw-r--r--lib/inets/src/http_client/httpc_handler.erl66
-rw-r--r--lib/inets/src/http_client/httpc_internal.hrl6
-rw-r--r--lib/inets/src/http_client/httpc_manager.erl46
-rw-r--r--lib/inets/src/http_server/httpd_example.erl4
-rw-r--r--lib/inets/src/http_server/httpd_util.erl9
-rw-r--r--lib/inets/src/inets_app/inets.app.src4
-rw-r--r--lib/inets/test/Makefile2
-rw-r--r--lib/inets/test/httpc_SUITE.erl42
-rw-r--r--lib/inets/test/httpd_1_0.erl9
-rw-r--r--lib/inets/test/httpd_1_1.erl111
-rw-r--r--lib/inets/test/httpd_SUITE.erl1490
-rw-r--r--lib/inets/test/httpd_basic_SUITE.erl5
-rw-r--r--lib/inets/test/httpd_test_lib.erl119
-rw-r--r--lib/inets/test/inets_sup_SUITE.erl15
-rw-r--r--lib/inets/test/old_httpd_SUITE.erl140
-rw-r--r--lib/inets/vsn.mk2
-rw-r--r--lib/jinterface/vsn.mk2
-rw-r--r--lib/kernel/doc/src/app.xml36
-rw-r--r--lib/kernel/doc/src/application.xml5
-rw-r--r--lib/kernel/doc/src/file.xml14
-rw-r--r--lib/kernel/src/application.erl5
-rw-r--r--lib/kernel/src/disk_log_server.erl12
-rw-r--r--lib/kernel/src/file.erl3
-rw-r--r--lib/kernel/src/global.erl22
-rw-r--r--lib/kernel/src/hipe_unified_loader.erl11
-rw-r--r--lib/kernel/src/inet_config.erl3
-rw-r--r--lib/kernel/src/kernel.app.src3
-rw-r--r--lib/kernel/src/os.erl13
-rw-r--r--lib/kernel/test/file_SUITE.erl99
-rw-r--r--lib/kernel/test/gen_tcp_misc_SUITE.erl33
-rw-r--r--lib/kernel/test/heart_SUITE.erl8
-rw-r--r--lib/kernel/test/prim_file_SUITE.erl119
-rw-r--r--lib/megaco/aclocal.m46
-rw-r--r--lib/megaco/src/app/megaco.app.src5
-rw-r--r--lib/megaco/vsn.mk2
-rw-r--r--lib/mnesia/src/mnesia.app.src3
-rw-r--r--lib/mnesia/src/mnesia.hrl4
-rw-r--r--lib/mnesia/src/mnesia_index.erl6
-rw-r--r--lib/mnesia/src/mnesia_lib.erl13
-rw-r--r--lib/mnesia/src/mnesia_locker.erl3
-rw-r--r--lib/mnesia/src/mnesia_recover.erl6
-rw-r--r--lib/mnesia/src/mnesia_snmp_hook.erl8
-rw-r--r--lib/mnesia/test/mnesia_config_test.erl7
-rw-r--r--lib/mnesia/test/mnesia_evil_coverage_test.erl11
-rw-r--r--lib/mnesia/vsn.mk2
-rw-r--r--lib/observer/src/cdv_dist_cb.erl12
-rw-r--r--lib/observer/src/crashdump_viewer.erl14
-rw-r--r--lib/observer/src/observer.app.src5
-rw-r--r--lib/observer/src/observer.erl7
-rw-r--r--lib/observer/src/observer_lib.erl2
-rw-r--r--lib/observer/src/observer_procinfo.erl5
-rw-r--r--lib/observer/src/observer_tv_wx.erl6
-rw-r--r--lib/observer/src/observer_wx.erl13
-rw-r--r--lib/observer/test/crashdump_viewer_SUITE.erl82
-rw-r--r--lib/observer/test/observer_SUITE.erl232
-rw-r--r--lib/observer/vsn.mk2
-rw-r--r--lib/odbc/aclocal.m46
-rw-r--r--lib/odbc/src/odbc.app.src3
-rw-r--r--lib/odbc/vsn.mk2
-rw-r--r--lib/orber/src/orber.app.src4
-rw-r--r--lib/orber/vsn.mk2
-rw-r--r--lib/os_mon/c_src/memsup.c8
-rw-r--r--lib/os_mon/src/os_mon.app.src5
-rw-r--r--lib/os_mon/test/cpu_sup_SUITE.erl6
-rw-r--r--lib/os_mon/test/disksup_SUITE.erl17
-rw-r--r--lib/os_mon/vsn.mk2
-rw-r--r--lib/ose/doc/src/ose_intro.xml4
-rw-r--r--lib/ose/src/ose.app.src3
-rw-r--r--lib/otp_mibs/src/otp_mibs.app.src4
-rw-r--r--lib/otp_mibs/vsn.mk2
-rw-r--r--lib/parsetools/src/parsetools.app.src3
-rw-r--r--lib/parsetools/vsn.mk2
-rw-r--r--lib/percept/src/percept.app.src4
-rw-r--r--lib/percept/vsn.mk2
-rw-r--r--lib/public_key/src/pubkey_cert.erl17
-rw-r--r--lib/public_key/src/pubkey_crl.erl36
-rw-r--r--lib/public_key/src/public_key.app.src4
-rw-r--r--lib/public_key/vsn.mk2
-rw-r--r--lib/reltool/src/reltool.app.src4
-rw-r--r--lib/reltool/src/reltool.hrl3
-rw-r--r--lib/reltool/src/reltool_server.erl3
-rw-r--r--lib/reltool/vsn.mk2
-rw-r--r--lib/runtime_tools/doc/specs/.gitignore1
-rw-r--r--lib/runtime_tools/doc/src/Makefile10
-rw-r--r--lib/runtime_tools/doc/src/ref_man.xml1
-rw-r--r--lib/runtime_tools/doc/src/specs.xml4
-rw-r--r--lib/runtime_tools/doc/src/system_information.xml98
-rw-r--r--lib/runtime_tools/src/runtime_tools.app.src4
-rw-r--r--lib/runtime_tools/src/system_information.erl282
-rw-r--r--lib/runtime_tools/test/system_information_SUITE.erl10
-rw-r--r--lib/runtime_tools/test/system_information_SUITE_data/information_test_report.dat3
-rw-r--r--lib/runtime_tools/vsn.mk2
-rw-r--r--lib/sasl/src/sasl.app.src4
-rw-r--r--lib/sasl/src/systools_make.erl2
-rw-r--r--lib/sasl/test/systools_SUITE.erl34
-rw-r--r--lib/sasl/test/systools_SUITE_data/d_duplicate_modules/lib/app1-1.0/ebin/app1.app7
-rw-r--r--lib/sasl/test/systools_SUITE_data/d_duplicate_modules/lib/app1-1.0/src/myapp.erl2
-rw-r--r--lib/sasl/test/systools_SUITE_data/d_duplicate_modules/lib/app2-1.0/ebin/app2.app7
-rw-r--r--lib/sasl/test/systools_SUITE_data/d_duplicate_modules/lib/app2-1.0/src/myapp.erl2
-rw-r--r--lib/snmp/doc/src/snmpa_mib_data.xml4
-rw-r--r--lib/snmp/doc/src/snmpa_mib_storage.xml4
-rw-r--r--lib/snmp/src/app/snmp.app.src4
-rw-r--r--lib/snmp/test/Makefile4
-rw-r--r--lib/snmp/test/modules.mk3
-rw-r--r--lib/snmp/test/snmp_agent_test.erl300
-rw-r--r--lib/snmp/test/snmp_agent_test_lib.erl22
-rw-r--r--lib/snmp/test/snmp_manager_test.erl337
-rw-r--r--lib/snmp/test/snmp_test_mgr.erl3
-rw-r--r--lib/snmp/test/snmp_test_mgr_counter_server.erl152
-rw-r--r--lib/snmp/vsn.mk2
-rw-r--r--lib/ssh/doc/src/ssh.xml17
-rw-r--r--lib/ssh/src/ssh.app.src4
-rw-r--r--lib/ssh/src/ssh.erl12
-rw-r--r--lib/ssh/src/ssh_acceptor.erl5
-rw-r--r--lib/ssh/src/ssh_auth.erl4
-rw-r--r--lib/ssh/src/ssh_connection_handler.erl14
-rw-r--r--lib/ssh/test/ssh_unicode_SUITE.erl5
-rw-r--r--lib/ssl/doc/src/ssl.xml69
-rw-r--r--lib/ssl/src/dtls_connection.erl724
-rw-r--r--lib/ssl/src/dtls_connection.hrl21
-rw-r--r--lib/ssl/src/dtls_connection_sup.erl12
-rw-r--r--lib/ssl/src/dtls_handshake.erl402
-rw-r--r--lib/ssl/src/dtls_handshake.hrl4
-rw-r--r--lib/ssl/src/dtls_record.erl57
-rw-r--r--lib/ssl/src/dtls_record.hrl13
-rw-r--r--lib/ssl/src/dtls_v1.erl4
-rw-r--r--lib/ssl/src/ssl.app.src4
-rw-r--r--lib/ssl/src/ssl.erl41
-rw-r--r--lib/ssl/src/ssl_alert.erl18
-rw-r--r--lib/ssl/src/ssl_alert.hrl16
-rw-r--r--lib/ssl/src/ssl_api.hrl33
-rw-r--r--lib/ssl/src/ssl_cipher.erl27
-rw-r--r--lib/ssl/src/ssl_cipher.hrl12
-rw-r--r--lib/ssl/src/ssl_connection.erl32
-rw-r--r--lib/ssl/src/ssl_connection.hrl8
-rw-r--r--lib/ssl/src/ssl_handshake.erl61
-rw-r--r--lib/ssl/src/ssl_handshake.hrl16
-rw-r--r--lib/ssl/src/ssl_internal.hrl5
-rw-r--r--lib/ssl/src/ssl_record.erl19
-rw-r--r--lib/ssl/src/ssl_record.hrl4
-rw-r--r--lib/ssl/src/ssl_v3.erl4
-rw-r--r--lib/ssl/src/tls_handshake.erl16
-rw-r--r--lib/ssl/src/tls_handshake.hrl4
-rw-r--r--lib/ssl/src/tls_record.erl7
-rw-r--r--lib/ssl/src/tls_v1.erl10
-rw-r--r--lib/ssl/test/Makefile1
-rw-r--r--lib/ssl/test/make_certs.erl312
-rw-r--r--lib/ssl/test/ssl_basic_SUITE.erl40
-rw-r--r--lib/ssl/test/ssl_crl_SUITE.erl536
-rw-r--r--lib/ssl/test/ssl_handshake_SUITE.erl12
-rw-r--r--lib/ssl/test/ssl_test_lib.erl171
-rw-r--r--lib/stdlib/doc/src/epp.xml64
-rw-r--r--lib/stdlib/doc/src/erl_parse.xml10
-rw-r--r--lib/stdlib/doc/src/sys.xml73
-rw-r--r--lib/stdlib/doc/src/unicode_usage.xml1
-rw-r--r--lib/stdlib/doc/src/zip.xml13
-rw-r--r--lib/stdlib/src/dict.erl3
-rw-r--r--lib/stdlib/src/epp.erl177
-rw-r--r--lib/stdlib/src/erl_compile.erl18
-rw-r--r--lib/stdlib/src/erl_eval.erl25
-rw-r--r--lib/stdlib/src/erl_lint.erl185
-rw-r--r--lib/stdlib/src/erl_parse.yrl64
-rw-r--r--lib/stdlib/src/erl_pp.erl13
-rw-r--r--lib/stdlib/src/escript.erl15
-rw-r--r--lib/stdlib/src/gen_event.erl37
-rw-r--r--lib/stdlib/src/gen_fsm.erl20
-rw-r--r--lib/stdlib/src/gen_server.erl16
-rw-r--r--lib/stdlib/src/io.erl10
-rw-r--r--lib/stdlib/src/io_lib_pretty.erl2
-rw-r--r--lib/stdlib/src/maps.erl2
-rw-r--r--lib/stdlib/src/otp_internal.erl25
-rw-r--r--lib/stdlib/src/sets.erl5
-rw-r--r--lib/stdlib/src/slave.erl23
-rw-r--r--lib/stdlib/src/stdlib.app.src5
-rw-r--r--lib/stdlib/src/sys.erl65
-rw-r--r--lib/stdlib/src/zip.erl37
-rw-r--r--lib/stdlib/test/Makefile2
-rw-r--r--lib/stdlib/test/binary_module_SUITE.erl4
-rw-r--r--lib/stdlib/test/dets_SUITE.erl41
-rw-r--r--lib/stdlib/test/epp_SUITE.erl78
-rw-r--r--lib/stdlib/test/erl_eval_SUITE.erl2
-rw-r--r--lib/stdlib/test/erl_lint_SUITE.erl75
-rw-r--r--lib/stdlib/test/erl_pp_SUITE.erl10
-rw-r--r--lib/stdlib/test/erl_scan_SUITE.erl26
-rw-r--r--lib/stdlib/test/gen_event_SUITE.erl11
-rw-r--r--lib/stdlib/test/gen_fsm_SUITE.erl20
-rw-r--r--lib/stdlib/test/gen_server_SUITE.erl15
-rw-r--r--lib/stdlib/test/shell_SUITE.erl2
-rw-r--r--lib/stdlib/test/supervisor_SUITE.erl57
-rw-r--r--lib/stdlib/test/sys_SUITE.erl84
-rw-r--r--lib/stdlib/test/sys_sp1.erl114
-rw-r--r--lib/stdlib/test/sys_sp2.erl107
-rw-r--r--lib/stdlib/test/unicode_SUITE.erl12
-rw-r--r--lib/syntax_tools/src/syntax_tools.app.src3
-rw-r--r--lib/syntax_tools/vsn.mk2
-rw-r--r--lib/test_server/src/test_server.app.src5
-rw-r--r--lib/test_server/src/test_server.erl10
-rw-r--r--lib/test_server/src/test_server_sup.erl4
-rw-r--r--lib/test_server/src/ts.unix.config2
-rw-r--r--lib/test_server/test/test_server_SUITE_data/test_server_parallel01_SUITE.erl16
-rw-r--r--lib/test_server/vsn.mk2
-rw-r--r--lib/tools/emacs/erlang.el18
-rw-r--r--lib/tools/emacs/test.erl.indented11
-rw-r--r--lib/tools/emacs/test.erl.orig11
-rw-r--r--lib/tools/src/tools.app.src22
-rw-r--r--lib/tools/test/cover_SUITE.erl36
-rw-r--r--lib/tools/test/cover_SUITE_data/f.erl7
-rw-r--r--lib/tools/vsn.mk2
-rw-r--r--lib/typer/src/typer.app.src4
-rw-r--r--lib/typer/vsn.mk2
-rw-r--r--lib/webtool/src/webtool.app.src4
-rw-r--r--lib/webtool/vsn.mk2
-rw-r--r--lib/wx/aclocal.m46
-rw-r--r--lib/wx/api_gen/wx_doxygen.conf3
-rw-r--r--lib/wx/api_gen/wx_extra/wxListCtrl.c_src4
-rw-r--r--lib/wx/api_gen/wx_gen.erl12
-rw-r--r--lib/wx/api_gen/wx_gen_cpp.erl19
-rw-r--r--lib/wx/api_gen/wx_gen_erl.erl26
-rw-r--r--lib/wx/api_gen/wxapi.conf19
-rw-r--r--lib/wx/c_src/gen/wxe_derived_dest.h8
-rw-r--r--lib/wx/c_src/gen/wxe_events.cpp142
-rw-r--r--lib/wx/c_src/gen/wxe_funcs.cpp250
-rw-r--r--lib/wx/c_src/gen/wxe_macros.h1217
-rw-r--r--lib/wx/c_src/wxe_callback_impl.cpp2
-rw-r--r--lib/wx/c_src/wxe_callback_impl.h9
-rw-r--r--lib/wx/c_src/wxe_impl.cpp32
-rw-r--r--lib/wx/c_src/wxe_impl.h17
-rwxr-xr-xlib/wx/configure.in14
-rw-r--r--lib/wx/include/wx.hrl245
-rw-r--r--lib/wx/src/gen/wxLocale.erl278
-rw-r--r--lib/wx/src/gen/wx_misc.erl18
-rw-r--r--lib/wx/src/gen/wxe_debug.hrl1217
-rw-r--r--lib/wx/src/gen/wxe_funcs.hrl1217
-rw-r--r--lib/wx/src/wx.app.src3
-rw-r--r--lib/wx/src/wxe_master.erl18
-rw-r--r--lib/wx/src/wxe_server.erl13
-rw-r--r--lib/wx/test/wx_basic_SUITE.erl13
-rw-r--r--lib/wx/test/wx_class_SUITE.erl17
-rw-r--r--lib/wx/vsn.mk2
-rw-r--r--lib/xmerl/src/xmerl.app.src3
-rw-r--r--lib/xmerl/vsn.mk2
426 files changed, 17117 insertions, 5779 deletions
diff --git a/lib/asn1/doc/src/asn1_ug.xml b/lib/asn1/doc/src/asn1_ug.xml
index ee54fdffd7..020e58c615 100644
--- a/lib/asn1/doc/src/asn1_ug.xml
+++ b/lib/asn1/doc/src/asn1_ug.xml
@@ -34,23 +34,25 @@
<section>
<title>Features</title>
- <p>The Asn1 application provides:
- </p>
+ <p>The Asn1 application provides:</p>
<list type="bulleted">
<item>An ASN.1 compiler for Erlang, which generates encode and
decode functions to be used by Erlang programs sending and
receiving ASN.1 specified data.</item>
<item>Run-time functions used by the generated code.</item>
- <item>The supported encoding rules are:
+ <item>Support for the following encoding rules:
<list>
<item>
Basic Encoding Rules (<em>BER</em>)
</item>
<item>
- Distinguished Encoding Rules (<em>DER</em>), a specialized form of BER that is used in security-conscious applications.
+ Distinguished Encoding Rules (<em>DER</em>), a specialized
+ form of BER that is used in security-conscious
+ applications.
</item>
<item>
- Packed Encoding Rules (<em>PER</em>) both the aligned and unaligned variant.
+ Packed Encoding Rules (<em>PER</em>); both the aligned and
+ unaligned variant.
</item>
</list>
</item>
@@ -59,71 +61,41 @@
<section>
<title>Overview</title>
- <p>ASN.1 (Abstract Syntax Notation 1) is a formal language for describing data structures to be exchanged between distributed computer systems.
- The purpose of ASN.1 is to have
- a platform and programming language independent notation to express
- types using a
- standardized set of rules for the transformation of values of
- a defined type, into a stream of bytes. This stream of bytes
- can then be sent on a communication channel set up by the
- lower layers in the stack of communication protocols e.g.
- TCP/IP or encapsulated within UDP packets. This way, two
- different applications written in two completely different
- programming languages running on different computers with
- different internal representation of data can exchange
- instances of structured data types (instead of exchanging
- bytes or bits). This makes programming faster and easier since no code
- has to be written to process the transport format of the
- data.
- </p>
- <p>To write a network application which processes ASN.1 encoded
- messages, it is prudent and sometimes essential to have a set
- of off-line development tools such as an ASN.1 compiler which
- can generate the encode and decode logic for the specific ASN.1
- data types. It is also necessary to combine this with some
- general language-specific runtime support for ASN.1 encoding and
- decoding.
- </p>
- <p>The ASN.1 compiler must be directed towards a target language
- or a set of closely related languages. This manual describes a
- compiler which is directed towards the functional language
- Erlang. In order to use this compiler, familiarity with the
- language Erlang is essential. Therefore, the runtime support for ASN.1 is
- also closely related to the language Erlang and
- consist of a number of functions, which the
- compiler uses. The types in ASN.1 and how to represent
- values of those types in Erlang are described in this manual.
- </p>
- <p>The following document is structured so that the first part describes
- how to use ASN.1 compiler, and then there are descriptions of all
- the primitive and constructed ASN.1 types and their representation
- in Erlang,
- </p>
+ <p>ASN.1 (Abstract Syntax Notation One) is a formal language for
+ describing data structures to be exchanged between distributed
+ computer systems. The purpose of ASN.1 is to have a platform
+ and programming language independent notation to express types
+ using a standardized set of rules for the transformation of
+ values of a defined type into a stream of bytes. This stream of
+ bytes can then be sent on any type of communication
+ channel. This way, two applications written in different
+ programming languages running on different computers with
+ different internal representation of data can exchange instances
+ of structured data types.</p>
</section>
<section>
<title>Prerequisites</title>
- <p>It is assumed that the reader is familiar with the ASN.1 notation
- as documented in the standard definition [<cite id="X.680"></cite>] which is
- the primary text. It may also be helpful, but not necessary,
- to read the standard definitions
- [<cite id="X.681"></cite>] [<cite id="X.682"></cite>] [<cite id="X.683"></cite>]
- [<cite id="X.690"></cite>] [<cite id="X.691"></cite>]. </p>
- <p>A very good book explaining those reference texts is
- [<cite id="DUBUISSON"></cite>], free to download at
- <url href="http://www.oss.com/asn1/dubuisson.html">http://www.oss.com/asn1/dubuisson.html </url>.
+ <p>It is assumed that the reader is familiar with the ASN.1
+ notation as documented in the standard definition [<cite
+ id="X.680"></cite>] which is the primary text. It may also be
+ helpful, but not necessary, to read the standard definitions
+ [<cite id="X.681"></cite>] [<cite id="X.682"></cite>] [<cite
+ id="X.683"></cite>] [<cite id="X.690"></cite>] [<cite
+ id="X.691"></cite>]. </p>
+ <p>A good book explaining those reference texts is
+ [<cite id="DUBUISSON"></cite>], which is free to download at
+ <url href="http://www.oss.com/asn1/dubuisson.html">http://www.oss.com/asn1/dubuisson.html</url>.
</p>
</section>
<section>
- <title>Capability</title>
+ <title>Capabilities</title>
<p>This application covers all features of ASN.1 up to the 1997
- edition of the specification. In the 2002 edition of ASN.1 a number of
- new features where introduced of which some are supported while
- others are not. For example the
- ECN (Encoding Control Notation) and XML notation are still
- unsupported. Though, the other features of the 2002 edition are
- fully or partly supported as shown below:</p>
+ edition of the specification. In the 2002 edition of ASN.1 a
+ number of new features were introduced. The following features
+ of the 2002 edition are fully or partly supported as shown
+ below:</p>
<list type="bulleted">
<item>
<p>Decimal notation (e.g., "1.5e3") for REAL values. The
@@ -131,7 +103,7 @@
supported.</p>
</item>
<item>
- <p>The RELATIVE-OID type for relative object identifiers are
+ <p>The RELATIVE-OID type for relative object identifiers is
fully supported.</p>
</item>
<item>
@@ -141,16 +113,16 @@
constraint is not a PER-visible constraint.</p>
</item>
<item>
- <p>The subtype constraint by regular expressions (PATTERN) for character string types is parsed when compiling, but no further action is taken. This constraint is not a PER-visible constraint.</p>
+ <p>The subtype constraint by regular expressions (PATTERN)
+ for character string types is parsed when compiling, but no
+ further action is taken. This constraint is not a
+ PER-visible constraint.</p>
</item>
<item>
<p>Multiple-line comments as in C, <c>/* ... */</c>, are
supported.</p>
</item>
</list>
- <p>It should also be added here that the encoding formats
- supported are <em>BER</em>, <em>DER</em>, <em>PER aligned
- basic</em> variant and <em>PER unaligned basic</em> variant.</p>
</section>
</section>
@@ -162,19 +134,17 @@
<title>A First Example</title>
<p>The following example demonstrates the basic functionality used to run
the Erlang ASN.1 compiler.</p>
- <p>First, create a file called <c>People.asn</c> containing the following:</p>
+ <p>Create a file called <c>People.asn</c> containing the following:</p>
<pre>
-People DEFINITIONS IMPLICIT TAGS ::=
-
+People DEFINITIONS AUTOMATIC TAGS ::=
BEGIN
-EXPORTS Person;
-
-Person ::= [PRIVATE 19] SEQUENCE {
- name PrintableString,
- location INTEGER {home(0),field(1),roving(2)},
- age INTEGER OPTIONAL }
+ Person ::= SEQUENCE {
+ name PrintableString,
+ location INTEGER {home(0),field(1),roving(2)},
+ age INTEGER OPTIONAL
+ }
END </pre>
- <p>This file (<c>people.asn</c>) must be compiled before it can be
+ <p>This file (<c>People.asn</c>) must be compiled before it can be
used.
The ASN.1 compiler checks that the syntax is correct and that the
text represents proper ASN.1 code before generating an abstract
@@ -186,14 +156,14 @@ END </pre>
The following shows how the compiler
can be called from the Erlang shell:</p>
<pre>
-1><input>asn1ct:compile("People", [ber]).</input>
+1><input> asn1ct:compile("People", [ber]).</input>
ok
2> </pre>
<p>The <c>verbose</c> option can be given to have information
about the generated files printed:</p>
<pre>
-2><input>asn1ct:compile("People", [ber,verbose]).</input>
+2><input> asn1ct:compile("People", [ber,verbose]).</input>
Erlang ASN.1 compiling "People.asn"
--{generated,"People.asn1db"}--
--{generated,"People.hrl"}--
@@ -201,17 +171,17 @@ Erlang ASN.1 compiling "People.asn"
ok
3> </pre>
- <p>The ASN.1 module People is now accepted and the abstract syntax tree
- is saved in the <c>People.asn1db</c> file, the
- generated Erlang code is compiled using the Erlang compiler and
- loaded into the Erlang runtime system. Now there is a user interface
- for <c>encode/2</c> and <c>decode/2</c> in the module People,
- which is invoked by:
- <br></br>
-<c><![CDATA['People':encode(<Type name>,<Value>),]]></c> <br></br>
-
+ <p>The ASN.1 module <c>People</c> is now accepted and the
+ abstract syntax tree is saved in the <c>People.asn1db</c> file;
+ the generated Erlang code is compiled using the Erlang compiler
+ and loaded into the Erlang run-time system. Now there is an API
+ for <c>encode/2</c> and <c>decode/2</c> in the module
+ <c>People</c>, which is invoked by: <br></br>
+ <c><![CDATA['People':encode(<Type name>, <Value>)]]></c>
+ <br></br>
or <br></br>
-<c><![CDATA['People':decode(<Type name>,<Value>),]]></c></p>
+<c><![CDATA['People':decode(<Type name>, <Value>)]]></c></p>
+
<p>Assume there is a network
application which receives instances of the ASN.1 defined
type Person, modifies and sends them back again:</p>
@@ -234,8 +204,7 @@ receive
constructed and encoded using
<c>'People':encode('Person',Answer)</c> which takes an
instance of a defined ASN.1 type and transforms it to a
- binary according to the BER or PER
- encoding-rules.
+ binary according to the BER or PER encoding rules.
<br></br>
The encoder and the decoder can also be run from
the shell.</p>
@@ -252,13 +221,13 @@ The encoder and the decoder can also be run from
<section>
<title>Module dependencies</title>
- <p>It is common that asn1 modules import defined types, values and
- other entities from another asn1 module.</p>
- <p>Earlier versions of the asn1 compiler required that modules that
+ <p>It is common that ASN.1 modules import defined types, values and
+ other entities from another ASN.1 module.</p>
+ <p>Earlier versions of the ASN.1 compiler required that modules that
were imported from had to be compiled before the module that
- imported. This caused problems when asn1 modules had circular
+ imported. This caused problems when ASN.1 modules had circular
dependencies.</p>
- <p>Now are referenced modules parsed when the compiler finds an
+ <p>Referenced modules are now parsed when the compiler finds an
entity that is imported. There will not be any code generated for
the referenced module. However, the compiled module rely on
that the referenced modules also will be compiled.</p>
@@ -310,7 +279,7 @@ erlc -o ../asnfiles -I ../asnfiles -I /usr/local/standards/asn1 Person.asn
</item>
<tag><c>-I IncludeDir</c></tag>
<item>
- <p>Where to search for <c>.asn1db</c> files and asn1
+ <p>Where to search for <c>.asn1db</c> files and ASN.1
source specs in order to resolve references to other
modules. This option can be repeated many times if there
are several places to search in. The compiler will always
@@ -322,26 +291,26 @@ erlc -o ../asnfiles -I ../asnfiles -I /usr/local/standards/asn1 Person.asn
</item>
<tag><c>+asn1config</c></tag>
<item>
- <p>This functionality works together with the flags
- <c>ber</c>. It enables the
+ <p>This functionality works together with the
+ <c>ber</c> option. It enables the
specialized decodes, see the <seealso marker="asn1_spec">Specialized Decode</seealso> chapter.
</p>
</item>
<tag><c>+undec_rest</c></tag>
<item>
- <p>A buffer that holds a message, being decoded may
- also have some following bytes. Now it is possible to get
- those following bytes returned together with the decoded
- value. If an asn1 spec is compiled with this option a tuple
- <c>{ok,Value,Rest}</c> is returned. <c>Rest</c> may be a
- list or a binary. Earlier versions of the compiler ignored
- those following bytes.</p>
+ <p>A buffer that holds a message being decoded may also have
+ trailing bytes. If those trailing bytes are important they
+ can be returned along with the decoded value by compiling
+ the ASN.1 specification with the <c>+undec_rest</c> option.
+ The return value from the decoder will be
+ <c>{ok,Value,Rest}</c> where <c>Rest</c> is a binary
+ containing the trailing bytes.</p>
</item>
<tag><c>+'Any Erlc Option'</c></tag>
<item>
<p>You may add any option to the Erlang compiler when
compiling the generated Erlang files. Any option
- unrecognised by the asn1 compiler will be passed to the
+ unrecognized by the ASN.1 compiler will be passed to the
Erlang compiler.</p>
</item>
</taglist>
@@ -366,10 +335,6 @@ asn1ct:compile("H323-MESSAGES.asn1",[ber]). </pre>
asn1ct:compile("H323-MESSAGES.asn1",[per]). </pre>
<p>The generic encode and decode functions can be invoked like this:</p>
<pre>
-asn1ct:encode('H323-MESSAGES','SomeChoiceType',{call,"octetstring"}).
-asn1ct:decode('H323-MESSAGES','SomeChoiceType',Bytes). </pre>
- <p>Or, preferable like:</p>
- <pre>
'H323-MESSAGES':encode('SomeChoiceType',{call,"octetstring"}).
'H323-MESSAGES':decode('SomeChoiceType',Bytes). </pre>
</section>
@@ -389,7 +354,7 @@ asn1ct:decode('H323-MESSAGES','SomeChoiceType',Bytes). </pre>
compile time appear on the screen together with
a line number indicating where in the source file the error
was detected. If no errors are found, an Erlang ASN.1 module will
- be created as default.</p>
+ be created.</p>
<p>The run-time encoders and decoders execute within a catch and
returns <c>{ok, Data}</c> or
<c>{error, {asn1, Description}}</c> where
@@ -400,18 +365,18 @@ asn1ct:decode('H323-MESSAGES','SomeChoiceType',Bytes). </pre>
<section>
<marker id="inlineExamples"></marker>
- <title>Multi File Compilation</title>
- <p>There are various reasons for using a multi file compilation:</p>
+ <title>Multi-file Compilation</title>
+ <p>There are various reasons for using multi-file compilation:</p>
<list type="bulleted">
- <item>You want to choose name for the generated module by
- any reason. Maybe you need to compile the same specs for
- different encoding/decoding standards.</item>
+ <item>You want to choose the name for the generated module,
+ perhaps because you need to compile the same specs for
+ different encoding rules.</item>
<item>You want only one resulting module.</item>
</list>
- <p>You need to specify which asn1 specs you will
+ <p>You need to specify which ASN.1 specs you will
compile in a module that must have the extension
<c>.set.asn</c>. You chose name of the module and provide the
- names of the asn1 specs. For instance, if you have the specs
+ names of the ASN.1 specs. For instance, if you have the specs
<c>File1.asn</c>, <c>File2.asn</c> and <c>File3.asn</c> your
module <c>MyModule.set.asn</c> will look like:</p>
<pre>
@@ -422,11 +387,45 @@ File3.asn </pre>
<code type="none">
~> erlc MyModule.set.asn </code>
<p>the result will be one merged module <c>MyModule.erl</c> with
- the generated code from the three asn1 specs.
+ the generated code from the three ASN.1 specs.
</p>
</section>
<section>
+ <title>A quick note about tags</title>
+
+ <p>Tags used to be important for all users of ASN.1, because it
+ was necessary to manually add tags to certain constructs in order
+ for the ASN.1 specification to be valid. Here is an example of
+ an old-style specification:</p>
+
+ <pre>
+Tags DEFINITIONS ::=
+BEGIN
+ Afters ::= CHOICE { cheese [0] IA5String,
+ dessert [1] IA5String }
+END </pre>
+
+ <p>Without the tags (the numbers in square brackets) the ASN.1
+ compiler would refuse to compile the file.</p>
+
+ <p>In 1994 the global tagging mode AUTOMATIC TAGS was introduced.
+ By putting AUTOMATIC TAGS in the module header, the ASN.1 compiler
+ will automatically add tags when needed. Here is the same
+ specification in AUTOMATIC TAGS mode:</p>
+
+ <pre>
+Tags DEFINITIONS AUTOMATIC TAGS ::=
+BEGIN
+ Afters ::= CHOICE { cheese IA5String,
+ dessert IA5String }
+END
+</pre>
+
+ <p>Tags will not be mentioned any more in this manual.</p>
+ </section>
+
+ <section>
<marker id="ASN1Types"></marker>
<title>The ASN.1 Types</title>
<p>This section describes the ASN.1 types including their
@@ -497,7 +496,7 @@ Operational ::= BOOLEAN --ASN.1 definition </pre>
<p>In Erlang code it may look like:</p>
<pre>
Val = true,
-{ok,Bytes}=asn1rt:encode(MyModule,'Operational',Val), </pre>
+{ok,Bytes} = MyModule:encode('Operational', Val), </pre>
<p>Below follows a description of how
values of each type can be represented in Erlang.
</p>
@@ -563,20 +562,18 @@ T6value3 = white
<section>
<marker id="REAL"></marker>
<title>REAL</title>
- <p>In this version reals are not implemented. When they are,
- the following
- ASN.1 type is used:</p>
+ <p>The following ASN.1 type is used for real numbers:</p>
<pre>
R1 ::= REAL
</pre>
- <p>Can be assigned a value in Erlang as:</p>
+ <p>It can be assigned a value in Erlang as:</p>
<pre>
-R1value1 = 2.14,
+R1value1 = "2.14",
R1value2 = {256,10,-2},
</pre>
<p>In the last line note that the tuple {256,10,-2} is the real number
2.56 in a special notation, which will encode faster than simply
- stating the number as 2.56. The arity three tuple is
+ stating the number as <c>"2.56"</c>. The arity three tuple is
<c>{Mantissa,Base,Exponent}</c> i.e. Mantissa * Base^Exponent.</p>
</section>
@@ -736,13 +733,11 @@ O2Val = &lt;&lt;"must be exactly 28 chars...."&gt;&gt;,</pre>
specified for a type are especially important for PER, where
they affect the encoding.
</p>
- <p>Please note that <em>all</em> the Character strings are
- supported and it is possible to use the following ASN.1 type
- definitions:</p>
+ <p>Here are some examples:</p>
<pre>
Digs ::= NumericString (SIZE(1..3))
TextFile ::= IA5String (SIZE(0..64000)) </pre>
- <p>and the following Erlang assignments:</p>
+ <p>with corresponding Erlang assignments:</p>
<pre>
DigsVal1 = "456",
DigsVal2 = "123",
@@ -755,70 +750,86 @@ TextFileVal2 = [88,76,55,44,99,121 .......... a lot of characters here ....]
characters are all represented by quadruples beginning with
three zeros like {0,0,0,65} for the 'A' character. When
decoding a value for these strings the result is a list of
- quadruples, or integers when the value is an ASCII character.
- The following example shows how it works:</p>
- <p>In a file <c>PrimStrings.asn1</c> the type <c>BMP</c> is defined as
- <br></br>
-<c>BMP ::= BMPString</c> then using BER encoding (<c>ber</c>
- option)the input/output format will be:</p>
+ quadruples, or integers when the value is an ASCII character.</p>
+
+ <p>The following example shows how it works. We have the following
+ specification in the file <c>PrimStrings.asn1</c>.</p>
+ <pre>
+PrimStrings DEFINITIONS AUTOMATIC TAGS ::=
+BEGIN
+ BMP ::= BMPString
+END
+ </pre>
+
+ <p>Encoding and decoding some strings:</p>
+
<pre>
-1> <input>{ok,Bytes1} = asn1rt:encode('PrimStrings','BMP',[{0,0,53,53},{0,0,45,56}]).</input>
-{ok,[30,4,"55-8"]}
-2> <input>asn1rt:decode('PrimStrings','BMP',list_to_binary(Bytes1)).</input>
+1> <input>asn1ct:compile('PrimStrings', [ber]).</input>
+ok
+2> <input>{ok,Bytes1} = 'PrimStrings':encode('BMP', [{0,0,53,53},{0,0,45,56}]).</input>
+{ok,&lt;&lt;30,4,53,54,45,56>>}
+3> <input>'PrimStrings':decode('BMP', Bytes1).</input>
{ok,[{0,0,53,53},{0,0,45,56}]}
-3> <input>{ok,Bytes2} = asn1rt:encode('PrimStrings','BMP',[{0,0,53,53},{0,0,0,65}]).</input>
-{ok,[30,4,[53,53,0,65]]}
-4> <input>asn1rt:decode('PrimStrings','BMP',list_to_binary(Bytes2)).</input>
+4> <input>{ok,Bytes2} = 'PrimStrings':encode('BMP', [{0,0,53,53},{0,0,0,65}]).</input>
+{ok,&lt;&lt;30,4,53,53,0,65>>}
+5> <input>'PrimStrings':decode('BMP', Bytes2).</input>
{ok,[{0,0,53,53},65]}
-5> <input>{ok,Bytes3} = asn1rt:encode('PrimStrings','BMP',"BMP string").</input>
-{ok,[30,20,[0,66,0,77,0,80,0,32,0,115,0,116,0,114,0,105,0,110,0,103]]}
-6> <input>asn1rt:decode('PrimStrings','BMP',list_to_binary(Bytes3)).</input>
+6> <input>{ok,Bytes3} = 'PrimStrings':encode('BMP', "BMP string").</input>
+{ok,&lt;&lt;30,20,0,66,0,77,0,80,0,32,0,115,0,116,0,114,0,105,0,110,0,103>>}
+7> <input>'PrimStrings':decode('BMP', Bytes3).</input>
{ok,"BMP string"} </pre>
- <p>The UTF8String is represented in Erlang as a list of integers,
- where each integer represents the unicode value of one
- character. When a value shall be encoded one first has to
- transform it to a UTF8 encoded binary, then it can be encoded by
- asn1. When decoding the result is a UTF8 encoded binary, which
- may be transformed to an integer list. The transformation
- functions, <c>utf8_binary_to_list</c> and
- <c>utf8_list_to_binary</c>, are in the <c>asn1rt</c> module. In
- the example below we assume an asn1 definition <c>UTF ::= UTF8String</c> in a module <c>UTF.asn</c>:</p>
+
+ <p>The UTF8String type is represented as a UTF-8 encoded binary in
+ Erlang. Such binaries can be created directly using the binary syntax
+ or by converting from a list of Unicode code points using the
+ <c>unicode:characters_to_binary/1</c> function.</p>
+
+ <p>Here are some examples showing how UTF-8 encoded binaries can
+ be created and manipulated:</p>
+
+ <pre>
+1> <input>Gs = "Мой маленький Гном".</input>
+[1052,1086,1081,32,1084,1072,1083,1077,1085,1100,1082,1080,
+ 1081,32,1043,1085,1086,1084]
+2> <input>Gbin = unicode:characters_to_binary(Gs).</input>
+&lt;&lt;208,156,208,190,208,185,32,208,188,208,176,208,187,208,
+ 181,208,189,209,140,208,186,208,184,208,185,32,208,147,
+ 208,...>>
+3> <input>Gbin = &lt;&lt;"Мой маленький Гном"/utf8>>.</input>
+&lt;&lt;208,156,208,190,208,185,32,208,188,208,176,208,187,208,
+ 181,208,189,209,140,208,186,208,184,208,185,32,208,147,
+ 208,...>>
+4> <input>Gs = unicode:characters_to_list(Gbin).</input>
+[1052,1086,1081,32,1084,1072,1083,1077,1085,1100,1082,1080,
+ 1081,32,1043,1085,1086,1084]
+ </pre>
+
+ <p>See the <seealso marker="stdlib:unicode">unicode</seealso> module
+ for more details.</p>
+
+ <p>In the following example we will use this ASN.1 specification:</p>
<pre>
-1> <input>asn1ct:compile('UTF',[ber]).</input>
-Erlang ASN.1 version "1.4.3.3" compiling "UTF.asn"
-Compiler Options: [ber]
---{generated,"UTF.asn1db"}--
---{generated,"UTF.erl"}--
+UTF DEFINITIONS AUTOMATIC TAGS ::=
+BEGIN
+ UTF ::= UTF8String
+END
+ </pre>
+
+ <p>Encoding and decoding a string with Unicode characters:</p>
+
+ <pre>
+5> <input>asn1ct:compile('UTF', [ber]).</input>
+ok
+6> <input>{ok,Bytes1} = 'UTF':encode('UTF', &lt;&lt;"Гном"/utf8>>).</input>
+{ok,&lt;&lt;12,8,208,147,208,189,208,190,208,188>>}
+7> <input>{ok,Bin1} = 'UTF':decode('UTF', Bytes1).</input>
+{ok,&lt;&lt;208,147,208,189,208,190,208,188>>}
+8> <input>io:format("~ts\n", [Bin1]).</input>
+Гном
ok
-2> <input>UTF8Val1 = "hello".</input>
-"hello"
-3> <input>{ok,UTF8bin1} = asn1rt:utf8_list_to_binary(UTF8Val1).</input>
-{ok,&lt;&lt;104,101,108,108,111&gt;&gt;}
-4> <input>{ok,B}='UTF':encode('UTF',UTF8bin1).</input>
-{ok,[12,
- 5,
- &lt;&lt;104,101,108,108,111&gt;&gt;]}
-5> <input>Bin = list_to_binary(B).</input>
-&lt;&lt;12,5,104,101,108,108,111&gt;&gt;
-6> <input>{ok,UTF8bin1}='UTF':decode('UTF',Bin).</input>
-{ok,&lt;&lt;104,101,108,108,111&gt;&gt;}
-7> <input>asn1rt:utf8_binary_to_list(UTF8bin1).</input>
-{ok,"hello"}
-8> <input>UTF8Val2 = [16#00,16#100,16#ffff,16#ffffff].</input>
-[0,256,65535,16777215]
-9> <input>{ok,UTF8bin2} = asn1rt:utf8_list_to_binary(UTF8Val2).</input>
-{ok,&lt;&lt;0,196,128,239,191,191,248,191,191,191,191&gt;&gt;}
-10> <input>{ok,B2} = 'UTF':encode('UTF',UTF8bin2).</input>
-{ok,[12,
- 11,
- &lt;&lt;0,196,128,239,191,191,248,191,191,191,191&gt;&gt;]}
-11> <input>Bin2 = list_to_binary(B2).</input>
-&lt;&lt;12,11,0,196,128,239,191,191,248,191,191,191,191&gt;&gt;
-12> <input>{ok,UTF8bin2} = 'UTF':decode('UTF',Bin2).</input>
-{ok,&lt;&lt;0,196,128,239,191,191,248,191,191,191,191&gt;&gt;}
-13> <input>asn1rt:utf8_binary_to_list(UTF8bin2).</input>
-{ok,[0,256,65535,16777215]}
-14> </pre>
+9> <input>unicode:characters_to_list(Bin1).</input>
+[1043,1085,1086,1084]
+ </pre>
</section>
<section>
@@ -853,9 +864,11 @@ OidVal1 = {1,2,55},
<section>
<marker id="Object Descriptor"></marker>
<title>Object Descriptor</title>
- <p>Values of this type can be assigned a value as an ordinary string i.e. <br></br>
+ <p>Values of this type can be assigned a value as an ordinary string
+ like this:</p>
- "This is the value of an Object descriptor"</p>
+ <pre>
+ "This is the value of an Object descriptor"</pre>
</section>
<section>
@@ -898,19 +911,31 @@ Pdu ::= SEQUENCE {
<pre>
MyPdu = #'Pdu'{a=22,b=77.99,c={0,1,2,3,4},d='NULL'}. </pre>
<p>The decode functions will return a record as result when decoding
- a <c>SEQUENCE</c> or a <c>SET</c>.
- <marker id="DEFAULT"></marker>
-</p>
- <p>A <c>SEQUENCE</c> and a <c>SET</c> may contain a component with a
- <c>DEFAULT</c> key word followed by the actual value that is the
- default value. In case of BER encoding it is optional to encode the
- value if it equals the default value. If the application uses the
- atom asn1_DEFAULT as value or if the value is a primitive value
- that equals the default value the encoding omits the bytes for
- this value, which is more efficient and it results in fever
- bytes to send to the receiving application.</p>
- <p>For instance, if the following types exists in a file "File.asn":</p>
+ a <c>SEQUENCE</c> or a <c>SET</c>.</p>
+
+ <p>A <c>SEQUENCE</c> and a <c>SET</c> may contain a component
+ with a <c>DEFAULT</c> key word followed by the actual value that
+ is the default value. The <c>DEFAULT</c> keyword means that the
+ application doing the encoding can omit encoding of the value,
+ thus resulting in fewer bytes to send to the receiving
+ application.</p>
+
+ <p>An application can use the atom <c>asn1_DEFAULT</c> to indicate
+ that the encoding should be omitted for that position in
+ the SEQUENCE.</p>
+
+ <p>Depending on the encoding rules, the encoder may also compare
+ the given value to the default value and automatically omit the
+ encoding if they are equal. How much effort the encoder makes to
+ to compare the values depends on the encoding rules. The DER
+ encoding rules forbids encoding a value equal to the default value,
+ so it has a more thorough and time-consuming comparison than the
+ encoders for the other encoding rules.</p>
+
+ <p>In the following example we will use this ASN.1 specification:</p>
<pre>
+File DEFINITIONS AUTOMATIC TAGS ::=
+BEGIN
Seq1 ::= SEQUENCE {
a INTEGER DEFAULT 1,
b Seq2 DEFAULT {aa TRUE, bb 15}
@@ -920,131 +945,50 @@ Seq2 ::= SEQUENCE {
aa BOOLEAN,
bb INTEGER
}
- </pre>
- <p>Some values and the corresponding encoding in an Erlang terminal
- is shown below:</p>
+
+Seq3 ::= SEQUENCE {
+ bs BIT STRING {a(0), b(1), c(2)} DEFAULT {a, c}
+}
+END </pre>
+ <p>Here is an example where the BER encoder is able to omit encoding
+ of the default values:</p>
<pre>
-1> <input>asn1ct:compile('File').</input>
-Erlang ASN.1 version "1.3.2" compiling "File.asn1"
-Compiler Options: []
---{generated,"File.asn1db"}--
---{generated,"File.hrl"}--
---{generated,"File.erl"}--
+1> <input>asn1ct:compile('File', [ber]).</input>
ok
-2> <input>'File':encode('Seq1',{'Seq1',asn1_DEFAULT,asn1_DEFAULT}).</input>
-{ok,["0",[0],[[],[]]]}
-3> <input>lists:flatten(["0",[0],[[],[]]]).</input>
-[48,0]
-4> <input>'File':encode('Seq1',{'Seq1',1,{'Seq2',true,15}}).</input>
-{ok,["0","\\b",[[],["\\241",[6],[[[128],[1],"\\377"],[[129],[1],[15]]]]]]}
-5> <input>lists:flatten(["0","\\b",[[],["\\241",[6],[[[128],[1],"\\377"],[[129],[1],[15]]]]]]).</input>
-[48,8,161,6,128,1,255,129,1,15]
-6> </pre>
- <p>The result after command line 3, in the example above,shows that the
- encoder omits the encoding of default values when they are specific
- by asn1_DEFAULT. Line 5 shows that even primitive values that equals
- the default value are detected and not encoded. But the constructed
- value of component <c>b</c> in <c>Seq1</c> is not recognized as the
- default value. Checking of default values in <c>BER</c> is not done
- in case of complex values, because it would be to expensive.
- <marker id="DEFAULT DER"></marker>
-</p>
- <p>But, the DER encoding format has stronger requirements regarding
- default values both for SET and SEQUENCE. A more elaborate and time
- expensive check of default values will take place. The following is
- an example with the same types and values as above but with der
- encoding format.</p>
- <pre>
-1> <input>asn1ct:compile('File',[der]).</input>
-Erlang ASN.1 version "1.3.2" compiling "File.asn1"
-Compiler Options: [der]
---{generated,"File.asn1db"}--
---{generated,"File.hrl"}--
---{generated,"File.erl"}--
+2> <input>'File':encode('Seq1', {'Seq1',asn1_DEFAULT,asn1_DEFAULT}).</input>
+{ok,&lt;&lt;48,0>>}
+3> <input>'File':encode('Seq1', {'Seq1',1,{'Seq2',true,15}}).</input>
+{ok,&lt;&lt;48,0>>} </pre>
+
+ <p>And here is an example with a named BIT STRING where the BER
+ encoder will not omit the encoding:</p>
+ <pre>
+4> <input>'File':encode('Seq3', {'Seq3',asn1_DEFAULT).</input>
+{ok,&lt;&lt;48,0>>}
+5> <input>'File':encode('Seq3', {'Seq3',&lt;&lt;16#101:3>>).</input>
+{ok,&lt;&lt;48,4,128,2,5,160>>} </pre>
+
+ <p>The DER encoder will omit the encoding for the same BIT STRING:</p>
+ <pre>
+6> <input>asn1ct:compile('File', [ber,der]).</input>
ok
-2> <input>'File':encode('Seq1',{'Seq1',asn1_DEFAULT,asn1_DEFAULT}).</input>
-{ok,["0",[0],[[],[]]]}
-3> <input>lists:flatten(["0",[0],[[],[]]]).</input>
-[48,0]
-4> <input>'File':encode('Seq1',{'Seq1',1,{'Seq2',true,15}}).</input>
-{ok,["0",[0],[[],[]]]}
-5> <input>lists:flatten(["0",[0],[[],[]]]).</input>
-[48,0]
-6>
- </pre>
- <p>Line 5 shows that even values of constructed types is checked and if
- it equals the default value it will not be encoded.</p>
+7> <input>'File':encode('Seq3', {'Seq3',asn1_DEFAULT).</input>
+{ok,&lt;&lt;48,0>>}
+8> <input>'File':encode('Seq3', {'Seq3',&lt;&lt;16#101:3>>).</input>
+{ok,&lt;&lt;48,0>>} </pre>
</section>
<section>
<marker id="SET"></marker>
<title>SET</title>
- <p>The SET type is an unusual construct and normally the SEQUENCE
- type is more appropriate to use. Set is also inefficient compared with SEQUENCE, as the components can be in any order. Hence, it must be possible
- to distinguish every component in 'SET', both when
- encoding and decoding a value of a type defined to be a SET.
- The tags of all components must be different from each other
- in order to be easily recognizable.</p>
- <p>A SET may be defined as:</p>
- <pre>
-Pdu2 ::= SET {
- a INTEGER,
- b BOOLEAN,
- c ENUMERATED {on(0),off(1)} } </pre>
- <p>A SET is represented as an Erlang record.
- For each SEQUENCE and <c>SET</c> in
- an ASN.1 module an Erlang record declaration is generated. For
- <c>Pdu2</c> above a record is defined like this:</p>
- <pre>
--record('Pdu2',{a, b, c}). </pre>
- <p>The record declarations for a module <c>M</c> are placed in a
- separate <c>M.hrl</c> file.</p>
- <p>Values can be assigned in Erlang as demonstrated below:</p>
- <pre>
-V = #'Pdu2'{a=44,b=false,c=off}. </pre>
- <p>The decode functions will return a record as result when decoding
- a SET.
- </p>
- <p>The difference between SET and SEQUENCE is that the order of
- the components (in the BER encoded format) is undefined for SET
- and defined as the lexical order from the ASN.1 definition for
- SEQUENCE. The ASN.1 compiler for Erlang will always encode a
- SET in the lexical order. The decode routines can handle SET
- components encoded in any order but will always return the
- result as a record. Since all components of the SET must be
- distinguishable both in the encoding phase as well as the
- decoding phase the following type is not allowed in a module
- with EXPLICIT or IMPLICIT as tag-default :</p>
- <p></p>
- <pre>
-Bad ::= SET {i INTEGER,
- j INTEGER } </pre>
- <p>The ASN.1 to Erlang compiler rejects the above type. We
- shall not explain the concept of tag further here, we refer to
- [<cite id="X.680"></cite>].
- </p>
- <p>Encoding of a SET with components with DEFAULT values behaves
- similar as a SEQUENCE, <seealso marker="#DEFAULT">see above</seealso>. The DER encoding format restrictions on DEFAULT
- values is the same for SET as for SEQUENCE, and is supported by
- the compiler, <seealso marker="#DEFAULT DER">see above</seealso>.</p>
- <p>Moreover, in DER the elements of a SET will be sorted. If a
- component is an un-tagged choice the sorting have to take place
- in run-time. This fact emphasizes the following recommendation
- if DER encoding format is used.</p>
- <p>The concept of SET is an unusual
- construct and one cannot think of one single application
- where the set type is essential. (Imagine if someone
- "invented'' the shuffled array in 'C') People tend to think
- that 'SET' sounds nicer and more mathematical than 'SEQUENCE'
- and hence use it when 'SEQUENCE' would have been more
- appropriate. It is also most inefficient, since every correct
- implementation of SET must always be prepared to accept the
- components in any order. So, if possible use SEQUENCE instead
- of SET.</p>
+ <p>In Erlang, the SET type is used exactly as SEQUENCE. Note
+ that if the BER or DER encoding rules are used, decoding a
+ SET is slower than decoding a SEQUENCE because the components
+ must be sorted.</p>
</section>
<section>
- <title>Notes about Extend-ability for SEQUENCE and SET</title>
+ <title>Notes about extensibility for SEQUENCE and SET</title>
<p>When a SEQUENCE or SET contains an extension marker and
extension components like this:</p>
<pre>
@@ -1071,51 +1015,28 @@ SExt ::= SEQUENCE {
<marker id="CHOICE"></marker>
<title>CHOICE</title>
<p>The CHOICE type is a space saver and is similar to the concept of a
- 'union' in the C-language. As with the previous SET-type, the
- tags of all components of a CHOICE need to be distinct. If
- AUTOMATIC TAGS are defined for the module (which is
- preferable) the tags can be omitted completely in the ASN.1
- specification of a CHOICE.
- </p>
+ 'union' in the C language.</p>
<p>Assume:</p>
<pre>
+SomeModuleName DEFINITIONS AUTOMATIC TAGS ::=
+BEGIN
T ::= CHOICE {
- x [0] REAL,
- y [1] INTEGER,
- z [2] OBJECT IDENTIFIER }
- </pre>
+ x REAL,
+ y INTEGER,
+ z OBJECT IDENTIFIER }
+END </pre>
<p>It is then possible to assign values:</p>
<pre>
TVal1 = {y,17},
TVal2 = {z,{0,1,2}},
</pre>
- <p>A CHOICE value is always represented as the tuple
+ <p>A CHOICE value is always represented as the tuple
<c>{ChoiceAlternative, Val}</c> where <c>ChoiceAlternative</c>
- is an atom denoting the selected choice
- alternative.
- </p>
- <p>It is also allowed to have a CHOICE type tagged as follow:</p>
- <p></p>
- <pre>
-C ::= [PRIVATE 111] CHOICE {
- C1,
- C2 }
-
-C1 ::= CHOICE {
- a [0] INTEGER,
- b [1] BOOLEAN }
-
-C2 ::= CHOICE {
- c [2] INTEGER,
- d [3] OCTET STRING } </pre>
- <p>In this case, the top type C appears to have no tags at all in
- its components, however, both C1 and C2 are also defined as
- CHOICE types and they have distinct tags among themselves.
- Hence, the above type C is both legal and allowed.
+ is an atom denoting the selected choice alternative.
</p>
<section>
- <title>Extendable CHOICE</title>
+ <title>Extensible CHOICE</title>
<p>When a CHOICE contains an extension marker and the decoder detects
an unknown alternative of the CHOICE the value is represented as:</p>
<pre>
@@ -1192,26 +1113,29 @@ Arr2Val = ["abc",[14,34,54],"Octets"], </pre>
Where <c>Value</c> may be a value of yet another type T2.</p>
<p>For example:</p>
<pre>
+EmbeddedExample DEFINITIONS AUTOMATIC TAGS ::=
+BEGIN
B ::= SEQUENCE {
a Arr1,
- b [0] T }
+ b T }
Arr1 ::= SET SIZE (5) OF INTEGER (4..9)
T ::= CHOICE {
- x [0] REAL,
- y [1] INTEGER,
- z [2] OBJECT IDENTIFIER } </pre>
- <p>The above example can be assigned like this in Erlang:</p>
+ x REAL,
+ y INTEGER,
+ z OBJECT IDENTIFIER }
+ END </pre>
+ <p>The SEQUENCE b can be encoded like this in Erlang:</p>
<pre>
-V2 = #'B'{a=[4,5,6,7,8], b={x,7.77}}.
- </pre>
+1> 'EmbeddedExample':encode('B', {'B',[4,5,6,7,8],{x,"7.77"}}).
+{ok,&lt;&lt;5,56,0,8,3,55,55,55,46,69,45,50>>} </pre>
</section>
</section>
<section>
<title>Naming of Records in .hrl Files</title>
- <p>When an asn1 specification is compiled all defined types of
+ <p>When an ASN.1 specification is compiled all defined types of
type SET or SEQUENCE will result in a corresponding record in the
generated hrl file. This is because the values for SET/SEQUENCE
as mentioned in sections above are represented as records.</p>
@@ -1227,8 +1151,8 @@ V2 = #'B'{a=[4,5,6,7,8], b={x,7.77}}.
Emb ::= SEQUENCE {
a SEQUENCE OF OCTET STRING,
b SET {
- a [0] INTEGER,
- b [1] INTEGER DEFAULT 66},
+ a INTEGER,
+ b INTEGER DEFAULT 66},
c CHOICE {
a INTEGER,
b FooType } }
@@ -1299,7 +1223,7 @@ PType{T} ::= SEQUENCE{
<p>Types may refer to themselves. Suppose:</p>
<pre>
Rec ::= CHOICE {
- nothing [0] NULL,
+ nothing NULL,
something SEQUENCE {
a INTEGER,
b OCTET STRING,
@@ -1331,7 +1255,7 @@ tt TT ::= {a 77,b {"kalle","kula"}} </pre>
Firstly, it could be used as the value in some DEFAULT component:</p>
<pre>
SS ::= SET {
- s [0] OBJECT IDENTIFIER,
+ s OBJECT IDENTIFIER,
val TT DEFAULT tt } </pre>
<p>It could also be used from inside an Erlang program. If the above ASN.1
code was defined in ASN.1 module <c>Values</c>, then the ASN.1 value
@@ -1365,8 +1289,8 @@ SS ::= SET {
<marker id="Information Object"></marker>
<title>ASN.1 Information Objects (X.681)</title>
<p>Information Object Classes, Information Objects and Information
- Object Sets, (in the following called classes, objects and
- object sets respectively), are defined in the standard
+ Object Sets (in the following called classes, objects and
+ object sets respectively) are defined in the standard
definition [<cite id="X.681"></cite>]. In the following only a brief
explanation is given. </p>
<p>These constructs makes it possible to define open types,
@@ -1435,9 +1359,26 @@ StartMessage ::= SEQUENCE {
<p><c>StartMessage</c> can in the <c>content</c> field be
encoded with a value of any type that an object in the
<c>GENERAL-PROCEDURES</c> object set has in its <c>NEW MESSAGE</c> field. This field refers to a type field
- <c><![CDATA[&amp;Message]]></c> in the class. The <c>msgId</c> field is always
+ <c>&amp;Message</c> in the class. The <c>msgId</c> field is always
encoded as a PrintableString, since the field refers to a fixed type
in the class.</p>
+ <p>In practice, object sets are usually declared to be extensible so
+ so that more objects can be added to the set later. Extensibility is
+ indicated like this:</p>
+ <pre>
+GENERAL-PROCEDURES GENERAL-PROCEDURE ::= {
+ object1 | object2, ...} </pre>
+ <p>When decoding a type that uses an extensible set constraint,
+ there is always the possibility that the value in the UNIQUE
+ field is unknown (i.e. the type has been encoded with a later
+ version of the ASN.1 specification). When that happens, the
+ unencoded data will be returned wrapped in a tuple like this:</p>
+
+ <pre>
+{asn1_OPENTYPE,Binary}</pre>
+ <p>where <c>Binary</c> is an Erlang binary that contains the encoded
+ data. (If the option <c>legacy_erlang_types</c> has been given,
+ just the binary will be returned.)</p>
</section>
<section>
@@ -1466,132 +1407,11 @@ T1 ::= General{PrintableString}
T2 ::= General{BIT STRING}
</pre>
<p>An example of a value that can be encoded as type T1 is {12,"hello"}.</p>
- <p>Observe that the compiler not generates encode/decode functions for
- parameterized types, only for the instances of the parameterized
- types. So, if a file contains the types General{}, T1 and T2 above,
+ <p>Note that the compiler does not generate encode/decode functions for
+ parameterized types, but only for the instances of the parameterized
+ types. Therefore, if a file contains the types General{}, T1 and T2 above,
encode/decode functions will only be generated for T1 and T2.
</p>
</section>
-
- <section>
- <title>Tags</title>
- <p>Every built-in ASN.1 type, except CHOICE and ANY have a universal tag.
- This is a unique number that clearly identifies the type. <br></br>
-
- It is essential for all users of ASN.1 to
- understand all the details about tags.</p>
- <p>Tags are implicitly encoded in the BER encoding as shown below, but
- are hardly not accounted for in the PER encoding. In PER tags are
- used for instance to sort the components of a SET.</p>
- <p>There are four different types of tags.</p>
- <taglist>
- <tag><em>universal</em></tag>
- <item>
- <p>For types whose meaning is the same in all
- applications. Such as integers, sequences and so on; that is, all the built in
- types.</p>
- </item>
- <tag><em>application</em></tag>
- <item>
- <p>For application specific types for example, the types in
- X.400 Message handling service have this sort of tag.</p>
- </item>
- <tag><em>private</em></tag>
- <item>
- <p>For your own private types.</p>
- </item>
- <tag><em>context</em></tag>
- <item>
- <p>This is used to distinguish otherwise indistinguishable
- types in a specific context. For example, if we have two
- components of a
- CHOICE type that are both <c>INTEGER</c> values, there is no
- way for the decoder to
- decipher which component was actually chosen, since both
- components will be
- tagged as <c>INTEGER</c>. When this or similar situations occur,
- one or both of the components should be given a context specific
- to resolve the ambiguity.</p>
- </item>
- </taglist>
- <p>The tag in the case of the 'Apdu' type [PRIVATE 1] is encoded to a
- sequence of bytes making it possible for a
- decoder to look at the (initial) bytes that arrive and determine
- whether the rest of the bytes must be of the type associated
- with that particular sequence of bytes. This means that each
- tag must be uniquely associated with <em>only</em> one ASN.1
- type.
- </p>
- <p>Immediately following the tag is a sequence of bytes
- informing the decoder of the length of the instance. This is
- sometimes referred to as TLV (Tag length value) encoding.
- Hence, the structure of a BER encoded series of bytes is as shown in the table below.</p>
- <p></p>
- <table>
- <row>
- <cell align="left" valign="middle">Tag</cell>
- <cell align="left" valign="middle">Len</cell>
- <cell align="left" valign="middle">Value</cell>
- </row>
- <tcaption>Structure of a BER encoded series of bytes</tcaption>
- </table>
- </section>
-
- <section>
- <title>Encoding Rules</title>
- <p>When the first recommendation on ASN.1 was released 1988 it was
- accompanied with the Basic Encoding Rules, BER, as the only
- alternative for encoding.
- BER is a somewhat verbose protocol. It adopts a so-called TLV (type,
- length, value) approach to encoding in which every element of the
- encoding carries some type information, some length information and
- then the value of that element. Where the element is itself
- structured, then the Value part of the element is itself a series of
- embedded TLV components, to whatever depth is necessary. In summary,
- BER is not a compact encoding but is relatively fast and easy to
- produce.</p>
- <p>The DER (Distinguished Encoding Rule) encoding format was included in
- the standard in 1994. It is a specialized form of BER, which gives
- the encoder the option to encode some entities differently. For
- instance, is the value for TRUE any octet with any bit set to one. But,
- DER does not leave any such choices. The value for TRUE in the DER
- case is encoded as the octet <c>11111111</c>. So, the same value
- encoded by two different DER encoders must result in the same bit
- stream.</p>
- <p>A more compact encoding is achieved with the Packed Encoding
- Rules PER which was introduced together with the revised
- recommendation in 1994. PER takes a rather different approach from
- that taken by BER. The first difference is that the tag part in
- the TLV is omitted from the encodings, and any tags in the
- notation are not encoded. The potential ambiguities are resolved
- as follows:</p>
- <list type="bulleted">
- <item>
- <p>A CHOICE is encoded by first encoding a choice index which
- identifies the chosen
- alternative by its position in the notation.</p>
- </item>
- <item>
- <p>The elements of a SEQUENCE are transmitted in textual
- order. OPTIONAL or DEFAULT elements are preceded by a bit map
- to identify which elements are present. After sorting the
- elements of a SET in the "canonical tag order" as defined in
- X.680 8.6 they are treated as a SEQUENCE regarding OPTIONAL
- and DEFAULT elements. A SET is transferred in the sorted
- order.</p>
- </item>
- </list>
- <p>A second difference is that PER takes full account of the sub-typing
- information in that the encoded bytes are affected by the constraints.
- The BER encoded bytes are unaffected by the constraints.
- PER uses the sub-typing information to for example omit length fields
- whenever possible. </p>
- <p>The run-time functions, sometimes take the constraints into account
- both for BER and PER. For instance are SIZE constrained strings checked.</p>
- <p>There are two variants of PER, <em>aligned</em> and <em>unaligned</em>.
- In summary, PER results in compact encodings which require much more
- computation to produce than BER.
- </p>
- </section>
</chapter>
diff --git a/lib/asn1/doc/src/asn1ct.xml b/lib/asn1/doc/src/asn1ct.xml
index 4d5a1a402a..32ff2d52cf 100644
--- a/lib/asn1/doc/src/asn1ct.xml
+++ b/lib/asn1/doc/src/asn1ct.xml
@@ -45,10 +45,11 @@
<p>By default in OTP 17, the representation of the BIT STRING
and OCTET STRING types as Erlang terms have changed. BIT
STRING values are now Erlang bitstrings and OCTET STRING values
- are binaries. For details see <seealso
- marker="asn1_ug#BIT STRING">BIT STRING</seealso> and <seealso
- marker="asn1_ug#OCTET STRING">OCTET STRING</seealso> in User's
- Guide.</p>
+ are binaries. Also, an undecoded open type will now be wrapped in
+ a <c>asn1_OPENTYPE</c> tuple. For details see <seealso
+ marker="asn1_ug#BIT STRING">BIT STRING</seealso>, <seealso
+ marker="asn1_ug#OCTET STRING">OCTET STRING</seealso>, and
+ <seealso marker="asn1_ug#Information%20Object">ASN.1 Information Objects</seealso> in User's Guide.</p>
<p>To revert to the old representation of the types, use the
<c>legacy_erlang_types</c> option.</p>
</note>
diff --git a/lib/asn1/src/asn1.app.src b/lib/asn1/src/asn1.app.src
index f2ee8deb75..02cbba0f10 100644
--- a/lib/asn1/src/asn1.app.src
+++ b/lib/asn1/src/asn1.app.src
@@ -10,5 +10,6 @@
asn1db
]},
{env, []},
- {applications, [kernel, stdlib]}
+ {applications, [kernel, stdlib]},
+ {runtime_dependencies, ["stdlib-2.0","kernel-3.0","erts-6.0"]}
]}.
diff --git a/lib/asn1/src/asn1ct.erl b/lib/asn1/src/asn1ct.erl
index 9ec43197bf..8470e5a1b4 100644
--- a/lib/asn1/src/asn1ct.erl
+++ b/lib/asn1/src/asn1ct.erl
@@ -566,6 +566,8 @@ get_pos_of_def(#pobjectdef{pos=Pos}) ->
Pos;
get_pos_of_def(#pobjectsetdef{pos=Pos}) ->
Pos;
+get_pos_of_def(#'Externaltypereference'{pos=Pos}) ->
+ Pos;
get_pos_of_def(#'Externalvaluereference'{pos=Pos}) ->
Pos;
get_pos_of_def(_) ->
diff --git a/lib/asn1/src/asn1ct_check.erl b/lib/asn1/src/asn1ct_check.erl
index b9f2cb876a..e788aa5c6c 100644
--- a/lib/asn1/src/asn1ct_check.erl
+++ b/lib/asn1/src/asn1ct_check.erl
@@ -270,46 +270,30 @@ check_exports(S,Module = #module{}) ->
end
end.
-check_imports(S,Module = #module{ }) ->
- case Module#module.imports of
- {imports,[]} ->
- [];
- {imports,ImportList} when is_list(ImportList) ->
- check_imports2(S,ImportList,[]);
- _ ->
- []
- end.
-check_imports2(_S,[],Acc) ->
+check_imports(S, #module{imports={imports,Imports}}) ->
+ check_imports_1(S, Imports, []).
+
+check_imports_1(_S, [], Acc) ->
Acc;
-check_imports2(S,[#'SymbolsFromModule'{symbols=Imports,module=ModuleRef}|SFMs],Acc) ->
- NameOfDef =
- fun(#'Externaltypereference'{type=N}) -> N;
- (#'Externalvaluereference'{value=N}) -> N
- end,
- Module = NameOfDef(ModuleRef),
- Refs = [{M,R}||{{M,_},R} <- [{catch get_referenced_type(S,Ref),Ref}||Ref <- Imports]],
- {Illegal,Other} = lists:splitwith(fun({error,_}) -> true;(_) -> false end,
- Refs),
- ChainedRefs = [R||{M,R} <- Other, M =/= Module],
- IllegalRefs = [R||{error,R} <- Illegal] ++
- [R||{M,R} <- ChainedRefs,
- ok =/= chained_import(S,Module,M,NameOfDef(R))],
- ReportError =
- fun(Ref) ->
- NewS=S#state{type=Ref,tname=NameOfDef(Ref)},
- error({import,"imported undefined entity",NewS})
- end,
- check_imports2(S,SFMs,[ReportError(Err)||Err <- IllegalRefs]++Acc).
+check_imports_1(S, [#'SymbolsFromModule'{symbols=Imports,module=ModuleRef}|SFMs], Acc0) ->
+ Module = name_of_def(ModuleRef),
+ Refs0 = [{catch get_referenced_type(S, Ref),Ref} || Ref <- Imports],
+ Refs = [{M,R} || {{M,_},R} <- Refs0],
+ {Illegal,Other} = lists:splitwith(fun({error,_}) -> true;
+ (_) -> false
+ end, Refs),
+ ChainedRefs = [R || {M,R} <- Other, M =/= Module],
+ IllegalRefs = [R || {error,R} <- Illegal] ++
+ [R || {M,R} <- ChainedRefs,
+ ok =/= chained_import(S, Module, M, name_of_def(R))],
+ Acc = [return_asn1_error(S, Ref, {undefined_import,name_of_def(Ref),Module}) ||
+ Ref <- IllegalRefs] ++ Acc0,
+ check_imports_1(S, SFMs, Acc).
chained_import(S,ImpMod,DefMod,Name) ->
%% Name is a referenced structure that is not defined in ImpMod,
%% but must be present in the Imports list of ImpMod. The chain of
%% imports of Name must end in DefMod.
- NameOfDef =
- fun(#'Externaltypereference'{type=N}) -> N;
- (#'Externalvaluereference'{value=N}) -> N;
- (Other) -> Other
- end,
GetImports =
fun(_M_) ->
case asn1_db:dbget(_M_,'MODULE') of
@@ -321,9 +305,9 @@ chained_import(S,ImpMod,DefMod,Name) ->
FindNameInImports =
fun([],N,_) -> {no_mod,N};
([#'SymbolsFromModule'{symbols=Imports,module=ModuleRef}|SFMs],N,F) ->
- case [NameOfDef(X)||X <- Imports, NameOfDef(X) =:= N] of
+ case [name_of_def(X) || X <- Imports, name_of_def(X) =:= N] of
[] -> F(SFMs,N,F);
- [N] -> {NameOfDef(ModuleRef),N}
+ [N] -> {name_of_def(ModuleRef),N}
end
end,
case GetImports(ImpMod) of
@@ -1567,13 +1551,13 @@ check_defaultfields(S, Fields, ClassFields) ->
[] ->
ok;
[_|_]=Invalid ->
- throw(asn1_error(S, T, {invalid_fields,Invalid,Obj}))
+ asn1_error(S, T, {invalid_fields,Invalid,Obj})
end,
case ordsets:subtract(Mandatory, Present) of
[] ->
check_defaultfields_1(S, Fields, ClassFields, []);
[_|_]=Missing ->
- throw(asn1_error(S, T, {missing_mandatory_fields,Missing,Obj}))
+ asn1_error(S, T, {missing_mandatory_fields,Missing,Obj})
end.
check_defaultfields_1(_S, [], _ClassFields, Acc) ->
@@ -2614,7 +2598,7 @@ normalize_octetstring(S,Value,CType) ->
normalize_octetstring(S,String,CType);
_ ->
Item = S#state.value,
- throw(asn1_error(S, Item, illegal_octet_string_value))
+ asn1_error(S, Item, illegal_octet_string_value)
end.
normalize_objectidentifier(S, Value) ->
@@ -2645,7 +2629,7 @@ lookup_enum_value(S, Id, NNL) when is_atom(Id) ->
{_,_}=Ret ->
Ret;
false ->
- throw(asn1_error(S, S#state.value, {undefined,Id}))
+ asn1_error(S, S#state.value, {undefined,Id})
end.
normalize_choice(S,{'CHOICE',{C,V}},CType,NameList) when is_atom(C) ->
@@ -3084,7 +3068,7 @@ check_type(S=#state{recordtopname=TopName},Type,Ts) when is_record(Ts,type) ->
merge_tags(Tag,?TAG_PRIMITIVE(?N_INTEGER))};
{'INTEGER',NamedNumberList} ->
- TempNewDef#newt{type={'INTEGER',check_integer(S,NamedNumberList,Constr)},
+ TempNewDef#newt{type={'INTEGER',check_integer(S,NamedNumberList)},
tag=
merge_tags(Tag,?TAG_PRIMITIVE(?N_INTEGER))};
'REAL' ->
@@ -3092,8 +3076,7 @@ check_type(S=#state{recordtopname=TopName},Type,Ts) when is_record(Ts,type) ->
TempNewDef#newt{tag=merge_tags(Tag,?TAG_PRIMITIVE(?N_REAL))};
{'BIT STRING',NamedNumberList} ->
- NewL = check_bitstring(S,NamedNumberList,Constr),
-%% erlang:display({asn1ct_check,NamedNumberList,NewL}),
+ NewL = check_bitstring(S, NamedNumberList),
TempNewDef#newt{type={'BIT STRING',NewL},
tag=
merge_tags(Tag,?TAG_PRIMITIVE(?N_BIT_STRING))};
@@ -4910,73 +4893,46 @@ imported1(Name,
end;
imported1(_Name,[]) ->
false.
-
-check_integer(_S,[],_C) ->
+%% Check the named number list for an INTEGER or a BIT STRING.
+check_named_number_list(_S, []) ->
[];
-check_integer(S,NamedNumberList,_C) ->
- case [X || X <- NamedNumberList, tuple_size(X) =:= 2] of
- NamedNumberList ->
- %% An already checked integer with NamedNumberList
- NamedNumberList;
- _ ->
- case check_unique(NamedNumberList,2) of
- [] ->
- check_int(S,NamedNumberList,[]);
- L when is_list(L) ->
- error({type,{duplicates,L},S}),
- unchanged
- end
+check_named_number_list(_S, [{_,_}|_]=NNL) ->
+ %% The named number list has already been checked.
+ NNL;
+check_named_number_list(S, NNL0) ->
+ %% Check that the names are unique.
+ T = S#state.type,
+ case check_unique(NNL0, 2) of
+ [] ->
+ NNL1 = [{Id,resolve_valueref(S, Val)} || {'NamedNumber',Id,Val} <- NNL0],
+ NNL = lists:keysort(2, NNL1),
+ case check_unique(NNL, 2) of
+ [] ->
+ NNL;
+ [Val|_] ->
+ asn1_error(S, T, {value_reused,Val})
+ end;
+ [H|_] ->
+ asn1_error(S, T, {namelist_redefinition,H})
end.
-
-check_int(S,[{'NamedNumber',Id,Num}|T],Acc) when is_integer(Num) ->
- check_int(S,T,[{Id,Num}|Acc]);
-check_int(S,[{'NamedNumber',Id,{identifier,_,Name}}|T],Acc) ->
- Val = dbget_ex(S,S#state.mname,Name),
- check_int(S,[{'NamedNumber',Id,Val#valuedef.value}|T],Acc);
-check_int(S,[{'NamedNumber',Id,{'Externalvaluereference',_,Mod,Name}}|T],Acc) ->
- Val = dbget_ex(S,Mod,Name),
- check_int(S,[{'NamedNumber',Id,Val#valuedef.value}|T],Acc);
-check_int(_S,[],Acc) ->
- lists:keysort(2,Acc).
+resolve_valueref(S, #'Externalvaluereference'{module=Mod,value=Name}) ->
+ dbget_ex(S, Mod, Name);
+resolve_valueref(_, Val) when is_integer(Val) ->
+ Val.
-check_real(_S,_Constr) ->
- ok.
+check_integer(S, NNL) ->
+ check_named_number_list(S, NNL).
-check_bitstring(_S,[],_Constr) ->
- [];
-check_bitstring(S,NamedNumberList,_Constr) ->
- case check_unique(NamedNumberList,2) of
- [] ->
- check_bitstr(S,NamedNumberList,[]);
- L when is_list(L) ->
- error({type,{duplicates,L},S}),
- unchanged
- end.
+check_bitstring(S, NNL0) ->
+ NNL = check_named_number_list(S, NNL0),
+ _ = [asn1_error(S, S#state.type, {invalid_bit_number,Bit}) ||
+ {_,Bit} <- NNL, Bit < 0],
+ NNL.
-check_bitstr(S,[{'NamedNumber',Id,Num}|T],Acc)when is_integer(Num) ->
- check_bitstr(S,T,[{Id,Num}|Acc]);
-check_bitstr(S,[{'NamedNumber',Id,Name}|T],Acc) when is_atom(Name) ->
-%%check_bitstr(S,[{'NamedNumber',Id,{identifier,_,Name}}|T],Acc) ->
-%% io:format("asn1ct_check:check_bitstr/3 hej hop ~w~n",[Name]),
- Val = dbget_ex(S,S#state.mname,Name),
-%% io:format("asn1ct_check:check_bitstr/3: ~w~n",[Val]),
- check_bitstr(S,[{'NamedNumber',Id,Val#valuedef.value}|T],Acc);
-check_bitstr(S,[],Acc) ->
- case check_unique(Acc,2) of
- [] ->
- lists:keysort(2,Acc);
- L when is_list(L) ->
- error({type,{duplicate_values,L},S}),
- unchanged
- end;
-%% When a BIT STRING already is checked, for instance a COMPONENTS OF S
-%% where S is a sequence that has a component that is a checked BS, the
-%% NamedNumber list is a list of {atom(),integer()} elements.
-check_bitstr(S,[El={Id,Num}|Rest],Acc) when is_atom(Id),is_integer(Num) ->
- check_bitstr(S,Rest,[El|Acc]).
-
+check_real(_S,_Constr) ->
+ ok.
%% Check INSTANCE OF
%% check that DefinedObjectClass is of TYPE-IDENTIFIER class
@@ -4987,20 +4943,16 @@ check_instance_of(S,DefinedObjectClass,Constraint) ->
check_type_identifier(S,DefinedObjectClass),
iof_associated_type(S,Constraint).
-
-check_type_identifier(_S,'TYPE-IDENTIFIER') ->
- ok;
-check_type_identifier(S,Eref=#'Externaltypereference'{}) ->
- case get_referenced_type(S,Eref) of
- {_,#classdef{name='TYPE-IDENTIFIER'}} -> ok;
- {_,#classdef{typespec=NextEref}}
- when is_record(NextEref,'Externaltypereference') ->
- check_type_identifier(S,NextEref);
+check_type_identifier(S, Eref=#'Externaltypereference'{type=Class}) ->
+ case get_referenced_type(S, Eref) of
+ {_,#classdef{name='TYPE-IDENTIFIER'}} ->
+ ok;
+ {_,#classdef{typespec=#'Externaltypereference'{}=NextEref}} ->
+ check_type_identifier(S, NextEref);
{_,TD=#typedef{typespec=#type{def=#'Externaltypereference'{}}}} ->
- check_type_identifier(S,(TD#typedef.typespec)#type.def);
- Err ->
- error({type,{"object set in type INSTANCE OF "
- "not of class TYPE-IDENTIFIER",Eref,Err},S})
+ check_type_identifier(S, (TD#typedef.typespec)#type.def);
+ _ ->
+ asn1_error(S, S#state.type, {illegal_instance_of,Class})
end.
iof_associated_type(S,[]) ->
@@ -5130,9 +5082,6 @@ check_enumerated(S,NamedNumberList,_Constr) ->
%% the latter is returned if the ENUMERATION contains EXTENSIONMARK
check_enum(S,[{'NamedNumber',Id,Num}|T],Acc1,Acc2,Root) when is_integer(Num) ->
check_enum(S,T,[{Id,Num}|Acc1],Acc2,Root);
-check_enum(S,[{'NamedNumber',Id,{identifier,_,Name}}|T],Acc1,Acc2,Root) ->
- Val = dbget_ex(S,S#state.mname,Name),
- check_enum(S,[{'NamedNumber',Id,Val#valuedef.value}|T],Acc1,Acc2,Root);
check_enum(S,['EXTENSIONMARK'|T],Acc1,Acc2,_Root) ->
NewAcc2 = lists:keysort(2,Acc1),
NewList = enum_number(lists:reverse(Acc2),NewAcc2,0,[],[]),
@@ -6748,7 +6697,7 @@ storeindb(#state{mname=Module}=S, [H|T], Errors) ->
storeindb(S, T, Errors);
Prev ->
PrevLine = asn1ct:get_pos_of_def(Prev),
- {error,Error} = asn1_error(S, H, {already_defined,Name,PrevLine}),
+ Error = return_asn1_error(S, H, {already_defined,Name,PrevLine}),
storeindb(S, T, [Error|Errors])
end;
storeindb(_, [], []) ->
@@ -6795,22 +6744,37 @@ findtypes_and_values([],Tacc,Vacc,Pacc,Cacc,Oacc,OSacc) ->
{lists:reverse(Tacc),lists:reverse(Vacc),lists:reverse(Pacc),
lists:reverse(Cacc),lists:reverse(Oacc),lists:reverse(OSacc)}.
-asn1_error(#state{mname=Where}, Item, Error) ->
+return_asn1_error(#state{mname=Where}, Item, Error) ->
Pos = asn1ct:get_pos_of_def(Item),
- {error,{structured_error,{Where,Pos},?MODULE,Error}}.
+ {structured_error,{Where,Pos},?MODULE,Error}.
+
+asn1_error(S, Item, Error) ->
+ throw({error,return_asn1_error(S, Item, Error)}).
format_error({already_defined,Name,PrevLine}) ->
io_lib:format("the name ~p has already been defined at line ~p",
[Name,PrevLine]);
+format_error({illegal_instance_of,Class}) ->
+ io_lib:format("using INSTANCE OF on class '~s' is illegal, "
+ "because INSTANCE OF may only be used on the class TYPE-IDENTFIER",
+ [Class]);
format_error(illegal_octet_string_value) ->
"expecting a bstring or an hstring as value for an OCTET STRING";
format_error({invalid_fields,Fields,Obj}) ->
io_lib:format("invalid ~s in ~p", [format_fields(Fields),Obj]);
+format_error({invalid_bit_number,Bit}) ->
+ io_lib:format("the bit number '~p' is invalid", [Bit]);
format_error({missing_mandatory_fields,Fields,Obj}) ->
io_lib:format("missing mandatory ~s in ~p",
[format_fields(Fields),Obj]);
+format_error({namelist_redefinition,Name}) ->
+ io_lib:format("the name '~s' can not be redefined", [Name]);
format_error({undefined,Name}) ->
io_lib:format("'~s' is referenced, but is not defined", [Name]);
+format_error({undefined_import,Ref,Module}) ->
+ io_lib:format("'~s' is not exported from ~s", [Ref,Module]);
+format_error({value_reused,Val}) ->
+ io_lib:format("the value '~p' is used more than once", [Val]);
format_error(Other) ->
io_lib:format("~p", [Other]).
@@ -6826,14 +6790,6 @@ error({export,Msg,#state{mname=Mname,type=Ref,tname=Typename}}) ->
Pos = Ref#'Externaltypereference'.pos,
io:format("asn1error:~p:~p:~p~n~p~n",[Pos,Mname,Typename,Msg]),
{error,{export,Pos,Mname,Typename,Msg}};
-error({import,Msg,#state{mname=Mname,type=Ref,tname=Typename}}) ->
- PosOfDef =
- fun(#'Externaltypereference'{pos=P}) -> P;
- (#'Externalvaluereference'{pos=P}) -> P
- end,
- Pos = PosOfDef(Ref),
- io:format("asn1error:~p:~p:~p~n~p~n",[Pos,Mname,Typename,Msg]),
- {error,{import,Pos,Mname,Typename,Msg}};
% error({type,{Msg1,Msg2},#state{mname=Mname,type=Type,tname=Typename}})
% when is_record(Type,typedef) ->
% io:format("asn1error:~p:~p:~p ~p~n",
@@ -7134,3 +7090,6 @@ check_fold(S, [H|T], Check) ->
[Error|check_fold(S, T, Check)]
end;
check_fold(_, [], Check) when is_function(Check, 3) -> [].
+
+name_of_def(#'Externaltypereference'{type=N}) -> N;
+name_of_def(#'Externalvaluereference'{value=N}) -> N.
diff --git a/lib/asn1/src/asn1ct_gen.erl b/lib/asn1/src/asn1ct_gen.erl
index 4707e517b4..44b050e59d 100644
--- a/lib/asn1/src/asn1ct_gen.erl
+++ b/lib/asn1/src/asn1ct_gen.erl
@@ -1125,7 +1125,22 @@ pgen_info() ->
open_hrl(OutFile,Module) ->
File = lists:concat([OutFile,".hrl"]),
_ = open_output_file(File),
- gen_hrlhead(Module).
+ gen_hrlhead(Module),
+ Protector = hrl_protector(OutFile),
+ emit(["-ifndef(",Protector,").\n",
+ "-define(",Protector,", true).\n"
+ "\n"]).
+
+hrl_protector(OutFile) ->
+ BaseName = filename:basename(OutFile),
+ P = "_" ++ string:to_upper(BaseName) ++ "_HRL_",
+ [if
+ $A =< C, C =< $Z -> C;
+ $a =< C, C =< $a -> C;
+ $0 =< C, C =< $9 -> C;
+ true -> $_
+ end || C <- P].
+
%% EMIT functions ************************
%% ***************************************
@@ -1232,6 +1247,8 @@ pgen_hrl(Erules,Module,TypeOrVal,Options,_Indent) ->
0 ->
0;
Y ->
+ Protector = hrl_protector(get(outfile)),
+ emit(["-endif. %% ",Protector,"\n"]),
close_output_file(),
asn1ct:verbose("--~p--~n",
[{generated,lists:concat([get(outfile),".hrl"])}],
diff --git a/lib/asn1/test/asn1_SUITE.erl b/lib/asn1/test/asn1_SUITE.erl
index d438300596..782217ed2d 100644
--- a/lib/asn1/test/asn1_SUITE.erl
+++ b/lib/asn1/test/asn1_SUITE.erl
@@ -813,10 +813,10 @@ testExport(Config) ->
testImport(Config) ->
test(Config, fun testImport/3).
testImport(Config, Rule, Opts) ->
- {error, _} = asn1ct:compile(filename:join(?config(data_dir, Config),
- "ImportsFrom"),
- [Rule, {outdir, ?config(priv_dir, Config)}
- |Opts]).
+ Files = ["ImportsFrom","ImportsFrom2","ImportsFrom3"],
+ asn1_test_lib:compile_all(Files, Config, [Rule|Opts]),
+ 42 = 'ImportsFrom':i(),
+ ok.
testMegaco(Config) -> test(Config, fun testMegaco/3).
testMegaco(Config, Rule, Opts) ->
diff --git a/lib/asn1/test/asn1_SUITE_data/INSTANCEOF.asn1 b/lib/asn1/test/asn1_SUITE_data/INSTANCEOF.asn1
index 8c4f3a8f7e..b4ea943040 100644
--- a/lib/asn1/test/asn1_SUITE_data/INSTANCEOF.asn1
+++ b/lib/asn1/test/asn1_SUITE_data/INSTANCEOF.asn1
@@ -16,7 +16,9 @@ Names ::= SEQUENCE {
thirdName [2] INSTANCE OF OTHER-NAME ({TI})
}
-OTHER-NAME ::= TYPE-IDENTIFIER
+OTHER-NAME ::= YET-ANOTHER-NAME
+
+YET-ANOTHER-NAME ::= TYPE-IDENTIFIER
TI OTHER-NAME ::= {{INTEGER IDENTIFIED BY {2 4}} |
{Seq IDENTIFIED BY {2 3 4}} |
diff --git a/lib/asn1/test/asn1_SUITE_data/ImportsFrom.asn1 b/lib/asn1/test/asn1_SUITE_data/ImportsFrom.asn1
index 896a35d627..32b8f75dde 100644
--- a/lib/asn1/test/asn1_SUITE_data/ImportsFrom.asn1
+++ b/lib/asn1/test/asn1_SUITE_data/ImportsFrom.asn1
@@ -1,16 +1,8 @@
-ImportsFrom DEFINITIONS ::=
-
+ImportsFrom DEFINITIONS AUTOMATIC TAGS ::=
BEGIN
-IMPORTS
-Type1, Type2, Type3
-FROM RemoteFile1 objid
-val1, val2, val3
-FROM RemoteFile2;
-
-objid OBJECT IDENTIFIER ::= {joint-iso-ccitt(2) remote-operations(4) notation(0)}
-
-LocalType ::= INTEGER
+IMPORTS Int FROM ImportsFrom2;
+i Int ::= 42
END
diff --git a/lib/asn1/test/asn1_SUITE_data/ImportsFrom2.asn1 b/lib/asn1/test/asn1_SUITE_data/ImportsFrom2.asn1
new file mode 100644
index 0000000000..b0c29d24ae
--- /dev/null
+++ b/lib/asn1/test/asn1_SUITE_data/ImportsFrom2.asn1
@@ -0,0 +1,7 @@
+ImportsFrom2 DEFINITIONS AUTOMATIC TAGS ::=
+BEGIN
+IMPORTS Int FROM ImportsFrom3;
+
+LocalDef ::= OCTET STRING
+
+END
diff --git a/lib/asn1/test/asn1_SUITE_data/ImportsFrom3.asn1 b/lib/asn1/test/asn1_SUITE_data/ImportsFrom3.asn1
new file mode 100644
index 0000000000..ca27b20697
--- /dev/null
+++ b/lib/asn1/test/asn1_SUITE_data/ImportsFrom3.asn1
@@ -0,0 +1,4 @@
+ImportsFrom3 DEFINITIONS AUTOMATIC TAGS ::=
+BEGIN
+ Int ::= INTEGER (0..63)
+END
diff --git a/lib/asn1/test/error_SUITE.erl b/lib/asn1/test/error_SUITE.erl
index 930b44cea6..8a0414708d 100644
--- a/lib/asn1/test/error_SUITE.erl
+++ b/lib/asn1/test/error_SUITE.erl
@@ -19,7 +19,8 @@
-module(error_SUITE).
-export([suite/0,all/0,groups/0,
- already_defined/1,enumerated/1,objects/1,values/1]).
+ already_defined/1,bitstrings/1,enumerated/1,
+ imports/1,instance_of/1,integers/1,objects/1,values/1]).
-include_lib("test_server/include/test_server.hrl").
@@ -31,7 +32,11 @@ all() ->
groups() ->
[{p,parallel(),
[already_defined,
+ bitstrings,
enumerated,
+ imports,
+ instance_of,
+ integers,
objects,
values]}].
@@ -70,6 +75,23 @@ already_defined(Config) ->
} = run(P, Config),
ok.
+bitstrings(Config) ->
+ M = 'Bitstrings',
+ P = {M,
+ <<"Bitstrings DEFINITIONS AUTOMATIC TAGS ::= BEGIN\n"
+ " Bs1 ::= BIT STRING {a(1), a(1)}\n"
+ " Bs2 ::= BIT STRING {a(1), b(2), a(3)}\n"
+ " Bs3 ::= BIT STRING {x(1), y(1)}\n"
+ " Bs4 ::= BIT STRING {x(-1), y(0)}\n"
+ "END\n">>},
+ {error,
+ [{structured_error,{M,2},asn1ct_check,{namelist_redefinition,a}},
+ {structured_error,{M,3},asn1ct_check,{namelist_redefinition,a}},
+ {structured_error,{M,4},asn1ct_check,{value_reused,1}},
+ {structured_error,{M,5},asn1ct_check,{invalid_bit_number,-1}}
+ ]} = run(P, Config),
+ ok.
+
enumerated(Config) ->
M = 'Enumerated',
P = {M,
@@ -98,6 +120,63 @@ enumerated(Config) ->
} = run(P, Config),
ok.
+imports(Config) ->
+ Ext = 'ExternalModule',
+ ExtP = {Ext,
+ <<"ExternalModule DEFINITIONS AUTOMATIC TAGS ::= BEGIN\n"
+ "END\n">>},
+ ok = run(ExtP, Config),
+
+ M = 'Imports',
+ P = {M,
+ <<"Imports DEFINITIONS AUTOMATIC TAGS ::= BEGIN\n"
+ "IMPORTS NotDefined FROM ExternalModule\n"
+ "X FROM UndefinedModule objid\n"
+ "Y, Z FROM UndefinedModule2;\n"
+ "objid OBJECT IDENTIFIER ::= {joint-iso-ccitt(2) remote-operations(4)\n"
+ " notation(0)}\n"
+ "END\n">>},
+ {error,[{structured_error,{M,2},asn1ct_check,
+ {undefined_import,'NotDefined','ExternalModule'}},
+ {structured_error,{M,3},asn1ct_check,{undefined_import,'X','UndefinedModule'}},
+ {structured_error,{M,4},asn1ct_check,{undefined_import,'Y','UndefinedModule2'}},
+ {structured_error,{M,4},asn1ct_check,{undefined_import,'Z','UndefinedModule2'}}
+ ]} = run(P, Config),
+ ok.
+
+instance_of(Config) ->
+ M = 'InstanceOf',
+ P = {M,
+ <<"InstanceOf DEFINITIONS AUTOMATIC TAGS ::= BEGIN\n"
+ "XX ::= INSTANCE OF CL ({TI})\n"
+ "CL ::= CLASS {\n"
+ "&id INTEGER,\n"
+ "&Type\n"
+ "}\n"
+ "o1 CL ::= {&id 1, &Type OCTET STRING}\n"
+ "TI CL ::= { o1 }\n"
+ "END\n">>},
+ {error,
+ [{structured_error,{M,2},asn1ct_check,{illegal_instance_of,'CL'}}
+ ]} = run(P, Config),
+ ok.
+
+integers(Config) ->
+ M = 'Integers',
+ P = {M,
+ <<"Integers DEFINITIONS AUTOMATIC TAGS ::= BEGIN\n"
+ " Int1 ::= INTEGER {a(1), a(1)}\n"
+ " Int2 ::= INTEGER {a(1), b(2), a(3)}\n"
+ " Int3 ::= INTEGER {x(1), y(1)}\n"
+ "END\n">>},
+ {error,
+ [{structured_error,{M,2},asn1ct_check,{namelist_redefinition,a}},
+ {structured_error,{M,3},asn1ct_check,{namelist_redefinition,a}},
+ {structured_error,{M,4},asn1ct_check,{value_reused,1}}
+ ]} = run(P, Config),
+ ok.
+
+
objects(Config) ->
M = 'Objects',
P = {M,
diff --git a/lib/asn1/vsn.mk b/lib/asn1/vsn.mk
index 153c64ebdd..1f16f31f6b 100644
--- a/lib/asn1/vsn.mk
+++ b/lib/asn1/vsn.mk
@@ -1,2 +1,2 @@
#next version number to use is 2.0
-ASN1_VSN = 2.0.4
+ASN1_VSN = 3.0
diff --git a/lib/common_test/doc/src/run_test_chapter.xml b/lib/common_test/doc/src/run_test_chapter.xml
index a4a77ee400..ef21948f89 100644
--- a/lib/common_test/doc/src/run_test_chapter.xml
+++ b/lib/common_test/doc/src/run_test_chapter.xml
@@ -589,8 +589,8 @@
Common Test will either execute one test run per specification file, or
join the files and perform all tests within one single test run. The first
behaviour is the default one. The latter requires that the start
- flag/option <c>join_suites</c> is provided, e.g.
- <c>run_test -spec ./my_tests1.ts ./my_tests2.ts -join_suites</c>.</p>
+ flag/option <c>join_specs</c> is provided, e.g.
+ <c>run_test -spec ./my_tests1.ts ./my_tests2.ts -join_specs</c>.</p>
<p>Joining a number of specifications, or running them separately, can
also be accomplished with (and may be combined with) test specification
diff --git a/lib/common_test/src/common_test.app.src b/lib/common_test/src/common_test.app.src
index 18c1dec784..e28751fb59 100644
--- a/lib/common_test/src/common_test.app.src
+++ b/lib/common_test/src/common_test.app.src
@@ -62,5 +62,10 @@
ct_master,
ct_master_logs]},
{applications, [kernel,stdlib]},
- {env, []}]}.
+ {env, []},
+ {runtime_dependencies,["xmerl-1.3.7","webtool-0.8.10","tools-2.6.14",
+ "test_server-3.7","stdlib-2.0","ssh-3.0.1",
+ "snmp-4.25.1","sasl-2.4","runtime_tools-1.8.14",
+ "kernel-3.0","inets-5.10","erts-6.0",
+ "debugger-4.0","crypto-3.3","compiler-5.0"]}]}.
diff --git a/lib/common_test/src/ct_conn_log_h.erl b/lib/common_test/src/ct_conn_log_h.erl
index d733df27dc..cff02a46d9 100644
--- a/lib/common_test/src/ct_conn_log_h.erl
+++ b/lib/common_test/src/ct_conn_log_h.erl
@@ -204,13 +204,8 @@ pretty_head({{{Y,Mo,D},{H,Mi,S}},MicroS},ConnMod,Text0) ->
micro2milli(MicroS)]).
pretty_title(#conn_log{client=Client}=Info) ->
- case actionstr(Info) of
- {no_server,Action} ->
- io_lib:format("= Client ~w ~s ",[Client,Action]);
- Action ->
- io_lib:format("= Client ~w ~s ~ts ",[Client,Action,
- serverstr(Info)])
- end.
+ io_lib:format("= Client ~w ~s ~ts ",
+ [Client,actionstr(Info),serverstr(Info)]).
actionstr(#conn_log{action=send}) -> "----->";
actionstr(#conn_log{action=cmd}) -> "----->";
diff --git a/lib/common_test/src/ct_framework.erl b/lib/common_test/src/ct_framework.erl
index 63bfea68c4..7d577462b0 100644
--- a/lib/common_test/src/ct_framework.erl
+++ b/lib/common_test/src/ct_framework.erl
@@ -249,8 +249,8 @@ init_tc2(Mod,Suite,Func,SuiteInfo,MergeResult,Config) ->
end
end.
-ct_suite_init(Suite, Func, PostInitHook, Config) when is_list(Config) ->
- case ct_hooks:init_tc(Suite, Func, Config) of
+ct_suite_init(Suite, FuncSpec, PostInitHook, Config) when is_list(Config) ->
+ case ct_hooks:init_tc(Suite, FuncSpec, Config) of
NewConfig when is_list(NewConfig) ->
PostInitHookResult = do_post_init_hook(PostInitHook, NewConfig),
{ok, [PostInitHookResult ++ NewConfig]};
@@ -660,10 +660,7 @@ end_tc(Mod,Func,TCPid,Result,Args,Return) ->
ct_util:delete_testdata(comment),
ct_util:delete_suite_data(last_saved_config),
- FuncSpec = case group_or_func(Func,Args) of
- {_,_GroupName,_} = Group -> Group;
- _ -> Func
- end,
+ FuncSpec = group_or_func(Func,Args),
{Result1,FinalNotify} =
case ct_hooks:end_tc(
diff --git a/lib/common_test/src/ct_gen_conn.erl b/lib/common_test/src/ct_gen_conn.erl
index 078d6b1a44..56082086f6 100644
--- a/lib/common_test/src/ct_gen_conn.erl
+++ b/lib/common_test/src/ct_gen_conn.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2003-2013. All Rights Reserved.
+%% Copyright Ericsson AB 2003-2014. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -307,7 +307,8 @@ call(Pid, Msg, Timeout) ->
end.
return({To,Ref},Result) ->
- To ! {Ref, Result}.
+ To ! {Ref, Result},
+ ok.
init_gen(Parent,Opts) ->
process_flag(trap_exit,true),
@@ -344,7 +345,7 @@ loop(Opts) ->
link(NewPid),
put(conn_pid,NewPid),
loop(Opts#gen_opts{conn_pid=NewPid,
- cb_state=NewState});
+ cb_state=NewState});
Error ->
ct_util:unregister_connection(self()),
log("Reconnect failed. Giving up!",
diff --git a/lib/common_test/src/ct_hooks.erl b/lib/common_test/src/ct_hooks.erl
index 2e667030a9..df4c98d9d1 100644
--- a/lib/common_test/src/ct_hooks.erl
+++ b/lib/common_test/src/ct_hooks.erl
@@ -64,11 +64,16 @@ terminate(Hooks) ->
%% @doc Called as each test case is started. This includes all configuration
%% tests.
--spec init_tc(Mod :: atom(), Func :: atom(), Args :: list()) ->
+-spec init_tc(Mod :: atom(),
+ FuncSpec :: atom() |
+ {ConfigFunc :: init_per_group | end_per_group,
+ GroupName :: atom(),
+ Properties :: list()},
+ Args :: list()) ->
NewConfig :: proplists:proplist() |
- {skip, Reason :: term()} |
- {auto_skip, Reason :: term()} |
- {fail, Reason :: term()}.
+ {skip, Reason :: term()} |
+ {auto_skip, Reason :: term()} |
+ {fail, Reason :: term()}.
init_tc(Mod, init_per_suite, Config) ->
Info = try proplists:get_value(ct_hooks, Mod:suite(),[]) of
@@ -82,8 +87,8 @@ init_tc(Mod, init_per_suite, Config) ->
call(fun call_generic/3, Config ++ Info, [pre_init_per_suite, Mod]);
init_tc(Mod, end_per_suite, Config) ->
call(fun call_generic/3, Config, [pre_end_per_suite, Mod]);
-init_tc(Mod, {init_per_group, GroupName, Opts}, Config) ->
- maybe_start_locker(Mod, GroupName, Opts),
+init_tc(Mod, {init_per_group, GroupName, Properties}, Config) ->
+ maybe_start_locker(Mod, GroupName, Properties),
call(fun call_generic/3, Config, [pre_init_per_group, GroupName]);
init_tc(_Mod, {end_per_group, GroupName, _}, Config) ->
call(fun call_generic/3, Config, [pre_end_per_group, GroupName]);
@@ -93,15 +98,18 @@ init_tc(_Mod, TC, Config) ->
%% @doc Called as each test case is completed. This includes all configuration
%% tests.
-spec end_tc(Mod :: atom(),
- Func :: atom(),
+ FuncSpec :: atom() |
+ {ConfigFunc :: init_per_group | end_per_group,
+ GroupName :: atom(),
+ Properties :: list()},
Args :: list(),
Result :: term(),
- Resturn :: term()) ->
+ Return :: term()) ->
NewConfig :: proplists:proplist() |
- {skip, Reason :: term()} |
- {auto_skip, Reason :: term()} |
- {fail, Reason :: term()} |
- ok | '$ct_no_change'.
+ {skip, Reason :: term()} |
+ {auto_skip, Reason :: term()} |
+ {fail, Reason :: term()} |
+ ok | '$ct_no_change'.
end_tc(Mod, init_per_suite, Config, _Result, Return) ->
call(fun call_generic/3, Return, [post_init_per_suite, Mod, Config],
@@ -112,10 +120,10 @@ end_tc(Mod, end_per_suite, Config, Result, _Return) ->
end_tc(_Mod, {init_per_group, GroupName, _}, Config, _Result, Return) ->
call(fun call_generic/3, Return, [post_init_per_group, GroupName, Config],
'$ct_no_change');
-end_tc(Mod, {end_per_group, GroupName, Opts}, Config, Result, _Return) ->
+end_tc(Mod, {end_per_group, GroupName, Properties}, Config, Result, _Return) ->
Res = call(fun call_generic/3, Result,
[post_end_per_group, GroupName, Config], '$ct_no_change'),
- maybe_stop_locker(Mod, GroupName,Opts),
+ maybe_stop_locker(Mod, GroupName, Properties),
Res;
end_tc(_Mod, TC, Config, Result, _Return) ->
call(fun call_generic/3, Result, [post_end_per_testcase, TC, Config],
diff --git a/lib/common_test/src/ct_netconfc.erl b/lib/common_test/src/ct_netconfc.erl
index 35920ec1dc..6fc840745d 100644
--- a/lib/common_test/src/ct_netconfc.erl
+++ b/lib/common_test/src/ct_netconfc.erl
@@ -1,7 +1,7 @@
%%----------------------------------------------------------------------
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2012-2013. All Rights Reserved.
+%% Copyright Ericsson AB 2012-2014. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -1334,7 +1334,7 @@ handle_data(NewData,#state{connection=Connection,buff=Buff} = State) ->
%% first answer
P=#pending{tref=TRef,caller=Caller} =
lists:last(Pending),
- timer:cancel(TRef),
+ _ = timer:cancel(TRef),
Reason1 = {failed_to_parse_received_data,Reason},
ct_gen_conn:return(Caller,{error,Reason1}),
lists:delete(P,Pending)
@@ -1454,7 +1454,7 @@ decode({Tag,Attrs,_}=E, #state{connection=Connection,pending=Pending}=State) ->
{noreply,State#state{hello_status = {error,Reason}}}
end;
#pending{tref=TRef,caller=Caller} ->
- timer:cancel(TRef),
+ _ = timer:cancel(TRef),
case decode_hello(E) of
{ok,SessionId,Capabilities} ->
ct_gen_conn:return(Caller,ok),
@@ -1482,7 +1482,7 @@ decode({Tag,Attrs,_}=E, #state{connection=Connection,pending=Pending}=State) ->
case [P || P = #pending{msg_id=undefined,op=undefined} <- Pending] of
[#pending{tref=TRef,
caller=Caller}] ->
- timer:cancel(TRef),
+ _ = timer:cancel(TRef),
ct_gen_conn:return(Caller,E),
{noreply,State#state{pending=[]}};
_ ->
@@ -1504,7 +1504,7 @@ get_msg_id(Attrs) ->
decode_rpc_reply(MsgId,{_,Attrs,Content0}=E,#state{pending=Pending} = State) ->
case lists:keytake(MsgId,#pending.msg_id,Pending) of
{value, #pending{tref=TRef,op=Op,caller=Caller}, Pending1} ->
- timer:cancel(TRef),
+ _ = timer:cancel(TRef),
Content = forward_xmlns_attr(Attrs,Content0),
{CallerReply,{ServerReply,State2}} =
do_decode_rpc_reply(Op,Content,State#state{pending=Pending1}),
@@ -1519,7 +1519,7 @@ decode_rpc_reply(MsgId,{_,Attrs,Content0}=E,#state{pending=Pending} = State) ->
msg_id=undefined,
op=undefined,
caller=Caller}] ->
- timer:cancel(TRef),
+ _ = timer:cancel(TRef),
ct_gen_conn:return(Caller,E),
{noreply,State#state{pending=[]}};
_ ->
@@ -1862,10 +1862,7 @@ ssh_open(#options{host=Host,timeout=Timeout,port=Port,ssh=SshOpts,name=Name}) ->
end;
{error, Reason} ->
ssh:close(CM),
- {error,{ssh,could_not_open_channel,Reason}};
- Other ->
- %% Bug in ssh?? got {closed,0} here once...
- {error,{ssh,unexpected_from_session_channel,Other}}
+ {error,{ssh,could_not_open_channel,Reason}}
end;
{error,Reason} ->
{error,{ssh,could_not_connect_to_server,Reason}}
diff --git a/lib/common_test/src/ct_telnet.erl b/lib/common_test/src/ct_telnet.erl
index b4d82a53cf..bc22a99741 100644
--- a/lib/common_test/src/ct_telnet.erl
+++ b/lib/common_test/src/ct_telnet.erl
@@ -281,8 +281,16 @@ open(KeyOrName,ConnType,TargetMod,Extra) ->
end,
log(undefined,open,"Connecting to ~p(~p)",
[KeyOrName,Addr1]),
- ct_gen_conn:start(KeyOrName,full_addr(Addr1,ConnType),
- {TargetMod,KeepAlive,Extra},?MODULE)
+ Reconnect =
+ case ct:get_config({telnet_settings,reconnection_attempts}) of
+ 0 -> false;
+ _ -> true
+ end,
+ ct_gen_conn:start(full_addr(Addr1,ConnType),
+ {TargetMod,KeepAlive,Extra},
+ ?MODULE, [{name,KeyOrName},
+ {reconnect,Reconnect},
+ {old,true}])
end.
%%%-----------------------------------------------------------------
@@ -300,7 +308,7 @@ close(Connection) ->
{ok,Pid} ->
log(undefined,close,"Connection closed, handle: ~w",[Pid]),
case ct_gen_conn:stop(Pid) of
- {error,{process_down,Pid,noproc}} ->
+ {error,{process_down,Pid,_}} ->
{error,already_closed};
Result ->
Result
@@ -405,9 +413,11 @@ expect(Connection,Patterns) ->
%%% Prompt = string()
%%% Tag = term()
%%% Opts = [Opt]
-%%% Opt = {timeout,Timeout} | repeat | {repeat,N} | sequence |
-%%% {halt,HaltPatterns} | ignore_prompt | no_prompt_check
-%%% Timeout = integer()
+%%% Opt = {idle_timeout,IdleTimeout} | {total_timeout,TotalTimeout} |
+%%% repeat | {repeat,N} | sequence | {halt,HaltPatterns} |
+%%% ignore_prompt | no_prompt_check
+%%% IdleTimeout = infinity | integer()
+%%% TotalTimeout = infinity | integer()
%%% N = integer()
%%% HaltPatterns = Patterns
%%% MatchList = [Match]
@@ -433,11 +443,16 @@ expect(Connection,Patterns) ->
%%% will also include the matched <code>Tag</code>. Else, only
%%% <code>RxMatch</code> is returned.</p>
%%%
-%%% <p>The <code>timeout</code> option indicates that the function
+%%% <p>The <code>idle_timeout</code> option indicates that the function
%%% shall return if the telnet client is idle (i.e. if no data is
-%%% received) for more than <code>Timeout</code> milliseconds. Default
+%%% received) for more than <code>IdleTimeout</code> milliseconds. Default
%%% timeout is 10 seconds.</p>
%%%
+%%% <p>The <code>total_timeout</code> option sets a time limit for
+%%% the complete expect operation. After <code>TotalTimeout</code>
+%%% milliseconds, <code>{error,timeout}</code> is returned. The default
+%%% value is <code>infinity</code> (i.e. no time limit).</p>
+%%%
%%% <p>The function will always return when a prompt is found, unless
%%% any of the <code>ignore_prompt</code> or
%%% <code>no_prompt_check</code> options are used, in which case it
@@ -570,14 +585,14 @@ handle_msg({cmd,Cmd,Timeout},State) ->
State#state.buffer,
prompt,
State#state.prx,
- [{timeout,2000}]);
+ [{idle_timeout,2000}]);
{ip,false} ->
silent_teln_expect(State#state.name,
State#state.teln_pid,
State#state.buffer,
prompt,
State#state.prx,
- [{timeout,200}]);
+ [{idle_timeout,200}]);
{ip,true} ->
ok
end,
@@ -601,11 +616,9 @@ handle_msg({cmd,Cmd,Timeout},State) ->
end_gen_log(),
{Return,State#state{buffer=NewBuffer,prompt=Prompt}};
handle_msg({send,Cmd},State) ->
- log(State,send,"Cmd: ~p",[Cmd]),
-
+ log(State,send,"Sending: ~p",[Cmd]),
debug_cont_gen_log("Throwing Buffer:",[]),
debug_log_lines(State#state.buffer),
-
case {State#state.type,State#state.prompt} of
{ts,_} ->
silent_teln_expect(State#state.name,
@@ -613,14 +626,14 @@ handle_msg({send,Cmd},State) ->
State#state.buffer,
prompt,
State#state.prx,
- [{timeout,2000}]);
+ [{idle_timeout,2000}]);
{ip,false} ->
silent_teln_expect(State#state.name,
State#state.teln_pid,
State#state.buffer,
prompt,
State#state.prx,
- [{timeout,200}]);
+ [{idle_timeout,200}]);
{ip,true} ->
ok
end,
@@ -783,66 +796,61 @@ log(#state{name=Name,teln_pid=TelnPid,host=Host,port=Port},
true -> Name
end,
Silent = get(silent),
- case ct_util:get_testdata({cth_conn_log,?MODULE}) of
- Result when Result /= undefined, Result /= silent, Silent /= true ->
- {PrintHeader,PreBR} = if Action==undefined ->
- {false,""};
- true ->
- {true,"\n"}
- end,
- error_logger:info_report(#conn_log{header=PrintHeader,
- client=self(),
- conn_pid=TelnPid,
- address={Host,Port},
- name=Name1,
- action=Action,
- module=?MODULE},
- {PreBR++String,Args});
- Result when Result /= undefined ->
- ok;
- _ when Action == open; Action == close; Action == reconnect;
- Action == info; Action == error ->
- ct_gen_conn:log(heading(Action,Name1),String,Args);
- _ when ForcePrint == false ->
- case ct_util:is_silenced(telnet) of
- true ->
- ok;
- false ->
- ct_gen_conn:cont_log(String,Args)
+
+ if Action == general_io ->
+ case ct_util:get_testdata({cth_conn_log,?MODULE}) of
+ HookMode when HookMode /= undefined, HookMode /= silent,
+ Silent /= true ->
+ error_logger:info_report(#conn_log{header=false,
+ client=self(),
+ conn_pid=TelnPid,
+ address={Host,Port},
+ name=Name1,
+ action=Action,
+ module=?MODULE},
+ {String,Args});
+ _ -> %% hook inactive or silence requested
+ ok
end;
- _ when ForcePrint == true ->
- case ct_util:is_silenced(telnet) of
- true ->
- %% call log/3 now instead of cont_log/2 since
- %% start_gen_log/1 will not have been previously called
+
+ true ->
+ if Action == open; Action == close; Action == reconnect;
+ Action == info; Action == error ->
ct_gen_conn:log(heading(Action,Name1),String,Args);
- false ->
- ct_gen_conn:cont_log(String,Args)
+
+ ForcePrint == false ->
+ case ct_util:is_silenced(telnet) of
+ true ->
+ ok;
+ false ->
+ ct_gen_conn:cont_log(String,Args)
+ end;
+
+ ForcePrint == true ->
+ case ct_util:is_silenced(telnet) of
+ true ->
+ %% call log/3 now instead of cont_log/2 since
+ %% start_gen_log/1 will not have been previously
+ %% called
+ ct_gen_conn:log(heading(Action,Name1),String,Args);
+ false ->
+ ct_gen_conn:cont_log(String,Args)
+ end
end
end.
start_gen_log(Heading) ->
- case ct_util:get_testdata({cth_conn_log,?MODULE}) of
- undefined ->
- %% check if output is suppressed
- case ct_util:is_silenced(telnet) of
- true -> ok;
- false -> ct_gen_conn:start_log(Heading)
- end;
- _ ->
- ok
+ %% check if output is suppressed
+ case ct_util:is_silenced(telnet) of
+ true -> ok;
+ false -> ct_gen_conn:start_log(Heading)
end.
end_gen_log() ->
- case ct_util:get_testdata({cth_conn_log,?MODULE}) of
- undefined ->
- %% check if output is suppressed
- case ct_util:is_silenced(telnet) of
- true -> ok;
- false -> ct_gen_conn:end_log()
- end;
- _ ->
- ok
+ %% check if output is suppressed
+ case ct_util:is_silenced(telnet) of
+ true -> ok;
+ false -> ct_gen_conn:end_log()
end.
%%% @hidden
@@ -879,7 +887,8 @@ teln_get_all_data(Pid,Prx,Data,Acc,LastLine) ->
%% Expect options record
-record(eo,{teln_pid,
prx,
- timeout,
+ idle_timeout,
+ total_timeout,
haltpatterns=[],
seq=false,
repeat=false,
@@ -921,11 +930,12 @@ teln_expect(Name,Pid,Data,Pattern0,Prx,Opts) ->
Seq = get_seq(Opts),
Pattern = convert_pattern(Pattern0,Seq),
- Timeout = get_timeout(Opts),
+ {IdleTimeout,TotalTimeout} = get_timeouts(Opts),
EO = #eo{teln_pid=Pid,
prx=Prx,
- timeout=Timeout,
+ idle_timeout=IdleTimeout,
+ total_timeout=TotalTimeout,
seq=Seq,
haltpatterns=HaltPatterns,
prompt_check=PromptCheck},
@@ -964,11 +974,22 @@ rm_dupl([P|Ps],Acc) ->
rm_dupl([],Acc) ->
lists:reverse(Acc).
-get_timeout(Opts) ->
- case lists:keysearch(timeout,1,Opts) of
- {value,{timeout,T}} -> T;
- false -> ?DEFAULT_TIMEOUT
- end.
+get_timeouts(Opts) ->
+ {case lists:keysearch(idle_timeout,1,Opts) of
+ {value,{_,T}} ->
+ T;
+ false ->
+ %% this check is for backwards compatibility (pre CT v1.8)
+ case lists:keysearch(timeout,1,Opts) of
+ {value,{_,T}} -> T;
+ false -> ?DEFAULT_TIMEOUT
+ end
+ end,
+ case lists:keysearch(total_timeout,1,Opts) of
+ {value,{_,T}} -> T;
+ false -> infinity
+ end}.
+
get_repeat(Opts) ->
case lists:keysearch(repeat,1,Opts) of
{value,{repeat,N}} when is_integer(N) ->
@@ -1010,7 +1031,8 @@ repeat_expect(Name,Pid,Data,Pattern,Acc,EO) ->
{error,Reason}
end.
-teln_expect1(Name,Pid,Data,Pattern,Acc,EO) ->
+teln_expect1(Name,Pid,Data,Pattern,Acc,EO=#eo{idle_timeout=IdleTO,
+ total_timeout=TotalTO}) ->
ExpectFun = case EO#eo.seq of
true -> fun() ->
seq_expect(Name,Pid,Data,Pattern,Acc,EO)
@@ -1027,12 +1049,12 @@ teln_expect1(Name,Pid,Data,Pattern,Acc,EO) ->
NotFinished ->
%% Get more data
Fun = fun() -> get_data1(EO#eo.teln_pid) end,
- case ct_gen_conn:do_within_time(Fun, EO#eo.timeout) of
- {error,Reason} ->
+ case timer:tc(ct_gen_conn, do_within_time, [Fun, IdleTO]) of
+ {_,{error,Reason}} ->
%% A timeout will occur when the telnet connection
- %% is idle for EO#eo.timeout milliseconds.
+ %% is idle for EO#eo.idle_timeout milliseconds.
{error,Reason};
- {ok,Data1} ->
+ {_,{ok,Data1}} when TotalTO == infinity ->
case NotFinished of
{nomatch,Rest} ->
%% One expect
@@ -1040,6 +1062,21 @@ teln_expect1(Name,Pid,Data,Pattern,Acc,EO) ->
{continue,Patterns1,Acc1,Rest} ->
%% Sequence
teln_expect1(Name,Pid,Rest++Data1,Patterns1,Acc1,EO)
+ end;
+ {Elapsed,{ok,Data1}} ->
+ TVal = trunc(TotalTO - (Elapsed/1000)),
+ if TVal =< 0 ->
+ {error,timeout};
+ true ->
+ EO1 = EO#eo{total_timeout = TVal},
+ case NotFinished of
+ {nomatch,Rest} ->
+ %% One expect
+ teln_expect1(Name,Pid,Rest++Data1,Pattern,[],EO1);
+ {continue,Patterns1,Acc1,Rest} ->
+ %% Sequence
+ teln_expect1(Name,Pid,Rest++Data1,Patterns1,Acc1,EO1)
+ end
end
end
end.
diff --git a/lib/common_test/src/ct_telnet_client.erl b/lib/common_test/src/ct_telnet_client.erl
index 2cbcba9c77..ce30dcb74b 100644
--- a/lib/common_test/src/ct_telnet_client.erl
+++ b/lib/common_test/src/ct_telnet_client.erl
@@ -32,7 +32,9 @@
-module(ct_telnet_client).
--export([open/1, open/2, open/3, open/4, close/1]).
+%% -define(debug, true).
+
+-export([open/2, open/3, open/4, open/5, close/1]).
-export([send_data/2, get_data/1]).
-define(TELNET_PORT, 23).
@@ -64,20 +66,23 @@
-define(TERMINAL_TYPE, 24).
-define(WINDOW_SIZE, 31).
--record(state,{get_data, keep_alive=true}).
+-record(state,{conn_name, get_data, keep_alive=true, log_pos=1}).
-open(Server) ->
- open(Server, ?TELNET_PORT, ?OPEN_TIMEOUT, true).
+open(Server, ConnName) ->
+ open(Server, ?TELNET_PORT, ?OPEN_TIMEOUT, true, ConnName).
-open(Server, Port) ->
- open(Server, Port, ?OPEN_TIMEOUT, true).
+open(Server, Port, ConnName) ->
+ open(Server, Port, ?OPEN_TIMEOUT, true, ConnName).
-open(Server, Port, Timeout) ->
- open(Server, Port, Timeout, true).
+open(Server, Port, Timeout, ConnName) ->
+ open(Server, Port, Timeout, true, ConnName).
-open(Server, Port, Timeout, KeepAlive) ->
+open(Server, Port, Timeout, KeepAlive, ConnName) ->
Self = self(),
- Pid = spawn(fun() -> init(Self, Server, Port, Timeout, KeepAlive) end),
+ Pid = spawn(fun() ->
+ init(Self, Server, Port, Timeout,
+ KeepAlive, ConnName)
+ end),
receive
{open,Pid} ->
{ok,Pid};
@@ -86,29 +91,34 @@ open(Server, Port, Timeout, KeepAlive) ->
end.
close(Pid) ->
- Pid ! close.
+ Pid ! {close,self()},
+ receive closed -> ok
+ after 5000 -> ok
+ end.
send_data(Pid, Data) ->
Pid ! {send_data, Data++"\n"},
ok.
get_data(Pid) ->
- Pid ! {get_data, self()},
+ Pid ! {get_data,self()},
receive
{data,Data} ->
- {ok, Data}
+ {ok,Data}
end.
%%%-----------------------------------------------------------------
%%% Internal functions
-init(Parent, Server, Port, Timeout, KeepAlive) ->
+init(Parent, Server, Port, Timeout, KeepAlive, ConnName) ->
case gen_tcp:connect(Server, Port, [list,{packet,0}], Timeout) of
{ok,Sock} ->
- dbg("Connected to: ~p (port: ~w, keep_alive: ~w)\n", [Server,Port,KeepAlive]),
- send([?IAC,?DO,?SUPPRESS_GO_AHEAD], Sock),
+ dbg("~p connected to: ~p (port: ~w, keep_alive: ~w)\n",
+ [ConnName,Server,Port,KeepAlive]),
+ send([?IAC,?DO,?SUPPRESS_GO_AHEAD], Sock, ConnName),
Parent ! {open,self()},
- loop(#state{get_data=10, keep_alive=KeepAlive}, Sock, []),
+ loop(#state{conn_name=ConnName, get_data=10, keep_alive=KeepAlive},
+ Sock, []),
gen_tcp:close(Sock);
Error ->
Parent ! {Error,self()}
@@ -118,6 +128,13 @@ loop(State, Sock, Acc) ->
receive
{tcp_closed,_} ->
dbg("Connection closed\n", []),
+ Data = lists:reverse(lists:append(Acc)),
+ dbg("Printing queued messages: ~tp",[Data]),
+ ct_telnet:log(State#state.conn_name,
+ general_io, "~ts",
+ [lists:sublist(Data,
+ State#state.log_pos,
+ length(Data))]),
receive
{get_data,Pid} ->
Pid ! closed
@@ -125,11 +142,11 @@ loop(State, Sock, Acc) ->
ok
end;
{tcp,_,Msg0} ->
- dbg("tcp msg: ~p~n",[Msg0]),
+ dbg("tcp msg: ~tp~n",[Msg0]),
Msg = check_msg(Sock,Msg0,[]),
loop(State, Sock, [Msg | Acc]);
{send_data,Data} ->
- send(Data, Sock),
+ send(Data, Sock, State#state.conn_name),
loop(State, Sock, Acc);
{get_data,Pid} ->
NewState =
@@ -144,54 +161,100 @@ loop(State, Sock, Acc) ->
end;
_ ->
Data = lists:reverse(lists:append(Acc)),
- dbg("get_data ~p\n",[Data]),
+ Len = length(Data),
+ dbg("get_data ~tp\n",[Data]),
+ ct_telnet:log(State#state.conn_name,
+ general_io, "~ts",
+ [lists:sublist(Data,
+ State#state.log_pos,
+ Len)]),
Pid ! {data,Data},
- State
+ State#state{log_pos = 1}
end,
loop(NewState, Sock, []);
{get_data_delayed,Pid} ->
NewState =
case State of
#state{keep_alive = true, get_data = 0} ->
- if Acc == [] -> send([?IAC,?NOP], Sock);
+ if Acc == [] -> send([?IAC,?NOP], Sock,
+ State#state.conn_name);
true -> ok
end,
State#state{get_data=10};
_ ->
State
end,
- NewAcc =
+ {NewAcc,Pos} =
case erlang:is_process_alive(Pid) of
- true ->
+ true when Acc /= [] ->
Data = lists:reverse(lists:append(Acc)),
- dbg("get_data_delayed ~p\n",[Data]),
+ Len = length(Data),
+ dbg("get_data_delayed ~tp\n",[Data]),
+ ct_telnet:log(State#state.conn_name,
+ general_io, "~ts",
+ [lists:sublist(Data,
+ State#state.log_pos,
+ Len)]),
Pid ! {data,Data},
- [];
+ {[],1};
+ true when Acc == [] ->
+ dbg("get_data_delayed nodata\n",[]),
+ Pid ! {data,[]},
+ {[],1};
false ->
- Acc
+ {Acc,NewState#state.log_pos}
end,
- loop(NewState, Sock, NewAcc);
- close ->
+ loop(NewState#state{log_pos=Pos}, Sock, NewAcc);
+ {close,Pid} ->
dbg("Closing connection\n", []),
+ if Acc == [] ->
+ ok;
+ true ->
+ Data = lists:reverse(lists:append(Acc)),
+ dbg("Printing queued messages: ~tp",[Data]),
+ ct_telnet:log(State#state.conn_name,
+ general_io, "~ts",
+ [lists:sublist(Data,
+ State#state.log_pos,
+ length(Data))])
+ end,
gen_tcp:close(Sock),
- ok
+ Pid ! closed
after wait(State#state.keep_alive,?IDLE_TIMEOUT) ->
- if
- Acc == [] -> send([?IAC,?NOP], Sock);
- true -> ok
- end,
- loop(State, Sock, Acc)
+ Data = lists:reverse(lists:append(Acc)),
+ case Data of
+ [] ->
+ send([?IAC,?NOP], Sock, State#state.conn_name),
+ loop(State, Sock, Acc);
+ _ when State#state.log_pos == length(Data)+1 ->
+ loop(State, Sock, Acc);
+ _ ->
+ dbg("Idle timeout, printing ~tp\n",[Data]),
+ Len = length(Data),
+ ct_telnet:log(State#state.conn_name,
+ general_io, "~ts",
+ [lists:sublist(Data,
+ State#state.log_pos,
+ Len)]),
+ loop(State#state{log_pos = Len+1}, Sock, Acc)
+ end
end.
wait(true, Time) -> Time;
wait(false, _) -> infinity.
-send(Data, Sock) ->
+send(Data, Sock, ConnName) ->
case Data of
[?IAC|_] = Cmd ->
cmd_dbg(Cmd);
_ ->
- dbg("Sending: ~p\n", [Data])
+ dbg("Sending: ~tp\n", [Data]),
+ try io_lib:format("[~w] ~ts", [?MODULE,Data]) of
+ Str ->
+ ct_telnet:log(ConnName, general_io, Str, [])
+ catch
+ _:_ -> ok
+ end
end,
gen_tcp:send(Sock, Data),
ok.
diff --git a/lib/common_test/src/cth_conn_log.erl b/lib/common_test/src/cth_conn_log.erl
index a731c8054c..0e6c877c5d 100644
--- a/lib/common_test/src/cth_conn_log.erl
+++ b/lib/common_test/src/cth_conn_log.erl
@@ -100,7 +100,6 @@ get_log_opts(Opts) ->
Hosts = proplists:get_value(hosts,Opts,[]),
{LogType,Hosts}.
-
pre_init_per_testcase(TestCase,Config,CthState) ->
Logs =
lists:map(
diff --git a/lib/common_test/src/cth_surefire.erl b/lib/common_test/src/cth_surefire.erl
index 7ed2018bdf..bb12171ea7 100644
--- a/lib/common_test/src/cth_surefire.erl
+++ b/lib/common_test/src/cth_surefire.erl
@@ -79,6 +79,10 @@ init(Path, Opts) ->
url_base = proplists:get_value(url_base,Opts),
timer = now() }.
+pre_init_per_suite(Suite,SkipOrFail,State) when is_tuple(SkipOrFail) ->
+ {SkipOrFail, init_tc(State#state{curr_suite = Suite,
+ curr_suite_ts = now()},
+ SkipOrFail) };
pre_init_per_suite(Suite,Config,#state{ test_cases = [] } = State) ->
TcLog = proplists:get_value(tc_logfile,Config),
CurrLogDir = filename:dirname(TcLog),
diff --git a/lib/common_test/src/unix_telnet.erl b/lib/common_test/src/unix_telnet.erl
index e049c3bf39..b05386a5ab 100644
--- a/lib/common_test/src/unix_telnet.erl
+++ b/lib/common_test/src/unix_telnet.erl
@@ -109,7 +109,7 @@ connect(ConnName,Ip,Port,Timeout,KeepAlive,Extra) ->
connect1(Name,Ip,Port,Timeout,KeepAlive,Username,Password) ->
start_gen_log("unix_telnet connect"),
Result =
- case ct_telnet_client:open(Ip,Port,Timeout,KeepAlive) of
+ case ct_telnet_client:open(Ip,Port,Timeout,KeepAlive,Name) of
{ok,Pid} ->
case ct_telnet:silent_teln_expect(Name,Pid,[],
[prompt],?prx,[]) of
@@ -143,13 +143,13 @@ connect1(Name,Ip,Port,Timeout,KeepAlive,Username,Password) ->
{ok,[{prompt,_OtherPrompt1},{prompt,_OtherPrompt2}],_} ->
{ok,Pid};
Error ->
- log(Name,error,
+ log(Name,conn_error,
"Did not get expected prompt from ~p:~p\n~p\n",
[Ip,Port,Error]),
{error,Error}
end;
Error ->
- log(Name,error,
+ log(Name,conn_error,
"Could not open telnet connection to ~p:~p\n~p\n",
[Ip,Port,Error]),
Error
diff --git a/lib/common_test/test/ct_master_SUITE.erl b/lib/common_test/test/ct_master_SUITE.erl
index 7408cbe376..e90513f888 100644
--- a/lib/common_test/test/ct_master_SUITE.erl
+++ b/lib/common_test/test/ct_master_SUITE.erl
@@ -81,7 +81,8 @@ end_per_testcase(TestCase, Config) ->
ct_test_support:end_per_testcase(TestCase, Config).
-suite() -> [{ct_hooks,[ts_install_cth]}].
+suite() -> [{timetrap,{seconds,60}},
+ {ct_hooks,[ts_install_cth]}].
all() ->
[ct_master_test].
diff --git a/lib/common_test/test/ct_telnet_SUITE.erl b/lib/common_test/test/ct_telnet_SUITE.erl
index acce4eca14..f5cff76fd1 100644
--- a/lib/common_test/test/ct_telnet_SUITE.erl
+++ b/lib/common_test/test/ct_telnet_SUITE.erl
@@ -72,19 +72,32 @@ init_per_suite(Config) ->
end_per_suite(Config) ->
ct_test_support:end_per_suite(Config).
-init_per_testcase(TestCase, Config) when TestCase=/=unix_telnet->
+init_per_testcase(TestCase, Config) when TestCase /= unix_telnet ->
+ ct:pal("Testcase ~p starting!", [TestCase]),
TS = telnet_server:start([{port,?erl_telnet_server_port},
{users,[{?erl_telnet_server_user,
?erl_telnet_server_pwd}]}]),
ct_test_support:init_per_testcase(TestCase, [{telnet_server,TS}|Config]);
init_per_testcase(TestCase, Config) ->
- ct_test_support:init_per_testcase(TestCase, Config).
-
+ ct:pal("Testcase ~p starting. Checking connection to telnet server...",
+ [TestCase]),
+ ct:require(testconn, {unix,[telnet]}),
+ case {os:type(),ct_telnet:open(testconn)} of
+ {_,{ok,Handle}} ->
+ ok = ct_telnet:close(Handle),
+ ct:pal("Connection ok, starting tests!", []),
+ ct_test_support:init_per_testcase(TestCase, Config);
+ {{unix,_},{error,Reason}} ->
+ ct:fail("No connection to telnet server! Reason: ~tp", [Reason]);
+ {_,{error,Reason}} ->
+ {skip,{no_access_to_telnet_server,Reason}}
+ end.
+
+end_per_testcase(TestCase, Config) when TestCase /= unix_telnet ->
+ ct:pal("Stopping the telnet_server now!", []),
+ telnet_server:stop(?config(telnet_server,Config)),
+ ct_test_support:end_per_testcase(TestCase, Config);
end_per_testcase(TestCase, Config) ->
- case ?config(telnet_server,Config) of
- undefined -> ok;
- TS -> telnet_server:stop(TS)
- end,
ct_test_support:end_per_testcase(TestCase, Config).
@@ -179,7 +192,12 @@ telnet_config(_, LogType) ->
{port, ?erl_telnet_server_port},
{username,?erl_telnet_server_user},
{password,?erl_telnet_server_pwd},
- {keep_alive,true}]} |
+ {keep_alive,true}]},
+ {telnet_settings, [{connect_timeout,10000},
+ {command_timeout,10000},
+ {reconnection_attempts,0},
+ {reconnection_interval,0},
+ {keep_alive,true}]} |
if LogType == legacy ->
[{ct_conn_log,[]}];
true ->
diff --git a/lib/common_test/test/ct_telnet_SUITE_data/ct_telnet_own_server_SUITE.erl b/lib/common_test/test/ct_telnet_SUITE_data/ct_telnet_own_server_SUITE.erl
index 8d142e85a8..0ee0525216 100644
--- a/lib/common_test/test/ct_telnet_SUITE_data/ct_telnet_own_server_SUITE.erl
+++ b/lib/common_test/test/ct_telnet_SUITE_data/ct_telnet_own_server_SUITE.erl
@@ -20,7 +20,9 @@ all() ->
expect_repeat,
expect_sequence,
expect_error_prompt,
- expect_error_timeout,
+ expect_error_timeout1,
+ expect_error_timeout2,
+ expect_error_timeout3,
no_prompt_check,
no_prompt_check_repeat,
no_prompt_check_sequence,
@@ -28,7 +30,9 @@ all() ->
ignore_prompt,
ignore_prompt_repeat,
ignore_prompt_sequence,
- ignore_prompt_timeout].
+ ignore_prompt_timeout,
+ server_speaks,
+ server_disconnects].
groups() ->
[].
@@ -85,13 +89,34 @@ expect_error_prompt(_) ->
%% Check that expect returns after idle timeout, and even if the
%% expected pattern is received - as long as not newline or prompt is
%% received it will not match.
-expect_error_timeout(_) ->
+expect_error_timeout1(_) ->
{ok, Handle} = ct_telnet:open(telnet_server_conn1),
ok = ct_telnet:send(Handle, "echo_no_prompt xxx"),
{error,timeout} = ct_telnet:expect(Handle, ["xxx"], [{timeout,1000}]),
ok = ct_telnet:close(Handle),
ok.
+expect_error_timeout2(_) ->
+ {ok, Handle} = ct_telnet:open(telnet_server_conn1),
+ ok = ct_telnet:send(Handle, "echo_no_prompt xxx"),
+ {error,timeout} = ct_telnet:expect(Handle, ["xxx"], [{idle_timeout,1000},
+ {total_timeout,infinity}]),
+ ok = ct_telnet:close(Handle),
+ ok.
+
+%% Check that if server loops and pattern not matching, the operation
+%% can be aborted
+expect_error_timeout3(_) ->
+ {ok, Handle} = ct_telnet:open(telnet_server_conn1),
+ ok = ct_telnet:send(Handle, "echo_loop 5000 xxx"),
+ {error,timeout} = ct_telnet:expect(Handle, ["yyy"],
+ [{idle_timeout,infinity},
+ {total_timeout,3000}]),
+ ok = ct_telnet:send(Handle, "echo ayt"),
+ {ok,["ayt"]} = ct_telnet:expect(Handle, ["ayt"]),
+ ok = ct_telnet:close(Handle),
+ ok.
+
%% expect with ignore_prompt option should not return even if a prompt
%% is found. The pattern after the prompt (here "> ") can be matched.
ignore_prompt(_) ->
@@ -188,3 +213,37 @@ no_prompt_check_timeout(_) ->
{timeout,1000}]),
ok = ct_telnet:close(Handle),
ok.
+
+%% The server says things. Manually check that it gets printed correctly
+%% in the general IO log.
+server_speaks(_) ->
+ {ok, Handle} = ct_telnet:open(telnet_server_conn1),
+ ok = ct_telnet:send(Handle, "echo_no_prompt This is the first message\r\n"),
+ ok = ct_telnet:send(Handle, "echo_no_prompt This is the second message\r\n"),
+ %% let ct_telnet_client get an idle timeout
+ timer:sleep(15000),
+ ok = ct_telnet:send(Handle, "echo_no_prompt This is the third message\r\n"),
+ {ok,_} = ct_telnet:expect(Handle, ["the"], [no_prompt_check]),
+ {error,timeout} = ct_telnet:expect(Handle, ["the"], [no_prompt_check,
+ {timeout,1000}]),
+ ok = ct_telnet:send(Handle, "echo_no_prompt This is the fourth message\r\n"),
+ %% give the server time to respond
+ timer:sleep(2000),
+ %% closing the connection should print last message in log
+ ok = ct_telnet:close(Handle),
+ ok.
+
+%% Let the server close the connection. Make sure buffered data gets printed
+%% to the general IO log.
+server_disconnects(_) ->
+ {ok, Handle} = ct_telnet:open(telnet_server_conn1),
+ ok = ct_telnet:send(Handle, "disconnect_after 1500"),
+ %% wait until the get_data operation (triggered by send/2) times out
+ %% before sending the msg
+ timer:sleep(500),
+ ok = ct_telnet:send(Handle, "echo_no_prompt This is the message\r\n"),
+ %% when the server closes the connection, the last message should be
+ %% printed in the log
+ timer:sleep(3000),
+ _ = ct_telnet:close(Handle),
+ ok.
diff --git a/lib/common_test/test/telnet_server.erl b/lib/common_test/test/telnet_server.erl
index 1760100d8e..ae56787819 100644
--- a/lib/common_test/test/telnet_server.erl
+++ b/lib/common_test/test/telnet_server.erl
@@ -51,32 +51,51 @@ stop(Pid) ->
init(Opts) ->
Port = proplists:get_value(port,Opts),
Users = proplists:get_value(users,Opts,[]),
- {ok, LSock} = gen_tcp:listen(Port, [list, {packet, 0},
- {active, true}]),
+ {ok, LSock} = listen(5, Port, [list, {packet, 0},
+ {active, true},
+ {reuseaddr,true}]),
State = #state{listen=LSock,users=Users},
accept(State),
- ok = gen_tcp:close(LSock).
+ ok = gen_tcp:close(LSock),
+ dbg("telnet_server closed the listen socket ~p\n", [LSock]),
+ timer:sleep(1000),
+ ok.
+
+listen(0, _Port, _Opts) ->
+ {error,eaddrinuse};
+listen(Retries, Port, Opts) ->
+ case gen_tcp:listen(Port, Opts) of
+ {error,eaddrinuse} ->
+ dbg("Listen port not released, trying again..."),
+ timer:sleep(5000),
+ listen(Retries-1, Port, Opts);
+ Ok = {ok,_LSock} ->
+ Ok;
+ Error ->
+ exit(Error)
+ end.
accept(#state{listen=LSock}=State) ->
Server = self(),
Acceptor = spawn_link(fun() -> do_accept(LSock,Server) end),
receive
{Acceptor,Sock} when is_port(Sock) ->
+ dbg("Connected to client on socket ~p\n", [Sock]),
case init_client(State#state{client=Sock}) of
stopped ->
- io:format("[telnet_server] telnet_server stopped\n"),
+ dbg("telnet_server stopped\n"),
ok;
R ->
- io:format("[telnet_server] connection to client"
- "closed with reason ~p~n",[R]),
+ dbg("Connection to client "
+ "closed with reason ~p~n",[R]),
accept(State)
end;
{Acceptor,closed} ->
- io:format("[telnet_server] listen socket closed unexpectedly, "
- "terminating telnet_server\n"),
+ dbg("Listen socket closed unexpectedly, "
+ "terminating telnet_server\n"),
ok;
stop ->
- io:format("[telnet_server] telnet_server stopped\n"),
+ dbg("telnet_server stopped\n"),
ok
end.
@@ -97,19 +116,21 @@ init_client(#state{client=Sock}=State) ->
dbg("Server sending: ~p~n",["login: "]),
R = case gen_tcp:send(Sock,"login: ") of
ok ->
- loop(State);
+ loop(State, 1);
Error ->
Error
end,
_ = gen_tcp:close(Sock),
R.
-loop(State) ->
+loop(State, N) ->
receive
{tcp,_,Data} ->
try handle_data(Data,State) of
{ok,State1} ->
- loop(State1)
+ loop(State1, N);
+ closed ->
+ closed
catch
throw:Error ->
Error
@@ -118,6 +139,11 @@ loop(State) ->
closed;
{tcp_error,_,Error} ->
{error,tcp,Error};
+ disconnect ->
+ Sock = State#state.client,
+ dbg("Server closing connection on socket ~p~n", [Sock]),
+ ok = gen_tcp:close(Sock),
+ closed;
stop ->
stopped
end.
@@ -130,10 +156,16 @@ handle_data(Data,State) ->
case get_line(Data,[]) of
{Line,Rest} ->
WholeLine = lists:flatten(lists:reverse(State#state.buffer,Line)),
- {ok,State1} = do_handle_data(WholeLine,State),
- case Rest of
- [] -> {ok,State1};
- _ -> handle_data(Rest,State1)
+ case do_handle_data(WholeLine,State) of
+ {ok,State1} ->
+ case Rest of
+ [] -> {ok,State1};
+ _ -> handle_data(Rest,State1)
+ end;
+ {close,State1} ->
+ dbg("Server closing connection~n",[]),
+ gen_tcp:close(State1#state.client),
+ closed
end;
false ->
{ok,State#state{buffer=[Data|State#state.buffer]}}
@@ -163,22 +195,34 @@ do_handle_data(Data,#state{authorized=false}=State) ->
check_user(Data,State);
do_handle_data(Data,#state{authorized={user,_}}=State) ->
check_pwd(Data,State);
-do_handle_data("echo "++ Data,State) ->
+do_handle_data("echo " ++ Data,State) ->
send(Data++"\r\n> ",State),
{ok,State};
-do_handle_data("echo_no_prompt "++ Data,State) ->
+do_handle_data("echo_no_prompt " ++ Data,State) ->
send(Data,State),
{ok,State};
-do_handle_data("echo_ml "++ Data,State) ->
+do_handle_data("echo_ml " ++ Data,State) ->
Lines = string:tokens(Data," "),
ReturnData = string:join(Lines,"\n"),
send(ReturnData++"\r\n> ",State),
{ok,State};
-do_handle_data("echo_ml_no_prompt "++ Data,State) ->
+do_handle_data("echo_ml_no_prompt " ++ Data,State) ->
Lines = string:tokens(Data," "),
ReturnData = string:join(Lines,"\n"),
send(ReturnData,State),
{ok,State};
+do_handle_data("echo_loop " ++ Data,State) ->
+ [TStr|Lines] = string:tokens(Data," "),
+ ReturnData = string:join(Lines,"\n"),
+ send_loop(list_to_integer(TStr),ReturnData,State),
+ {ok,State};
+do_handle_data("disconnect_after " ++WaitStr,State) ->
+ Wait = list_to_integer(string:strip(WaitStr,right,$\n)),
+ dbg("Server will close connection in ~w ms...", [Wait]),
+ erlang:send_after(Wait,self(),disconnect),
+ {ok,State};
+do_handle_data("disconnect" ++_,State) ->
+ {close,State};
do_handle_data([],State) ->
send("> ",State),
{ok,State};
@@ -212,6 +256,20 @@ send(Data,State) ->
throw({error,send,Error})
end.
+send_loop(T,Data,State) ->
+ dbg("Server sending ~p in loop for ~w ms...~n",[Data,T]),
+ send_loop(now(),T,Data,State).
+
+send_loop(T0,T,Data,State) ->
+ ElapsedMS = trunc(timer:now_diff(now(),T0)/1000),
+ if ElapsedMS >= T ->
+ ok;
+ true ->
+ send(Data,State),
+ timer:sleep(500),
+ send_loop(T0,T,Data,State)
+ end.
+
get_line([$\r,$\n|Rest],Acc) ->
{lists:reverse(Acc),Rest};
get_line([$\r,0|Rest],Acc) ->
@@ -226,4 +284,4 @@ get_line([],_) ->
dbg(_F) ->
dbg(_F,[]).
dbg(_F,_A) ->
- io:format("[telnet_server] "++_F,_A).
+ io:format("[telnet_server] " ++ _F,_A).
diff --git a/lib/common_test/vsn.mk b/lib/common_test/vsn.mk
index 568405b110..f8a5aab686 100644
--- a/lib/common_test/vsn.mk
+++ b/lib/common_test/vsn.mk
@@ -1 +1 @@
-COMMON_TEST_VSN = 1.7.4
+COMMON_TEST_VSN = 1.8
diff --git a/lib/compiler/src/beam_disasm.erl b/lib/compiler/src/beam_disasm.erl
index 4bdfe4e0c2..c45596f236 100644
--- a/lib/compiler/src/beam_disasm.erl
+++ b/lib/compiler/src/beam_disasm.erl
@@ -1030,6 +1030,7 @@ resolve_inst({gc_bif2,Args},Imports,_,_) ->
[F,Live,Bif,A1,A2,Reg] = resolve_args(Args),
{extfunc,_Mod,BifName,_Arity} = lookup(Bif+1,Imports),
{gc_bif,BifName,F,Live,[A1,A2],Reg};
+
%%
%% New instruction in R14, gc_bif with 3 arguments
%%
@@ -1146,21 +1147,17 @@ resolve_inst({put_map_assoc,Args},_,_,_) ->
[FLbl,Src,Dst,{u,N},{{z,1},{u,_Len},List0}] = Args,
List = resolve_args(List0),
{put_map_assoc,FLbl,Src,Dst,N,{list,List}};
-
resolve_inst({put_map_exact,Args},_,_,_) ->
[FLbl,Src,Dst,{u,N},{{z,1},{u,_Len},List0}] = Args,
List = resolve_args(List0),
{put_map_exact,FLbl,Src,Dst,N,{list,List}};
-
-resolve_inst({is_map,Args0},_,_,_) ->
+resolve_inst({is_map=I,Args0},_,_,_) ->
[FLbl|Args] = resolve_args(Args0),
- {test, is_map, FLbl, Args};
-
+ {test,I,FLbl,Args};
resolve_inst({has_map_fields,Args0},_,_,_) ->
[FLbl,Src,{{z,1},{u,_Len},List0}] = Args0,
List = resolve_args(List0),
{test,has_map_fields,FLbl,Src,{list,List}};
-
resolve_inst({get_map_elements,Args0},_,_,_) ->
[FLbl,Src,{{z,1},{u,_Len},List0}] = Args0,
List = resolve_args(List0),
diff --git a/lib/compiler/src/cerl.erl b/lib/compiler/src/cerl.erl
index 3c121f3b04..ed11c8de4d 100644
--- a/lib/compiler/src/cerl.erl
+++ b/lib/compiler/src/cerl.erl
@@ -124,21 +124,17 @@
%% keep map exports here for now
map_es/1,
- map_val/1,
+ map_arg/1,
update_c_map/3,
- ann_c_map/3,
+ ann_c_map/2, ann_c_map/3,
map_pair_op/1,map_pair_key/1,map_pair_val/1,
update_c_map_pair/4,
ann_c_map_pair/4
]).
--export_type([c_binary/0, c_call/0, c_clause/0, c_cons/0, c_fun/0, c_literal/0,
- c_module/0, c_tuple/0, c_values/0, c_var/0, cerl/0, var_name/0]).
-
-%%
-%% needed by the include file below -- do not move
-%%
--type var_name() :: integer() | atom() | {atom(), integer()}.
+-export_type([c_binary/0, c_bitstr/0, c_call/0, c_clause/0, c_cons/0, c_fun/0,
+ c_literal/0, c_map_pair/0, c_module/0, c_tuple/0,
+ c_values/0, c_var/0, cerl/0, var_name/0]).
-include("core_parse.hrl").
@@ -173,6 +169,8 @@
| c_module() | c_primop() | c_receive() | c_seq()
| c_try() | c_tuple() | c_values() | c_var().
+-type var_name() :: integer() | atom() | {atom(), integer()}.
+
%% =====================================================================
%% Representation (general)
%%
@@ -204,13 +202,15 @@
%% <td>call</td>
%% <td>case</td>
%% <td>catch</td>
-%% </tr><tr>
%% <td>clause</td>
+%% </tr><tr>
%% <td>cons</td>
%% <td>fun</td>
%% <td>let</td>
%% <td>letrec</td>
%% <td>literal</td>
+%% <td>map</td>
+%% <td>map_pair</td>
%% <td>module</td>
%% </tr><tr>
%% <td>primop</td>
@@ -261,10 +261,10 @@
%% @see subtrees/1
%% @see meta/1
--type ctype() :: 'alias' | 'apply' | 'binary' | 'bitrst' | 'call' | 'case'
- | 'catch' | 'clause' | 'cons' | 'fun' | 'let' | 'letrec'
- | 'literal' | 'map' | 'module' | 'primop' | 'receive' | 'seq'
- | 'try' | 'tuple' | 'values' | 'var'.
+-type ctype() :: 'alias' | 'apply' | 'binary' | 'bitrst' | 'call' | 'case'
+ | 'catch' | 'clause' | 'cons' | 'fun' | 'let' | 'letrec'
+ | 'literal' | 'map' | 'map_pair' | 'module' | 'primop'
+ | 'receive' | 'seq' | 'try' | 'tuple' | 'values' | 'var'.
-spec type(cerl()) -> ctype().
@@ -1575,20 +1575,70 @@ ann_make_list(_, [], Node) ->
%% ---------------------------------------------------------------------
%% maps
--spec map_es(c_map()) -> [cerl()].
+-spec map_es(c_map()) -> [c_map_pair()].
map_es(#c_map{es = Es}) ->
Es.
--spec map_val(c_map()) -> cerl().
-map_val(#c_map{var = M}) ->
+-spec map_arg(c_map()) -> c_map() | c_literal().
+
+map_arg(#c_map{arg = M}) ->
M.
+-spec ann_c_map([term()], [cerl()]) -> c_map() | c_literal().
+
+ann_c_map(As,Es) ->
+ ann_c_map(As, #c_literal{val=#{}}, Es).
+
+-spec ann_c_map([term()], c_map() | c_literal(), [c_map_pair()]) -> c_map() | c_literal().
+
+ann_c_map(As,#c_literal{val=Mval}=M,Es) when is_map(Mval), map_size(Mval) =:= 0 ->
+ Pairs = [[Ck,Cv]||#c_map_pair{key=Ck,val=Cv}<-Es],
+ IsLit = lists:foldl(fun(Pair,Res) ->
+ Res andalso is_lit_list(Pair)
+ end, true, Pairs),
+ Fun = fun(Pair) -> [K,V] = lit_list_vals(Pair), {K,V} end,
+ case IsLit of
+ false ->
+ #c_map{arg=M, es=Es, anno=As };
+ true ->
+ #c_literal{anno=As, val=maps:from_list(lists:map(Fun, Pairs))}
+ end;
+ann_c_map(As,#c_literal{val=M},Es) when is_map(M) ->
+ fold_map_pairs(As,Es,M);
ann_c_map(As,M,Es) ->
- #c_map{var=M,es = Es, anno = As }.
+ #c_map{arg=M, es=Es, anno=As }.
+
+fold_map_pairs(As,[],M) -> #c_literal{anno=As,val=M};
+%% M#{ K => V}
+fold_map_pairs(As,[#c_map_pair{op=#c_literal{val=assoc},key=Ck,val=Cv}=E|Es],M) ->
+ case is_lit_list([Ck,Cv]) of
+ true ->
+ [K,V] = lit_list_vals([Ck,Cv]),
+ fold_map_pairs(As,Es,maps:put(K,V,M));
+ false ->
+ #c_map{arg=#c_literal{val=M,anno=As}, es=[E|Es], anno=As }
+ end;
+%% M#{ K := V}
+fold_map_pairs(As,[#c_map_pair{op=#c_literal{val=exact},key=Ck,val=Cv}=E|Es],M) ->
+ case is_lit_list([Ck,Cv]) of
+ true ->
+ [K,V] = lit_list_vals([Ck,Cv]),
+ case maps:is_key(K,M) of
+ true -> fold_map_pairs(As,Es,maps:put(K,V,M));
+ false ->
+ #c_map{arg=#c_literal{val=M,anno=As}, es=[E|Es], anno=As }
+ end;
+ false ->
+ #c_map{arg=#c_literal{val=M,anno=As}, es=[E|Es], anno=As }
+ end;
+fold_map_pairs(As,Es,M) ->
+ #c_map{arg=#c_literal{val=M,anno=As}, es=Es, anno=As }.
+
+%-spec update_c_map(c_map() | c_literal(), [c_map_pair()]) -> c_map() | c_literal().
update_c_map(Old,M,Es) ->
- #c_map{var=M, es = Es, anno = get_ann(Old)}.
+ #c_map{arg=M, es = Es, anno = get_ann(Old)}.
map_pair_key(#c_map_pair{key=K}) -> K.
map_pair_val(#c_map_pair{val=V}) -> V.
@@ -4324,12 +4374,8 @@ meta_1(cons, Node) ->
%% we get exactly one element, we generate a 'c_cons' call
%% instead of 'make_list' to reconstruct the node.
case split_list(Node) of
- {[H], none} ->
- meta_call(c_cons, [meta(H), meta(c_nil())]);
{[H], Node1} ->
meta_call(c_cons, [meta(H), meta(Node1)]);
- {L, none} ->
- meta_call(make_list, [make_list(meta_list(L))]);
{L, Node1} ->
meta_call(make_list,
[make_list(meta_list(L)), meta(Node1)])
@@ -4416,8 +4462,6 @@ split_list(Node, L) ->
case type(Node) of
cons when A =:= [] ->
split_list(cons_tl(Node), [cons_hd(Node) | L]);
- nil when A =:= [] ->
- {lists:reverse(L), none};
_ ->
{lists:reverse(L), Node}
end.
diff --git a/lib/compiler/src/cerl_clauses.erl b/lib/compiler/src/cerl_clauses.erl
index 76d70dcabf..87bd47c08b 100644
--- a/lib/compiler/src/cerl_clauses.erl
+++ b/lib/compiler/src/cerl_clauses.erl
@@ -356,14 +356,19 @@ match(P, E, Bs) ->
end;
map ->
%% The most we can do is to say "definitely no match" if a
- %% binary pattern is matched against non-binary data.
+ %% map pattern is matched against non-map data.
case E of
any ->
{false, Bs};
_ ->
case type(E) of
- literal ->
- none;
+ literal ->
+ case is_map(concrete(E)) of
+ false ->
+ none;
+ true ->
+ {false, Bs}
+ end;
cons ->
none;
tuple ->
diff --git a/lib/compiler/src/cerl_inline.erl b/lib/compiler/src/cerl_inline.erl
index fa1d34cc9b..75740e8b9d 100644
--- a/lib/compiler/src/cerl_inline.erl
+++ b/lib/compiler/src/cerl_inline.erl
@@ -64,7 +64,7 @@
seq_body/1, set_ann/2, try_arg/1, try_body/1, try_vars/1,
try_evars/1, try_handler/1, tuple_es/1, tuple_arity/1,
type/1, values_es/1, var_name/1,
- map_val/1, map_es/1, update_c_map/3,
+ map_arg/1, map_es/1, update_c_map/3,
update_c_map_pair/4,
map_pair_op/1, map_pair_key/1, map_pair_val/1
]).
@@ -1343,7 +1343,7 @@ i_bitstr(E, Ren, Env, S) ->
i_map(E, Ctx, Ren, Env, S) ->
%% Visit the segments for value.
- {M1, S1} = i(map_val(E), value, Ren, Env, S),
+ {M1, S1} = i(map_arg(E), value, Ren, Env, S),
{Es, S2} = mapfoldl(fun (E, S) ->
i_map_pair(E, Ctx, Ren, Env, S)
end, S1, map_es(E)),
@@ -1420,8 +1420,8 @@ i_pattern(E, Ren, Env, Ren0, Env0, S) ->
S2 = count_size(weight(binary), S1),
{update_c_binary(E, Es), S2};
map ->
- %% map patterns should not have vals
- M = map_val(E),
+ %% map patterns should not have args
+ M = map_arg(E),
{Es, S1} = mapfoldl(fun (E, S) ->
i_map_pair_pattern(E, Ren, Env, Ren0, Env0, S)
diff --git a/lib/compiler/src/cerl_trees.erl b/lib/compiler/src/cerl_trees.erl
index 2ebeab243f..e53bdd4efb 100644
--- a/lib/compiler/src/cerl_trees.erl
+++ b/lib/compiler/src/cerl_trees.erl
@@ -57,7 +57,7 @@
update_c_try/6, update_c_tuple/2, update_c_tuple_skel/2,
update_c_values/2, values_es/1, var_name/1,
- map_val/1, map_es/1,
+ map_arg/1, map_es/1,
ann_c_map/3,
update_c_map/3,
map_pair_key/1,map_pair_val/1,map_pair_op/1,
@@ -138,7 +138,7 @@ map_1(F, T) ->
tuple ->
update_c_tuple_skel(T, map_list(F, tuple_es(T)));
map ->
- update_c_map(T, map(F,map_val(T)), map_list(F, map_es(T)));
+ update_c_map(T, map(F, map_arg(T)), map_list(F, map_es(T)));
map_pair ->
update_c_map_pair(T, map(F, map_pair_op(T)),
map(F, map_pair_key(T)),
@@ -372,7 +372,7 @@ mapfold(F, S0, T) ->
{Ts, S1} = mapfold_list(F, S0, tuple_es(T)),
F(update_c_tuple_skel(T, Ts), S1);
map ->
- {M , S1} = mapfold(F, S0, map_val(T)),
+ {M , S1} = mapfold(F, S0, map_arg(T)),
{Ts, S2} = mapfold_list(F, S1, map_es(T)),
F(update_c_map(T, M, Ts), S2);
map_pair ->
@@ -724,7 +724,7 @@ label(T, N, Env) ->
{As, N2} = label_ann(T, N1),
{ann_c_tuple_skel(As, Ts), N2};
map ->
- {M, N1} = label(map_val(T), N, Env),
+ {M, N1} = label(map_arg(T), N, Env),
{Ts, N2} = label_list(map_es(T), N1, Env),
{As, N3} = label_ann(T, N2),
{ann_c_map(As, M, Ts), N3};
diff --git a/lib/compiler/src/compile.erl b/lib/compiler/src/compile.erl
index 9030dd998b..c7d91070f6 100644
--- a/lib/compiler/src/compile.erl
+++ b/lib/compiler/src/compile.erl
@@ -234,7 +234,9 @@ format_error({crash,Pass,Reason}) ->
format_error({bad_return,Pass,Reason}) ->
io_lib:format("internal error in ~p;\nbad return value: ~ts", [Pass,format_error_reason(Reason)]);
format_error({module_name,Mod,Filename}) ->
- io_lib:format("Module name '~s' does not match file name '~ts'", [Mod,Filename]).
+ io_lib:format("Module name '~s' does not match file name '~ts'", [Mod,Filename]);
+format_error(reparsing_invalid_unicode) ->
+ "Non-UTF-8 character(s) detected, but no encoding declared. Encode the file in UTF-8 or add \"%% coding: latin-1\" at the beginning of the file. Retrying with latin-1 encoding.".
format_error_reason({Reason, Stack}) when is_list(Stack) ->
StackFun = fun
@@ -792,20 +794,59 @@ no_native_compilation(BeamFile, #compile{options=Opts0}) ->
_ -> false
end.
-parse_module(St) ->
- Opts = St#compile.options,
- Cwd = ".",
- IncludePath = [Cwd, St#compile.dir|inc_paths(Opts)],
- R = epp:parse_file(St#compile.ifile, IncludePath, pre_defs(Opts)),
+parse_module(St0) ->
+ case do_parse_module(utf8, St0) of
+ {ok,_}=Ret ->
+ Ret;
+ {error,_}=Ret ->
+ Ret;
+ {invalid_unicode,File,Line} ->
+ case do_parse_module(latin1, St0) of
+ {ok,St} ->
+ Es = [{File,[{Line,?MODULE,reparsing_invalid_unicode}]}],
+ {ok,St#compile{warnings=Es++St#compile.warnings}};
+ {error,St} ->
+ Es = [{File,[{Line,?MODULE,reparsing_invalid_unicode}]}],
+ {error,St#compile{errors=Es++St#compile.errors}}
+ end
+ end.
+
+do_parse_module(DefEncoding, #compile{ifile=File,options=Opts,dir=Dir}=St) ->
+ R = epp:parse_file(File,
+ [{includes,[".",Dir|inc_paths(Opts)]},
+ {macros,pre_defs(Opts)},
+ {default_encoding,DefEncoding},
+ extra]),
case R of
- {ok,Forms} ->
- Encoding = epp:read_encoding(St#compile.ifile),
- {ok,St#compile{code=Forms,encoding=Encoding}};
+ {ok,Forms,Extra} ->
+ Encoding = proplists:get_value(encoding, Extra),
+ case find_invalid_unicode(Forms, File) of
+ none ->
+ {ok,St#compile{code=Forms,encoding=Encoding}};
+ {invalid_unicode,_,_}=Ret ->
+ case Encoding of
+ none ->
+ Ret;
+ _ ->
+ {ok,St#compile{code=Forms,encoding=Encoding}}
+ end
+ end;
{error,E} ->
Es = [{St#compile.ifile,[{none,?MODULE,{epp,E}}]}],
{error,St#compile{errors=St#compile.errors ++ Es}}
end.
+find_invalid_unicode([H|T], File0) ->
+ case H of
+ {attribute,_,file,{File,_}} ->
+ find_invalid_unicode(T, File);
+ {error,{Line,file_io_server,invalid_unicode}} ->
+ {invalid_unicode,File0,Line};
+ _Other ->
+ find_invalid_unicode(T, File0)
+ end;
+find_invalid_unicode([], _) -> none.
+
parse_core(St) ->
case file:read_file(St#compile.ifile) of
{ok,Bin} ->
diff --git a/lib/compiler/src/compiler.app.src b/lib/compiler/src/compiler.app.src
index 8775c84698..8f68915f8e 100644
--- a/lib/compiler/src/compiler.app.src
+++ b/lib/compiler/src/compiler.app.src
@@ -67,4 +67,6 @@
]},
{registered, []},
{applications, [kernel, stdlib]},
- {env, []}]}.
+ {env, []},
+ {runtime_dependencies, ["stdlib-2.0","kernel-3.0","hipe-3.10.3","erts-6.0",
+ "crypto-3.3"]}]}.
diff --git a/lib/compiler/src/core_lib.erl b/lib/compiler/src/core_lib.erl
index ed181e3baa..93ec3bbad5 100644
--- a/lib/compiler/src/core_lib.erl
+++ b/lib/compiler/src/core_lib.erl
@@ -105,7 +105,7 @@ vu_expr(V, #c_cons{hd=H,tl=T}) ->
vu_expr(V, H) orelse vu_expr(V, T);
vu_expr(V, #c_tuple{es=Es}) ->
vu_expr_list(V, Es);
-vu_expr(V, #c_map{var=M,es=Es}) ->
+vu_expr(V, #c_map{arg=M,es=Es}) ->
vu_expr(V, M) orelse vu_expr_list(V, Es);
vu_expr(V, #c_map_pair{key=Key,val=Val}) ->
vu_expr_list(V, [Key,Val]);
diff --git a/lib/compiler/src/core_parse.hrl b/lib/compiler/src/core_parse.hrl
index d54715ef59..4a00535360 100644
--- a/lib/compiler/src/core_parse.hrl
+++ b/lib/compiler/src/core_parse.hrl
@@ -34,7 +34,7 @@
-record(c_apply, {anno=[], op, % op :: Tree,
args}). % args :: [Tree]
--record(c_binary, {anno=[], segments}). % segments :: [#c_bitstr{}]
+-record(c_binary, {anno=[], segments :: [cerl:c_bitstr()]}).
-record(c_bitstr, {anno=[], val, % val :: Tree,
size, % size :: Tree,
@@ -70,6 +70,15 @@
-record(c_literal, {anno=[], val}). % val :: literal()
+-record(c_map, {anno=[],
+ arg=#c_literal{val=#{}} :: cerl:c_var() | cerl:c_literal(),
+ es :: [cerl:c_map_pair()]}).
+
+-record(c_map_pair, {anno=[],
+ op :: #c_literal{val::'assoc'} | #c_literal{val::'exact'},
+ key,
+ val}).
+
-record(c_module, {anno=[], name, % name :: Tree,
exports, % exports :: [Tree],
attrs, % attrs :: [#c_def{}],
@@ -96,12 +105,3 @@
-record(c_values, {anno=[], es}). % es :: [Tree]
-record(c_var, {anno=[], name :: cerl:var_name()}).
-
--record(c_map_pair, {anno=[],
- op :: #c_literal{val::'assoc'} | #c_literal{val::'exact'},
- key,
- val}).
-
--record(c_map, {anno=[],
- var=#c_literal{val=[]} :: #c_var{} | #c_literal{},
- es :: [#c_map_pair{}]}).
diff --git a/lib/compiler/src/core_parse.yrl b/lib/compiler/src/core_parse.yrl
index b8db0f683a..a66ad4235f 100644
--- a/lib/compiler/src/core_parse.yrl
+++ b/lib/compiler/src/core_parse.yrl
@@ -21,7 +21,7 @@
%% Have explicit productions for annotated phrases named anno_XXX.
%% This just does an XXX and adds the annotation.
-Expect 1.
+Expect 0.
Nonterminals
@@ -285,9 +285,9 @@ tuple -> '{' '}' : c_tuple([]).
tuple -> '{' anno_expressions '}' : c_tuple('$2').
map_expr -> '~' '{' '}' '~' : #c_map{es=[]}.
-map_expr -> '~' '{' map_pairs '}' '~' : #c_map{es='$3'}.
-map_expr -> variable '~' '{' '}' '~' : #c_map{var='$1',es=[]}.
-map_expr -> variable '~' '{' map_pairs '}' '~' : #c_map{var='$1',es='$4'}.
+map_expr -> '~' '{' map_pairs '}' '~' : #c_map{es='$3'}.
+map_expr -> '~' '{' map_pairs '|' variable '}' '~' : #c_map{arg='$5',es='$3'}.
+map_expr -> '~' '{' map_pairs '|' map_expr '}' '~' : #c_map{arg='$5',es='$3'}.
map_pairs -> map_pair : ['$1'].
map_pairs -> map_pair ',' map_pairs : ['$1' | '$3'].
diff --git a/lib/compiler/src/core_pp.erl b/lib/compiler/src/core_pp.erl
index faa26ec6df..a76327457d 100644
--- a/lib/compiler/src/core_pp.erl
+++ b/lib/compiler/src/core_pp.erl
@@ -118,6 +118,12 @@ format_1(#c_literal{val=Tuple}, Ctxt) when is_tuple(Tuple) ->
format_1(#c_literal{anno=A,val=Bitstring}, Ctxt) when is_bitstring(Bitstring) ->
Segs = segs_from_bitstring(Bitstring),
format_1(#c_binary{anno=A,segments=Segs}, Ctxt);
+format_1(#c_literal{anno=A,val=M},Ctxt) when is_map(M) ->
+ Pairs = maps:to_list(M),
+ Cpairs = [#c_map_pair{op=#c_literal{val=assoc},
+ key=#c_literal{val=V},
+ val=#c_literal{val=K}} || {K,V} <- Pairs],
+ format_1(#c_map{anno=A,arg=#c_literal{val=#{}},es=Cpairs},Ctxt);
format_1(#c_var{name={I,A}}, _) ->
[core_atom(I),$/,integer_to_list(A)];
format_1(#c_var{name=V}, _) ->
@@ -161,15 +167,15 @@ format_1(#c_tuple{es=Es}, Ctxt) ->
format_hseq(Es, ",", add_indent(Ctxt, 1), fun format/2),
$}
];
-format_1(#c_map{var=#c_var{}=Var,es=Es}, Ctxt) ->
- [format_1(Var, Ctxt),
- "~{",
+format_1(#c_map{arg=#c_literal{val=M},es=Es}, Ctxt) when is_map(M),map_size(M)=:=0 ->
+ ["~{",
format_hseq(Es, ",", add_indent(Ctxt, 1), fun format/2),
"}~"
];
-format_1(#c_map{es=Es}, Ctxt) ->
+format_1(#c_map{arg=Var,es=Es}, Ctxt) ->
["~{",
format_hseq(Es, ",", add_indent(Ctxt, 1), fun format/2),
+ "|",format(Var, add_indent(Ctxt, 1)),
"}~"
];
format_1(#c_map_pair{op=#c_literal{val=assoc},key=K,val=V}, Ctxt) ->
diff --git a/lib/compiler/src/erl_bifs.erl b/lib/compiler/src/erl_bifs.erl
index 3ad3c8c690..6c75538194 100644
--- a/lib/compiler/src/erl_bifs.erl
+++ b/lib/compiler/src/erl_bifs.erl
@@ -91,6 +91,7 @@ is_pure(erlang, is_float, 1) -> true;
is_pure(erlang, is_function, 1) -> true;
is_pure(erlang, is_integer, 1) -> true;
is_pure(erlang, is_list, 1) -> true;
+is_pure(erlang, is_map, 1) -> true;
is_pure(erlang, is_number, 1) -> true;
is_pure(erlang, is_pid, 1) -> true;
is_pure(erlang, is_port, 1) -> true;
diff --git a/lib/compiler/src/sys_core_fold.erl b/lib/compiler/src/sys_core_fold.erl
index 058abd3357..b7422318b2 100644
--- a/lib/compiler/src/sys_core_fold.erl
+++ b/lib/compiler/src/sys_core_fold.erl
@@ -72,7 +72,7 @@
-import(lists, [map/2,foldl/3,foldr/3,mapfoldl/3,all/2,any/2,
reverse/1,reverse/2,member/2,nth/2,flatten/1,unzip/1]).
--import(cerl, [ann_c_cons/3,ann_c_tuple/2]).
+-import(cerl, [ann_c_cons/3,ann_c_map/3,ann_c_tuple/2]).
-include("core_parse.hrl").
@@ -246,7 +246,7 @@ expr(#c_tuple{anno=Anno,es=Es0}=Tuple, Ctxt, Sub) ->
value ->
ann_c_tuple(Anno, Es)
end;
-expr(#c_map{var=V0,es=Es0}=Map, Ctxt, Sub) ->
+expr(#c_map{anno=Anno,arg=V0,es=Es0}=Map, Ctxt, Sub) ->
Es = pair_list(Es0, Ctxt, Sub),
case Ctxt of
effect ->
@@ -254,7 +254,7 @@ expr(#c_map{var=V0,es=Es0}=Map, Ctxt, Sub) ->
expr(make_effect_seq(Es, Sub), Ctxt, Sub);
value ->
V = expr(V0, Ctxt, Sub),
- Map#c_map{var=V,es=Es}
+ ann_c_map(Anno,V,Es)
end;
expr(#c_binary{segments=Ss}=Bin0, Ctxt, Sub) ->
%% Warn for useless building, but always build the binary
@@ -1378,6 +1378,7 @@ eval_is_record(Call, _, _, _, _) -> Call.
is_not_integer(#c_literal{val=Val}) when not is_integer(Val) -> true;
is_not_integer(#c_tuple{}) -> true;
is_not_integer(#c_cons{}) -> true;
+is_not_integer(#c_map{}) -> true;
is_not_integer(_) -> false.
%% is_not_tuple(Core) -> true | false.
@@ -1385,6 +1386,7 @@ is_not_integer(_) -> false.
is_not_tuple(#c_literal{val=Val}) when not is_tuple(Val) -> true;
is_not_tuple(#c_cons{}) -> true;
+is_not_tuple(#c_map{}) -> true;
is_not_tuple(_) -> false.
%% eval_setelement(Call, Pos, Tuple, NewVal) -> Core.
@@ -2029,9 +2031,9 @@ case_opt(Arg, Cs0, Sub) ->
case_opt_args([A0|As0], Cs0, Sub, LitExpr, Acc) ->
case case_opt_arg(A0, Sub, Cs0, LitExpr) of
- error ->
+ {error,Cs1} ->
%% Nothing to be done. Move on to the next argument.
- Cs = [{Ps,C,[P|PsAcc],Bs} || {[P|Ps],C,PsAcc,Bs} <- Cs0],
+ Cs = [{Ps,C,[P|PsAcc],Bs} || {[P|Ps],C,PsAcc,Bs} <- Cs1],
case_opt_args(As0, Cs, Sub, LitExpr, [A0|Acc]);
{ok,As1,Cs} ->
%% The argument was either expanded (from tuple/list) or
@@ -2050,7 +2052,7 @@ case_opt_arg(E0, Sub, Cs, LitExpr) ->
E = maybe_replace_var(E0, Sub),
case cerl:is_data(E) of
false ->
- error;
+ {error,Cs};
true ->
case cerl:data_type(E) of
{atomic,_} ->
@@ -2100,35 +2102,44 @@ maybe_replace_var_1(E, #sub{t=Tdb}) ->
%% pattern matching is tricky, so we will give up in that case.
case_opt_lit(Lit, Cs0, LitExpr) ->
- try case_opt_lit_1(Cs0, Lit, LitExpr) of
+ Cs1 = case_opt_lit_1(Lit, Cs0, LitExpr),
+ try case_opt_lit_2(Lit, Cs1) of
Cs ->
{ok,[],Cs}
catch
throw:impossible ->
- error
+ {error,Cs1}
end.
-case_opt_lit_1([{[P|Ps],C,PsAcc,Bs0}|Cs], E, LitExpr) ->
+case_opt_lit_1(E, [{[P|_],C,_,_}=Current|Cs], LitExpr) ->
+ case cerl_clauses:match(P, E) of
+ none ->
+ %% The pattern will not match the literal. Remove the clause.
+ %% Unless the entire case expression is a literal, also
+ %% emit a warning.
+ case LitExpr of
+ false -> add_warning(C, nomatch_clause_type);
+ true -> ok
+ end,
+ case_opt_lit_1(E, Cs, LitExpr);
+ _ ->
+ [Current|case_opt_lit_1(E, Cs, LitExpr)]
+ end;
+case_opt_lit_1(_, [], _) -> [].
+
+case_opt_lit_2(E, [{[P|Ps],C,PsAcc,Bs0}|Cs]) ->
+ %% Non-matching clauses have already been removed in case_opt_lit_1/3.
case cerl_clauses:match(P, E) of
- none ->
- %% The pattern will not match the literal. Remove the clause.
- %% Unless the entire case expression is a literal, also
- %% emit a warning.
- case LitExpr of
- false -> add_warning(C, nomatch_clause_type);
- true -> ok
- end,
- case_opt_lit_1(Cs, E, LitExpr);
{true,Bs} ->
%% The pattern matches the literal. Remove the pattern
%% and update the bindings.
- [{Ps,C,PsAcc,Bs++Bs0}|case_opt_lit_1(Cs, E, LitExpr)];
+ [{Ps,C,PsAcc,Bs++Bs0}|case_opt_lit_2(E, Cs)];
{false,_} ->
%% Binary literal and pattern. We are not sure whether
%% the pattern will match.
throw(impossible)
end;
-case_opt_lit_1([], _, _) -> [].
+case_opt_lit_2(_, []) -> [].
%% case_opt_data(Expr, Clauses0, LitExpr) -> {ok,Exprs,Clauses}
diff --git a/lib/compiler/src/v3_codegen.erl b/lib/compiler/src/v3_codegen.erl
index f1331d1fe7..47a357c23d 100644
--- a/lib/compiler/src/v3_codegen.erl
+++ b/lib/compiler/src/v3_codegen.erl
@@ -960,7 +960,6 @@ select_extract_map(Src, Vs, Fail, I, Vdb, Bef, St) ->
end, {{[],[]},Bef}, Vs),
Code = case {HasKs,GetVs} of
- {[],[]} -> {[],Aft,St};
{HasKs,[]} ->
[{test,has_map_fields,{f,Fail},Rsrc,{list,HasKs}}];
{[],GetVs} ->
@@ -1553,8 +1552,7 @@ map_pair_strip_and_termsort(Es) ->
Ls = [{K,V}||{_,K,V}<-Es],
lists:sort(fun ({{_,A},_}, {{_,B},_}) -> erts_internal:cmp_term(A,B) =< 0;
({nil,_}, {{_,B},_}) -> [] =< B;
- ({{_,A},_}, {nil,_}) -> A =< [];
- ({nil,_}, {nil,_}) -> true
+ ({{_,A},_}, {nil,_}) -> A =< []
end, Ls).
%%%
diff --git a/lib/compiler/src/v3_core.erl b/lib/compiler/src/v3_core.erl
index 3d17557e01..a548ba2f7c 100644
--- a/lib/compiler/src/v3_core.erl
+++ b/lib/compiler/src/v3_core.erl
@@ -77,7 +77,8 @@
splitwith/2,keyfind/3,sort/1,foreach/2,droplast/1,last/1]).
-import(ordsets, [add_element/2,del_element/2,is_element/2,
union/1,union/2,intersection/2,subtract/2]).
--import(cerl, [ann_c_cons/3,ann_c_cons_skel/3,ann_c_tuple/2,c_tuple/1]).
+-import(cerl, [ann_c_cons/3,ann_c_cons_skel/3,ann_c_tuple/2,c_tuple/1,
+ ann_c_map/2, ann_c_map/3]).
-include("core_parse.hrl").
@@ -513,14 +514,33 @@ expr({tuple,L,Es0}, St0) ->
expr({map,L,Es0}, St0) ->
% erl_lint should make sure only #{ K => V } are allowed
% in map construction.
- {Es1,Eps,St1} = map_pair_list(Es0, St0),
- A = lineno_anno(L, St1),
- {#c_map{anno=A,es=Es1},Eps,St1};
+ try map_pair_list(Es0, St0) of
+ {Es1,Eps,St1} ->
+ A = lineno_anno(L, St1),
+ {ann_c_map(A,Es1),Eps,St1}
+ catch
+ throw:{bad_map,Warning} ->
+ St = add_warning(L, Warning, St0),
+ LineAnno = lineno_anno(L, St),
+ As = [#c_literal{anno=LineAnno,val=badarg}],
+ {#icall{anno=#a{anno=LineAnno}, %Must have an #a{}
+ module=#c_literal{anno=LineAnno,val=erlang},
+ name=#c_literal{anno=LineAnno,val=error},
+ args=As},[],St}
+ end;
expr({map,L,M0,Es0}, St0) ->
- {M1,Mps,St1} = safe(M0, St0),
- {Es1,Eps,St2} = map_pair_list(Es0, St1),
- A = lineno_anno(L, St2),
- {#c_map{anno=A,var=M1,es=Es1},Mps++Eps,St2};
+ try expr_map(M0,Es0,lineno_anno(L, St0),St0) of
+ {_,_,_}=Res -> Res
+ catch
+ throw:{bad_map,Warning} ->
+ St = add_warning(L, Warning, St0),
+ LineAnno = lineno_anno(L, St),
+ As = [#c_literal{anno=LineAnno,val=badarg}],
+ {#icall{anno=#a{anno=LineAnno}, %Must have an #a{}
+ module=#c_literal{anno=LineAnno,val=erlang},
+ name=#c_literal{anno=LineAnno,val=error},
+ args=As},[],St}
+ end;
expr({bin,L,Es0}, St0) ->
try expr_bin(Es0, lineno_anno(L, St0), St0) of
{_,_,_}=Res -> Res
@@ -730,22 +750,58 @@ make_bool_switch_guard(L, E, V, T, F) ->
{clause,NegL,[V],[],[V]}
]}.
+expr_map(M0,Es0,A,St0) ->
+ {M1,Mps,St1} = safe(M0, St0),
+ case is_valid_map_src(M1) of
+ true ->
+ case {M1,Es0} of
+ {#c_var{}, []} ->
+ %% transform M#{} to is_map(M)
+ {Vpat,St2} = new_var(St1),
+ {Fpat,St3} = new_var(St2),
+ Cs = [#iclause{
+ anno=A,
+ pats=[Vpat],
+ guard=[#icall{anno=#a{anno=A},
+ module=#c_literal{anno=A,val=erlang},
+ name=#c_literal{anno=A,val=is_map},
+ args=[Vpat]}],
+ body=[Vpat]}],
+ Fc = fail_clause([Fpat], A, #c_literal{val=badarg}),
+ {#icase{anno=#a{anno=A},args=[M1],clauses=Cs,fc=Fc},Mps,St3};
+ {_,_} ->
+ {Es1,Eps,St2} = map_pair_list(Es0, St1),
+ {ann_c_map(A,M1,Es1),Mps++Eps,St2}
+ end;
+ false -> throw({bad_map,bad_map})
+ end.
+
+is_valid_map_src(#c_literal{val = M}) when is_map(M) -> true;
+is_valid_map_src(#c_map{}) -> true;
+is_valid_map_src(#c_var{}) -> true;
+is_valid_map_src(_) -> false.
+
map_pair_list(Es, St) ->
foldr(fun
({map_field_assoc,L,K0,V0}, {Ces,Esp,St0}) ->
{K,Ep0,St1} = safe(K0, St0),
+ ok = ensure_valid_map_key(K),
{V,Ep1,St2} = safe(V0, St1),
A = lineno_anno(L, St2),
Pair = #c_map_pair{op=#c_literal{val=assoc},anno=A,key=K,val=V},
{[Pair|Ces],Ep0 ++ Ep1 ++ Esp,St2};
({map_field_exact,L,K0,V0}, {Ces,Esp,St0}) ->
{K,Ep0,St1} = safe(K0, St0),
+ ok = ensure_valid_map_key(K),
{V,Ep1,St2} = safe(V0, St1),
A = lineno_anno(L, St2),
Pair = #c_map_pair{op=#c_literal{val=exact},anno=A,key=K,val=V},
{[Pair|Ces],Ep0 ++ Ep1 ++ Esp,St2}
end, {[],[],St}, Es).
+ensure_valid_map_key(#c_literal{}) -> ok;
+ensure_valid_map_key(_) -> throw({bad_map,bad_map_key}).
+
%% try_exception([ExcpClause], St) -> {[ExcpVar],Handler,St}.
try_exception(Ecs0, St0) ->
@@ -1555,7 +1611,9 @@ pattern_map_pair({map_field_exact,L,K,V}, St) ->
{bin,L,Es0} ->
case constant_bin(Es0) of
error ->
- throw(badmatch);
+ %% this will throw a cryptic error message
+ %% but it is better than nothing
+ throw(nomatch);
Bin ->
#c_literal{anno=lineno_anno(L,St),val=Bin}
end;
@@ -2166,6 +2224,8 @@ lit_vars(Lit) -> lit_vars(Lit, []).
lit_vars(#c_cons{hd=H,tl=T}, Vs) -> lit_vars(H, lit_vars(T, Vs));
lit_vars(#c_tuple{es=Es}, Vs) -> lit_list_vars(Es, Vs);
+lit_vars(#c_map{arg=V,es=Es}, Vs) -> lit_vars(V, lit_list_vars(Es, Vs));
+lit_vars(#c_map_pair{key=K,val=V}, Vs) -> lit_vars(K, lit_vars(V, Vs));
lit_vars(#c_var{name=V}, Vs) -> add_element(V, Vs);
lit_vars(_, Vs) -> Vs. %These are atomic
@@ -2256,7 +2316,11 @@ is_simple_list(Es) -> lists:all(fun is_simple/1, Es).
format_error(nomatch) ->
"pattern cannot possibly match";
format_error(bad_binary) ->
- "binary construction will fail because of a type mismatch".
+ "binary construction will fail because of a type mismatch";
+format_error(bad_map_key) ->
+ "map construction will fail because of none literal key (large binaries are not literals)";
+format_error(bad_map) ->
+ "map construction will fail because of a type mismatch".
add_warning(Line, Term, #core{ws=Ws,file=[{file,File}]}=St) when Line >= 0 ->
St#core{ws=[{File,[{location(Line),?MODULE,Term}]}|Ws]};
diff --git a/lib/compiler/src/v3_kernel.erl b/lib/compiler/src/v3_kernel.erl
index d00dd56f30..40d2f72b4c 100644
--- a/lib/compiler/src/v3_kernel.erl
+++ b/lib/compiler/src/v3_kernel.erl
@@ -272,9 +272,18 @@ expr(#c_cons{anno=A,hd=Ch,tl=Ct}, Sub, St0) ->
expr(#c_tuple{anno=A,es=Ces}, Sub, St0) ->
{Kes,Ep,St1} = atomic_list(Ces, Sub, St0),
{#k_tuple{anno=A,es=Kes},Ep,St1};
-expr(#c_map{anno=A,var=Var0,es=Ces}, Sub, St0) ->
- {Var,[],St1} = expr(Var0, Sub, St0),
- map_split_pairs(A, Var, Ces, Sub, St1);
+expr(#c_map{anno=A,arg=Var,es=Ces}, Sub, St0) ->
+ try expr_map(A,Var,Ces,Sub,St0) of
+ {_,_,_}=Res -> Res
+ catch
+ throw:bad_map ->
+ St1 = add_warning(get_line(A), bad_map, A, St0),
+ Erl = #c_literal{val=erlang},
+ Name = #c_literal{val=error},
+ Args = [#c_literal{val=badarg}],
+ Error = #c_call{anno=A,module=Erl,name=Name,args=Args},
+ expr(Error, Sub, St1)
+ end;
expr(#c_binary{anno=A,segments=Cv}, Sub, St0) ->
try atomic_bin(Cv, Sub, St0) of
{Kv,Ep,St1} ->
@@ -496,6 +505,21 @@ translate_match_fail_1(Anno, As, Sub, #kern{ff=FF}) ->
translate_fc(Args) ->
[#c_literal{val=function_clause},make_list(Args)].
+expr_map(A,Var0,Ces,Sub,St0) ->
+ %% An extra pass of validation of Map src because of inlining
+ {Var,Mps,St1} = expr(Var0, Sub, St0),
+ case is_valid_map_src(Var) of
+ true ->
+ {Km,Eps,St2} = map_split_pairs(A, Var, Ces, Sub, St1),
+ {Km,Eps++Mps,St2};
+ false -> throw(bad_map)
+ end.
+
+is_valid_map_src(#k_map{}) -> true;
+is_valid_map_src(#k_literal{val=M}) when is_map(M) -> true;
+is_valid_map_src(#k_var{}) -> true;
+is_valid_map_src(_) -> false.
+
map_split_pairs(A, Var, Ces, Sub, St0) ->
%% two steps
%% 1. force variables
@@ -557,8 +581,7 @@ map_key_clean(#k_literal{val=V}) -> {k_literal,V};
map_key_clean(#k_int{val=V}) -> {k_int,V};
map_key_clean(#k_float{val=V}) -> {k_float,V};
map_key_clean(#k_atom{val=V}) -> {k_atom,V};
-map_key_clean(#k_nil{}) -> k_nil;
-map_key_clean(#k_var{name=V}) -> {k_var,V}.
+map_key_clean(#k_nil{}) -> k_nil.
%% call_type(Module, Function, Arity) -> call | bif | apply | error.
@@ -1986,7 +2009,9 @@ format_error(nomatch_shadow) ->
format_error(bad_call) ->
"invalid module and/or function name; this call will always fail";
format_error(bad_segment_size) ->
- "binary construction will fail because of a type mismatch".
+ "binary construction will fail because of a type mismatch";
+format_error(bad_map) ->
+ "map construction will fail because of a type mismatch".
add_warning(none, Term, Anno, #kern{ws=Ws}=St) ->
File = get_file(Anno),
diff --git a/lib/compiler/src/v3_kernel_pp.erl b/lib/compiler/src/v3_kernel_pp.erl
index b4e486f97c..b33eba50eb 100644
--- a/lib/compiler/src/v3_kernel_pp.erl
+++ b/lib/compiler/src/v3_kernel_pp.erl
@@ -104,20 +104,26 @@ format_1(#k_tuple{es=Es}, Ctxt) ->
format_hseq(Es, ",", ctxt_bump_indent(Ctxt, 1), fun format/2),
$}
];
-format_1(#k_map{var=#k_var{}=Var,es=Es}, Ctxt) ->
- [$~,${,
+format_1(#k_map{var=#k_literal{val=M},op=assoc,es=Es}, Ctxt) when is_map(M), map_size(M) =:= 0 ->
+ ["~{",
format_hseq(Es, ",", ctxt_bump_indent(Ctxt, 1), fun format/2),
- " | ",format_1(Var, Ctxt),
- $},$~
+ "}~"
];
-format_1(#k_map{op=assoc,es=Es}, Ctxt) ->
+format_1(#k_map{var=#k_literal{val=M},op=exact,es=Es}, Ctxt) when is_map(M), map_size(M) =:= 0 ->
+ ["::{",
+ format_hseq(Es, ",", ctxt_bump_indent(Ctxt, 1), fun format/2),
+ "}::"
+ ];
+format_1(#k_map{var=Var,op=assoc,es=Es}, Ctxt) ->
["~{",
format_hseq(Es, ",", ctxt_bump_indent(Ctxt, 1), fun format/2),
+ " | ",format_1(Var, Ctxt),
"}~"
];
-format_1(#k_map{es=Es}, Ctxt) ->
+format_1(#k_map{var=Var,op=exact,es=Es}, Ctxt) ->
["::{",
format_hseq(Es, ",", ctxt_bump_indent(Ctxt, 1), fun format/2),
+ " | ",format_1(Var, Ctxt),
"}::"
];
format_1(#k_map_pair{key=K,val=V}, Ctxt) ->
diff --git a/lib/compiler/src/v3_life.erl b/lib/compiler/src/v3_life.erl
index c4f54a7970..cd4b5fd674 100644
--- a/lib/compiler/src/v3_life.erl
+++ b/lib/compiler/src/v3_life.erl
@@ -324,8 +324,7 @@ type(k_binary) -> binary;
type(k_bin_seg) -> bin_seg;
type(k_bin_int) -> bin_int;
type(k_bin_end) -> bin_end;
-type(k_map) -> map;
-type(k_map_pair) -> map_pair.
+type(k_map) -> map.
%% variable(Klit) -> Lit.
%% var_list([Klit]) -> [Lit].
diff --git a/lib/compiler/test/core_SUITE_data/map_core_test.core b/lib/compiler/test/core_SUITE_data/map_core_test.core
index 7ece8a8bbd..2aa853d450 100644
--- a/lib/compiler/test/core_SUITE_data/map_core_test.core
+++ b/lib/compiler/test/core_SUITE_data/map_core_test.core
@@ -67,7 +67,7 @@ module 'map_core_test' ['map_core_test'/0,
(Val, V)
in let <_cor5> =
%% Line 21
- M~{~<1337,_cor4>,~<'val',_cor2>}~
+ ~{~<1337,_cor4>,~<'val',_cor2>|M}~
in %% Line 21
apply 'call'/2
(_cor5, Vs)
@@ -92,4 +92,4 @@ module 'map_core_test' ['map_core_test'/0,
fun (_cor0) ->
call 'erlang':'get_module_info'
('map_core_test', _cor0)
-end \ No newline at end of file
+end
diff --git a/lib/compiler/test/core_fold_SUITE.erl b/lib/compiler/test/core_fold_SUITE.erl
index 9c986576d5..6a7036d728 100644
--- a/lib/compiler/test/core_fold_SUITE.erl
+++ b/lib/compiler/test/core_fold_SUITE.erl
@@ -23,7 +23,7 @@
t_element/1,setelement/1,t_length/1,append/1,t_apply/1,bifs/1,
eq/1,nested_call_in_case/1,guard_try_catch/1,coverage/1,
unused_multiple_values_error/1,unused_multiple_values/1,
- multiple_aliases/1,redundant_boolean_clauses/1]).
+ multiple_aliases/1,redundant_boolean_clauses/1,mixed_matching_clauses/1]).
-export([foo/0,foo/1,foo/2,foo/3]).
@@ -40,7 +40,7 @@ groups() ->
[t_element,setelement,t_length,append,t_apply,bifs,
eq,nested_call_in_case,guard_try_catch,coverage,
unused_multiple_values_error,unused_multiple_values,
- multiple_aliases,redundant_boolean_clauses]}].
+ multiple_aliases,redundant_boolean_clauses,mixed_matching_clauses]}].
init_per_suite(Config) ->
@@ -373,5 +373,15 @@ redundant_boolean_clauses(Config) when is_list(Config) ->
true -> yes
end.
+mixed_matching_clauses(Config) when is_list(Config) ->
+ 0 = case #{} of
+ #{} -> 0;
+ a -> 1
+ end,
+ 0 = case <<>> of
+ <<>> -> 0;
+ a -> 1
+ end,
+ ok.
id(I) -> I.
diff --git a/lib/compiler/test/error_SUITE.erl b/lib/compiler/test/error_SUITE.erl
index 5cdf429a5f..bd877bb528 100644
--- a/lib/compiler/test/error_SUITE.erl
+++ b/lib/compiler/test/error_SUITE.erl
@@ -23,7 +23,7 @@
-export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1,
init_per_group/2,end_per_group/2,
head_mismatch_line/1,warnings_as_errors/1, bif_clashes/1,
- transforms/1,forbidden_maps/1]).
+ transforms/1,forbidden_maps/1,bad_utf8/1]).
%% Used by transforms/1 test case.
-export([parse_transform/2]).
@@ -36,7 +36,8 @@ all() ->
groups() ->
[{p,test_lib:parallel(),
- [head_mismatch_line,warnings_as_errors,bif_clashes,transforms,forbidden_maps]}].
+ [head_mismatch_line,warnings_as_errors,bif_clashes,
+ transforms,forbidden_maps,bad_utf8]}].
init_per_suite(Config) ->
Config.
@@ -254,6 +255,23 @@ forbidden_maps(Config) when is_list(Config) ->
[] = run2(Config, Ts1),
ok.
+bad_utf8(Config) ->
+ Ts = [{bad_utf8,
+ %% If coding is specified explicitly as utf-8, there should be
+ %% a compilation error; we must not fallback to parsing the
+ %% file in latin-1 mode.
+ <<"%% coding: utf-8
+ %% Bj",246,"rn
+ t() -> \"",246,"\".
+ ">>,
+ [],
+ {error,[{2,epp,cannot_parse},
+ {2,file_io_server,invalid_unicode}],
+ []}
+ }],
+ [] = run2(Config, Ts),
+ ok.
+
run(Config, Tests) ->
?line File = test_filename(Config),
@@ -318,6 +336,7 @@ run_test(Test0, File, Warnings, WriteBeam) ->
?line compile:file(File, [binary,report|Warnings]),
%% Test result of compilation.
+ io:format("~p\n", [Opts]),
?line Res = case compile:file(File, Opts) of
{ok,Mod,_,[{_File,Ws}]} ->
%io:format("compile:file(~s,~p) ->~n~p~n",
@@ -335,6 +354,11 @@ run_test(Test0, File, Warnings, WriteBeam) ->
%io:format("compile:file(~s,~p) ->~n~p~n",
% [File,Opts,_ZZ]),
{error,Es,Ws};
+ {error,[{XFile,Es1},{XFile,Es2}],Ws} = _ZZ
+ when is_list(XFile) ->
+ %io:format("compile:file(~s,~p) ->~n~p~n",
+ % [File,Opts,_ZZ]),
+ {error,Es1++Es2,Ws};
{error,Es,[{_File,Ws}]} = _ZZ->
%io:format("compile:file(~s,~p) ->~n~p~n",
% [File,Opts,_ZZ]),
diff --git a/lib/compiler/test/map_SUITE.erl b/lib/compiler/test/map_SUITE.erl
index b7e27afef1..cc018e4305 100644
--- a/lib/compiler/test/map_SUITE.erl
+++ b/lib/compiler/test/map_SUITE.erl
@@ -40,10 +40,13 @@
t_build_and_match_over_alloc/1,
t_build_and_match_empty_val/1,
t_build_and_match_val/1,
+ t_build_and_match_nil/1,
+ t_build_and_match_structure/1,
%% errors in 17.0-rc1
t_update_values/1,
- t_expand_map_update/1
+ t_expand_map_update/1,
+ t_export/1
]).
suite() -> [].
@@ -67,10 +70,13 @@ all() -> [
t_build_and_match_over_alloc,
t_build_and_match_empty_val,
t_build_and_match_val,
+ t_build_and_match_nil,
+ t_build_and_match_structure,
%% errors in 17.0-rc1
t_update_values,
- t_expand_map_update
+ t_expand_map_update,
+ t_export
].
groups() -> [].
@@ -116,6 +122,7 @@ t_build_and_match_literals(Config) when is_list(Config) ->
{'EXIT',{{badmatch,_},_}} = (catch (#{x:=3} = id({a,b,c}))),
{'EXIT',{{badmatch,_},_}} = (catch (#{x:=3} = id(#{y=>3}))),
{'EXIT',{{badmatch,_},_}} = (catch (#{x:=3} = id(#{x=>"three"}))),
+ {'EXIT',{badarg,_}} = (catch id(#{<<0:258>> =>"three"})),
ok.
t_build_and_match_aliasing(Config) when is_list(Config) ->
@@ -232,7 +239,8 @@ t_update_assoc(Config) when is_list(Config) ->
%% Errors cases.
BadMap = id(badmap),
{'EXIT',{badarg,_}} = (catch BadMap#{nonexisting=>val}),
-
+ {'EXIT',{badarg,_}} = (catch <<>>#{nonexisting=>val}),
+ {'EXIT',{badarg,_}} = (catch M0#{<<0:257>> => val}), %% limitation
ok.
t_update_exact(Config) when is_list(Config) ->
@@ -260,6 +268,8 @@ t_update_exact(Config) when is_list(Config) ->
{'EXIT',{badarg,_}} = (catch M0#{1.0:=v,1.0=>v2}),
{'EXIT',{badarg,_}} = (catch M0#{42.0:=v,42:=v2}),
{'EXIT',{badarg,_}} = (catch M0#{42=>v1,42.0:=v2,42:=v3}),
+ {'EXIT',{badarg,_}} = (catch <<>>#{nonexisting:=val}),
+ {'EXIT',{badarg,_}} = (catch M0#{<<0:257>> := val}), %% limitation
ok.
t_update_values(Config) when is_list(Config) ->
@@ -285,6 +295,12 @@ t_expand_map_update(Config) when is_list(Config) ->
#{<<"hello">> := <<"les gens">>} = M,
ok.
+t_export(Config) when is_list(Config) ->
+ Raclette = id(#{}),
+ case brie of brie -> Fromage = Raclette end,
+ Raclette = Fromage#{},
+ ok.
+
check_val(#{val1:=V1, val2:=V2},V1,V2) -> ok.
get_val(#{ "wazzup" := _, val := V}) -> V;
@@ -553,6 +569,32 @@ t_build_and_match_val(Config) when is_list(Config) ->
test_server:fail({no_match, Other})
end.
+t_build_and_match_nil(Config) when is_list(Config) ->
+ %% literals removed the coverage
+ V1 = id(cookie),
+ V2 = id(cake),
+ V3 = id(crisps),
+
+ #{ [] := V1, "treat" := V2, {your,treat} := V3 } = id(#{
+ {your,treat} => V3,
+ "treat" => V2,
+ [] => V1 }),
+ #{ [] := V3, [] := V3 } = id(#{ [] => V1, [] => V3 }),
+ ok.
+
+t_build_and_match_structure(Config) when is_list(Config) ->
+ V2 = id("it"),
+ S = id([42,{"hi", "=)", #{ "a" => 42, any => any, val => "get_" ++ V2}}]),
+
+ %% match deep map values
+ V2 = case S of
+ [42,{"hi",_, #{ "a" := 42, val := "get_" ++ V1, any := _ }}] -> V1
+ end,
+ %% match deep map
+ ok = case S of
+ [42,{"hi",_, #{ }}] -> ok
+ end,
+ ok.
%% Use this function to avoid compile-time evaluation of an expression.
id(I) -> I.
diff --git a/lib/compiler/test/warnings_SUITE.erl b/lib/compiler/test/warnings_SUITE.erl
index de56a59e12..ad4ad91f74 100644
--- a/lib/compiler/test/warnings_SUITE.erl
+++ b/lib/compiler/test/warnings_SUITE.erl
@@ -37,8 +37,9 @@
-export([pattern/1,pattern2/1,pattern3/1,pattern4/1,
guard/1,bad_arith/1,bool_cases/1,bad_apply/1,
- files/1,effect/1,bin_opt_info/1,bin_construction/1, comprehensions/1,
- maps/1,redundant_boolean_clauses/1]).
+ files/1,effect/1,bin_opt_info/1,bin_construction/1,
+ comprehensions/1,maps/1,redundant_boolean_clauses/1,
+ latin1_fallback/1]).
% Default timetrap timeout (set in init_per_testcase).
-define(default_timeout, ?t:minutes(2)).
@@ -63,7 +64,7 @@ groups() ->
[pattern,pattern2,pattern3,pattern4,guard,
bad_arith,bool_cases,bad_apply,files,effect,
bin_opt_info,bin_construction,comprehensions,maps,
- redundant_boolean_clauses]}].
+ redundant_boolean_clauses,latin1_fallback]}].
init_per_suite(Config) ->
Config.
@@ -572,7 +573,48 @@ maps(Config) when is_list(Config) ->
">>,
[],
{warnings,[{3,sys_core_fold,no_clause_match},
- {9,sys_core_fold,nomatch_clause_type}]}}],
+ {9,sys_core_fold,nomatch_clause_type}]}},
+ {bad_map_src1,
+ <<"
+ t() ->
+ M = {a,[]},
+ {'EXIT',{badarg,_}} = (catch(M#{ a => 1})),
+ ok.
+ ">>,
+ [],
+ {warnings,[{4,v3_kernel,bad_map}]}},
+ {bad_map_src2,
+ <<"
+ t() ->
+ M = id({a,[]}),
+ {'EXIT',{badarg,_}} = (catch(M#{ a => 1})),
+ ok.
+ id(I) -> I.
+ ">>,
+ [inline],
+ {warnings,[{4,v3_kernel,bad_map}]}},
+ {bad_map_src3,
+ <<"
+ t() ->
+ {'EXIT',{badarg,_}} = (catch <<>>#{ a := 1}),
+ ok.
+ ">>,
+ [],
+ {warnings,[{3,v3_core,bad_map}]}},
+ {bad_map_literal_key,
+ <<"
+ t() ->
+ V = id(1),
+ M = id(#{ <<$h,$i>> => V }),
+ V = case M of
+ #{ <<0:257>> := Val } -> Val;
+ #{ <<$h,$i>> := Val } -> Val
+ end,
+ ok.
+ id(I) -> I.
+ ">>,
+ [],
+ {warnings,[{6,v3_core,nomatch}]}}],
run(Config, Ts),
ok.
@@ -591,6 +633,37 @@ redundant_boolean_clauses(Config) when is_list(Config) ->
run(Config, Ts),
ok.
+latin1_fallback(Conf) when is_list(Conf) ->
+ DataDir = ?privdir,
+ IncFile = filename:join(DataDir, "include_me.hrl"),
+ file:write_file(IncFile, <<"%% ",246," in include file\n">>),
+ Ts1 = [{latin1_fallback1,
+ %% Test that the compiler fall backs to latin-1 with
+ %% a warning if a file has no encoding and does not
+ %% contain correct UTF-8 sequences.
+ <<"%% Bj",246,"rn
+ t(_) -> \"",246,"\";
+ t(x) -> ok.
+ ">>,
+ [],
+ {warnings,[{1,compile,reparsing_invalid_unicode},
+ {3,sys_core_fold,{nomatch_shadow,2}}]}}],
+ [] = run(Conf, Ts1),
+
+ Ts2 = [{latin1_fallback2,
+ %% Test that the compiler fall backs to latin-1 with
+ %% a warning if a file has no encoding and does not
+ %% contain correct UTF-8 sequences.
+ <<"
+
+ -include(\"include_me.hrl\").
+ ">>,
+ [],
+ {warnings,[{1,compile,reparsing_invalid_unicode}]}
+ }],
+ [] = run(Conf, Ts2),
+ ok.
+
%%%
%%% End of test cases.
%%%
diff --git a/lib/compiler/vsn.mk b/lib/compiler/vsn.mk
index cbdf57f177..c0c3d56472 100644
--- a/lib/compiler/vsn.mk
+++ b/lib/compiler/vsn.mk
@@ -1 +1 @@
-COMPILER_VSN = 4.9.4
+COMPILER_VSN = 5.0
diff --git a/lib/cosEvent/src/cosEvent.app.src b/lib/cosEvent/src/cosEvent.app.src
index c1cb9e0cc9..66b0d2e168 100644
--- a/lib/cosEvent/src/cosEvent.app.src
+++ b/lib/cosEvent/src/cosEvent.app.src
@@ -38,7 +38,8 @@
{registered, []},
{applications, [orber, stdlib, kernel]},
{env, []},
- {mod, {cosEventApp, []}}
+ {mod, {cosEventApp, []}},
+ {runtime_dependencies, ["stdlib-2.0","orber-3.6.27","kernel-3.0","erts-6.0"]}
]}.
diff --git a/lib/cosEvent/vsn.mk b/lib/cosEvent/vsn.mk
index 6745bee079..40bf1ba49d 100644
--- a/lib/cosEvent/vsn.mk
+++ b/lib/cosEvent/vsn.mk
@@ -1,3 +1,3 @@
-COSEVENT_VSN = 2.1.14
+COSEVENT_VSN = 2.1.15
diff --git a/lib/cosEventDomain/src/cosEventDomain.app.src b/lib/cosEventDomain/src/cosEventDomain.app.src
index e4307e1f99..60114b6a91 100644
--- a/lib/cosEventDomain/src/cosEventDomain.app.src
+++ b/lib/cosEventDomain/src/cosEventDomain.app.src
@@ -27,5 +27,7 @@
{registered, []},
{applications, [orber, stdlib, kernel]},
{env, []},
- {mod, {cosEventDomainApp, []}}
+ {mod, {cosEventDomainApp, []}},
+ {runtime_dependencies, ["stdlib-2.0","orber-3.6.27","kernel-3.0","erts-6.0",
+ "cosNotification-1.1.21"]}
]}.
diff --git a/lib/cosEventDomain/vsn.mk b/lib/cosEventDomain/vsn.mk
index e9cf92395a..6317ed3c22 100644
--- a/lib/cosEventDomain/vsn.mk
+++ b/lib/cosEventDomain/vsn.mk
@@ -1,3 +1,3 @@
-COSEVENTDOMAIN_VSN = 1.1.13
+COSEVENTDOMAIN_VSN = 1.1.14
diff --git a/lib/cosFileTransfer/src/cosFileTransfer.app.src b/lib/cosFileTransfer/src/cosFileTransfer.app.src
index 31d94b6f0d..21226b0c6b 100644
--- a/lib/cosFileTransfer/src/cosFileTransfer.app.src
+++ b/lib/cosFileTransfer/src/cosFileTransfer.app.src
@@ -36,6 +36,8 @@
{registered, []},
{applications, [orber, stdlib, kernel]},
{env, []},
- {mod, {cosFileTransferApp, []}}
+ {mod, {cosFileTransferApp, []}},
+ {runtime_dependencies, ["stdlib-2.0","ssl-5.3.4","orber-3.6.27","kernel-3.0",
+ "inets-5.10","erts-6.0","cosProperty-1.1.17"]}
]}.
diff --git a/lib/cosFileTransfer/vsn.mk b/lib/cosFileTransfer/vsn.mk
index cf33926334..f52a1bd800 100644
--- a/lib/cosFileTransfer/vsn.mk
+++ b/lib/cosFileTransfer/vsn.mk
@@ -1 +1 @@
-COSFILETRANSFER_VSN = 1.1.15
+COSFILETRANSFER_VSN = 1.1.16
diff --git a/lib/cosNotification/src/cosNotification.app.src b/lib/cosNotification/src/cosNotification.app.src
index 04beac36e8..ad02eb4421 100644
--- a/lib/cosNotification/src/cosNotification.app.src
+++ b/lib/cosNotification/src/cosNotification.app.src
@@ -116,5 +116,7 @@
{registered, [cosNotificationSup, oe_cosNotificationFactory]},
{applications, [orber, stdlib, kernel]},
{env, []},
- {mod, {cosNotificationApp, []}}
+ {mod, {cosNotificationApp, []}},
+ {runtime_dependencies, ["stdlib-2.0","orber-3.6.27","kernel-3.0","erts-6.0",
+ "cosTime-1.1.14","cosEvent-2.1.15"]}
]}.
diff --git a/lib/cosNotification/vsn.mk b/lib/cosNotification/vsn.mk
index ea59800164..28d6ec71bf 100644
--- a/lib/cosNotification/vsn.mk
+++ b/lib/cosNotification/vsn.mk
@@ -1,2 +1,2 @@
-COSNOTIFICATION_VSN = 1.1.20
+COSNOTIFICATION_VSN = 1.1.21
diff --git a/lib/cosProperty/src/cosProperty.app.src b/lib/cosProperty/src/cosProperty.app.src
index 3099e904f7..b977bb5984 100644
--- a/lib/cosProperty/src/cosProperty.app.src
+++ b/lib/cosProperty/src/cosProperty.app.src
@@ -41,5 +41,7 @@
{registered, [oe_cosPropertySup]},
{applications, [orber, stdlib, kernel]},
{env, []},
- {mod, {cosProperty, []}}
+ {mod, {cosProperty, []}},
+ {runtime_dependencies, ["stdlib-2.0","orber-3.6.27","mnesia-4.12",
+ "kernel-3.0","erts-6.0"]}
]}.
diff --git a/lib/cosProperty/vsn.mk b/lib/cosProperty/vsn.mk
index ac7820216e..0f546a2da8 100644
--- a/lib/cosProperty/vsn.mk
+++ b/lib/cosProperty/vsn.mk
@@ -1,2 +1,2 @@
-COSPROPERTY_VSN = 1.1.16
+COSPROPERTY_VSN = 1.1.17
diff --git a/lib/cosTime/src/cosTime.app.src b/lib/cosTime/src/cosTime.app.src
index 191ee5f3db..cd01de35cb 100644
--- a/lib/cosTime/src/cosTime.app.src
+++ b/lib/cosTime/src/cosTime.app.src
@@ -26,5 +26,7 @@
{registered, [oe_cosTimeSup, oe_cosTimerEventService]},
{applications, [orber, stdlib, kernel]},
{env, []},
- {mod, {cosTime, []}}
+ {mod, {cosTime, []}},
+ {runtime_dependencies, ["stdlib-2.0","orber-3.6.27","kernel-3.0","erts-6.0",
+ "cosEvent-2.1.15"]}
]}.
diff --git a/lib/cosTime/vsn.mk b/lib/cosTime/vsn.mk
index 02cd669222..9e9e5c0250 100644
--- a/lib/cosTime/vsn.mk
+++ b/lib/cosTime/vsn.mk
@@ -1,2 +1,3 @@
-COSTIME_VSN = 1.1.13
+COSTIME_VSN = 1.1.14
+
diff --git a/lib/cosTransactions/src/cosTransactions.app.src b/lib/cosTransactions/src/cosTransactions.app.src
index 52769b1711..6b99915ad6 100644
--- a/lib/cosTransactions/src/cosTransactions.app.src
+++ b/lib/cosTransactions/src/cosTransactions.app.src
@@ -39,5 +39,6 @@
{registered, [cosTransactions_sup, oe_cosTransactionsFactory]},
{applications, [orber, stdlib, kernel]},
{env, []},
- {mod, {cosTransactions, []}}
+ {mod, {cosTransactions, []}},
+ {runtime_dependencies, ["stdlib-2.0","orber-3.6.27","kernel-3.0","erts-6.0"]}
]}.
diff --git a/lib/cosTransactions/vsn.mk b/lib/cosTransactions/vsn.mk
index 5414270a3d..7aed212523 100644
--- a/lib/cosTransactions/vsn.mk
+++ b/lib/cosTransactions/vsn.mk
@@ -1 +1 @@
-COSTRANSACTIONS_VSN = 1.2.13
+COSTRANSACTIONS_VSN = 1.2.14
diff --git a/lib/crypto/doc/src/crypto_app.xml b/lib/crypto/doc/src/crypto_app.xml
index 6d26076c04..1d10773401 100644
--- a/lib/crypto/doc/src/crypto_app.xml
+++ b/lib/crypto/doc/src/crypto_app.xml
@@ -1,11 +1,11 @@
-<?xml version="1.0" encoding="iso-8859-1" ?>
+<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE appref SYSTEM "appref.dtd">
<appref>
<header>
<copyright>
<year>1999</year>
- <year>2013</year>
+ <year>2014</year>
<holder>Ericsson AB, All Rights Reserved</holder>
</copyright>
<legalnotice>
diff --git a/lib/crypto/src/crypto.app.src b/lib/crypto/src/crypto.app.src
index d3084ff336..823a27ee39 100644
--- a/lib/crypto/src/crypto.app.src
+++ b/lib/crypto/src/crypto.app.src
@@ -23,6 +23,7 @@
crypto_ec_curves]},
{registered, []},
{applications, [kernel, stdlib]},
- {env, []}]}.
+ {env, []},
+ {runtime_dependencies, ["erts-6.0","stdlib-2.0","kernel-3.0"]}]}.
diff --git a/lib/crypto/vsn.mk b/lib/crypto/vsn.mk
index 98c071cf87..a2bd6f851a 100644
--- a/lib/crypto/vsn.mk
+++ b/lib/crypto/vsn.mk
@@ -1 +1 @@
-CRYPTO_VSN = 3.2
+CRYPTO_VSN = 3.3
diff --git a/lib/debugger/src/dbg_ieval.erl b/lib/debugger/src/dbg_ieval.erl
index 1d36aae8ee..0653ce4c00 100644
--- a/lib/debugger/src/dbg_ieval.erl
+++ b/lib/debugger/src/dbg_ieval.erl
@@ -663,12 +663,16 @@ expr({map,Line,Fs0}, Bs0, Ieval) ->
expr({map,Line,E0,Fs0}, Bs0, Ieval0) ->
Ieval = Ieval0#ieval{line=Line,top=false},
{value,E,Bs1} = expr(E0, Bs0, Ieval),
- {Fs,Bs2} = eval_map_fields(Fs0, Bs1, Ieval),
- Value = lists:foldl(fun ({map_assoc,K,V}, Mi) -> maps:put(K,V,Mi);
- ({map_exact,K,V}, Mi) -> maps:update(K,V,Mi) end,
- E, Fs),
- {value,Value,Bs2};
-
+ case E of
+ #{} ->
+ {Fs,Bs2} = eval_map_fields(Fs0, Bs1, Ieval),
+ Value = lists:foldl(fun ({map_assoc,K,V}, Mi) -> maps:put(K,V,Mi);
+ ({map_exact,K,V}, Mi) -> maps:update(K,V,Mi)
+ end, E, Fs),
+ {value,Value,Bs2};
+ _ ->
+ exception(error, {badarg,E}, Bs1, Ieval)
+ end;
%% A block of statements
expr({block,Line,Es},Bs,Ieval) ->
seq(Es, Bs, Ieval#ieval{line=Line});
diff --git a/lib/debugger/src/dbg_iload.erl b/lib/debugger/src/dbg_iload.erl
index 266cf239dd..ad05a7c529 100644
--- a/lib/debugger/src/dbg_iload.erl
+++ b/lib/debugger/src/dbg_iload.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1998-2010. All Rights Reserved.
+%% Copyright Ericsson AB 1998-2014. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -42,18 +42,21 @@
load_mod(Mod, File, Binary, Db) ->
Flag = process_flag(trap_exit, true),
- Pid = spawn_link(fun () -> load_mod1(Mod, File, Binary, Db) end),
+ Pid = spawn_link(load_mod1(Mod, File, Binary, Db)),
receive
{'EXIT', Pid, What} ->
process_flag(trap_exit, Flag),
What
end.
--spec load_mod1(atom(), file:filename(), binary(), ets:tid()) -> no_return().
+-spec load_mod1(atom(), file:filename(), binary(), ets:tid()) ->
+ fun(() -> no_return()).
load_mod1(Mod, File, Binary, Db) ->
- store_module(Mod, File, Binary, Db),
- exit({ok, Mod}).
+ fun() ->
+ store_module(Mod, File, Binary, Db),
+ exit({ok, Mod})
+ end.
%%====================================================================
%% Internal functions
diff --git a/lib/debugger/src/debugger.app.src b/lib/debugger/src/debugger.app.src
index 84fb98c94e..f102385d39 100644
--- a/lib/debugger/src/debugger.app.src
+++ b/lib/debugger/src/debugger.app.src
@@ -46,4 +46,6 @@
int
]},
{registered, [dbg_iserver, dbg_wx_mon, dbg_wx_winman]},
- {applications, [kernel, stdlib]}]}.
+ {applications, [kernel, stdlib]},
+ {runtime_dependencies, ["wx-1.2","stdlib-2.0","kernel-3.0","erts-6.0",
+ "compiler-5.0"]}]}.
diff --git a/lib/debugger/src/debugger.erl b/lib/debugger/src/debugger.erl
index 8a2ac28df5..77fd0acb70 100644
--- a/lib/debugger/src/debugger.erl
+++ b/lib/debugger/src/debugger.erl
@@ -51,12 +51,6 @@
%% ------------------------------
%% Help window for creating new breakpoints.
%%
-%% dbg_wx_edit, dbg_wx_edit_win
-%% --------------------------------------
-%% Help window for editing terms, used for setting backtrace size
-%% (i.e. how many stack frames to display in the attach process window)
-%% and changing variable values.
-%%
%% dbg_wx_interpret, dbg_wx_filedialog_win
%% --------------------------------------
%% Help window for selecting modules to interpret.
diff --git a/lib/debugger/test/int_eval_SUITE.erl b/lib/debugger/test/int_eval_SUITE.erl
index 4ffcf7888e..ecbd68ab40 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, stacktrace/1]).
+ interpreted_exit/1, otp_8310/1, stacktrace/1, maps/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, stacktrace].
+ interpreted_exit, otp_8310, stacktrace, maps].
groups() ->
[].
@@ -291,6 +291,11 @@ stacktrace(Config) when is_list(Config) ->
end,
ok.
+maps(Config) when is_list(Config) ->
+ Fun = fun () -> ?IM:empty_map_update([camembert]) end,
+ {'EXIT',{{badarg,[camembert]},_}} = spawn_eval(Fun),
+ ok.
+
do_eval(Config, Mod) ->
?line DataDir = ?config(data_dir, Config),
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 ab485fd350..e047a33d8c 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
@@ -29,6 +29,7 @@
-export([more_catch/1,more_nocatch/1,exit_me/0]).
-export([f/1, f_try/1, f_catch/1]).
-export([otp_5837/1, otp_8310/0]).
+-export([empty_map_update/1]).
%% Internal exports.
-export([echo/2,my_subtract/2,catch_a_ball/0,throw_a_ball/0]).
@@ -241,3 +242,5 @@ otp_8310() ->
true = begin (X3 = true) orelse X3, X3 end,
false = begin (X4 = false) orelse X4, X4 end,
ok.
+
+empty_map_update(Map) -> Map#{}.
diff --git a/lib/debugger/test/map_SUITE.erl b/lib/debugger/test/map_SUITE.erl
index 741ad2dc41..0076193725 100644
--- a/lib/debugger/test/map_SUITE.erl
+++ b/lib/debugger/test/map_SUITE.erl
@@ -226,8 +226,8 @@ t_update_map_expressions(Config) when is_list(Config) ->
#{ "a" :=1, "b":=42, "c":=42 } = (maps:from_list([{"a",1},{"b",2}]))#{ "b" := 42, "c" => 42 },
%% Error cases, FIXME: should be 'badmap'?
- {'EXIT',{badarg,_}} = (catch (id(<<>>))#{ a := 42, b => 2 }),
- {'EXIT',{badarg,_}} = (catch (id([]))#{ a := 42, b => 2 }),
+ {'EXIT',{{badarg,<<>>},_}} = (catch (id(<<>>))#{ a := 42, b => 2 }),
+ {'EXIT',{{badarg,[]},_}} = (catch (id([]))#{ a := 42, b => 2 }),
ok.
@@ -244,7 +244,7 @@ t_update_assoc(Config) when is_list(Config) ->
%% Errors cases.
BadMap = id(badmap),
- {'EXIT',{badarg,_}} = (catch BadMap#{nonexisting=>val}),
+ {'EXIT',{{badarg,BadMap},_}} = (catch BadMap#{nonexisting=>val}),
ok.
diff --git a/lib/debugger/vsn.mk b/lib/debugger/vsn.mk
index a245e26a55..cd107599e9 100644
--- a/lib/debugger/vsn.mk
+++ b/lib/debugger/vsn.mk
@@ -1 +1 @@
-DEBUGGER_VSN = 3.2.12
+DEBUGGER_VSN = 4.0
diff --git a/lib/dialyzer/src/dialyzer.app.src b/lib/dialyzer/src/dialyzer.app.src
index 0d048b607e..1756800c4f 100644
--- a/lib/dialyzer/src/dialyzer.app.src
+++ b/lib/dialyzer/src/dialyzer.app.src
@@ -44,4 +44,7 @@
dialyzer_worker]},
{registered, []},
{applications, [compiler, gs, hipe, kernel, stdlib, wx]},
- {env, []}]}.
+ {env, []},
+ {runtime_dependencies, ["wx-1.2","syntax_tools-1.6.14","stdlib-2.0",
+ "kernel-3.0","hipe-3.10.3","erts-6.0",
+ "compiler-5.0"]}]}.
diff --git a/lib/dialyzer/src/dialyzer.erl b/lib/dialyzer/src/dialyzer.erl
index bb7e39dfda..cec94a49fd 100644
--- a/lib/dialyzer/src/dialyzer.erl
+++ b/lib/dialyzer/src/dialyzer.erl
@@ -2,7 +2,7 @@
%%-----------------------------------------------------------------------
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2006-2013. All Rights Reserved.
+%% Copyright Ericsson AB 2006-2014. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -172,7 +172,7 @@ run(Opts) ->
end,
case dialyzer_cl:start(OptsRecord) of
{?RET_DISCREPANCIES, Warnings} -> Warnings;
- {?RET_NOTHING_SUSPICIOUS, []} -> []
+ {?RET_NOTHING_SUSPICIOUS, _} -> []
end
catch
throw:{dialyzer_error, ErrorMsg} ->
@@ -447,7 +447,6 @@ message_to_string({opaque_size, [SizeType, Size]}) ->
message_to_string({opaque_call, [M, F, Args, Culprit, OpaqueType]}) ->
io_lib:format("The call ~s:~s~s breaks the opaqueness of the term ~s :: ~s\n",
[M, F, Args, Culprit, OpaqueType]);
-
%%----- Warnings for concurrency errors --------------------
message_to_string({race_condition, [M, F, Args, Reason]}) ->
io_lib:format("The call ~w:~w~s ~s\n", [M, F, Args, Reason]);
@@ -474,7 +473,14 @@ 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({callback_info_missing, [B]}) ->
- io_lib:format("Callback info about the ~w behaviour is not available\n", [B]).
+ io_lib:format("Callback info about the ~w behaviour is not available\n", [B]);
+%%----- Warnings for unknown functions, types, and behaviours -------------
+message_to_string({unknown_type, {M, F, A}}) ->
+ io_lib:format("Unknown type ~w:~w/~w", [M, F, A]);
+message_to_string({unknown_function, {M, F, A}}) ->
+ io_lib:format("Unknown function ~w:~w/~w", [M, F, A]);
+message_to_string({unknown_behaviour, B}) ->
+ io_lib:format("Unknown behaviour ~w", [B]).
%%-----------------------------------------------------------------------------
%% Auxiliary functions below
@@ -557,4 +563,4 @@ form_position_string(ArgNs) ->
ordinal(1) -> "1st";
ordinal(2) -> "2nd";
ordinal(3) -> "3rd";
-ordinal(N) when is_integer(N) -> io_lib:format("~wth",[N]).
+ordinal(N) when is_integer(N) -> io_lib:format("~wth", [N]).
diff --git a/lib/dialyzer/src/dialyzer.hrl b/lib/dialyzer/src/dialyzer.hrl
index 105a174e31..9a25f86512 100644
--- a/lib/dialyzer/src/dialyzer.hrl
+++ b/lib/dialyzer/src/dialyzer.hrl
@@ -2,7 +2,7 @@
%%%
%%% %CopyrightBegin%
%%%
-%%% Copyright Ericsson AB 2006-2012. All Rights Reserved.
+%%% Copyright Ericsson AB 2006-2014. All Rights Reserved.
%%%
%%% The contents of this file are subject to the Erlang Public License,
%%% Version 1.1, (the "License"); you may not use this file except in
@@ -58,6 +58,7 @@
-define(WARN_RACE_CONDITION, warn_race_condition).
-define(WARN_BEHAVIOUR, warn_behaviour).
-define(WARN_UNDEFINED_CALLBACK, warn_undefined_callbacks).
+-define(WARN_UNKNOWN, warn_unknown).
%%
%% The following type has double role:
@@ -73,7 +74,7 @@
| ?WARN_CONTRACT_SUPERTYPE | ?WARN_CALLGRAPH
| ?WARN_UNMATCHED_RETURN | ?WARN_RACE_CONDITION
| ?WARN_BEHAVIOUR | ?WARN_CONTRACT_RANGE
- | ?WARN_UNDEFINED_CALLBACK.
+ | ?WARN_UNDEFINED_CALLBACK | ?WARN_UNKNOWN.
%%
%% This is the representation of each warning as they will be returned
@@ -88,12 +89,6 @@
-type dial_error() :: any(). %% XXX: underspecified
%%--------------------------------------------------------------------
-%% THIS TYPE SHOULD ONE DAY DISAPPEAR -- IT DOES NOT BELONG HERE
-%%--------------------------------------------------------------------
-
--type ordset(T) :: [T] . %% XXX: temporarily
-
-%%--------------------------------------------------------------------
%% Basic types used either in the record definitions below or in other
%% parts of the application
%%--------------------------------------------------------------------
@@ -143,7 +138,7 @@
init_plts = [] :: [file:filename()],
include_dirs = [] :: [file:filename()],
output_plt = none :: 'none' | file:filename(),
- legal_warnings = ordsets:new() :: ordset(dial_warn_tag()),
+ legal_warnings = ordsets:new() :: ordsets:ordset(dial_warn_tag()),
report_mode = normal :: rep_mode(),
erlang_mode = false :: boolean(),
use_contracts = true :: boolean(),
@@ -167,4 +162,4 @@
dialyzer_timing:end_stamp(Server),
Var
end).
--define(timing(Server, Msg, Expr),?timing(Server, Msg, _T, Expr)).
+-define(timing(Server, Msg, Expr), ?timing(Server, Msg, _T, Expr)).
diff --git a/lib/dialyzer/src/dialyzer_analysis_callgraph.erl b/lib/dialyzer/src/dialyzer_analysis_callgraph.erl
index 2a633c5e37..6a33a2acb3 100644
--- a/lib/dialyzer/src/dialyzer_analysis_callgraph.erl
+++ b/lib/dialyzer/src/dialyzer_analysis_callgraph.erl
@@ -249,7 +249,7 @@ compile_and_store(Files, #analysis_state{codeserver = CServer,
timing_server = Timing,
parent = Parent} = State) ->
send_log(Parent, "Reading files and computing callgraph... "),
- {T1, _} = statistics(runtime),
+ {T1, _} = statistics(wall_clock),
Callgraph = dialyzer_callgraph:new(),
CompileInit = make_compile_init(State, Callgraph),
{{Failed, NoWarn, Modules}, NextLabel} =
@@ -272,13 +272,13 @@ compile_and_store(Files, #analysis_state{codeserver = CServer,
[[Reason || {_Filename, Reason} <- Failed]]),
exit({error, Msg})
end,
- {T2, _} = statistics(runtime),
+ {T2, _} = statistics(wall_clock),
Msg1 = io_lib:format("done in ~.2f secs\nRemoving edges... ", [(T2-T1)/1000]),
send_log(Parent, Msg1),
Callgraph =
?timing(Timing, "clean", _C2,
cleanup_callgraph(State, CServer2, Callgraph, Modules)),
- {T3, _} = statistics(runtime),
+ {T3, _} = statistics(wall_clock),
Msg2 = io_lib:format("done in ~.2f secs\n", [(T3-T2)/1000]),
send_log(Parent, Msg2),
{Callgraph, sets:from_list(NoWarn), CServer2}.
@@ -620,9 +620,9 @@ dump_callgraph(CallGraph, State, #analysis{callgraph_file = File} = Analysis) ->
Extension = filename:extension(File),
Start_Msg = io_lib:format("Dumping the callgraph... ", []),
send_log(State#analysis_state.parent, Start_Msg),
- {T1, _} = statistics(runtime),
+ {T1, _} = statistics(wall_clock),
dump_callgraph(CallGraph, State, Analysis, Extension),
- {T2, _} = statistics(runtime),
+ {T2, _} = statistics(wall_clock),
Finish_Msg = io_lib:format("done in ~2f secs\n", [(T2-T1)/1000]),
send_log(State#analysis_state.parent, Finish_Msg),
ok.
diff --git a/lib/dialyzer/src/dialyzer_cl.erl b/lib/dialyzer/src/dialyzer_cl.erl
index 3e68d64d53..3e7d9dfa99 100644
--- a/lib/dialyzer/src/dialyzer_cl.erl
+++ b/lib/dialyzer/src/dialyzer_cl.erl
@@ -504,7 +504,7 @@ hipe_compile(Files, #options{erlang_mode = ErlangMode} = Options) ->
_ ->
Mods = [lists, dict, digraph, digraph_utils, ets,
gb_sets, gb_trees, ordsets, sets, sofs,
- cerl, cerl_trees, erl_types, erl_bif_types,
+ cerl, erl_types, cerl_trees, erl_bif_types,
dialyzer_analysis_callgraph, dialyzer, dialyzer_behaviours,
dialyzer_codeserver, dialyzer_contracts,
dialyzer_coordinator, dialyzer_dataflow, dialyzer_dep,
@@ -533,7 +533,7 @@ hc(Mod) ->
case code:is_module_native(Mod) of
true -> ok;
false ->
- %% io:format(" ~s", [Mod]),
+ %% io:format(" ~w", [Mod]),
{ok, Mod} = hipe:c(Mod),
ok
end.
@@ -656,7 +656,8 @@ return_value(State = #cl_state{erlang_mode = ErlangMode,
mod_deps = ModDeps,
output_plt = OutputPlt,
plt_info = PltInfo,
- stored_warnings = StoredWarnings},
+ stored_warnings = StoredWarnings,
+ legal_warnings = LegalWarnings},
Plt) ->
case OutputPlt =:= none of
true -> ok;
@@ -676,16 +677,33 @@ return_value(State = #cl_state{erlang_mode = ErlangMode,
maybe_close_output_file(State),
{RetValue, []};
true ->
- {RetValue, process_warnings(StoredWarnings)}
+ Unknown =
+ case ordsets:is_element(?WARN_UNKNOWN, LegalWarnings) of
+ true ->
+ unknown_functions(State) ++
+ unknown_types(State) ++
+ unknown_behaviours(State);
+ false -> []
+ end,
+ UnknownWarnings =
+ [{?WARN_UNKNOWN, {_Filename = "", _Line = 0}, W} || W <- Unknown],
+ AllWarnings =
+ UnknownWarnings ++ process_warnings(StoredWarnings),
+ {RetValue, AllWarnings}
end.
+unknown_functions(#cl_state{external_calls = Calls}) ->
+ [{unknown_function, MFA} || MFA <- Calls].
+
print_ext_calls(#cl_state{report_mode = quiet}) ->
ok;
print_ext_calls(#cl_state{output = Output,
external_calls = Calls,
stored_warnings = Warnings,
- output_format = Format}) ->
- case Calls =:= [] of
+ output_format = Format,
+ legal_warnings = LegalWarnings}) ->
+ case not ordsets:is_element(?WARN_UNKNOWN, LegalWarnings)
+ orelse Calls =:= [] of
true -> ok;
false ->
case Warnings =:= [] of
@@ -708,14 +726,19 @@ do_print_ext_calls(Output, [{M,F,A}|T], Before) ->
do_print_ext_calls(_, [], _) ->
ok.
+unknown_types(#cl_state{external_types = Types}) ->
+ [{unknown_type, MFA} || MFA <- Types].
+
print_ext_types(#cl_state{report_mode = quiet}) ->
ok;
print_ext_types(#cl_state{output = Output,
external_calls = Calls,
external_types = Types,
stored_warnings = Warnings,
- output_format = Format}) ->
- case Types =:= [] of
+ output_format = Format,
+ legal_warnings = LegalWarnings}) ->
+ case not ordsets:is_element(?WARN_UNKNOWN, LegalWarnings)
+ orelse Types =:= [] of
true -> ok;
false ->
case Warnings =:= [] andalso Calls =:= [] of
@@ -738,6 +761,15 @@ do_print_ext_types(Output, [{M,F,A}|T], Before) ->
do_print_ext_types(_, [], _) ->
ok.
+unknown_behaviours(#cl_state{unknown_behaviours = DupBehaviours,
+ legal_warnings = LegalWarnings}) ->
+ case ordsets:is_element(?WARN_BEHAVIOUR, LegalWarnings) of
+ false -> [];
+ true ->
+ Behaviours = lists:usort(DupBehaviours),
+ [{unknown_behaviour, B} || B <- Behaviours]
+ end.
+
%%print_unknown_behaviours(#cl_state{report_mode = quiet}) ->
%% ok;
print_unknown_behaviours(#cl_state{output = Output,
diff --git a/lib/dialyzer/src/dialyzer_contracts.erl b/lib/dialyzer/src/dialyzer_contracts.erl
index 46eaeaa303..283031eb9a 100644
--- a/lib/dialyzer/src/dialyzer_contracts.erl
+++ b/lib/dialyzer/src/dialyzer_contracts.erl
@@ -20,6 +20,8 @@
-module(dialyzer_contracts).
+-compile(export_all).
+
-export([check_contract/2,
check_contracts/4,
contracts_without_fun/3,
@@ -439,7 +441,8 @@ contract_from_form([], _RecDict, _FileLine, TypeAcc, FormAcc) ->
{lists:reverse(TypeAcc), lists:reverse(FormAcc)}.
process_constraints(Constrs, RecDict, ExpTypes, AllRecords) ->
- Init = initialize_constraints(Constrs, RecDict, ExpTypes, AllRecords),
+ Init0 = initialize_constraints(Constrs, RecDict, ExpTypes, AllRecords),
+ Init = remove_cycles(Init0),
constraints_fixpoint(Init, RecDict, ExpTypes, AllRecords).
initialize_constraints(Constrs, RecDict, ExpTypes, AllRecords) ->
@@ -479,12 +482,9 @@ constraints_fixpoint(OldVarDict, Constrs, RecDict, ExpTypes, AllRecords) ->
constraints_fixpoint(NewVarDict, Constrs, RecDict, ExpTypes, AllRecords)
end.
--define(TYPE_LIMIT, 4).
-
final_form(Form, RecDict, ExpTypes, AllRecords, VarDict) ->
T1 = erl_types:t_from_form(Form, RecDict, VarDict),
- T2 = erl_types:t_solve_remote(T1, ExpTypes, AllRecords),
- erl_types:t_limit(T2, ?TYPE_LIMIT).
+ erl_types:t_solve_remote(T1, ExpTypes, AllRecords).
constraints_to_dict(Constrs, RecDict, ExpTypes, AllRecords, VarDict) ->
Subtypes =
@@ -499,6 +499,74 @@ constraints_to_subs([C|Rest], RecDict, ExpTypes, AllRecords, VarDict, Acc) ->
NewAcc = [{subtype, T1, T2}|Acc],
constraints_to_subs(Rest, RecDict, ExpTypes, AllRecords, VarDict, NewAcc).
+%% Replaces variables with '_' when necessary to break up cycles among
+%% the constraints.
+
+remove_cycles(Constrs0) ->
+ Uses = find_uses(Constrs0),
+ G = digraph:new(),
+ Vs0 = [V || {V, _} <- Uses] ++ [V || {_, V} <- Uses],
+ Vs = lists:usort(Vs0),
+ lists:foreach(fun(V) -> _ = digraph:add_vertex(G, V) end, Vs),
+ lists:foreach(fun({From, To}) ->
+ _ = digraph:add_edge(G, {From, To}, From, To, [])
+ end, Uses),
+ ok = remove_cycles(G, Vs),
+ ToRemove = ordsets:subtract(ordsets:from_list(Uses),
+ ordsets:from_list(digraph:edges(G))),
+ Constrs = remove_uses(ToRemove, Constrs0),
+ digraph:delete(G),
+ Constrs.
+
+find_uses([{Var, Form}|Constrs]) ->
+ UsedVars = form_vars(Form, []),
+ VarName = erl_types:t_var_name(Var),
+ [{VarName, UsedVar} || UsedVar <- UsedVars] ++ find_uses(Constrs);
+find_uses([]) ->
+ [].
+
+form_vars({var, _, '_'}, Vs) -> Vs;
+form_vars({var, _, V}, Vs) -> [V|Vs];
+form_vars(T, Vs) when is_tuple(T) ->
+ form_vars(tuple_to_list(T), Vs);
+form_vars([E|Es], Vs) ->
+ form_vars(Es, form_vars(E, Vs));
+form_vars(_, Vs) -> Vs.
+
+remove_cycles(G, Vs) ->
+ NumberOfEdges = digraph:no_edges(G),
+ lists:foreach(fun(V) ->
+ case digraph:get_cycle(G, V) of
+ false -> true;
+ [V] -> digraph:del_edge(G, {V, V});
+ [V, V1|_] -> digraph:del_edge(G, {V, V1})
+ end
+ end, Vs),
+ case digraph:no_edges(G) =:= NumberOfEdges of
+ true -> ok;
+ false -> remove_cycles(G, Vs)
+ end.
+
+remove_uses([], Constrs) -> Constrs;
+remove_uses([{Var, Use}|ToRemove], Constrs0) ->
+ Constrs = remove_uses(Var, Use, Constrs0),
+ remove_uses(ToRemove, Constrs).
+
+remove_uses(_Var, _Use, []) -> [];
+remove_uses(Var, Use, [Constr|Constrs]) ->
+ {V, Form} = Constr,
+ case erl_types:t_var_name(V) =:= Var of
+ true -> [{V, remove_use(Form, Use)}|Constrs];
+ false -> [Constr|remove_uses(Var, Use, Constrs)]
+ end.
+
+remove_use({var, L, V}, V) -> {var, L, '_'};
+remove_use(T, V) when is_tuple(T) ->
+ list_to_tuple(remove_use(tuple_to_list(T), V));
+remove_use([E|Es], V) ->
+ [remove_use(E, V)|remove_use(Es, V)];
+remove_use(T, _V) -> T.
+
%% Gets the most general domain of a list of domains of all
%% the overloaded contracts
diff --git a/lib/dialyzer/src/dialyzer_dataflow.erl b/lib/dialyzer/src/dialyzer_dataflow.erl
index 692684cd99..e0873b17f8 100644
--- a/lib/dialyzer/src/dialyzer_dataflow.erl
+++ b/lib/dialyzer/src/dialyzer_dataflow.erl
@@ -363,20 +363,24 @@ traverse_list([], Map, State, Acc) ->
handle_apply(Tree, Map, State) ->
Args = cerl:apply_args(Tree),
Op = cerl:apply_op(Tree),
- {State1, Map1, ArgTypes} = traverse_list(Args, Map, State),
- {State2, Map2, OpType} = traverse(Op, Map1, State1),
+ {State0, Map1, ArgTypes} = traverse_list(Args, Map, State),
+ {State1, Map2, OpType} = traverse(Op, Map1, State0),
case any_none(ArgTypes) of
true ->
- {State2, Map2, t_none()};
+ {State1, Map2, t_none()};
false ->
- {CallSitesKnown, FunList} =
- case state__lookup_call_site(Tree, State2) of
- error -> {false, []};
- {ok, [external]} -> {false, []};
- {ok, List} -> {true, List}
+ FunList =
+ case state__lookup_call_site(Tree, State) of
+ error -> [external]; %% so that we go directly in the fallback
+ {ok, List} -> List
end,
- case CallSitesKnown of
- false ->
+ FunInfoList = [{local, state__fun_info(Fun, State)} || Fun <- FunList],
+ case
+ handle_apply_or_call(FunInfoList, Args, ArgTypes, Map2, Tree, State1)
+ of
+ {had_external, State2} ->
+ %% Fallback: use whatever info we collected from traversing the op
+ %% instead of the result that has been generalized to t_any().
Arity = length(Args),
OpType1 = t_inf(OpType, t_fun(Arity, t_any())),
case t_is_none(OpType1) of
@@ -408,25 +412,23 @@ handle_apply(Tree, Map, State) ->
{State2, enter_type(Op, OpType1, Map3), Range}
end
end;
- true ->
- FunInfoList = [{local, state__fun_info(Fun, State)}
- || Fun <- FunList],
- handle_apply_or_call(FunInfoList, Args, ArgTypes, Map2, Tree, State1)
+ Normal -> Normal
end
end.
handle_apply_or_call(FunInfoList, Args, ArgTypes, Map, Tree, State) ->
None = t_none(),
handle_apply_or_call(FunInfoList, Args, ArgTypes, Map, Tree, State,
- [None || _ <- ArgTypes], None).
+ [None || _ <- ArgTypes], None, false).
handle_apply_or_call([{local, external}|Left], Args, ArgTypes, Map, Tree, State,
- _AccArgTypes, _AccRet) ->
+ _AccArgTypes, _AccRet, _HadExternal) ->
handle_apply_or_call(Left, Args, ArgTypes, Map, Tree, State,
- ArgTypes, t_any());
+ ArgTypes, t_any(), true);
handle_apply_or_call([{TypeOfApply, {Fun, Sig, Contr, LocalRet}}|Left],
Args, ArgTypes, Map, Tree,
- #state{opaques = Opaques} = State, AccArgTypes, AccRet) ->
+ #state{opaques = Opaques} = State,
+ AccArgTypes, AccRet, HadExternal) ->
Any = t_any(),
AnyArgs = [Any || _ <- Args],
GenSig = {AnyArgs, fun(_) -> t_any() end},
@@ -573,11 +575,16 @@ handle_apply_or_call([{TypeOfApply, {Fun, Sig, Contr, LocalRet}}|Left],
NewAccRet = t_sup(AccRet, TotalRet),
?debug("NewAccRet: ~s\n", [t_to_string(NewAccRet)]),
handle_apply_or_call(Left, Args, ArgTypes, Map, Tree,
- State3, NewAccArgTypes, NewAccRet);
+ State3, NewAccArgTypes, NewAccRet, HadExternal);
handle_apply_or_call([], Args, _ArgTypes, Map, _Tree, State,
- AccArgTypes, AccRet) ->
- NewMap = enter_type_lists(Args, AccArgTypes, Map),
- {State, NewMap, AccRet}.
+ AccArgTypes, AccRet, HadExternal) ->
+ case HadExternal of
+ false ->
+ NewMap = enter_type_lists(Args, AccArgTypes, Map),
+ {State, NewMap, AccRet};
+ true ->
+ {had_external, State}
+ end.
apply_fail_reason(FailedSig, FailedBif, FailedContract) ->
if
diff --git a/lib/dialyzer/src/dialyzer_dep.erl b/lib/dialyzer/src/dialyzer_dep.erl
index f1ac41ff04..572e60278d 100644
--- a/lib/dialyzer/src/dialyzer_dep.erl
+++ b/lib/dialyzer/src/dialyzer_dep.erl
@@ -55,11 +55,11 @@
%%
%% Letrecs = a dict mapping var labels to their recursive definition.
%% top-level letrecs are not included as they are handled
-%% separatedly.
+%% separately.
%%
-spec analyze(cerl:c_module()) ->
- {dict:dict(), ordset('external' | label()), dict:dict(), dict:dict()}.
+ {dict:dict(), ordsets:ordset('external' | label()), dict:dict(), dict:dict()}.
analyze(Tree) ->
%% io:format("Handling ~w\n", [cerl:atom_val(cerl:module_name(Tree))]),
@@ -124,8 +124,10 @@ traverse(Tree, Out, State, CurrentFun) ->
TmpState = state__add_deps(Label, O1, State),
state__add_deps(CurrentFun, O2,TmpState)
end,
- {BodyFuns, State2} = traverse(Body, Out, State1,
- cerl_trees:get_label(Tree)),
+ Vars = cerl:fun_vars(Tree),
+ Out1 = bind_single(Vars, output(set__singleton(external)), Out),
+ {BodyFuns, State2} =
+ traverse(Body, Out1, State1, cerl_trees:get_label(Tree)),
{output(set__singleton(Label)), state__add_esc(BodyFuns, State2)};
'let' ->
Vars = cerl:let_vars(Tree),
diff --git a/lib/dialyzer/src/dialyzer_gui_wx.erl b/lib/dialyzer/src/dialyzer_gui_wx.erl
index 08f31c1e13..7070fa240d 100644
--- a/lib/dialyzer/src/dialyzer_gui_wx.erl
+++ b/lib/dialyzer/src/dialyzer_gui_wx.erl
@@ -61,7 +61,7 @@
init_plt :: dialyzer_plt:plt(),
dir_entry :: wx:wx_object(),
file_box :: wx:wx_object(),
- files_to_analyze :: ordset(string()),
+ files_to_analyze :: ordsets:ordset(string()),
gui :: wx:wx_object(),
log :: wx:wx_object(),
menu :: menu(),
diff --git a/lib/dialyzer/src/dialyzer_options.erl b/lib/dialyzer/src/dialyzer_options.erl
index 06672e595f..a92b8b1958 100644
--- a/lib/dialyzer/src/dialyzer_options.erl
+++ b/lib/dialyzer/src/dialyzer_options.erl
@@ -2,7 +2,7 @@
%%-----------------------------------------------------------------------
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2006-2012. All Rights Reserved.
+%% Copyright Ericsson AB 2006-2014. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -51,7 +51,8 @@ build(Opts) ->
?WARN_CONTRACT_TYPES,
?WARN_CONTRACT_SYNTAX,
?WARN_BEHAVIOUR,
- ?WARN_UNDEFINED_CALLBACK],
+ ?WARN_UNDEFINED_CALLBACK,
+ ?WARN_UNKNOWN],
DefaultWarns1 = ordsets:from_list(DefaultWarns),
InitPlt = dialyzer_plt:get_default_plt(),
DefaultOpts = #options{},
@@ -310,6 +311,8 @@ build_warnings([Opt|Opts], Warnings) ->
ordsets:add_element(?WARN_CONTRACT_SUBTYPE, Warnings);
underspecs ->
ordsets:add_element(?WARN_CONTRACT_SUPERTYPE, Warnings);
+ no_unknown ->
+ ordsets:del_element(?WARN_UNKNOWN, Warnings);
OtherAtom ->
bad_option("Unknown dialyzer warning option", OtherAtom)
end,
diff --git a/lib/dialyzer/src/dialyzer_races.erl b/lib/dialyzer/src/dialyzer_races.erl
index 48fcde8014..b1f849b16f 100644
--- a/lib/dialyzer/src/dialyzer_races.erl
+++ b/lib/dialyzer/src/dialyzer_races.erl
@@ -85,6 +85,12 @@
-type race_tag() :: 'whereis_register' | 'whereis_unregister'
| 'ets_lookup_insert' | 'mnesia_dirty_read_write'.
+%% The following type is similar to the dial_warning() type but has a
+%% tag which is local to this module and is not propagated to outside
+-type dial_race_warning() :: {race_warn_tag(), file_line(), {atom(), [term()]}}.
+-type race_warn_tag() :: ?WARN_WHEREIS_REGISTER | ?WARN_WHEREIS_UNREGISTER
+ | ?WARN_ETS_LOOKUP_INSERT | ?WARN_MNESIA_DIRTY_READ_WRITE.
+
-record(beg_clause, {arg :: var_to_map1(),
pats :: var_to_map1(),
guard :: cerl:cerl()}).
@@ -103,7 +109,7 @@
args :: args(),
arg_types :: [erl_types:erl_type()],
vars :: [core_vars()],
- state :: _, %% XXX: recursive
+ state :: dialyzer_dataflow:state(),
file_line :: file_line(),
var_map :: dict:dict()}).
-record(fun_call, {caller :: dialyzer_callgraph:mfa_or_funlbl(),
@@ -141,7 +147,7 @@
race_tags = [] :: [#race_fun{}],
%% true for fun types and warning mode
race_analysis = false :: boolean(),
- race_warnings = [] :: [dial_warning()]}).
+ race_warnings = [] :: [dial_race_warning()]}).
%%% ===========================================================================
%%%
@@ -1763,7 +1769,7 @@ ets_list_args(MaybeList) ->
catch _:_ -> [?no_label]
end;
false -> [ets_tuple_args(MaybeList)]
- end.
+ end.
ets_list_argtypes(ListStr) ->
ListStr1 = string:strip(ListStr, left, $[),
diff --git a/lib/dialyzer/test/opaque_SUITE_data/dialyzer_options b/lib/dialyzer/test/opaque_SUITE_data/dialyzer_options
index 3ff26b87db..44a65f6e90 100644
--- a/lib/dialyzer/test/opaque_SUITE_data/dialyzer_options
+++ b/lib/dialyzer/test/opaque_SUITE_data/dialyzer_options
@@ -1 +1 @@
-{dialyzer_options, [{warnings, [no_unused, no_return]}]}.
+{dialyzer_options, [{warnings, [no_unused, no_return, no_unknown]}]}.
diff --git a/lib/dialyzer/test/opaque_SUITE_data/src/modules/opaque_erl_scan.erl b/lib/dialyzer/test/opaque_SUITE_data/src/modules/opaque_erl_scan.erl
index 9ecd4f92a1..24d0793a7c 100644
--- a/lib/dialyzer/test/opaque_SUITE_data/src/modules/opaque_erl_scan.erl
+++ b/lib/dialyzer/test/opaque_SUITE_data/src/modules/opaque_erl_scan.erl
@@ -1,4 +1,4 @@
-%% -*- coding: utf-8 -*-
+%%
%%
%% %CopyrightBegin%
%%
diff --git a/lib/dialyzer/test/options1_SUITE_data/dialyzer_options b/lib/dialyzer/test/options1_SUITE_data/dialyzer_options
index c612e77d3e..65d233ac0d 100644
--- a/lib/dialyzer/test/options1_SUITE_data/dialyzer_options
+++ b/lib/dialyzer/test/options1_SUITE_data/dialyzer_options
@@ -1,2 +1,2 @@
-{dialyzer_options, [{include_dirs, ["my_include"]}, {defines, [{'COMPILER_VSN', 42}]}, {warnings, [no_improper_lists]}]}.
+{dialyzer_options, [{include_dirs, ["my_include"]}, {defines, [{'COMPILER_VSN', 42}]}, {warnings, [no_improper_lists, no_unknown]}]}.
{time_limit, 30}.
diff --git a/lib/dialyzer/test/r9c_SUITE_data/dialyzer_options b/lib/dialyzer/test/r9c_SUITE_data/dialyzer_options
index e00e23bb66..ba0e6b1ad7 100644
--- a/lib/dialyzer/test/r9c_SUITE_data/dialyzer_options
+++ b/lib/dialyzer/test/r9c_SUITE_data/dialyzer_options
@@ -1,2 +1,2 @@
-{dialyzer_options, [{defines, [{vsn, 42}]}]}.
+{dialyzer_options, [{defines, [{vsn, 42}]}, {warnings, [no_unknown]}]}.
{time_limit, 20}.
diff --git a/lib/dialyzer/test/race_SUITE_data/dialyzer_options b/lib/dialyzer/test/race_SUITE_data/dialyzer_options
index 44e1720715..6992fc6c40 100644
--- a/lib/dialyzer/test/race_SUITE_data/dialyzer_options
+++ b/lib/dialyzer/test/race_SUITE_data/dialyzer_options
@@ -1 +1 @@
-{dialyzer_options, [{warnings, [race_conditions]}]}.
+{dialyzer_options, [{warnings, [race_conditions, no_unknown]}]}.
diff --git a/lib/dialyzer/test/small_SUITE_data/dialyzer_options b/lib/dialyzer/test/small_SUITE_data/dialyzer_options
index 50991c9bc5..0d91699e4d 100644
--- a/lib/dialyzer/test/small_SUITE_data/dialyzer_options
+++ b/lib/dialyzer/test/small_SUITE_data/dialyzer_options
@@ -1 +1 @@
-{dialyzer_options, []}.
+{dialyzer_options, [{warnings, [no_unknown]}]}.
diff --git a/lib/dialyzer/test/small_SUITE_data/results/contracts_with_subtypes b/lib/dialyzer/test/small_SUITE_data/results/contracts_with_subtypes
index bfa33cd296..fbdd182358 100644
--- a/lib/dialyzer/test/small_SUITE_data/results/contracts_with_subtypes
+++ b/lib/dialyzer/test/small_SUITE_data/results/contracts_with_subtypes
@@ -1,27 +1,28 @@
contracts_with_subtypes.erl:106: The call contracts_with_subtypes:rec_arg({'a','b'}) breaks the contract (Arg) -> 'ok' when is_subtype(Arg,{'a',A} | {'b',B}), is_subtype(A,'a' | {'b',B}), is_subtype(B,'b' | {'a',A})
contracts_with_subtypes.erl:107: The call contracts_with_subtypes:rec_arg({'b','a'}) breaks the contract (Arg) -> 'ok' when is_subtype(Arg,{'a',A} | {'b',B}), is_subtype(A,'a' | {'b',B}), is_subtype(B,'b' | {'a',A})
-contracts_with_subtypes.erl:108: The call contracts_with_subtypes:rec_arg({'a',{'b','a'}}) breaks the contract (Arg) -> 'ok' when is_subtype(Arg,{'a',A} | {'b',B}), is_subtype(A,'a' | {'b',B}), is_subtype(B,'b' | {'a',A})
contracts_with_subtypes.erl:109: The call contracts_with_subtypes:rec_arg({'b',{'a','b'}}) breaks the contract (Arg) -> 'ok' when is_subtype(Arg,{'a',A} | {'b',B}), is_subtype(A,'a' | {'b',B}), is_subtype(B,'b' | {'a',A})
-contracts_with_subtypes.erl:110: The call contracts_with_subtypes:rec_arg({'a',{'b',{'a','b'}}}) breaks the contract (Arg) -> 'ok' when is_subtype(Arg,{'a',A} | {'b',B}), is_subtype(A,'a' | {'b',B}), is_subtype(B,'b' | {'a',A})
-contracts_with_subtypes.erl:111: The call contracts_with_subtypes:rec_arg({'b',{'a',{'b','a'}}}) breaks the contract (Arg) -> 'ok' when is_subtype(Arg,{'a',A} | {'b',B}), is_subtype(A,'a' | {'b',B}), is_subtype(B,'b' | {'a',A})
-contracts_with_subtypes.erl:142: The pattern 1 can never match the type string()
-contracts_with_subtypes.erl:145: The pattern 'alpha' can never match the type {'ok',_} | {'ok',_,string()}
-contracts_with_subtypes.erl:147: The pattern 42 can never match the type {'ok',_} | {'ok',_,string()}
-contracts_with_subtypes.erl:163: The pattern 'alpha' can never match the type {'ok',_}
-contracts_with_subtypes.erl:165: The pattern 42 can never match the type {'ok',_}
-contracts_with_subtypes.erl:183: The pattern 'alpha' can never match the type {'ok',_}
-contracts_with_subtypes.erl:185: The pattern 42 can never match the type {'ok',_}
-contracts_with_subtypes.erl:202: The pattern 1 can never match the type string()
-contracts_with_subtypes.erl:205: The pattern {'ok', _} can never match the type {'ok',_,string()}
-contracts_with_subtypes.erl:206: The pattern 'alpha' can never match the type {'ok',_,string()}
-contracts_with_subtypes.erl:207: The pattern {'ok', 42} can never match the type {'ok',_,string()}
-contracts_with_subtypes.erl:208: The pattern 42 can never match the type {'ok',_,string()}
-contracts_with_subtypes.erl:234: Function flat_ets_new_t/0 has no local return
-contracts_with_subtypes.erl:235: The call contracts_with_subtypes:flat_ets_new(12,[]) breaks the contract (Name,Options) -> atom() when is_subtype(Name,atom()), is_subtype(Options,[Option]), is_subtype(Option,'set' | 'ordered_set' | 'bag' | 'duplicate_bag' | 'public' | 'protected' | 'private' | 'named_table' | {'keypos',integer()} | {'heir',pid(),term()} | {'heir','none'} | {'write_concurrency',boolean()} | {'read_concurrency',boolean()} | 'compressed')
+contracts_with_subtypes.erl:135: The call contracts_with_subtypes:rec2({'a','b'}) breaks the contract (Arg) -> 'ok' when is_subtype(Arg,ab())
+contracts_with_subtypes.erl:136: The call contracts_with_subtypes:rec2({'b','a'}) breaks the contract (Arg) -> 'ok' when is_subtype(Arg,ab())
+contracts_with_subtypes.erl:137: The call contracts_with_subtypes:rec2({'a',{'b','a'}}) breaks the contract (Arg) -> 'ok' when is_subtype(Arg,ab())
+contracts_with_subtypes.erl:138: The call contracts_with_subtypes:rec2({'b',{'a','b'}}) breaks the contract (Arg) -> 'ok' when is_subtype(Arg,ab())
+contracts_with_subtypes.erl:171: The pattern 1 can never match the type string()
+contracts_with_subtypes.erl:174: The pattern 'alpha' can never match the type {'ok',_} | {'ok',_,string()}
+contracts_with_subtypes.erl:176: The pattern 42 can never match the type {'ok',_} | {'ok',_,string()}
+contracts_with_subtypes.erl:192: The pattern 'alpha' can never match the type {'ok',_}
+contracts_with_subtypes.erl:194: The pattern 42 can never match the type {'ok',_}
+contracts_with_subtypes.erl:212: The pattern 'alpha' can never match the type {'ok',_}
+contracts_with_subtypes.erl:214: The pattern 42 can never match the type {'ok',_}
+contracts_with_subtypes.erl:231: The pattern 1 can never match the type string()
+contracts_with_subtypes.erl:234: The pattern {'ok', _} can never match the type {'ok',_,string()}
+contracts_with_subtypes.erl:235: The pattern 'alpha' can never match the type {'ok',_,string()}
+contracts_with_subtypes.erl:236: The pattern {'ok', 42} can never match the type {'ok',_,string()}
+contracts_with_subtypes.erl:237: The pattern 42 can never match the type {'ok',_,string()}
contracts_with_subtypes.erl:23: Invalid type specification for function contracts_with_subtypes:extract2/0. The success typing is () -> 'something'
-contracts_with_subtypes.erl:261: Function factored_ets_new_t/0 has no local return
-contracts_with_subtypes.erl:262: The call contracts_with_subtypes:factored_ets_new(12,[]) breaks the contract (Name,Options) -> atom() when is_subtype(Name,atom()), is_subtype(Options,[Option]), is_subtype(Option,Type | Access | 'named_table' | {'keypos',Pos} | {'heir',Pid::pid(),HeirData} | {'heir','none'} | Tweaks), is_subtype(Type,type()), is_subtype(Access,access()), is_subtype(Tweaks,{'write_concurrency',boolean()} | {'read_concurrency',boolean()} | 'compressed'), is_subtype(Pos,pos_integer()), is_subtype(HeirData,term())
+contracts_with_subtypes.erl:263: Function flat_ets_new_t/0 has no local return
+contracts_with_subtypes.erl:264: The call contracts_with_subtypes:flat_ets_new(12,[]) breaks the contract (Name,Options) -> atom() when is_subtype(Name,atom()), is_subtype(Options,[Option]), is_subtype(Option,'set' | 'ordered_set' | 'bag' | 'duplicate_bag' | 'public' | 'protected' | 'private' | 'named_table' | {'keypos',integer()} | {'heir',pid(),term()} | {'heir','none'} | {'write_concurrency',boolean()} | {'read_concurrency',boolean()} | 'compressed')
+contracts_with_subtypes.erl:290: Function factored_ets_new_t/0 has no local return
+contracts_with_subtypes.erl:291: The call contracts_with_subtypes:factored_ets_new(12,[]) breaks the contract (Name,Options) -> atom() when is_subtype(Name,atom()), is_subtype(Options,[Option]), is_subtype(Option,Type | Access | 'named_table' | {'keypos',Pos} | {'heir',Pid::pid(),HeirData} | {'heir','none'} | Tweaks), is_subtype(Type,type()), is_subtype(Access,access()), is_subtype(Tweaks,{'write_concurrency',boolean()} | {'read_concurrency',boolean()} | 'compressed'), is_subtype(Pos,pos_integer()), is_subtype(HeirData,term())
contracts_with_subtypes.erl:77: The call contracts_with_subtypes:foo1(5) breaks the contract (Arg1) -> Res when is_subtype(Arg1,atom()), is_subtype(Res,atom())
contracts_with_subtypes.erl:78: The call contracts_with_subtypes:foo2(5) breaks the contract (Arg1) -> Res when is_subtype(Arg1,Arg2), is_subtype(Arg2,atom()), is_subtype(Res,atom())
contracts_with_subtypes.erl:79: The call contracts_with_subtypes:foo3(5) breaks the contract (Arg1) -> Res when is_subtype(Arg2,atom()), is_subtype(Arg1,Arg2), is_subtype(Res,atom())
diff --git a/lib/dialyzer/test/small_SUITE_data/results/contracts_with_subtypes2 b/lib/dialyzer/test/small_SUITE_data/results/contracts_with_subtypes2
new file mode 100644
index 0000000000..9f5433a13d
--- /dev/null
+++ b/lib/dialyzer/test/small_SUITE_data/results/contracts_with_subtypes2
@@ -0,0 +1,3 @@
+
+contracts_with_subtypes2.erl:18: Function t/0 has no local return
+contracts_with_subtypes2.erl:19: The call contracts_with_subtypes2:t({'a',{'b',{'c',{'d',{'e',{'g',3}}}}}}) breaks the contract (Arg) -> 'ok' when is_subtype(Arg,{'a',A}), is_subtype(A,{'b',B}), is_subtype(B,{'c',C}), is_subtype(C,{'d',D}), is_subtype(D,{'e',E}), is_subtype(E,{'f',_})
diff --git a/lib/dialyzer/test/small_SUITE_data/results/funs_from_outside b/lib/dialyzer/test/small_SUITE_data/results/funs_from_outside
new file mode 100644
index 0000000000..3e597ef1bc
--- /dev/null
+++ b/lib/dialyzer/test/small_SUITE_data/results/funs_from_outside
@@ -0,0 +1,7 @@
+
+funs_from_outside.erl:18: The pattern 'error' can never match the type {'ok','nothing' | 'something'}
+funs_from_outside.erl:32: Function run2/2 has no local return
+funs_from_outside.erl:35: Function testb/3 has no local return
+funs_from_outside.erl:41: The pattern 'error' can never match the type {'ok','nothing' | 'something'}
+funs_from_outside.erl:78: Function test2/1 has no local return
+funs_from_outside.erl:83: The pattern 'error' can never match the type 'ok'
diff --git a/lib/dialyzer/test/small_SUITE_data/results/invalid_spec_2 b/lib/dialyzer/test/small_SUITE_data/results/invalid_spec_2
new file mode 100644
index 0000000000..4565112ea0
--- /dev/null
+++ b/lib/dialyzer/test/small_SUITE_data/results/invalid_spec_2
@@ -0,0 +1,2 @@
+
+scala_user.erl:5: Invalid type specification for function scala_user:is_list/2. The success typing is (maybe_improper_list() | tuple(),_) -> boolean()
diff --git a/lib/dialyzer/test/small_SUITE_data/src/contracts_with_subtypes.erl b/lib/dialyzer/test/small_SUITE_data/src/contracts_with_subtypes.erl
index d72138d509..d7dfd9752e 100644
--- a/lib/dialyzer/test/small_SUITE_data/src/contracts_with_subtypes.erl
+++ b/lib/dialyzer/test/small_SUITE_data/src/contracts_with_subtypes.erl
@@ -103,15 +103,44 @@ c(babb) -> rec_arg({b, {a, {b, b}}});
c(ababb) -> rec_arg({a, {b, {a, {b, b}}}});
c(babaa) -> rec_arg({b, {a, {b, {a, a}}}}).
-w(ab) -> rec_arg({a, b});
-w(ba) -> rec_arg({b, a});
-w(aba) -> rec_arg({a, {b, a}});
-w(bab) -> rec_arg({b, {a, b}});
-w(abab) -> rec_arg({a, {b, {a, b}}});
-w(baba) -> rec_arg({b, {a, {b, a}}});
+w(ab) -> rec_arg({a, b}); % breaks the contract
+w(ba) -> rec_arg({b, a}); % breaks the contract
+w(aba) -> rec_arg({a, {b, a}}); % no longer breaks the contract
+w(bab) -> rec_arg({b, {a, b}}); % breaks the contract
+w(abab) -> rec_arg({a, {b, {a, b}}}); % no longer breaks the contract
+w(baba) -> rec_arg({b, {a, {b, a}}}); % no longer breaks the contract
w(ababa) -> rec_arg({a, {b, {a, {b, a}}}});
w(babab) -> rec_arg({b, {a, {b, {a, b}}}}).
+%% For comparison: the same thing with types
+
+-type ab() :: {a, a()} | {b, b()}.
+-type a() :: a | {b, b()}.
+-type b() :: b | {a, a()}.
+
+-spec rec2(Arg) -> ok when
+ Arg :: ab().
+
+rec2(X) -> get(X).
+
+d(aa) -> rec2({a, a});
+d(bb) -> rec2({b, b});
+d(abb) -> rec2({a, {b, b}});
+d(baa) -> rec2({b, {a, a}});
+d(abaa) -> rec2({a, {b, {a, a}}});
+d(babb) -> rec2({b, {a, {b, b}}});
+d(ababb) -> rec2({a, {b, {a, {b, b}}}});
+d(babaa) -> rec2({b, {a, {b, {a, a}}}}).
+
+q(ab) -> rec2({a, b}); % breaks the contract
+q(ba) -> rec2({b, a}); % breaks the contract
+q(aba) -> rec2({a, {b, a}}); % breaks the contract
+q(bab) -> rec2({b, {a, b}}); % breaks the contract
+q(abab) -> rec2({a, {b, {a, b}}});
+q(baba) -> rec2({b, {a, {b, a}}});
+q(ababa) -> rec2({a, {b, {a, {b, a}}}});
+q(babab) -> rec2({b, {a, {b, {a, b}}}}).
+
%===============================================================================
-type dublo(X) :: {X, X}.
@@ -143,7 +172,7 @@ st(X) when is_atom(X) ->
_Other -> ok
end;
alpha -> bad;
- {ok, 42} -> bad;
+ {ok, 42} -> ok;
42 -> bad
end.
@@ -161,7 +190,7 @@ dt(X) when is_atom(X) ->
err2 -> ok;
{ok, X} -> ok;
alpha -> bad;
- {ok, 42} -> bad;
+ {ok, 42} -> ok;
42 -> bad
end.
@@ -181,7 +210,7 @@ dt2(X) when is_atom(X) ->
err2 -> ok;
{ok, X} -> ok;
alpha -> bad;
- {ok, 42} -> bad;
+ {ok, 42} -> ok;
42 -> bad
end.
diff --git a/lib/dialyzer/test/small_SUITE_data/src/contracts_with_subtypes2.erl b/lib/dialyzer/test/small_SUITE_data/src/contracts_with_subtypes2.erl
new file mode 100644
index 0000000000..d2f945b284
--- /dev/null
+++ b/lib/dialyzer/test/small_SUITE_data/src/contracts_with_subtypes2.erl
@@ -0,0 +1,40 @@
+-module(contracts_with_subtypes2).
+
+-compile(export_all).
+
+-behaviour(supervisor).
+
+-spec t(Arg) -> ok when
+ Arg :: {a, A},
+ A :: {b, B},
+ B :: {c, C},
+ C :: {d, D},
+ D :: {e, E},
+ E :: {f, _}.
+
+t(X) ->
+ get(X).
+
+t() ->
+ t({a, {b, {c, {d, {e, {g, 3}}}}}}). % breaks the contract
+
+%% This one should possibly result in warnings about unused variables.
+-spec l() -> ok when
+ X :: Y,
+ Y :: X.
+
+l() ->
+ ok.
+
+%% This is the example from seq12547 (ticket OTP-11798).
+%% There used to be a warning.
+
+-spec init(term()) -> Result when
+ Result :: {ok, {{supervisor:strategy(),
+ non_neg_integer(),
+ pos_integer()},
+ [supervisor:child_spec()]}}
+ | ignore.
+
+init(_) ->
+ foo:bar().
diff --git a/lib/dialyzer/test/small_SUITE_data/src/funs_from_outside.erl b/lib/dialyzer/test/small_SUITE_data/src/funs_from_outside.erl
new file mode 100644
index 0000000000..f4cbf31160
--- /dev/null
+++ b/lib/dialyzer/test/small_SUITE_data/src/funs_from_outside.erl
@@ -0,0 +1,83 @@
+-module(funs_from_outside).
+
+-export([run1/2, run2/2, run3/2]).
+-export([test1/1, test2/1]).
+
+%%------------------------------------------------------------------------------
+
+run1(X, Y) ->
+ testa(fun do_something/1, X, Y).
+
+testa(Fun, X, Y) ->
+ F = case even(X) of
+ true -> Fun;
+ false -> fun do_nothing/1
+ end,
+ case F(Y) of
+ {ok, _} -> ok;
+ error -> error
+ end.
+
+do_nothing(_) -> {ok, nothing}.
+
+do_something(_) -> {ok, something}.
+
+even(X) ->
+ X rem 2 =:= 0.
+
+%%------------------------------------------------------------------------------
+
+%% Duplicating code since we are monovariant...
+
+run2(X, Y) ->
+ testb(fun do_something/1, X, Y).
+
+testb(Fun, X, Y) ->
+ F = case even(X) of
+ true -> Fun;
+ false -> fun do_nothing/1
+ end,
+ case F(Y) of
+ error -> error
+ end.
+
+%%------------------------------------------------------------------------------
+
+%% Duplicating code since we are monovariant...
+
+run3(X, Y) ->
+ testc(fun do_something_2/1, X, Y).
+
+testc(Fun, X, Y) ->
+ F = case even(X) of
+ true -> Fun;
+ false -> fun do_nothing/1
+ end,
+ case F(Y) of
+ {ok, _} -> ok;
+ %% This pattern can match.
+ error -> error
+ end.
+
+do_something_2(foo) -> {ok, something};
+do_something_2(_) -> error.
+
+%%------------------------------------------------------------------------------
+
+test1(Fun) ->
+ F = case get(test1) of
+ test1_t -> Fun;
+ test1_f -> fun fok/0
+ end,
+ error = F().
+
+fok() -> ok.
+
+%%------------------------------------------------------------------------------
+
+test2(Fun) ->
+ F = case get(test1) of
+ test1_t -> fun fok/0;
+ test1_f -> fun fok/0
+ end,
+ error = F().
diff --git a/lib/dialyzer/test/small_SUITE_data/src/invalid_spec_2/scala_data.erl b/lib/dialyzer/test/small_SUITE_data/src/invalid_spec_2/scala_data.erl
new file mode 100644
index 0000000000..c26787fe24
--- /dev/null
+++ b/lib/dialyzer/test/small_SUITE_data/src/invalid_spec_2/scala_data.erl
@@ -0,0 +1,5 @@
+-module(scala_data).
+
+-export_type([data/0]).
+
+-opaque data() :: {'data', term()}.
diff --git a/lib/dialyzer/test/small_SUITE_data/src/invalid_spec_2/scala_user.erl b/lib/dialyzer/test/small_SUITE_data/src/invalid_spec_2/scala_user.erl
new file mode 100644
index 0000000000..4e981f3b74
--- /dev/null
+++ b/lib/dialyzer/test/small_SUITE_data/src/invalid_spec_2/scala_user.erl
@@ -0,0 +1,8 @@
+-module(scala_user).
+
+-export([is_list/2]).
+
+-spec is_list(atom(), scala_data:data()) -> boolean().
+
+is_list( List,Data) when is_list(List) -> true;
+is_list(Tuple,Data) when is_tuple(Tuple) -> false.
diff --git a/lib/dialyzer/test/small_SUITE_data/src/maps_redef.erl b/lib/dialyzer/test/small_SUITE_data/src/maps_redef.erl
new file mode 100644
index 0000000000..70059f73b6
--- /dev/null
+++ b/lib/dialyzer/test/small_SUITE_data/src/maps_redef.erl
@@ -0,0 +1,12 @@
+-module(maps_redef).
+
+-export([t/0]).
+
+%% OK in Erlang/OTP 17, at least.
+
+-type map() :: atom(). % redefine built-in type
+
+-spec t() -> map().
+
+t() ->
+ a. % OK
diff --git a/lib/dialyzer/test/underspecs_SUITE_data/dialyzer_options b/lib/dialyzer/test/underspecs_SUITE_data/dialyzer_options
index f7197ac30f..6843119b9d 100644
--- a/lib/dialyzer/test/underspecs_SUITE_data/dialyzer_options
+++ b/lib/dialyzer/test/underspecs_SUITE_data/dialyzer_options
@@ -1 +1 @@
-{dialyzer_options, [{warnings, [underspecs]}]}.
+{dialyzer_options, [{warnings, [underspecs, no_unknown]}]}.
diff --git a/lib/dialyzer/test/user_SUITE_data/dialyzer_options b/lib/dialyzer/test/user_SUITE_data/dialyzer_options
index 513ed7752b..d20ecd389f 100644
--- a/lib/dialyzer/test/user_SUITE_data/dialyzer_options
+++ b/lib/dialyzer/test/user_SUITE_data/dialyzer_options
@@ -1,2 +1,2 @@
-{dialyzer_options, []}.
+{dialyzer_options, [{warnings, [no_unknown]}]}.
{time_limit, 3}. \ No newline at end of file
diff --git a/lib/diameter/doc/src/diameter_make.xml b/lib/diameter/doc/src/diameter_make.xml
index 13ec5bbfc1..0c7e6b794d 100644
--- a/lib/diameter/doc/src/diameter_make.xml
+++ b/lib/diameter/doc/src/diameter_make.xml
@@ -52,7 +52,7 @@ under the License.
<p>
The function &codec; is used to compile a diameter
&dictionary; into Erlang source.
-The resulting source implements the interface diameter required
+The resulting source implements the interface diameter requires
to encode and decode the dictionary's messages and AVPs.</p>
<p>
diff --git a/lib/diameter/doc/src/notes.xml b/lib/diameter/doc/src/notes.xml
index cd14195e78..e2390df37c 100644
--- a/lib/diameter/doc/src/notes.xml
+++ b/lib/diameter/doc/src/notes.xml
@@ -11,7 +11,7 @@
<header>
<copyright>
<year>2011</year>
-<year>2013</year>
+<year>2014</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -73,12 +73,6 @@ first.</p>
<p>
Own Id: OTP-11361</p>
</item>
- <item>
- <p>
- Fix silent make rules (Thanks to Anthony Ramine)</p>
- <p>
- Own Id: OTP-11514</p>
- </item>
</list>
</section>
diff --git a/lib/diameter/src/Makefile b/lib/diameter/src/Makefile
index 578bbaee2e..127406ae23 100644
--- a/lib/diameter/src/Makefile
+++ b/lib/diameter/src/Makefile
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2010-2013. All Rights Reserved.
+# Copyright Ericsson AB 2010-2014. All Rights Reserved.
#
# The contents of this file are subject to the Erlang Public License,
# Version 1.1, (the "License"); you may not use this file except in
@@ -41,7 +41,7 @@ INCDIR = ../include
ABS_EBIN := $(shell cd $(EBIN) && pwd)
# Where make should look for dependencies.
-VPATH = .:base:compiler:transport:gen
+VPATH = .:base:compiler:transport:gen:info
# ----------------------------------------------------
# Target specs
@@ -55,13 +55,13 @@ DICT_ERLS = $(DICT_MODULES:%=%.erl)
DICT_HRLS = $(DICT_MODULES:%=%.hrl)
# Modules to build before compiling dictionaries.
-COMPILER_MODULES = $(notdir $(filter compiler/%, $(CT_MODULES))) \
- $(DICT_YRL)
+COMPILER_MODULES = $(notdir $(CT_MODULES)) $(DICT_YRL)
# All handwritten modules from which a depend.mk is generated.
MODULES = \
$(RT_MODULES) \
- $(CT_MODULES)
+ $(CT_MODULES) \
+ $(INFO_MODULES)
# Modules whose names are inserted into the app file.
APP_MODULES = \
@@ -72,6 +72,7 @@ APP_MODULES = \
TARGET_MODULES = \
$(APP_MODULES) \
$(CT_MODULES) \
+ $(INFO_MODULES) \
$(DICT_YRL:%=gen/%)
# What to build for the 'opt' target.
@@ -150,9 +151,13 @@ gen/$(DICT_YRL).erl: compiler/$(DICT_YRL).yrl
$(APP_TARGET): $(APP_SRC) ../vsn.mk modules.mk
$(gen_verbose) \
M=`echo $(notdir $(APP_MODULES)) | tr ' ' ,`; \
+ C=`echo $(COMPILER_MODULES) | tr ' ' ,`; \
+ I=`echo $(notdir $(INFO_MODULES)) | tr ' ' ,`; \
R=`echo $(REGISTERED) | tr ' ' ,`; \
sed -e 's;%VSN%;$(VSN);' \
-e "s;%MODULES%;$$M;" \
+ -e "s;%COMPILER%;$$C;" \
+ -e "s;%INFO%;$$I;" \
-e "s;%REGISTERED%;$$R;" \
$< > $@
@@ -177,6 +182,8 @@ info:
@echo
@$(call list,CT_MODULES)
@echo
+ @$(call list,INFO_MODULES)
+ @echo
@$(call list,TARGET_MODULES)
@echo
@$(call list,TARGET_DIRS)
@@ -216,7 +223,7 @@ dialyze: opt $(PLT)
-Wno_improper_lists \
$(EBIN)/diameter_gen_base_rfc3588.$(EMULATOR) \
$(patsubst %, $(EBIN)/%.$(EMULATOR), \
- $(notdir $(RT_MODULES) $(CT_MODULES)))
+ $(notdir $(RT_MODULES) $(CT_MODULES) $(INFO_MODULES)))
# Omit all but the common dictionary module since these
# (diameter_gen_relay in particular) generate warning depending on how
# much of the included diameter_gen.hrl they use.
diff --git a/lib/diameter/src/base/diameter_service.erl b/lib/diameter/src/base/diameter_service.erl
index 1274e0fc48..8914992f17 100644
--- a/lib/diameter/src/base/diameter_service.erl
+++ b/lib/diameter/src/base/diameter_service.erl
@@ -1389,6 +1389,8 @@ pick_peer(Local, Remote, Pid, _SvcName, #diameter_app{mutable = true} = App)
case call_service(Pid, {pick_peer, Local, Remote, App}) of
{TPid, _} = T when is_pid(TPid) ->
T;
+ false = No ->
+ No;
{error, _} ->
false
end;
diff --git a/lib/diameter/src/compiler/diameter_codegen.erl b/lib/diameter/src/compiler/diameter_codegen.erl
index 22422f2ef2..5a068c1a25 100644
--- a/lib/diameter/src/compiler/diameter_codegen.erl
+++ b/lib/diameter/src/compiler/diameter_codegen.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2010-2013. All Rights Reserved.
+%% Copyright Ericsson AB 2010-2014. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -31,7 +31,8 @@
%% on the beam file of another dictionary.
%%
--export([from_dict/4]).
+-export([from_dict/4,
+ is_printable_ascii/1]). %% used by ?TERM/1 in diameter_forms.hrl
-include("diameter_forms.hrl").
-include("diameter_vsn.hrl").
@@ -121,6 +122,9 @@ eraser(Key) ->
%% ===========================================================================
%% ===========================================================================
+is_printable_ascii(C) ->
+ 16#20 =< C andalso C =< 16#7F.
+
get_value(Key, Plist) ->
proplists:get_value(Key, Plist, []).
diff --git a/lib/diameter/src/compiler/diameter_forms.hrl b/lib/diameter/src/compiler/diameter_forms.hrl
index 9b14c1715a..dd03401b9e 100644
--- a/lib/diameter/src/compiler/diameter_forms.hrl
+++ b/lib/diameter/src/compiler/diameter_forms.hrl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2010-2013. All Rights Reserved.
+%% Copyright Ericsson AB 2010-2014. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -57,4 +57,6 @@
-define(FIELDS(Fs), [{?record_field, ?ATOM(F), V} || {F,V} <- Fs]).
%% Literal term.
--define(TERM(T), erl_parse:abstract(T, ?LINE)).
+-define(TERM(T), erl_parse:abstract(T, [
+ {line, ?LINE},
+ {encoding, fun diameter_codegen:is_printable_ascii/1}])).
diff --git a/lib/diameter/src/compiler/diameter_make.erl b/lib/diameter/src/compiler/diameter_make.erl
index adc7808e49..72f5d36da4 100644
--- a/lib/diameter/src/compiler/diameter_make.erl
+++ b/lib/diameter/src/compiler/diameter_make.erl
@@ -232,21 +232,29 @@ identify([Vsn | [T|_] = ParseD])
identify({path, File} = T) ->
{T, File};
identify(File) ->
- Bin = iolist_to_binary([File]),
- case is_path(Bin) of
+ case is_path([File]) of
true -> {{path, File}, File};
- false -> {Bin, ?DEFAULT_DICT_FILE}
+ false -> {File, ?DEFAULT_DICT_FILE}
end.
-%% Interpret anything containing \n or \r as a literal dictionary,
-%% otherwise a path. (Which might be the wrong guess in the worst case.)
-is_path(Bin) ->
- try
- [throw(C) || <<C>> <= Bin, $\n == C orelse $\r == C],
- true
- catch
- throw:_ -> false
- end.
+%% Interpret anything containing \n or \r as a literal dictionary.
+
+is_path([<<C,B/binary>> | T]) ->
+ is_path([C, B | T]);
+
+is_path([[C|L] | T]) ->
+ is_path([C, L | T]);
+
+is_path([C|_])
+ when $\n == C;
+ $\r == C ->
+ false;
+
+is_path([_|T]) ->
+ is_path(T);
+
+is_path([]) ->
+ true.
make(File, Opts, Dict) ->
ok(lists:foldl(fun(M,A) -> [make(File, Opts, Dict, M) | A] end,
diff --git a/lib/diameter/src/diameter.app.src b/lib/diameter/src/diameter.app.src
index ceefb9b398..d2290aeccc 100644
--- a/lib/diameter/src/diameter.app.src
+++ b/lib/diameter/src/diameter.app.src
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2010-2013. All Rights Reserved.
+%% Copyright Ericsson AB 2010-2014. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -20,9 +20,20 @@
{application, diameter,
[{description, "Diameter protocol"},
{vsn, "%VSN%"},
- {modules, [%MODULES%]},
+ {modules, [
+ %MODULES%
+ %,%COMPILER%
+ %,%INFO%
+ ]},
{registered, [%REGISTERED%]},
- {applications, [stdlib, kernel]},
+ {applications, [
+ stdlib, kernel
+ %, syntax_tools
+ %, runtime_tools
+ %, ssl
+ ]},
{env, []},
- {mod, {diameter_app, []}}
+ {mod, {diameter_app, []}},
+ {runtime_dependencies, ["syntax_tools-1.6.14","stdlib-2.0","ssl-5.3.4",
+ "runtime_tools-1.8.14","kernel-3.0","erts-6.0"]}
]}.
diff --git a/lib/diameter/src/base/diameter_dbg.erl b/lib/diameter/src/info/diameter_dbg.erl
index 5b0ac3a3b6..1237007a75 100644
--- a/lib/diameter/src/base/diameter_dbg.erl
+++ b/lib/diameter/src/info/diameter_dbg.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2010-2011. All Rights Reserved.
+%% Copyright Ericsson AB 2010-2014. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -17,6 +17,10 @@
%% %CopyrightEnd%
%%
+%%
+%% Information and debug functions.
+%%
+
-module(diameter_dbg).
-export([table/1,
@@ -29,8 +33,7 @@
compiled/0,
procs/0,
latest/0,
- nl/0,
- log/4]).
+ nl/0]).
-export([diameter_config/0,
diameter_peer/0,
@@ -52,9 +55,8 @@
tp/1]).
-include_lib("diameter/include/diameter.hrl").
--include("diameter_internal.hrl").
-
+-define(APPLICATION, diameter).
-define(INFO, diameter_info).
-define(SEP(), ?INFO:sep()).
@@ -68,9 +70,6 @@
-define(VALUES(Rec), tl(tuple_to_list(Rec))).
-log(_Slogan, _Mod, _Line, _Details) ->
- ok.
-
%%% ----------------------------------------------------------
%%% # help()
%%% ----------------------------------------------------------
diff --git a/lib/diameter/src/base/diameter_info.erl b/lib/diameter/src/info/diameter_info.erl
index 39d32d07cd..10972f3231 100644
--- a/lib/diameter/src/base/diameter_info.erl
+++ b/lib/diameter/src/info/diameter_info.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2010-2011. All Rights Reserved.
+%% Copyright Ericsson AB 2010-2014. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -17,6 +17,11 @@
%% %CopyrightEnd%
%%
+%%
+%% Generic functions for formatting table listings and more. Used by
+%% diameter_dbg.
+%%
+
-module(diameter_info).
-export([usage/1,
@@ -573,12 +578,7 @@ sys_info() ->
{A,V}.
os_info() ->
- {os:version(), case os:type() of
- {_Fam, _Name} = T ->
- T;
- Fam ->
- {Fam, ""}
- end}.
+ {os:version(), os:type()}.
chomp(S) ->
string:strip(S, right, $\n).
diff --git a/lib/diameter/src/modules.mk b/lib/diameter/src/modules.mk
index f8d3cf1d6f..a2a7a51892 100644
--- a/lib/diameter/src/modules.mk
+++ b/lib/diameter/src/modules.mk
@@ -1,8 +1,7 @@
-#-*-makefile-*- ; force emacs to enter makefile-mode
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2010-2013. All Rights Reserved.
+# Copyright Ericsson AB 2010-2014. All Rights Reserved.
#
# The contents of this file are subject to the Erlang Public License,
# Version 1.1, (the "License"); you may not use this file except in
@@ -64,16 +63,19 @@ RT_MODULES = \
transport/diameter_transport \
transport/diameter_transport_sup
-# Handwritten (compile time) modules not included in the app file.
+# Handwritten compiler modules not included in the app file.
CT_MODULES = \
- base/diameter_dbg \
- base/diameter_info \
compiler/diameter_codegen \
compiler/diameter_exprecs \
compiler/diameter_dict_scanner \
compiler/diameter_dict_util \
compiler/diameter_make
+# Info/debug modules, also not included in the app file.
+INFO_MODULES = \
+ info/diameter_dbg \
+ info/diameter_info
+
# Released hrl files in ../include intended for public consumption.
EXTERNAL_HRLS = \
diameter.hrl \
diff --git a/lib/diameter/test/diameter_codec_test.erl b/lib/diameter/test/diameter_codec_test.erl
index 0b4568a9e5..90536dcf2b 100644
--- a/lib/diameter/test/diameter_codec_test.erl
+++ b/lib/diameter/test/diameter_codec_test.erl
@@ -1,8 +1,7 @@
-%% coding: utf-8
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2010-2013. All Rights Reserved.
+%% Copyright Ericsson AB 2010-2014. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
diff --git a/lib/diameter/test/diameter_compiler_SUITE.erl b/lib/diameter/test/diameter_compiler_SUITE.erl
index df4dde6240..08ffe5981d 100644
--- a/lib/diameter/test/diameter_compiler_SUITE.erl
+++ b/lib/diameter/test/diameter_compiler_SUITE.erl
@@ -120,6 +120,16 @@
{avp_has_duplicate_flag,
" -",
" MM"},
+ {ok,
+ "@vendor 0",
+ "@vendor 10415"},
+ {ok,
+ [{"@vendor 0", "@vendor 10415"},
+ {"Proxy-Info .*M$", "&V"},
+ {"Proxy-Info ::= [^>]*", "& 10415 "}]},
+ {grouped_vendor_id_without_flag,
+ [{"@vendor 0", "@vendor 10415"},
+ {"Proxy-Info ::= [^>]*", "& 10415 "}]},
{avp_has_vendor_id,
"@avp_types",
"@avp_vendor_id 667 Class\n&"},
diff --git a/lib/edoc/src/edoc.app.src b/lib/edoc/src/edoc.app.src
index 0c8d5b85f8..9e1155d3e8 100644
--- a/lib/edoc/src/edoc.app.src
+++ b/lib/edoc/src/edoc.app.src
@@ -22,4 +22,6 @@
otpsgml_layout]},
{registered,[]},
{applications, [compiler,kernel,stdlib,syntax_tools]},
- {env, []}]}.
+ {env, []},
+ {runtime_dependencies, ["xmerl-1.3.7","syntax_tools-1.6.14","stdlib-2.0",
+ "kernel-3.0","inets-5.10","erts-6.0"]}]}.
diff --git a/lib/edoc/vsn.mk b/lib/edoc/vsn.mk
index 2fcc97e406..0172aac48b 100644
--- a/lib/edoc/vsn.mk
+++ b/lib/edoc/vsn.mk
@@ -1 +1 @@
-EDOC_VSN = 0.7.12.1
+EDOC_VSN = 0.7.13
diff --git a/lib/eldap/src/Makefile b/lib/eldap/src/Makefile
index ebb7967e11..2e1110ec2c 100644
--- a/lib/eldap/src/Makefile
+++ b/lib/eldap/src/Makefile
@@ -88,7 +88,7 @@ $(TARGET_FILES): $(HRL_FILES)
# Special Build Targets
# ----------------------------------------------------
$(ASN1_HRL): ../asn1/$(ASN1_FILES)
- $(asn_verbose)$(ERLC) -o $(EBIN) -bber $(ERL_COMPILE_FLAGS) ../asn1/ELDAPv3.asn1
+ $(asn_verbose)$(ERLC) -o $(EBIN) +legacy_erlang_types -bber $(ERL_COMPILE_FLAGS) ../asn1/ELDAPv3.asn1
# ----------------------------------------------------
# Release Target
diff --git a/lib/eldap/src/eldap.app.src b/lib/eldap/src/eldap.app.src
index 8215328910..03a7d7c562 100644
--- a/lib/eldap/src/eldap.app.src
+++ b/lib/eldap/src/eldap.app.src
@@ -4,5 +4,7 @@
{modules, [eldap, 'ELDAPv3']},
{registered, []},
{applications, [kernel, stdlib]},
- {env, []}
+ {env, []},
+ {runtime_dependencies, ["stdlib-2.0","ssl-5.3.4","kernel-3.0","erts-6.0",
+ "asn1-3.0"]}
]}.
diff --git a/lib/eldap/test/eldap_misc_SUITE.erl b/lib/eldap/test/eldap_misc_SUITE.erl
new file mode 100644
index 0000000000..ca810ee33c
--- /dev/null
+++ b/lib/eldap/test/eldap_misc_SUITE.erl
@@ -0,0 +1,51 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2012-2014. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% 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(eldap_misc_SUITE).
+
+-compile(export_all). %% Use this only in test suites...
+
+-include_lib("common_test/include/ct.hrl").
+-include_lib("eldap/include/eldap.hrl").
+-include_lib("eldap/ebin/ELDAPv3.hrl").
+
+all() ->
+ [
+ encode,
+ decode
+ ].
+
+
+encode(_Config) ->
+ {ok,Bin} = 'ELDAPv3':encode('AddRequest', #'AddRequest'{entry="hejHopp" ,attributes=[]} ),
+ Expected = <<104,11,4,7,104,101,106,72,111,112,112,48,0>>,
+ Expected = Bin.
+
+decode(_Config) ->
+ {ok,Res} = 'ELDAPv3':decode('AddRequest', <<104,11,4,7,104,101,106,72,111,112,112,48,0>>),
+ ct:log("Res = ~p", [Res]),
+ Expected = #'AddRequest'{entry = "hejHopp",attributes = []},
+ case Res of
+ Expected -> ok;
+ #'AddRequest'{entry= <<"hejHopp">>, attributes=[]} ->
+ {fail, "decoded to (correct) binary!!"};
+ _ ->
+ {fail, "Bad decode"}
+ end.
+
diff --git a/lib/erl_docgen/src/erl_docgen.app.src b/lib/erl_docgen/src/erl_docgen.app.src
index daad172106..e2830b2692 100644
--- a/lib/erl_docgen/src/erl_docgen.app.src
+++ b/lib/erl_docgen/src/erl_docgen.app.src
@@ -8,7 +8,7 @@
},
{registered,[]},
{applications, [kernel,stdlib]},
- {env, []
- }
+ {env, []},
+ {runtime_dependencies, ["xmerl-1.3.7","stdlib-2.0","edoc-0.7.13","erts-6.0"]}
]
}.
diff --git a/lib/erl_docgen/vsn.mk b/lib/erl_docgen/vsn.mk
index cda8671cfd..0f89922275 100644
--- a/lib/erl_docgen/vsn.mk
+++ b/lib/erl_docgen/vsn.mk
@@ -1 +1 @@
-ERL_DOCGEN_VSN = 0.3.4.1
+ERL_DOCGEN_VSN = 0.3.5
diff --git a/lib/erl_interface/aclocal.m4 b/lib/erl_interface/aclocal.m4
index c51c26794a..2b47f7c4bc 100644
--- a/lib/erl_interface/aclocal.m4
+++ b/lib/erl_interface/aclocal.m4
@@ -83,8 +83,10 @@ AC_ARG_VAR(erl_xcomp_ose_LM_POST_LINK, [OSE postlink tool (only used when cross
AC_ARG_VAR(erl_xcomp_ose_LM_SET_CONF, [Sets the configuration for an OSE load module (only used when cross compiling for OSE)])
AC_ARG_VAR(erl_xcomp_ose_LM_ELF_SIZE, [Prints the section size information for an OSE load module (only used when cross compiling for OSE)])
AC_ARG_VAR(erl_xcomp_ose_LM_LCF, [OSE load module linker configuration file (only used when cross compiling for OSE)])
-AC_ARG_VAR(erl_xcomp_ose_LM_CONF, [OSE load module default configuration file (only used when cross compiling for OSE)])
-AC_ARG_VAR(erl_xcomp_ose_CONFD, [OSE OSE confd source file])
+AC_ARG_VAR(erl_xcomp_ose_BEAM_LM_CONF, [BEAM OSE load module default configuration file (only used when cross compiling for OSE)])
+AC_ARG_VAR(erl_xcomp_ose_EPMD_LM_CONF, [EPMD OSE load module default configuration file (only used when cross compiling for OSE)])
+AC_ARG_VAR(erl_xcomp_ose_RUN_ERL_LM_CONF, [run_erl_lm OSE load module default configuration file (only used when cross compiling for OSE)])
+AC_ARG_VAR(erl_xcomp_ose_CONFD, [OSE confd source file])
AC_ARG_VAR(erl_xcomp_ose_CRT0_LM, [OSE crt0 lm source file])
])
diff --git a/lib/erl_interface/src/connect/ei_connect.c b/lib/erl_interface/src/connect/ei_connect.c
index 3175d1bdfd..2e8418d61e 100644
--- a/lib/erl_interface/src/connect/ei_connect.c
+++ b/lib/erl_interface/src/connect/ei_connect.c
@@ -1166,7 +1166,11 @@ static unsigned int gen_challenge(void)
uname(&s.name);
s.cpu = clock();
s.pid = getpid();
+#ifndef __ANDROID__
s.hid = gethostid();
+#else
+ s.hid = 0;
+#endif
s.uid = getuid();
s.gid = getgid();
diff --git a/lib/erl_interface/src/connect/ei_resolve.c b/lib/erl_interface/src/connect/ei_resolve.c
index 74dcba61a7..cffcac801c 100644
--- a/lib/erl_interface/src/connect/ei_resolve.c
+++ b/lib/erl_interface/src/connect/ei_resolve.c
@@ -642,7 +642,7 @@ struct hostent *ei_gethostbyname_r(const char *name,
#ifndef HAVE_GETHOSTBYNAME_R
return my_gethostbyname_r(name,hostp,buffer,buflen,h_errnop);
#else
-#if (defined(__GLIBC__) || (__FreeBSD_version >= 602000) || defined(__DragonFly__))
+#if (defined(__GLIBC__) || (__FreeBSD_version >= 602000) || defined(__DragonFly__) || defined(__ANDROID__))
struct hostent *result;
gethostbyname_r(name, hostp, buffer, buflen, &result, h_errnop);
diff --git a/lib/erl_interface/vsn.mk b/lib/erl_interface/vsn.mk
index f386ce09a8..8731283265 100644
--- a/lib/erl_interface/vsn.mk
+++ b/lib/erl_interface/vsn.mk
@@ -1 +1,2 @@
-EI_VSN = 3.7.15
+EI_VSN = 3.7.16
+ERL_INTERFACE_VSN = $(EI_VSN)
diff --git a/lib/et/src/et.app.src b/lib/et/src/et.app.src
index f7189a4197..c26d9320d8 100644
--- a/lib/et/src/et.app.src
+++ b/lib/et/src/et.app.src
@@ -31,5 +31,7 @@
]},
{registered, [et_collector]},
{applications, [stdlib, kernel]},
- {env, []}
+ {env, []},
+ {runtime_dependencies, ["wx-1.2","stdlib-2.0","runtime_tools-1.8.14",
+ "kernel-3.0","erts-6.0"]}
]}.
diff --git a/lib/et/vsn.mk b/lib/et/vsn.mk
index 282991aa49..a47be678ca 100644
--- a/lib/et/vsn.mk
+++ b/lib/et/vsn.mk
@@ -1 +1 @@
-ET_VSN = 1.4.4.5
+ET_VSN = 1.5
diff --git a/lib/eunit/src/eunit.app.src b/lib/eunit/src/eunit.app.src
index 5e16dfa2ce..7a3978e200 100644
--- a/lib/eunit/src/eunit.app.src
+++ b/lib/eunit/src/eunit.app.src
@@ -18,4 +18,5 @@
eunit_tty]},
{registered,[]},
{applications, [kernel,stdlib]},
- {env, []}]}.
+ {env, []},
+ {runtime_dependencies, ["stdlib-2.0","kernel-3.0","erts-6.0"]}]}.
diff --git a/lib/eunit/vsn.mk b/lib/eunit/vsn.mk
index 8f816b3b94..f04c0536fe 100644
--- a/lib/eunit/vsn.mk
+++ b/lib/eunit/vsn.mk
@@ -1 +1 @@
-EUNIT_VSN = 2.2.6
+EUNIT_VSN = 2.2.7
diff --git a/lib/gs/src/gs.app.src b/lib/gs/src/gs.app.src
index c83c9b54d7..c6f88e5144 100644
--- a/lib/gs/src/gs.app.src
+++ b/lib/gs/src/gs.app.src
@@ -10,4 +10,5 @@
gstk_window,tcl2erl,tool_file_dialog,tool_utils,
gs_packer,gse]},
{registered, [gs_frontend]},
- {applications, [kernel, stdlib]}]}.
+ {applications, [kernel, stdlib]},
+ {runtime_dependencies, ["stdlib-2.0","kernel-3.0","erts-6.0"]}]}.
diff --git a/lib/gs/vsn.mk b/lib/gs/vsn.mk
index 5c18153c34..96786b300c 100644
--- a/lib/gs/vsn.mk
+++ b/lib/gs/vsn.mk
@@ -1,2 +1,2 @@
-GS_VSN = 1.5.15.2
+GS_VSN = 1.5.16
diff --git a/lib/hipe/Makefile b/lib/hipe/Makefile
index a9e24f4d17..46cbc33ae2 100644
--- a/lib/hipe/Makefile
+++ b/lib/hipe/Makefile
@@ -22,7 +22,7 @@ include $(ERL_TOP)/make/target.mk
include $(ERL_TOP)/make/$(TARGET)/otp.mk
ifdef HIPE_ENABLED
-HIPE_SUBDIRS = regalloc sparc ppc x86 amd64 arm opt tools
+HIPE_SUBDIRS = regalloc sparc ppc x86 amd64 arm opt tools llvm
else
HIPE_SUBDIRS =
endif
diff --git a/lib/hipe/arm/hipe_arm_assemble.erl b/lib/hipe/arm/hipe_arm_assemble.erl
index 2af786994e..e9de96a927 100644
--- a/lib/hipe/arm/hipe_arm_assemble.erl
+++ b/lib/hipe/arm/hipe_arm_assemble.erl
@@ -44,8 +44,8 @@ assemble(CompiledCode, Closures, Exports, Options) ->
print("Total num bytes=~w\n", [CodeSize], Options),
%%
SC = hipe_pack_constants:slim_constmap(ConstMap),
- DataRelocs = mk_data_relocs(RefsFromConsts, LabelMap),
- SSE = slim_sorted_exportmap(ExportMap,Closures,Exports),
+ DataRelocs = hipe_pack_constants:mk_data_relocs(RefsFromConsts, LabelMap),
+ SSE = hipe_pack_constants:slim_sorted_exportmap(ExportMap,Closures,Exports),
SlimRefs = hipe_pack_constants:slim_refs(AccRefs),
Bin = term_to_binary([{?VERSION_STRING(),?HIPE_SYSTEM_CRC},
ConstAlign, ConstSize,
@@ -320,7 +320,7 @@ do_pseudo_li(I, MFA, ConstMap, Address, PrevImms, PendImms) ->
Atom when is_atom(Atom) ->
{load_atom, Atom};
{Label,constant} ->
- ConstNo = find_const({MFA,Label}, ConstMap),
+ ConstNo = hipe_pack_constants:find_const({MFA,Label}, ConstMap),
{load_address, {constant,ConstNo}};
{Label,closure} ->
{load_address, {closure,Label}};
@@ -518,37 +518,6 @@ fix_pc_refs(I, InsnAddress, FunAddress, LabelMap) ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-mk_data_relocs(RefsFromConsts, LabelMap) ->
- lists:flatten(mk_data_relocs(RefsFromConsts, LabelMap, [])).
-
-mk_data_relocs([{MFA,Labels} | Rest], LabelMap, Acc) ->
- Map = [case Label of
- {L,Pos} ->
- Offset = find({MFA,L}, LabelMap),
- {Pos,Offset};
- {sorted,Base,OrderedLabels} ->
- {sorted, Base, [begin
- Offset = find({MFA,L}, LabelMap),
- {Order, Offset}
- end
- || {L,Order} <- OrderedLabels]}
- end
- || Label <- Labels],
- %% msg("Map: ~w Map\n",[Map]),
- mk_data_relocs(Rest, LabelMap, [Map,Acc]);
-mk_data_relocs([],_,Acc) -> Acc.
-
-find({_MFA,_L} = MFAL, LabelMap) ->
- gb_trees:get(MFAL, LabelMap).
-
-slim_sorted_exportmap([{Addr,M,F,A}|Rest], Closures, Exports) ->
- IsClosure = lists:member({M,F,A}, Closures),
- IsExported = is_exported(F, A, Exports),
- [Addr,M,F,A,IsClosure,IsExported | slim_sorted_exportmap(Rest, Closures, Exports)];
-slim_sorted_exportmap([],_,_) -> [].
-
-is_exported(F, A, Exports) -> lists:member({F,A}, Exports).
-
%%%
%%% Assembly listing support (pp_asm option).
%%%
@@ -594,17 +563,6 @@ fill_spaces(N) when N > 0 ->
fill_spaces(0) ->
[].
-%%%
-%%% Lookup a constant in a ConstMap.
-%%%
-
-find_const({MFA,Label},[{pcm_entry,MFA,Label,ConstNo,_,_,_}|_]) ->
- ConstNo;
-find_const(N,[_|R]) ->
- find_const(N,R);
-find_const(C,[]) ->
- ?EXIT({constant_not_found,C}).
-
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%
diff --git a/lib/hipe/cerl/Makefile b/lib/hipe/cerl/Makefile
index 506e993ff4..d13dfb33c2 100644
--- a/lib/hipe/cerl/Makefile
+++ b/lib/hipe/cerl/Makefile
@@ -42,8 +42,8 @@ RELSYSDIR = $(RELEASE_PATH)/lib/hipe-$(VSN)
# ----------------------------------------------------
# Target Specs
# ----------------------------------------------------
-MODULES = cerl_cconv cerl_closurean cerl_hipeify \
- cerl_lib cerl_messagean cerl_pmatch cerl_prettypr cerl_to_icode \
+MODULES = cerl_cconv cerl_closurean cerl_hipeify cerl_lib \
+ cerl_messagean cerl_pmatch cerl_prettypr cerl_to_icode \
cerl_typean erl_bif_types erl_types
HRL_FILES= cerl_hipe_primops.hrl
@@ -65,7 +65,7 @@ DOC_FILES= $(MODULES:%=$(DOCS)/%.html)
include ../native.mk
-ERL_COMPILE_FLAGS += +inline +warn_exported_vars +warn_unused_import +warn_missing_spec# +warn_untyped_record
+ERL_COMPILE_FLAGS += -Werror +inline +warn_exported_vars +warn_unused_import +warn_missing_spec #+warn_untyped_record
# ----------------------------------------------------
# Targets
@@ -107,7 +107,6 @@ release_spec: opt
release_docs_spec:
-$(EBIN)/cerl_to_icode.beam: cerl_hipe_primops.hrl ../icode/hipe_icode_primops.hrl
+$(EBIN)/cerl_cconv.beam: cerl_hipe_primops.hrl
$(EBIN)/cerl_hipeify.beam: cerl_hipe_primops.hrl
-$(EBIN)/cerl_lambdalift.beam: cerl_hipe_primops.hrl
-$(EBIN)/erl_bif_types.beam: ../icode/hipe_icode_primops.hrl
+$(EBIN)/cerl_to_icode.beam: cerl_hipe_primops.hrl ../icode/hipe_icode_primops.hrl
diff --git a/lib/hipe/cerl/cerl_to_icode.erl b/lib/hipe/cerl/cerl_to_icode.erl
index 1c1c10d9b0..2645056be1 100644
--- a/lib/hipe/cerl/cerl_to_icode.erl
+++ b/lib/hipe/cerl/cerl_to_icode.erl
@@ -29,9 +29,9 @@
-define(NO_UNUSED, true).
--export([module/2]).
+-export([module/1, module/2]).
-ifndef(NO_UNUSED).
--export([function/3, function/4, module/1]).
+-export([function/3, function/4]).
-endif.
%% Added in an attempt to suppress message by Dialyzer, but I run into
@@ -102,36 +102,32 @@
%% Record definitions
--record(ctxt, {final = false :: boolean(),
- effect = false,
- fail = [], % [] or fail-to label
- class = expr, % expr | guard
- line = 0, % current line number
- 'receive' % undefined | #receive{}
- }).
-
-record('receive', {loop}).
-record(cerl_to_icode__var, {name}).
-record('fun', {label, vars}).
+-record(ctxt, {final = false :: boolean(),
+ effect = false :: boolean(),
+ fail = [], % [] or fail-to label
+ class = expr :: 'expr' | 'guard',
+ line = 0 :: erl_scan:line(), % current line number
+ 'receive' :: 'undefined' | #'receive'{}
+ }).
%% ---------------------------------------------------------------------
%% Code
-
-%% @spec module(Module::cerl()) -> [icode()]
+%% @spec module(Module::cerl()) -> [{mfa(), icode()}]
%% @equiv module(Module, [])
--ifndef(NO_UNUSED).
+-spec module(cerl:c_module()) -> [{mfa(), hipe_icode:icode()}].
+
module(E) ->
module(E, []).
--endif.
-%% @clear
-
-%% @spec module(Module::cerl(), Options::[term()]) -> [icode()]
+%% @spec module(Module::cerl(), Options::[term()]) -> [{mfa(), icode()}]
%%
-%% cerl() = cerl:cerl()
+%% cerl() = cerl:c_module()
%% icode() = hipe_icode:icode()
%%
%% @doc Transforms a Core Erlang module to linear HiPE Icode. The result
@@ -149,7 +145,7 @@ module(E) ->
%% @see function/4
%% @see cerl_hipeify:transform/1
-%% -spec module(cerl:c_module(), [term()]) -> [{mfa(), hipe_icode:icode()}].
+-spec module(cerl:c_module(), [term()]) -> [{mfa(), hipe_icode:icode()}].
module(E, Options) ->
module_1(cerl_hipeify:transform(E, Options), Options).
@@ -163,8 +159,8 @@ module_1(E, Options) ->
throw(error)
end,
S0 = init(M),
- S1 = s__set_pmatch(proplists:get_value(pmatch, Options), S0),
- S2 = s__set_bitlevel_binaries(proplists:get_value(
+ S1 = s__set_pmatch(proplists:get_value(pmatch, Options), S0),
+ S2 = s__set_bitlevel_binaries(proplists:get_value(
bitlevel_binaries, Options), S1),
{Icode, _} = lists:mapfoldl(fun function_definition/2,
S2, cerl:module_defs(E)),
diff --git a/lib/hipe/cerl/erl_types.erl b/lib/hipe/cerl/erl_types.erl
index 32390045e3..47b8dc766a 100644
--- a/lib/hipe/cerl/erl_types.erl
+++ b/lib/hipe/cerl/erl_types.erl
@@ -126,6 +126,8 @@
t_is_instance/2,
t_is_integer/1, t_is_integer/2,
t_is_list/1,
+ t_is_map/1,
+ t_is_map/2,
t_is_matchstate/1,
t_is_nil/1, t_is_nil/2,
t_is_non_neg_integer/1,
@@ -148,6 +150,8 @@
t_list/1,
t_list_elements/1, t_list_elements/2,
t_list_termination/1,
+ t_map/0,
+ t_map/1,
t_matchstate/0,
t_matchstate/2,
t_matchstate_present/1,
@@ -208,11 +212,7 @@
lift_list_to_pos_empty/1,
is_opaque_type/2,
is_erl_type/1,
- atom_to_string/1,
-
- t_is_map/2,
- t_map/1,
- t_map/0
+ atom_to_string/1
]).
%%-define(DO_ERL_TYPES_TEST, true).
@@ -498,9 +498,9 @@ t_contains_opaque(?int_range(_From, _To), _Opaques) -> false;
t_contains_opaque(?int_set(_Set), _Opaques) -> false;
t_contains_opaque(?list(Type, Tail, _), Opaques) ->
t_contains_opaque(Type, Opaques) orelse t_contains_opaque(Tail, Opaques);
-t_contains_opaque(?map(Pairs), Opaques) ->
- list_contains_opaque([V||{_,V}<-Pairs], Opaques) orelse
- list_contains_opaque([K||{K,_}<-Pairs], Opaques);
+t_contains_opaque(?map(_) = Map, Opaques) ->
+ list_contains_opaque(map_values(Map), Opaques) orelse
+ list_contains_opaque(map_keys(Map), Opaques);
t_contains_opaque(?matchstate(_P, _Slots), _Opaques) -> false;
t_contains_opaque(?nil, _Opaques) -> false;
t_contains_opaque(?number(_Set, _Tag), _Opaques) -> false;
@@ -614,7 +614,7 @@ t_decorate_with_opaque(T1, T2, Opaques) ->
end
end.
-decorate(?none=Type, _, _Opaques) -> Type;
+decorate(Type, ?none, _Opaques) -> Type;
decorate(?function(Domain, Range), ?function(D, R), Opaques) ->
?function(decorate(Domain, D, Opaques), decorate(Range, R, Opaques));
decorate(?list(Types, Tail, Size), ?list(Ts, Tl, _Sz), Opaques) ->
@@ -680,6 +680,7 @@ union_decorate(U1, U2, Opaques) ->
List = [A,B,F,I,L,N,T,M,Map],
DecList = [Dec ||
E <- List,
+ not t_is_none(E),
not t_is_none(Dec = decorate(E, Opaque, Opaques))],
t_sup([Union|DecList]).
@@ -1728,11 +1729,16 @@ lift_list_to_pos_empty(?list(Content, Termination, _)) ->
t_map() ->
?map([]).
--spec t_map([{erl_type(),erl_type()}]) -> erl_type().
+-spec t_map([{erl_type(), erl_type()}]) -> erl_type().
t_map(_) ->
?map([]).
+-spec t_is_map(erl_type()) -> boolean().
+
+t_is_map(Type) ->
+ t_is_map(Type, 'universe').
+
-spec t_is_map(erl_type(), opaques()) -> boolean().
t_is_map(Type, Opaques) ->
@@ -1741,7 +1747,6 @@ t_is_map(Type, Opaques) ->
is_map1(?map(_)) -> true;
is_map1(_) -> false.
-
%%-----------------------------------------------------------------------------
%% Tuples
%%
@@ -2089,6 +2094,8 @@ t_has_var(?tuple(Elements, _, _)) ->
t_has_var_list(Elements);
t_has_var(?tuple_set(_) = T) ->
t_has_var_list(t_tuple_subtypes(T));
+t_has_var(?map(_)= Map) ->
+ t_has_var_list(map_keys(Map)) orelse t_has_var_list(map_values(Map));
t_has_var(?opaque(Set)) ->
%% Assume variables in 'args' are also present i 'struct'
t_has_var_list([O#opaque.struct || O <- set_to_list(Set)]);
@@ -2116,21 +2123,28 @@ t_collect_vars(?function(Domain, Range), Acc) ->
t_collect_vars(?list(Contents, Termination, _), Acc) ->
ordsets:union(t_collect_vars(Contents, Acc), t_collect_vars(Termination, []));
t_collect_vars(?product(Types), Acc) ->
- lists:foldl(fun(T, TmpAcc) -> t_collect_vars(T, TmpAcc) end, Acc, Types);
+ t_collect_vars_list(Types, Acc);
t_collect_vars(?tuple(?any, ?any, ?any), Acc) ->
Acc;
t_collect_vars(?tuple(Types, _, _), Acc) ->
- lists:foldl(fun(T, TmpAcc) -> t_collect_vars(T, TmpAcc) end, Acc, Types);
+ t_collect_vars_list(Types, Acc);
t_collect_vars(?tuple_set(_) = TS, Acc) ->
- lists:foldl(fun(T, TmpAcc) -> t_collect_vars(T, TmpAcc) end, Acc,
- t_tuple_subtypes(TS));
+ t_collect_vars_list(t_tuple_subtypes(TS), Acc);
+t_collect_vars(?map(_) = Map, Acc0) ->
+ Acc = t_collect_vars_list(map_keys(Map), Acc0),
+ t_collect_vars_list(map_values(Map), Acc);
t_collect_vars(?opaque(Set), Acc) ->
%% Assume variables in 'args' are also present i 'struct'
- lists:foldl(fun(T, TmpAcc) -> t_collect_vars(T, TmpAcc) end, Acc,
- [O#opaque.struct || O <- set_to_list(Set)]);
+ t_collect_vars_list([O#opaque.struct || O <- set_to_list(Set)], Acc);
+t_collect_vars(?union(List), Acc) ->
+ t_collect_vars_list(List, Acc);
t_collect_vars(_, Acc) ->
Acc.
+t_collect_vars_list([T|Ts], Acc0) ->
+ Acc = t_collect_vars(T, Acc0),
+ t_collect_vars_list(Ts, Acc);
+t_collect_vars_list([], Acc) -> Acc.
%%=============================================================================
%%
@@ -2153,6 +2167,7 @@ t_from_term(T) when is_function(T) ->
{arity, Arity} = erlang:fun_info(T, arity),
t_fun(Arity, t_any());
t_from_term(T) when is_integer(T) -> t_integer(T);
+t_from_term(T) when is_map(T) -> t_map();
t_from_term(T) when is_pid(T) -> t_pid();
t_from_term(T) when is_port(T) -> t_port();
t_from_term(T) when is_reference(T) -> t_reference();
@@ -2555,7 +2570,7 @@ force_union(T = ?function(_, _)) -> ?function_union(T);
force_union(T = ?identifier(_)) -> ?identifier_union(T);
force_union(T = ?list(_, _, _)) -> ?list_union(T);
force_union(T = ?nil) -> ?list_union(T);
-force_union(T = ?number(_,_)) -> ?number_union(T);
+force_union(T = ?number(_, _)) -> ?number_union(T);
force_union(T = ?opaque(_)) -> ?opaque_union(T);
force_union(T = ?remote(_)) -> ?remote_union(T);
force_union(T = ?map(_)) -> ?map_union(T);
@@ -3076,6 +3091,9 @@ t_subst_dict(?tuple(Elements, _Arity, _Tag), Dict) ->
t_tuple([t_subst_dict(E, Dict) || E <- Elements]);
t_subst_dict(?tuple_set(_) = TS, Dict) ->
t_sup([t_subst_dict(T, Dict) || T <- t_tuple_subtypes(TS)]);
+t_subst_dict(?map(Pairs), Dict) ->
+ ?map([{t_subst_dict(K, Dict), t_subst_dict(V, Dict)} ||
+ {K, V} <- Pairs]);
t_subst_dict(?opaque(Es), Dict) ->
List = [Opaque#opaque{args = [t_subst_dict(Arg, Dict) || Arg <- Args],
struct = t_subst_dict(S, Dict)} ||
@@ -3125,6 +3143,9 @@ t_subst_aux(?tuple(Elements, _Arity, _Tag), VarMap) ->
t_tuple([t_subst_aux(E, VarMap) || E <- Elements]);
t_subst_aux(?tuple_set(_) = TS, VarMap) ->
t_sup([t_subst_aux(T, VarMap) || T <- t_tuple_subtypes(TS)]);
+t_subst_aux(?map(Pairs), VarMap) ->
+ ?map([{t_subst_aux(K, VarMap), t_subst_aux(V, VarMap)} ||
+ {K, V} <- Pairs]);
t_subst_aux(?opaque(Es), VarMap) ->
List = [Opaque#opaque{args = [t_subst_aux(Arg, VarMap) || Arg <- Args],
struct = t_subst_aux(S, VarMap)} ||
@@ -3560,6 +3581,8 @@ t_subtract(?product(Elements1) = T1, ?product(Elements2)) ->
_ -> T1
end
end;
+t_subtract(?map(_) = T, _) -> % XXX: very crude; will probably need refinement
+ T;
t_subtract(?product(P1), _) ->
?product(P1);
t_subtract(T, ?product(_)) ->
@@ -3700,7 +3723,7 @@ t_unopaque(T) ->
t_unopaque(?opaque(_) = T, Opaques) ->
case Opaques =:= 'universe' orelse is_opaque_type(T, Opaques) of
true -> t_unopaque(t_opaque_structure(T), Opaques);
- false -> T % XXX: needs revision for parametric opaque data types
+ false -> T
end;
t_unopaque(?list(ElemT, Termination, Sz), Opaques) ->
?list(t_unopaque(ElemT, Opaques), t_unopaque(Termination, Opaques), Sz);
@@ -3720,11 +3743,12 @@ t_unopaque(?union([A,B,F,I,L,N,T,M,O,R,Map]), Opaques) ->
UL = t_unopaque(L, Opaques),
UT = t_unopaque(T, Opaques),
UF = t_unopaque(F, Opaques),
+ UMap = t_unopaque(Map, Opaques),
{OF,UO} = case t_unopaque(O, Opaques) of
?opaque(_) = O1 -> {O1, []};
Type -> {?none, [Type]}
end,
- t_sup([?union([A,B,UF,I,UL,N,UT,M,OF,R,Map])|UO]);
+ t_sup([?union([A,B,UF,I,UL,N,UT,M,OF,R,UMap])|UO]);
t_unopaque(T, _) ->
T.
@@ -4231,8 +4255,8 @@ t_from_form({type, _L, list, []}, _TypeNames, _RecDict, _VarDict) ->
t_from_form({type, _L, list, [Type]}, TypeNames, RecDict, VarDict) ->
{T, R} = t_from_form(Type, TypeNames, RecDict, VarDict),
{t_list(T), R};
-t_from_form({type, _L, map, _}, _TypeNames, _RecDict, _VarDict) ->
- {t_map([]), []};
+t_from_form({type, _L, map, _}, TypeNames, RecDict, VarDict) ->
+ builtin_type(map, t_map([]), TypeNames, RecDict, VarDict);
t_from_form({type, _L, mfa, []}, _TypeNames, _RecDict, _VarDict) ->
{t_mfa(), []};
t_from_form({type, _L, module, []}, _TypeNames, _RecDict, _VarDict) ->
@@ -4695,6 +4719,12 @@ is_same_type_name2(gb_trees, gb_tree, [], gb_trees, tree, [_, _]) -> true;
is_same_type_name2(gb_trees, tree, [_, _], gb_trees, gb_tree, []) -> true;
is_same_type_name2(_, _, _, _, _, _) -> false.
+map_keys(?map(Pairs)) ->
+ [K || {K, _} <- Pairs].
+
+map_values(?map(Pairs)) ->
+ [V || {_, V} <- Pairs].
+
%% -----------------------------------
%% Set
%%
diff --git a/lib/hipe/icode/hipe_beam_to_icode.erl b/lib/hipe/icode/hipe_beam_to_icode.erl
index 81249c958e..dcd547fd5f 100644
--- a/lib/hipe/icode/hipe_beam_to_icode.erl
+++ b/lib/hipe/icode/hipe_beam_to_icode.erl
@@ -509,6 +509,10 @@ trans_fun([{test,test_arity,{f,Lbl},[Reg,N]}|Instructions], Env) ->
I = hipe_icode:mk_type([trans_arg(Reg)],{tuple,N},
hipe_icode:label_name(True),map_label(Lbl)),
[I,True | trans_fun(Instructions,Env)];
+%%--- is_map ---
+trans_fun([{test,is_map,{f,Lbl},[Arg]}|Instructions], Env) ->
+ {Code,Env1} = trans_type_test(map,Lbl,Arg,Env),
+ [Code | trans_fun(Instructions,Env1)];
%%--------------------------------------------------------------------
%%--- select_val ---
trans_fun([{select_val,Reg,{f,Lbl},{list,Cases}}|Instructions], Env) ->
diff --git a/lib/hipe/icode/hipe_icode.erl b/lib/hipe/icode/hipe_icode.erl
index 0e651a351c..7b3d087e2d 100644
--- a/lib/hipe/icode/hipe_icode.erl
+++ b/lib/hipe/icode/hipe_icode.erl
@@ -503,7 +503,6 @@
enter_args_update/2,
enter_type/1,
is_enter/1,
-
mk_return/1, %% mk_return(Vars)
%% mk_fail/1, %% mk_fail(Args) class = exit
@@ -606,6 +605,12 @@
-export([highest_var/1, highest_label/1]).
+%%
+%% Exported types
+%%
+
+-export_type([icode/0]).
+
%%---------------------------------------------------------------------
%%
%% Icode
@@ -614,7 +619,7 @@
-spec mk_icode(mfa(), [icode_var()], boolean(), boolean(), [icode_instr()],
{non_neg_integer(),non_neg_integer()},
- {icode_lbl(),icode_lbl()}) -> #icode{}.
+ {icode_lbl(),icode_lbl()}) -> icode().
mk_icode(Fun, Params, IsClosure, IsLeaf, Code, VarRange, LabelRange) ->
#icode{'fun'=Fun, params=Params, code=Code,
is_closure=IsClosure,
@@ -1434,8 +1439,8 @@ subst1([_|Pairs], I) -> subst1(Pairs, I).
%%
%% @doc Returns the successors of an Icode instruction.
%% In CFG form only branch instructions have successors,
-%% but in linear form other instructions like e.g. moves and
-%% others might be the last instruction of some basic block.
+%% but in linear form other instructions like e.g. moves
+%% might be the last instruction of some basic block.
%%
-spec successors(icode_instr()) -> [icode_lbl()].
diff --git a/lib/hipe/icode/hipe_icode.hrl b/lib/hipe/icode/hipe_icode.hrl
index 060493e61e..46c04beb40 100644
--- a/lib/hipe/icode/hipe_icode.hrl
+++ b/lib/hipe/icode/hipe_icode.hrl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2013. All Rights Reserved.
+%% Copyright Ericsson AB 2004-2014. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -61,8 +61,8 @@
| 'op_exact_eqeq_2' | 'suspend_msg_timeout'.
-type icode_type_test() :: 'atom' | 'bignum' | 'binary' | 'bitstr' | 'boolean'
- | 'cons' | 'fixnum' | 'float'
- | 'function' | 'function2' | 'integer' | 'list' | 'nil'
+ | 'cons' | 'fixnum' | 'float' | 'function'
+ | 'function2' | 'integer' | 'list' | 'map' | 'nil'
| 'number' | 'pid' | 'port' | 'reference' | 'tuple'
| {'atom', atom()} | {'integer', integer()}
| {'record', atom(), non_neg_integer()}
@@ -108,7 +108,6 @@
length :: non_neg_integer(),
cases :: [icode_switch_case()]}).
-
-record(icode_type, {test :: icode_type_test(),
args :: [icode_term_arg()],
true_label :: icode_lbl(),
@@ -178,5 +177,6 @@
var_range :: {non_neg_integer(), non_neg_integer()},
label_range :: {icode_lbl(), icode_lbl()},
info = [] :: icode_info()}).
+-type icode() :: #icode{}.
%%---------------------------------------------------------------------
diff --git a/lib/hipe/icode/hipe_icode_fp.erl b/lib/hipe/icode/hipe_icode_fp.erl
index c0cd9bd2d1..38b3881a77 100644
--- a/lib/hipe/icode/hipe_icode_fp.erl
+++ b/lib/hipe/icode/hipe_icode_fp.erl
@@ -424,7 +424,7 @@ redirect_phis([I|Is] = Code, OldFrom, NewFrom, Acc) ->
NewI = hipe_icode:phi_redirect_pred(I, OldFrom, NewFrom),
redirect_phis(Is, OldFrom, NewFrom, [NewI|Acc]);
_ ->
- lists:reverse(Acc) ++ Code
+ lists:reverse(Acc, Code)
end;
redirect_phis([], _OldFrom, _NewFrom, Acc) ->
lists:reverse(Acc).
diff --git a/lib/hipe/icode/hipe_icode_mulret.erl b/lib/hipe/icode/hipe_icode_mulret.erl
index 2402bad42c..99522f6430 100644
--- a/lib/hipe/icode/hipe_icode_mulret.erl
+++ b/lib/hipe/icode/hipe_icode_mulret.erl
@@ -1166,9 +1166,9 @@ printCallList([]) -> io:format("~n").
%% removeUnElems([#icode_call{'fun'={unsafe_element,_}, args=Var}|List], Var, Res) ->
%% removeUnElems(List, Var, Res);
%% removeUnElems([I=#icode_move{dst=Var}|List], [Var], Res) ->
-%% lists:reverse(Res) ++ [I|List];
+%% lists:reverse(Res, [I|List]);
%% removeUnElems([I=#icode_call{dstlist=Var}|List], Var, Res) ->
-%% lists:reverse(Res) ++ [I|List];
+%% lists:reverse(Res, [I|List]);
%% removeUnElems([I|List], Var, Res) ->
%% removeUnElems(List, Var, [I|Res]);
%% removeUnElems([], _, Res) -> lists:reverse(Res).
@@ -1187,7 +1187,7 @@ printCallList([]) -> io:format("~n").
%% false ->
%% case lists:member(Var, Defs) of
%% true ->
-%% lists:reverse(Res) ++ [I|List];
+%% lists:reverse(Res, [I|List]);
%% false ->
%% removeUnElems(List, Var, [I|Res])
%% end
@@ -1195,7 +1195,7 @@ printCallList([]) -> io:format("~n").
%% false ->
%% case lists:member(Var, Defs) of
%% true ->
-%% lists:reverse(Res) ++ [I|List];
+%% lists:reverse(Res, [I|List]);
%% false ->
%% removeUnElems(List, Var, [I|Res])
%% end
@@ -1203,7 +1203,7 @@ printCallList([]) -> io:format("~n").
%% false ->
%% case lists:member(Var, Defs) of
%% true ->
-%% lists:reverse(Res) ++ [I|List];
+%% lists:reverse(Res, [I|List]);
%% false ->
%% removeUnElems(List, Var, [I|Res])
%% end
@@ -1248,16 +1248,16 @@ printCallList([]) -> io:format("~n").
%% modifyCode([I|Code], Var, Res) ->
%% case scanInstr(I, Var) of
%% {move, Arity, VarLst} ->
-%% Code2 = [#icode_return{vars=VarLst}, I |lists:reverse(Res) ++ Code],
+%% Code2 = [#icode_return{vars=VarLst}, I |lists:reverse(Res, Code)],
%% {Arity, lists:reverse(Code2)};
%% {mktuple, Arity, VarLst} ->
-%% Code2 = [#icode_return{vars=VarLst}|lists:reverse(Res) ++ Code],
+%% Code2 = [#icode_return{vars=VarLst}|lists:reverse(Res, Code)],
%% {Arity, lists:reverse(Code2)};
%% other ->
%% modifyCode(Code, Var, [I|Res])
%% end;
%% modifyCode([], Var, Res) ->
-%% {1, lists:reverse(Res) ++ [#icode_return{vars=Var}]}.
+%% {1, lists:reverse(Res, [#icode_return{vars=Var}]}.
%% scanInstr(#icode_call{dstlist=Var, 'fun'=mktuple, args=Lst}, Var) ->
%% {mktuple, length(Lst), Lst};
diff --git a/lib/hipe/icode/hipe_icode_type.erl b/lib/hipe/icode/hipe_icode_type.erl
index 65876b83ea..ebeb5e2c10 100644
--- a/lib/hipe/icode/hipe_icode_type.erl
+++ b/lib/hipe/icode/hipe_icode_type.erl
@@ -84,15 +84,15 @@
t_fun/0, t_fun/1, t_fun/2, t_fun_args/1, t_fun_arity/1,
t_inf/2, t_inf_lists/2, t_integer/0,
t_integer/1, t_is_atom/1, t_is_any/1,
- t_is_binary/1, t_is_bitstr/1, t_is_bitwidth/1, t_is_boolean/1,
- t_is_fixnum/1, t_is_cons/1,
+ t_is_binary/1, t_is_bitstr/1, t_is_bitwidth/1,
+ t_is_boolean/1, t_is_fixnum/1, t_is_cons/1, t_is_map/1,
t_is_maybe_improper_list/1, t_is_equal/2, t_is_float/1,
t_is_fun/1, t_is_integer/1, t_is_non_neg_integer/1,
t_is_number/1, t_is_matchstate/1,
- t_is_nil/1, t_is_none/1, t_is_port/1, t_is_pid/1,
+ t_is_none/1, t_is_port/1, t_is_pid/1,
t_is_reference/1, t_is_subtype/2, t_is_tuple/1,
t_limit/2, t_matchstate_present/1, t_matchstate/0,
- t_matchstate_slots/1, t_maybe_improper_list/0,
+ t_matchstate_slots/1, t_maybe_improper_list/0, t_map/0,
t_nil/0, t_none/0, t_number/0, t_number/1, t_number_vals/1,
t_pid/0, t_port/0, t_reference/0, t_subtract/2, t_sup/2,
t_to_tlist/1, t_tuple/0, t_tuple/1, t_tuple_sizes/1]).
@@ -213,7 +213,7 @@ analyse_blocks(Work, State, MFA) ->
{NewState, NewLabels} =
try analyse_block(Label, Info, State)
catch throw:none_type ->
- %% io:format("received none type at label: ~p~n",[Label]),
+ %% io:format("received none type at label: ~p~n", [Label]),
{State,[]}
end,
NewWork2 = add_work(NewWork, NewLabels),
@@ -265,7 +265,7 @@ analyse_insn(I, Info, LookupFun) ->
do_move(I, Info);
#icode_call{} ->
NewInfo = do_call(I, Info, LookupFun),
- %%io:format("Analysing Call: ~w~n~w~n", [I,NewInfo]),
+ %% io:format("Analysing Call: ~w~n~w~n", [I, NewInfo]),
update_call_arguments(I, NewInfo);
#icode_phi{} ->
Type = t_limit(join_list(hipe_icode:args(I), Info), ?TYPE_DEPTH),
@@ -788,16 +788,16 @@ test_record(Atom, Size, Var, VarInfo, TrueLab, FalseLab, Info) ->
end.
test_type(Test, Type) ->
- %%io:format("Test is: ~w\n", [Test]),
- %%io:format("Type is: ~s\n", [format_type(Type)]),
+ %% io:format("Test is: ~w\n", [Test]),
+ %% io:format("Type is: ~s\n", [format_type(Type)]),
Ans =
case t_is_any(Type) of
true -> maybe;
false ->
TrueTest = true_branch_info(Test),
Inf = t_inf(TrueTest, Type),
- %%io:format("TrueTest is: ~s\n", [format_type(TrueTest)]),
- %%io:format("Inf is: ~s\n", [format_type(Inf)]),
+ %% io:format("TrueTest is: ~s\n", [format_type(TrueTest)]),
+ %% io:format("Inf is: ~s\n", [format_type(Inf)]),
case t_is_equal(Type, Inf) of
true ->
not t_is_none(Type);
@@ -895,11 +895,12 @@ test_type0(boolean, T) ->
t_is_boolean(T);
test_type0(list, T) ->
t_is_maybe_improper_list(T);
-test_type0(cons, T) ->
- t_is_cons(T);
-test_type0(nil, T) ->
- t_is_nil(T).
-
+%% test_type0(cons, T) ->
+%% t_is_cons(T);
+%% test_type0(nil, T) ->
+%% t_is_nil(T).
+test_type0(map, T) ->
+ t_is_map(T).
true_branch_info(integer) ->
t_integer();
@@ -931,22 +932,24 @@ true_branch_info(reference) ->
t_reference();
true_branch_info(function) ->
t_fun();
-true_branch_info(cons) ->
- t_cons();
-true_branch_info(nil) ->
- t_nil();
+%% true_branch_info(cons) ->
+%% t_cons();
+%% true_branch_info(nil) ->
+%% t_nil();
true_branch_info(boolean) ->
t_boolean();
+true_branch_info(map) ->
+ t_map();
true_branch_info(T) ->
- exit({?MODULE,unknown_typetest,T}).
+ exit({?MODULE, unknown_typetest, T}).
%% _________________________________________________________________
%%
%% Remove the redundant type tests. If a test is removed, the trace
-%% that isn't taken is explicitly removed from the CFG to simpilify
+%% that isn't taken is explicitly removed from the CFG to simplify
%% the handling of Phi nodes. If a Phi node is left and at least one
-%% branch into it has disappeared, the SSA propagation pass can't
+%% branch into it has disappeared, the SSA propagation pass cannot
%% handle it.
%%
%% If the CFG has changed at the end of this pass, the analysis is
diff --git a/lib/hipe/llvm/Makefile b/lib/hipe/llvm/Makefile
new file mode 100644
index 0000000000..92f378924a
--- /dev/null
+++ b/lib/hipe/llvm/Makefile
@@ -0,0 +1,109 @@
+#
+# %CopyrightBegin%
+#
+# Copyright Ericsson AB 2001-2014. All Rights Reserved.
+#
+# The contents of this file are subject to the Erlang Public License,
+# Version 1.1, (the "License"); you may not use this file except in
+# 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 EBIN
+EBIN = ../ebin
+endif
+
+include $(ERL_TOP)/make/target.mk
+include $(ERL_TOP)/make/$(TARGET)/otp.mk
+
+# ----------------------------------------------------
+# Application version
+# ----------------------------------------------------
+include ../vsn.mk
+VSN=$(HIPE_VSN)
+
+# ----------------------------------------------------
+# Release directory specification
+# ----------------------------------------------------
+RELSYSDIR = $(RELEASE_PATH)/lib/hipe-$(VSN)
+
+# ----------------------------------------------------
+# Target Specs
+# ----------------------------------------------------
+ifdef HIPE_ENABLED
+HIPE_MODULES = hipe_rtl_to_llvm \
+ hipe_llvm \
+ elf_format \
+ hipe_llvm_main \
+ hipe_llvm_merge \
+ hipe_llvm_liveness
+else
+HIPE_MODULES =
+endif
+
+MODULES = $(HIPE_MODULES)
+
+HRL_FILES= elf_format.hrl elf32_format.hrl elf64_format.hrl \
+ hipe_llvm_arch.hrl
+ERL_FILES= $(MODULES:%=%.erl)
+TARGET_FILES= $(MODULES:%=$(EBIN)/%.$(EMULATOR))
+
+# APP_FILE=
+# App_SRC= $(APP_FILE).src
+# APP_TARGET= $(EBIN)/$(APP_FILE)
+#
+# APPUP_FILE=
+# APPUP_SRC= $(APPUP_FILE).src
+# APPUP_TARGET= $(EBIN)/$(APPUP_FILE)
+
+# ----------------------------------------------------
+# FLAGS: Please keep +inline below
+# ----------------------------------------------------
+
+include ../native.mk
+
+ERL_COMPILE_FLAGS += +inline #+warn_missing_spec
+
+# if in 32 bit backend define BIT32 symbol
+ARCH = $(shell echo $(TARGET) | sed 's/^\(x86_64\)-.*/64bit/')
+ifneq ($(ARCH), 64bit)
+ERL_COMPILE_FLAGS += -DBIT32
+endif
+
+# ----------------------------------------------------
+# Targets
+# ----------------------------------------------------
+
+debug opt: $(TARGET_FILES)
+
+docs:
+
+clean:
+ rm -f $(TARGET_FILES)
+ rm -f core erl_crash.dump
+
+# ----------------------------------------------------
+# Special Build Targets
+# ----------------------------------------------------
+
+
+# ----------------------------------------------------
+# Release Target
+# ----------------------------------------------------
+include $(ERL_TOP)/make/otp_release_targets.mk
+
+release_spec: opt
+ $(INSTALL_DIR) $(RELSYSDIR)/llvm
+ $(INSTALL_DATA) $(ERL_FILES) $(HRL_FILES) $(RELSYSDIR)/llvm
+ $(INSTALL_DIR) $(RELSYSDIR)/ebin
+ $(INSTALL_DATA) $(TARGET_FILES) $(RELSYSDIR)/ebin
+
+release_docs_spec:
diff --git a/lib/hipe/llvm/elf32_format.hrl b/lib/hipe/llvm/elf32_format.hrl
new file mode 100644
index 0000000000..af1d95bf5b
--- /dev/null
+++ b/lib/hipe/llvm/elf32_format.hrl
@@ -0,0 +1,59 @@
+%% -*- erlang-indent-level: 2 -*-
+
+%%% @copyright 2011-2014 Yiannis Tsiouris <[email protected]>,
+%%% Chris Stavrakakis <[email protected]>
+%%% @author Yiannis Tsiouris <[email protected]>
+%%% [http://www.softlab.ntua.gr/~gtsiour/]
+
+%%% @doc This header file contains very very useful macros for handling
+%%% various segments of an ELF-32 formated object file, such as sizes,
+%%% offsets and predefined constants. For further information about
+%%% each field take a quick look at
+%%% "[http://www.sco.com/developers/gabi/latest/contents.html]"
+%%% that contain the current HP/Intel definition of the ELF object
+%%% file format.
+
+%%------------------------------------------------------------------------------
+%% ELF-32 Data Types (in bytes)
+%%------------------------------------------------------------------------------
+-define(ELF_ADDR_SIZE, 4).
+-define(ELF_OFF_SIZE, 4).
+-define(ELF_HALF_SIZE, 2).
+-define(ELF_WORD_SIZE, 4).
+-define(ELF_SWORD_SIZE, 4).
+-define(ELF_XWORD_SIZE, ?ELF_WORD_SIZE). % for compatibility
+-define(ELF_SXWORD_SIZE, ?ELF_WORD_SIZE).
+-define(ELF_UNSIGNED_CHAR_SIZE, 1).
+
+%%------------------------------------------------------------------------------
+%% ELF-32 Symbol Table Entries
+%%------------------------------------------------------------------------------
+%% Precomputed offset for Symbol Table entries in SymTab binary (needed because
+%% of the different offsets in 32 and 64 bit formats).
+-define(ST_NAME_OFFSET, 0).
+-define(ST_VALUE_OFFSET, (?ST_NAME_OFFSET + ?ST_NAME_SIZE) ).
+-define(ST_SIZE_OFFSET, (?ST_VALUE_OFFSET + ?ST_VALUE_SIZE) ).
+-define(ST_INFO_OFFSET, (?ST_SIZE_OFFSET + ?ST_SIZE_SIZE) ).
+-define(ST_OTHER_OFFSET, (?ST_INFO_OFFSET + ?ST_INFO_SIZE) ).
+-define(ST_SHNDX_OFFSET, (?ST_OTHER_OFFSET + ?ST_OTHER_SIZE) ).
+
+%%------------------------------------------------------------------------------
+%% ELF-64 Relocation Entries
+%%------------------------------------------------------------------------------
+%% Useful macros to extract information from r_info field
+-define(ELF_R_SYM(I), (I bsr 8) ).
+-define(ELF_R_TYPE(I), (I band 16#ff) ).
+-define(ELF_R_INFO(S, T), ((S bsl 8) + (T band 16#ff)) ).
+
+%%------------------------------------------------------------------------------
+%% ELF-64 Program Header Table
+%%------------------------------------------------------------------------------
+%% Offsets of various fields in a Program Header Table entry binary.
+-define(P_TYPE_OFFSET, 0).
+-define(P_OFFSET_OFFSET, (?P_FLAGS_OFFSET + ?P_FLAGS_SIZE) ).
+-define(P_VADDR_OFFSET, (?P_OFFSET_OFFSET + ?P_OFFSET_SIZE) ).
+-define(P_PADDR_OFFSET, (?P_VADDR_OFFSET + ?P_VADDR_SIZE) ).
+-define(P_FILESZ_OFFSET, (?P_PVADDR_OFFSET + ?P_PVADDR_SIZE) ).
+-define(P_MEMSZ_OFFSET, (?P_FILESZ_OFFSET + ?P_FILESZ_SIZE) ).
+-define(P_FLAGS_OFFSET, (?P_TYPE_OFFSET + ?P_TYPE_SIZE) ).
+-define(P_ALIGN_OFFSET, (?P_MEMSZ_OFFSET + ?P_MEMSZ_SIZE) ).
diff --git a/lib/hipe/llvm/elf64_format.hrl b/lib/hipe/llvm/elf64_format.hrl
new file mode 100644
index 0000000000..794746ffdc
--- /dev/null
+++ b/lib/hipe/llvm/elf64_format.hrl
@@ -0,0 +1,58 @@
+%% -*- erlang-indent-level: 2 -*-
+
+%%% @copyright 2011-2014 Yiannis Tsiouris <[email protected]>,
+%%% Chris Stavrakakis <[email protected]>
+%%% @author Yiannis Tsiouris <[email protected]>
+%%% [http://www.softlab.ntua.gr/~gtsiour/]
+
+%%% @doc This header file contains very very useful macros for handling
+%%% various segments of an ELF-64 formated object file, such as sizes,
+%%% offsets and predefined constants. For further information about
+%%% each field take a quick look at
+%%% "[http://downloads.openwatcom.org/ftp/devel/docs/elf-64-gen.pdf]"
+%%% that contain the current HP/Intel definition of the ELF object
+%%% file format.
+
+%%------------------------------------------------------------------------------
+%% ELF-64 Data Types (in bytes)
+%%------------------------------------------------------------------------------
+-define(ELF_ADDR_SIZE, 8).
+-define(ELF_OFF_SIZE, 8).
+-define(ELF_HALF_SIZE, 2).
+-define(ELF_WORD_SIZE, 4).
+-define(ELF_SWORD_SIZE, 4).
+-define(ELF_XWORD_SIZE, 8).
+-define(ELF_SXWORD_SIZE, 8).
+-define(ELF_UNSIGNED_CHAR_SIZE, 1).
+
+%%------------------------------------------------------------------------------
+%% ELF-64 Symbol Table Entries
+%%------------------------------------------------------------------------------
+%% Precomputed offset for Symbol Table entries in SymTab binary
+-define(ST_NAME_OFFSET, 0).
+-define(ST_INFO_OFFSET, (?ST_NAME_OFFSET + ?ST_NAME_SIZE) ).
+-define(ST_OTHER_OFFSET, (?ST_INFO_OFFSET + ?ST_INFO_SIZE) ).
+-define(ST_SHNDX_OFFSET, (?ST_OTHER_OFFSET + ?ST_OTHER_SIZE) ).
+-define(ST_VALUE_OFFSET, (?ST_SHNDX_OFFSET + ?ST_SHNDX_SIZE) ).
+-define(ST_SIZE_OFFSET, (?ST_VALUE_OFFSET + ?ST_VALUE_SIZE) ).
+
+%%------------------------------------------------------------------------------
+%% ELF-64 Relocation Entries
+%%------------------------------------------------------------------------------
+%% Useful macros to extract information from r_info field
+-define(ELF_R_SYM(I), (I bsr 32) ).
+-define(ELF_R_TYPE(I), (I band 16#ffffffff) ).
+-define(ELF_R_INFO(S, T), ((S bsl 32) + (T band 16#ffffffff)) ).
+
+%%------------------------------------------------------------------------------
+%% ELF-64 Program Header Table
+%%------------------------------------------------------------------------------
+%% Offsets of various fields in a Program Header Table entry binary.
+-define(P_TYPE_OFFSET, 0).
+-define(P_FLAGS_OFFSET, (?P_TYPE_OFFSET + ?P_TYPE_SIZE) ).
+-define(P_OFFSET_OFFSET, (?P_FLAGS_OFFSET + ?P_FLAGS_SIZE) ).
+-define(P_VADDR_OFFSET, (?P_OFFSET_OFFSET + ?P_OFFSET_SIZE) ).
+-define(P_PADDR_OFFSET, (?P_VADDR_OFFSET + ?P_VADDR_SIZE) ).
+-define(P_FILESZ_OFFSET, (?P_PVADDR_OFFSET + ?P_PVADDR_SIZE) ).
+-define(P_MEMSZ_OFFSET, (?P_FILESZ_OFFSET + ?P_FILESZ_SIZE) ).
+-define(P_ALIGN_OFFSET, (?P_MEMSZ_OFFSET + ?P_MEMSZ_SIZE) ).
diff --git a/lib/hipe/llvm/elf_format.erl b/lib/hipe/llvm/elf_format.erl
new file mode 100644
index 0000000000..260da9b5e6
--- /dev/null
+++ b/lib/hipe/llvm/elf_format.erl
@@ -0,0 +1,790 @@
+%% -*- erlang-indent-level: 2 -*-
+
+%%% @copyright 2011-2014 Yiannis Tsiouris <[email protected]>,
+%%% Chris Stavrakakis <[email protected]>,
+%%% Kostis Sagonas <[email protected]>
+%%% @author Yiannis Tsiouris <[email protected]>
+%%% [http://www.softlab.ntua.gr/~gtsiour/]
+
+%%% @doc This module contains functions for extracting various pieces of
+%%% information from an ELF formated Object file. To fully understand
+%%% the ELF format and the use of these functions please read
+%%% "[http://www.linuxjournal.com/article/1060?page=0,0]" carefully.
+
+-module(elf_format).
+
+-export([get_tab_entries/1,
+ %% Relocations
+ get_rodata_relocs/1,
+ get_text_relocs/1,
+ extract_rela/2,
+ get_rela_addends/1,
+ %% Note
+ extract_note/2,
+ %% Executable code
+ extract_text/1,
+ %% GCC Exception Table
+ get_exn_handlers/1,
+ %% Misc.
+ set_architecture_flag/1,
+ is64bit/0
+ ]).
+
+-include("elf_format.hrl").
+
+%%------------------------------------------------------------------------------
+%% Types
+%%------------------------------------------------------------------------------
+
+-type elf() :: binary().
+
+-type lp() :: non_neg_integer(). % landing pad
+-type num() :: non_neg_integer().
+-type index() :: non_neg_integer().
+-type offset() :: non_neg_integer().
+-type size() :: non_neg_integer().
+-type start() :: non_neg_integer().
+
+-type info() :: index().
+-type nameoff() :: offset().
+-type valueoff() :: offset().
+
+-type name() :: string().
+-type name_size() :: {name(), size()}.
+-type name_sizes() :: [name_size()].
+
+%%------------------------------------------------------------------------------
+%% Abstract Data Types and Accessors for ELF Structures.
+%%------------------------------------------------------------------------------
+
+%% File header
+-record(elf_ehdr, {ident, % ELF identification
+ type, % Object file type
+ machine, % Machine Type
+ version, % Object file version
+ entry, % Entry point address
+ phoff, % Program header offset
+ shoff :: offset(), % Section header offset
+ flags, % Processor-specific flags
+ ehsize :: size(), % ELF header size
+ phentsize :: size(), % Size of program header entry
+ phnum :: num(), % Number of program header entries
+ shentsize :: size(), % Size of section header entry
+ shnum :: num(), % Number of section header entries
+ shstrndx :: index() % Section name string table index
+ }).
+-type elf_ehdr() :: #elf_ehdr{}.
+
+-record(elf_ehdr_ident, {class, % File class
+ data, % Data encoding
+ version, % File version
+ osabi, % OS/ABI identification
+ abiversion, % ABI version
+ pad, % Start of padding bytes
+ nident % Size of e_ident[]
+ }).
+%% -type elf_ehdr_ident() :: #elf_ehdr_ident{}.
+
+%% Section header entries
+-record(elf_shdr, {name, % Section name
+ type, % Section type
+ flags, % Section attributes
+ addr, % Virtual address in memory
+ offset :: offset(), % Offset in file
+ size :: size(), % Size of section
+ link, % Link to other section
+ info, % Miscellaneous information
+ addralign, % Address align boundary
+ entsize % Size of entries, if section has table
+ }).
+%% -type elf_shdr() :: #elf_shdr{}.
+
+%% Symbol table entries
+-record(elf_sym, {name :: nameoff(), % Symbol name
+ info, % Type and Binding attributes
+ other, % Reserved
+ shndx, % Section table index
+ value :: valueoff(), % Symbol value
+ size :: size() % Size of object
+ }).
+-type elf_sym() :: #elf_sym{}.
+
+%% Relocations
+-record(elf_rel, {r_offset :: offset(), % Address of reference
+ r_info :: info() % Symbol index and type of relocation
+ }).
+-type elf_rel() :: #elf_rel{}.
+
+-record(elf_rela, {r_offset :: offset(), % Address of reference
+ r_info :: info(), % Symbol index and type of relocation
+ r_addend :: offset() % Constant part of expression
+ }).
+-type elf_rela() :: #elf_rela{}.
+
+%% %% Program header table
+%% -record(elf_phdr, {type, % Type of segment
+%% flags, % Segment attributes
+%% offset, % Offset in file
+%% vaddr, % Virtual address in memory
+%% paddr, % Reserved
+%% filesz, % Size of segment in file
+%% memsz, % Size of segment in memory
+%% align % Alignment of segment
+%% }).
+
+%% %% GCC exception table
+%% -record(elf_gccexntab, {lpbenc, % Landing pad base encoding
+%% lpbase, % Landing pad base
+%% ttenc, % Type table encoding
+%% ttoff, % Type table offset
+%% csenc, % Call-site table encoding
+%% cstabsize, % Call-site table size
+%% cstab :: cstab() % Call-site table
+%% }).
+%% -type elf_gccexntab() :: #elf_gccexntab{}.
+
+-record(elf_gccexntab_callsite, {start :: start(), % Call-site start
+ size :: size(), % Call-site size
+ lp :: lp(), % Call-site landing pad
+ % (exception handler)
+ onaction % On action (e.g. cleanup)
+ }).
+%% -type elf_gccexntab_callsite() :: #elf_gccexntab_callsite{}.
+
+%%------------------------------------------------------------------------------
+%% Accessor Functions
+%%------------------------------------------------------------------------------
+
+%% File header
+%% -spec mk_ehdr(...) -> elf_ehrd().
+mk_ehdr(Ident, Type, Machine, Version, Entry, Phoff, Shoff, Flags, Ehsize,
+ Phentsize, Phnum, Shentsize, Shnum, Shstrndx) ->
+ #elf_ehdr{ident = Ident, type = Type, machine = Machine, version = Version,
+ entry = Entry, phoff = Phoff, shoff = Shoff, flags = Flags,
+ ehsize = Ehsize, phentsize = Phentsize, phnum = Phnum,
+ shentsize = Shentsize, shnum = Shnum, shstrndx = Shstrndx}.
+
+%% -spec ehdr_shoff(elf_ehdr()) -> offset().
+%% ehdr_shoff(#elf_ehdr{shoff = Offset}) -> Offset.
+%%
+%% -spec ehdr_shentsize(elf_ehdr()) -> size().
+%% ehdr_shentsize(#elf_ehdr{shentsize = Size}) -> Size.
+%%
+%% -spec ehdr_shnum(elf_ehdr()) -> num().
+%% ehdr_shnum(#elf_ehdr{shnum = Num}) -> Num.
+%%
+%% -spec ehdr_shstrndx(elf_ehdr()) -> index().
+%% ehdr_shstrndx(#elf_ehdr{shstrndx = Index}) -> Index.
+
+
+%%-spec mk_ehdr_ident(...) -> elf_ehdr_ident().
+mk_ehdr_ident(Class, Data, Version, OsABI, AbiVersion, Pad, Nident) ->
+ #elf_ehdr_ident{class = Class, data = Data, version = Version, osabi = OsABI,
+ abiversion = AbiVersion, pad = Pad, nident = Nident}.
+
+%%%-------------------------
+%%% Section header entries
+%%%-------------------------
+mk_shdr(Name, Type, Flags, Addr, Offset, Size, Link, Info, AddrAlign, EntSize) ->
+ #elf_shdr{name = Name, type = Type, flags = Flags, addr = Addr,
+ offset = Offset, size = Size, link = Link, info = Info,
+ addralign = AddrAlign, entsize = EntSize}.
+
+%% -spec shdr_offset(elf_shdr()) -> offset().
+%% shdr_offset(#elf_shdr{offset = Offset}) -> Offset.
+%%
+%% -spec shdr_size(elf_shdr()) -> size().
+%% shdr_size(#elf_shdr{size = Size}) -> Size.
+
+%%%-------------------------
+%%% Symbol Table Entries
+%%%-------------------------
+mk_sym(Name, Info, Other, Shndx, Value, Size) ->
+ #elf_sym{name = Name, info = Info, other = Other,
+ shndx = Shndx, value = Value, size = Size}.
+
+-spec sym_name(elf_sym()) -> nameoff().
+sym_name(#elf_sym{name = Name}) -> Name.
+
+%% -spec sym_value(elf_sym()) -> valueoff().
+%% sym_value(#elf_sym{value = Value}) -> Value.
+%%
+%% -spec sym_size(elf_sym()) -> size().
+%% sym_size(#elf_sym{size = Size}) -> Size.
+
+%%%-------------------------
+%%% Relocations
+%%%-------------------------
+-spec mk_rel(offset(), info()) -> elf_rel().
+mk_rel(Offset, Info) ->
+ #elf_rel{r_offset = Offset, r_info = Info}.
+
+%% The following two functions capitalize on the fact that the two kinds of
+%% relocation records (for 32- and 64-bit architectures have similar structure.
+
+-spec r_offset(elf_rel() | elf_rela()) -> offset().
+r_offset(#elf_rel{r_offset = Offset}) -> Offset;
+r_offset(#elf_rela{r_offset = Offset}) -> Offset.
+
+-spec r_info(elf_rel() | elf_rela()) -> info().
+r_info(#elf_rel{r_info = Info}) -> Info;
+r_info(#elf_rela{r_info = Info}) -> Info.
+
+-spec mk_rela(offset(), info(), offset()) -> elf_rela().
+mk_rela(Offset, Info, Addend) ->
+ #elf_rela{r_offset = Offset, r_info = Info, r_addend = Addend}.
+
+-spec rela_addend(elf_rela()) -> offset().
+rela_addend(#elf_rela{r_addend = Addend}) -> Addend.
+
+%% %%%-------------------------
+%% %%% GCC exception table
+%% %%%-------------------------
+%% -type cstab() :: [elf_gccexntab_callsite()].
+%%
+%% mk_gccexntab(LPbenc, LPbase, TTenc, TToff, CSenc, CStabsize, CStab) ->
+%% #elf_gccexntab{lpbenc = LPbenc, lpbase = LPbase, ttenc = TTenc,
+%% ttoff = TToff, csenc = CSenc, cstabsize = CStabsize,
+%% cstab = CStab}.
+%%
+%% -spec gccexntab_cstab(elf_gccexntab()) -> cstab().
+%% gccexntab_cstab(#elf_gccexntab{cstab = CSTab}) -> CSTab.
+
+mk_gccexntab_callsite(Start, Size, LP, Action) ->
+ #elf_gccexntab_callsite{start = Start, size=Size, lp=LP, onaction=Action}.
+
+%% -spec gccexntab_callsite_start(elf_gccexntab_callsite()) -> start().
+%% gccexntab_callsite_start(#elf_gccexntab_callsite{start = Start}) -> Start.
+%%
+%% -spec gccexntab_callsite_size(elf_gccexntab_callsite()) -> size().
+%% gccexntab_callsite_size(#elf_gccexntab_callsite{size = Size}) -> Size.
+%%
+%% -spec gccexntab_callsite_lp(elf_gccexntab_callsite()) -> lp().
+%% gccexntab_callsite_lp(#elf_gccexntab_callsite{lp = LP}) -> LP.
+
+%%------------------------------------------------------------------------------
+%% Functions to manipulate the ELF File Header
+%%------------------------------------------------------------------------------
+
+%% @doc Extracts the File Header from an ELF formatted object file. Also sets
+%% the ELF class variable in the process dictionary (used by many functions
+%% in this and hipe_llvm_main modules).
+-spec extract_header(elf()) -> elf_ehdr().
+extract_header(Elf) ->
+ Ehdr_bin = get_binary_segment(Elf, 0, ?ELF_EHDR_SIZE),
+ << %% Structural pattern matching on fields.
+ Ident_bin:?E_IDENT_SIZE/binary,
+ Type:?bits(?E_TYPE_SIZE)/integer-little,
+ Machine:?bits(?E_MACHINE_SIZE)/integer-little,
+ Version:?bits(?E_VERSION_SIZE)/integer-little,
+ Entry:?bits(?E_ENTRY_SIZE)/integer-little,
+ Phoff:?bits(?E_PHOFF_SIZE)/integer-little,
+ Shoff:?bits(?E_SHOFF_SIZE)/integer-little,
+ Flags:?bits(?E_FLAGS_SIZE)/integer-little,
+ Ehsize:?bits(?E_EHSIZE_SIZE)/integer-little,
+ Phentsize:?bits(?E_PHENTSIZE_SIZE)/integer-little,
+ Phnum:?bits(?E_PHNUM_SIZE)/integer-little,
+ Shentsize:?bits(?E_SHENTSIZE_SIZE)/integer-little,
+ Shnum:?bits(?E_SHENTSIZE_SIZE)/integer-little,
+ Shstrndx:?bits(?E_SHSTRNDX_SIZE)/integer-little
+ >> = Ehdr_bin,
+ <<16#7f, $E, $L, $F, Class, Data, Version, Osabi, Abiversion,
+ Pad:6/binary, Nident
+ >> = Ident_bin,
+ Ident = mk_ehdr_ident(Class, Data, Version, Osabi,
+ Abiversion, Pad, Nident),
+ mk_ehdr(Ident, Type, Machine, Version, Entry, Phoff, Shoff, Flags,
+ Ehsize, Phentsize, Phnum, Shentsize, Shnum, Shstrndx).
+
+%%------------------------------------------------------------------------------
+%% Functions to manipulate Section Header Entries
+%%------------------------------------------------------------------------------
+
+%% @doc Extracts the Section Header Table from an ELF formated Object File.
+extract_shdrtab(Elf) ->
+ %% Extract File Header to get info about Section Header Offset (in bytes),
+ %% Entry Size (in bytes) and Number of entries
+ #elf_ehdr{shoff = ShOff, shentsize = ShEntsize, shnum = ShNum} =
+ extract_header(Elf),
+ %% Get actual Section header table (binary)
+ ShdrBin = get_binary_segment(Elf, ShOff, ShNum * ShEntsize),
+ get_shdrtab_entries(ShdrBin, []).
+
+get_shdrtab_entries(<<>>, Acc) ->
+ lists:reverse(Acc);
+get_shdrtab_entries(ShdrBin, Acc) ->
+ <<%% Structural pattern matching on fields.
+ Name:?bits(?SH_NAME_SIZE)/integer-little,
+ Type:?bits(?SH_TYPE_SIZE)/integer-little,
+ Flags:?bits(?SH_FLAGS_SIZE)/integer-little,
+ Addr:?bits(?SH_ADDR_SIZE)/integer-little,
+ Offset:?bits(?SH_OFFSET_SIZE)/integer-little,
+ Size:?bits(?SH_SIZE_SIZE)/integer-little,
+ Link:?bits(?SH_LINK_SIZE)/integer-little,
+ Info:?bits(?SH_INFO_SIZE)/integer-little,
+ Addralign:?bits(?SH_ADDRALIGN_SIZE)/integer-little,
+ Entsize:?bits(?SH_ENTSIZE_SIZE)/integer-little,
+ MoreShdrE/binary
+ >> = ShdrBin,
+ ShdrE = mk_shdr(Name, Type, Flags, Addr, Offset,
+ Size, Link, Info, Addralign, Entsize),
+ get_shdrtab_entries(MoreShdrE, [ShdrE | Acc]).
+
+%% @doc Extracts a specific Entry of a Section Header Table. This function
+%% takes as argument the Section Header Table (`SHdrTab') and the entry's
+%% serial number (`EntryNum') and returns the entry (`shdr').
+get_shdrtab_entry(SHdrTab, EntryNum) ->
+ lists:nth(EntryNum + 1, SHdrTab).
+
+%%------------------------------------------------------------------------------
+%% Functions to manipulate Section Header String Table
+%%------------------------------------------------------------------------------
+
+%% @doc Extracts the Section Header String Table. This section is not a known
+%% ELF Object File section. It is just a "hidden" table storing the
+%% names of all sections that exist in current object file.
+-spec extract_shstrtab(elf()) -> [name()].
+extract_shstrtab(Elf) ->
+ %% Extract Section Name String Table Index
+ #elf_ehdr{shstrndx = ShStrNdx} = extract_header(Elf),
+ ShHdrTab = extract_shdrtab(Elf),
+ %% Extract Section header entry and get actual Section-header String Table
+ #elf_shdr{offset = ShStrOffset, size = ShStrSize} =
+ get_shdrtab_entry(ShHdrTab, ShStrNdx),
+ case get_binary_segment(Elf, ShStrOffset, ShStrSize) of
+ <<>> -> %% Segment empty
+ [];
+ ShStrTab -> %% Convert to string table
+ [Name || {Name, _Size} <- get_names(ShStrTab)]
+ end.
+
+%%------------------------------------------------------------------------------
+
+-spec get_tab_entries(elf()) -> [{name(), valueoff(), size()}].
+get_tab_entries(Elf) ->
+ SymTab = extract_symtab(Elf),
+ Ts = [{Name, Value, Size div ?ELF_XWORD_SIZE}
+ || #elf_sym{name = Name, value = Value, size = Size} <- SymTab,
+ Name =/= 0],
+ {NameIndices, ValueOffs, Sizes} = lists:unzip3(Ts),
+ %% Find the names of the symbols.
+ %% Get string table entries ([{Name, Offset in strtab section}]). Keep only
+ %% relevant entries:
+ StrTab = extract_strtab(Elf),
+ Relevant = [get_strtab_entry(StrTab, Off) || Off <- NameIndices],
+ %% Zip back to {Name, ValueOff, Size}
+ lists:zip3(Relevant, ValueOffs, Sizes).
+
+%%------------------------------------------------------------------------------
+%% Functions to manipulate Symbol Table
+%%------------------------------------------------------------------------------
+
+%% @doc Function that extracts Symbol Table from an ELF Object file.
+extract_symtab(Elf) ->
+ Symtab_bin = extract_segment_by_name(Elf, ?SYMTAB),
+ get_symtab_entries(Symtab_bin, []).
+
+get_symtab_entries(<<>>, Acc) ->
+ lists:reverse(Acc);
+get_symtab_entries(Symtab_bin, Acc) ->
+ <<SymE_bin:?ELF_SYM_SIZE/binary, MoreSymE/binary>> = Symtab_bin,
+ case is64bit() of
+ true ->
+ <<%% Structural pattern matching on fields.
+ Name:?bits(?ST_NAME_SIZE)/integer-little,
+ Info:?bits(?ST_INFO_SIZE)/integer-little,
+ Other:?bits(?ST_OTHER_SIZE)/integer-little,
+ Shndx:?bits(?ST_SHNDX_SIZE)/integer-little,
+ Value:?bits(?ST_VALUE_SIZE)/integer-little,
+ Size:?bits(?ST_SIZE_SIZE)/integer-little
+ >> = SymE_bin;
+ false ->
+ << %% Same fields in different order:
+ Name:?bits(?ST_NAME_SIZE)/integer-little,
+ Value:?bits(?ST_VALUE_SIZE)/integer-little,
+ Size:?bits(?ST_SIZE_SIZE)/integer-little,
+ Info:?bits(?ST_INFO_SIZE)/integer-little,
+ Other:?bits(?ST_OTHER_SIZE)/integer-little,
+ Shndx:?bits(?ST_SHNDX_SIZE)/integer-little
+ >> = SymE_bin
+ end,
+ SymE = mk_sym(Name, Info, Other, Shndx, Value, Size),
+ get_symtab_entries(MoreSymE, [SymE | Acc]).
+
+%% @doc Extracts a specific entry from the Symbol Table (as binary).
+%% This function takes as arguments the Symbol Table (`SymTab')
+%% and the entry's serial number and returns that entry (`sym').
+get_symtab_entry(SymTab, EntryNum) ->
+ lists:nth(EntryNum + 1, SymTab).
+
+%%------------------------------------------------------------------------------
+%% Functions to manipulate String Table
+%%------------------------------------------------------------------------------
+
+%% @doc Extracts String Table from an ELF formated Object File.
+-spec extract_strtab(elf()) -> [{string(), offset()}].
+extract_strtab(Elf) ->
+ Strtab_bin = extract_segment_by_name(Elf, ?STRTAB),
+ NamesSizes = get_names(Strtab_bin),
+ make_offsets(NamesSizes).
+
+%% @doc Returns the name of the symbol at the given offset. The string table
+%% contains entries of the form {Name, Offset}. If no such offset exists
+%% returns the empty string (`""').
+%% XXX: There might be a bug here because of the "compact" saving the ELF
+%% format uses: e.g. only stores ".rela.text" for ".rela.text" and ".text".
+get_strtab_entry(Strtab, Offset) ->
+ case lists:keyfind(Offset, 2, Strtab) of
+ {Name, Offset} -> Name;
+ false -> ""
+ end.
+
+%%------------------------------------------------------------------------------
+%% Functions to manipulate Relocations
+%%------------------------------------------------------------------------------
+
+%% @doc This function gets as argument an ELF binary file and returns a list
+%% with all .rela.rodata labels (i.e. constants and literals in code)
+%% or an empty list if no ".rela.rodata" section exists in code.
+-spec get_rodata_relocs(elf()) -> [offset()].
+get_rodata_relocs(Elf) ->
+ case is64bit() of
+ true ->
+ %% Only care about the addends (== offsets):
+ get_rela_addends(extract_rela(Elf, ?RODATA));
+ false ->
+ %% Find offsets hardcoded in ".rodata" entry
+ %%XXX: Treat all 0s as padding and skip them!
+ [SkipPadding || SkipPadding <- extract_rodata(Elf), SkipPadding =/= 0]
+ end.
+
+-spec get_rela_addends([elf_rela()]) -> [offset()].
+get_rela_addends(RelaEntries) ->
+ [rela_addend(E) || E <- RelaEntries].
+
+%% @doc Extract a list of the form `[{SymbolName, Offset}]' with all relocatable
+%% symbols and their offsets in the code from the ".text" section.
+-spec get_text_relocs(elf()) -> [{name(), offset()}].
+get_text_relocs(Elf) ->
+ %% Only care about the symbol table index and the offset:
+ NameOffsetTemp = [{?ELF_R_SYM(r_info(E)), r_offset(E)}
+ || E <- extract_rela(Elf, ?TEXT)],
+ {NameIndices, ActualOffsets} = lists:unzip(NameOffsetTemp),
+ %% Find the names of the symbols:
+ %%
+ %% Get those symbol table entries that are related to Text relocs:
+ Symtab = extract_symtab(Elf),
+ SymtabEs = [get_symtab_entry(Symtab, Index) || Index <- NameIndices],
+ %XXX: not zero-indexed!
+ %% Symbol table entries contain the offset of the name of the symbol in
+ %% String Table:
+ SymtabEs2 = [sym_name(E) || E <- SymtabEs], %XXX: Do we need to sort SymtabE?
+ %% Get string table entries ([{Name, Offset in strtab section}]). Keep only
+ %% relevant entries:
+ Strtab = extract_strtab(Elf),
+ Relevant = [get_strtab_entry(Strtab, Off) || Off <- SymtabEs2],
+ %% Zip back with actual offsets:
+ lists:zip(Relevant, ActualOffsets).
+
+%% @doc Extract the Relocations segment for section `Name' (that is passed
+%% as second argument) from an ELF formated Object file binary.
+-spec extract_rela(elf(), name()) -> [elf_rel() | elf_rela()].
+extract_rela(Elf, Name) ->
+ SegName =
+ case is64bit() of
+ true -> ?RELA(Name); % ELF-64 uses ".rela"
+ false -> ?REL(Name) % ...while ELF-32 uses ".rel"
+ end,
+ Rela_bin = extract_segment_by_name(Elf, SegName),
+ get_rela_entries(Rela_bin, []).
+
+get_rela_entries(<<>>, Acc) ->
+ lists:reverse(Acc);
+get_rela_entries(Bin, Acc) ->
+ E = case is64bit() of
+ true ->
+ <<%% Structural pattern matching on fields of a Rela Entry.
+ Offset:?bits(?R_OFFSET_SIZE)/integer-little,
+ Info:?bits(?R_INFO_SIZE)/integer-little,
+ Addend:?bits(?R_ADDEND_SIZE)/integer-little,
+ Rest/binary
+ >> = Bin,
+ mk_rela(Offset, Info, Addend);
+ false ->
+ <<%% Structural pattern matching on fields of a Rel Entry.
+ Offset:?bits(?R_OFFSET_SIZE)/integer-little,
+ Info:?bits(?R_INFO_SIZE)/integer-little,
+ Rest/binary
+ >> = Bin,
+ mk_rel(Offset, Info)
+ end,
+ get_rela_entries(Rest, [E | Acc]).
+
+%% %% @doc Extract the `EntryNum' (serial number) Relocation Entry.
+%% get_rela_entry(Rela, EntryNum) ->
+%% lists:nth(EntryNum + 1, Rela).
+
+%%------------------------------------------------------------------------------
+%% Functions to manipulate Executable Code segment
+%%------------------------------------------------------------------------------
+
+%% @doc This function gets as arguments an ELF formated binary file and
+%% returns the Executable Code (".text" segment) or an empty binary if it
+%% is not found.
+-spec extract_text(elf()) -> binary().
+extract_text(Elf) ->
+ extract_segment_by_name(Elf, ?TEXT).
+
+%%------------------------------------------------------------------------------
+%% Functions to manipulate Note Section
+%%------------------------------------------------------------------------------
+
+%% @doc Extract specific Note Section from an ELF Object file. The function
+%% takes as first argument the object file (`Elf') and the `Name' of the
+%% wanted Note Section (<b>without</b> the ".note" prefix!). It returns
+%% the specified binary segment or an empty binary if no such section
+%% exists.
+-spec extract_note(elf(), string()) -> binary().
+extract_note(Elf, Name) ->
+ extract_segment_by_name(Elf, ?NOTE(Name)).
+
+%%------------------------------------------------------------------------------
+%% Functions to manipulate GCC Exception Table segment
+%%------------------------------------------------------------------------------
+
+%% A description for the C++ exception table formats can be found at Exception
+%% Handling Tables (http://www.codesourcery.com/cxx-abi/exceptions.pdf).
+
+%% A list with `{Start, End, HandlerOffset}' for all call sites in the code
+-spec get_exn_handlers(elf()) -> [{start(), start(), lp()}].
+get_exn_handlers(Elf) ->
+ CallSites = extract_gccexntab_callsites(Elf),
+ [{Start, Start + Size, LP}
+ || #elf_gccexntab_callsite{start = Start, size = Size, lp = LP} <- CallSites].
+
+%% @doc This function gets as argument an ELF binary file and returns
+%% the table (list) of call sites which is stored in GCC
+%% Exception Table (".gcc_except_table") section.
+%% It returns an empty list if the Exception Table is not found.
+%% XXX: Assumes there is *no* Action Record Table.
+extract_gccexntab_callsites(Elf) ->
+ case extract_segment_by_name(Elf, ?GCC_EXN_TAB) of
+ <<>> ->
+ [];
+ ExnTab ->
+ %% First byte of LSDA is Landing Pad base encoding.
+ <<LBenc:8, More/binary>> = ExnTab,
+ %% Second byte is the Landing Pad base (if its encoding is not
+ %% DW_EH_PE_omit) (optional).
+ {_LPBase, LSDACont} =
+ case LBenc =:= ?DW_EH_PE_omit of
+ true -> % No landing pad base byte. (-1 denotes that)
+ {-1, More};
+ false -> % Landing pad base.
+ <<Base:8, More2/binary>> = More,
+ {Base, More2}
+ end,
+ %% Next byte of LSDA is the encoding of the Type Table.
+ <<TTenc:8, More3/binary>> = LSDACont,
+ %% Next byte is the Types Table offset encoded in U-LEB128 (optional).
+ {_TTOff, LSDACont2} =
+ case TTenc =:= ?DW_EH_PE_omit of
+ true -> % There is no Types Table pointer. (-1 denotes that)
+ {-1, More3};
+ false -> % The byte offset from this field to the start of the Types
+ % Table used for exception matching.
+ leb128_decode(More3)
+ end,
+ %% Next byte of LSDA is the encoding of the fields in the Call-site Table.
+ <<_CSenc:8, More4/binary>> = LSDACont2,
+ %% Sixth byte is the size (in bytes) of the Call-site Table encoded in
+ %% U-LEB128.
+ {_CSTabSize, CSTab} = leb128_decode(More4),
+ %% Extract all call site information
+ get_gccexntab_callsites(CSTab, [])
+ end.
+
+get_gccexntab_callsites(<<>>, Acc) ->
+ lists:reverse(Acc);
+get_gccexntab_callsites(CSTab, Acc) ->
+ %% We are only interested in the Landing Pad of every entry.
+ <<Start:32/integer-little, Size:32/integer-little,
+ LP:32/integer-little, OnAction:8, More/binary
+ >> = CSTab,
+ GccCS = mk_gccexntab_callsite(Start, Size, LP, OnAction),
+ get_gccexntab_callsites(More, [GccCS | Acc]).
+
+%%------------------------------------------------------------------------------
+%% Functions to manipulate Read-only Data (.rodata)
+%%------------------------------------------------------------------------------
+extract_rodata(Elf) ->
+ Rodata_bin = extract_segment_by_name(Elf, ?RODATA),
+ get_rodata_entries(Rodata_bin, []).
+
+get_rodata_entries(<<>>, Acc) ->
+ lists:reverse(Acc);
+get_rodata_entries(Rodata_bin, Acc) ->
+ <<Num:?bits(?ELF_ADDR_SIZE)/integer-little, More/binary>> = Rodata_bin,
+ get_rodata_entries(More, [Num | Acc]).
+
+%%------------------------------------------------------------------------------
+%% Helper functions
+%%------------------------------------------------------------------------------
+
+%% @doc Returns the binary segment starting at `Offset' with length `Size'
+%% (bytes) from a binary file. If `Offset' is bigger than the byte size of
+%% the binary, an empty binary (`<<>>') is returned.
+-spec get_binary_segment(binary(), offset(), size()) -> binary().
+get_binary_segment(Bin, Offset, _Size) when Offset > byte_size(Bin) ->
+ <<>>;
+get_binary_segment(Bin, Offset, Size) ->
+ <<_Hdr:Offset/binary, BinSeg:Size/binary, _More/binary>> = Bin,
+ BinSeg.
+
+%% @doc This function gets as arguments an ELF formated binary object and
+%% a string with the segments' name and returns the specified segment or
+%% an empty binary (`<<>>') if there exists no segment with that name.
+%% There are handy macros defined in elf_format.hrl for all Standard
+%% Section Names.
+-spec extract_segment_by_name(elf(), string()) -> binary().
+extract_segment_by_name(Elf, SectionName) ->
+ %% Extract Section Header Table and Section Header String Table from binary
+ SHdrTable = extract_shdrtab(Elf),
+ Names = extract_shstrtab(Elf),
+ %% Zip to a list of (Name,ShdrE)
+ [_Zero | ShdrEs] = lists:keysort(2, SHdrTable), % Skip first entry (zeros).
+ L = lists:zip(Names, ShdrEs),
+ %% Find Section Header Table entry by name
+ case lists:keyfind(SectionName, 1, L) of
+ {SectionName, ShdrE} -> %% Note: Same name.
+ #elf_shdr{offset = Offset, size = Size} = ShdrE,
+ get_binary_segment(Elf, Offset, Size);
+ false -> %% Not found.
+ <<>>
+ end.
+
+%% @doc Extracts a list of strings with (zero-separated) names from a binary.
+%% Returns tuples of `{Name, Size}'.
+%% XXX: Skip trailing 0.
+-spec get_names(<<_:8,_:_*8>>) -> name_sizes().
+get_names(<<0, Bin/binary>>) ->
+ NamesSizes = get_names(Bin, []),
+ fix_names(NamesSizes, []).
+
+get_names(<<>>, Acc) ->
+ lists:reverse(Acc);
+get_names(Bin, Acc) ->
+ {Name, MoreNames} = bin_get_string(Bin),
+ get_names(MoreNames, [{Name, length(Name)} | Acc]).
+
+%% @doc Fix names:
+%% e.g. If ".rela.text" exists, ".text" does not. Same goes for
+%% ".rel.text". In that way, the Section Header String Table is more
+%% compact. Add ".text" just *before* the corresponding rela-field,
+%% etc.
+-spec fix_names(name_sizes(), name_sizes()) -> name_sizes().
+fix_names([], Acc) ->
+ lists:reverse(Acc);
+fix_names([{Name, Size}=T | Names], Acc) ->
+ case is64bit() of
+ true ->
+ case string:str(Name, ".rela") =:= 1 of
+ true -> %% Name starts with ".rela":
+ Section = string:substr(Name, 6),
+ fix_names(Names, [{Section, Size - 5}
+ | [T | Acc]]); % XXX: Is order ok? (".text"
+ % always before ".rela.text")
+ false -> %% Name does not start with ".rela":
+ fix_names(Names, [T | Acc])
+ end;
+ false ->
+ case string:str(Name, ".rel") =:= 1 of
+ true -> %% Name starts with ".rel":
+ Section = string:substr(Name, 5),
+ fix_names(Names, [{Section, Size - 4}
+ | [T | Acc]]); % XXX: Is order ok? (".text"
+ % always before ".rela.text")
+ false -> %% Name does not start with ".rel":
+ fix_names(Names, [T | Acc])
+ end
+ end.
+
+
+%% @doc A function that byte-reverses a binary. This might be needed because of
+%% little (fucking!) endianess.
+-spec bin_reverse(binary()) -> binary().
+bin_reverse(Bin) when is_binary(Bin) ->
+ bin_reverse(Bin, <<>>).
+
+-spec bin_reverse(binary(), binary()) -> binary().
+bin_reverse(<<>>, Acc) ->
+ Acc;
+bin_reverse(<<Head, More/binary>>, Acc) ->
+ bin_reverse(More, <<Head, Acc/binary>>).
+
+%% @doc A function that extracts a null-terminated string from a binary. It
+%% returns the found string along with the rest of the binary.
+-spec bin_get_string(binary()) -> {string(), binary()}.
+bin_get_string(Bin) ->
+ bin_get_string(Bin, <<>>).
+
+bin_get_string(<<>>, BinAcc) ->
+ Bin = bin_reverse(BinAcc), % little endian!
+ {binary_to_list(Bin), <<>>};
+bin_get_string(<<0, MoreBin/binary>>, BinAcc) ->
+ Bin = bin_reverse(BinAcc), % little endian!
+ {binary_to_list(Bin), MoreBin};
+bin_get_string(<<Letter, Tail/binary>>, BinAcc) ->
+ bin_get_string(Tail, <<Letter, BinAcc/binary>>).
+
+%% @doc
+make_offsets(NamesSizes) ->
+ {Names, Sizes} = lists:unzip(NamesSizes),
+ Offsets = make_offsets_from_sizes(Sizes, 1, []),
+ lists:zip(Names, Offsets).
+
+make_offsets_from_sizes([], _, Acc) ->
+ lists:reverse(Acc);
+make_offsets_from_sizes([Size | Sizes], Cur, Acc) ->
+ make_offsets_from_sizes(Sizes, Size+Cur+1, [Cur | Acc]). % For the "."!
+
+%% @doc Little-Endian Base 128 (LEB128) Decoder
+%% This function extracts the <b>first</b> LEB128-encoded integer in a
+%% binary and returns that integer along with the remaining binary. This is
+%% done because a LEB128 number has variable bit-size and that is a way of
+%% extracting only one number in a binary and continuing parsing the binary
+%% for other kind of data (e.g. different encoding).
+%% FIXME: Only decodes unsigned data!
+-spec leb128_decode(binary()) -> {integer(), binary()}.
+leb128_decode(LebNum) ->
+ leb128_decode(LebNum, 0, <<>>).
+
+-spec leb128_decode(binary(), integer(), binary()) -> {integer(), binary()}.
+leb128_decode(LebNum, NoOfBits, Acc) ->
+ <<Sentinel:1/bits, NextBundle:7/bits, MoreLebNums/bits>> = LebNum,
+ case Sentinel of
+ <<1:1>> -> % more bytes to follow
+ leb128_decode(MoreLebNums, NoOfBits+7, <<NextBundle:7/bits, Acc/bits>>);
+ <<0:1>> -> % byte bundle stop
+ Size = NoOfBits+7,
+ <<Num:Size/integer>> = <<NextBundle:7/bits, Acc/bits>>,
+ {Num, MoreLebNums}
+ end.
+
+%% @doc Extract ELF Class from ELF header and export symbol to process
+%% dictionary.
+-spec set_architecture_flag(elf()) -> 'ok'.
+set_architecture_flag(Elf) ->
+ %% Extract information about ELF Class from ELF Header
+ <<16#7f, $E, $L, $F, EI_Class, _MoreHeader/binary>>
+ = get_binary_segment(Elf, 0, ?ELF_EHDR_SIZE),
+ put(elf_class, EI_Class),
+ ok.
+
+%% @doc Read from object file header if the file class is ELF32 or ELF64.
+-spec is64bit() -> boolean().
+is64bit() ->
+ case get(elf_class) of
+ ?ELFCLASS64 -> true;
+ ?ELFCLASS32 -> false
+ end.
diff --git a/lib/hipe/llvm/elf_format.hrl b/lib/hipe/llvm/elf_format.hrl
new file mode 100644
index 0000000000..78592e6e2a
--- /dev/null
+++ b/lib/hipe/llvm/elf_format.hrl
@@ -0,0 +1,488 @@
+%% -*- erlang-indent-level: 2 -*-
+
+%%% @copyright 2011-2014 Yiannis Tsiouris <[email protected]>,
+%%% Chris Stavrakakis <[email protected]>
+%%% @author Yiannis Tsiouris <[email protected]>
+%%% [http://www.softlab.ntua.gr/~gtsiour/]
+
+%%------------------------------------------------------------------------------
+%%
+%% ELF Header File
+%%
+%%------------------------------------------------------------------------------
+
+-ifdef(BIT32).
+-include("elf32_format.hrl"). % ELF32-specific definitions.
+-else.
+-include("elf64_format.hrl"). % ELF64-specific definitions.
+-endif.
+
+%%------------------------------------------------------------------------------
+%% ELF Data Types (in bytes)
+%%------------------------------------------------------------------------------
+%%XXX: Included in either elf32_format or elf64_format.
+
+%%------------------------------------------------------------------------------
+%% ELF File Header
+%%------------------------------------------------------------------------------
+-define(ELF_EHDR_SIZE, (?E_IDENT_SIZE + ?E_TYPE_SIZE + ?E_MACHINE_SIZE
+ +?E_VERSION_SIZE + ?E_ENTRY_SIZE + ?E_PHOFF_SIZE
+ +?E_SHOFF_SIZE + ?E_FLAGS_SIZE + ?E_EHSIZE_SIZE
+ +?E_PHENTSIZE_SIZE + ?E_PHNUM_SIZE + ?E_SHENTSIZE_SIZE
+ +?E_SHNUM_SIZE + ?E_SHSTRNDX_SIZE) ).
+
+-define(E_IDENT_SIZE, (16 * ?ELF_UNSIGNED_CHAR_SIZE) ).
+-define(E_TYPE_SIZE, ?ELF_HALF_SIZE).
+-define(E_MACHINE_SIZE, ?ELF_HALF_SIZE).
+-define(E_VERSION_SIZE, ?ELF_WORD_SIZE).
+-define(E_ENTRY_SIZE, ?ELF_ADDR_SIZE).
+-define(E_PHOFF_SIZE, ?ELF_OFF_SIZE).
+-define(E_SHOFF_SIZE, ?ELF_OFF_SIZE).
+-define(E_FLAGS_SIZE, ?ELF_WORD_SIZE).
+-define(E_EHSIZE_SIZE, ?ELF_HALF_SIZE).
+-define(E_PHENTSIZE_SIZE, ?ELF_HALF_SIZE).
+-define(E_PHNUM_SIZE, ?ELF_HALF_SIZE).
+-define(E_SHENTSIZE_SIZE, ?ELF_HALF_SIZE).
+-define(E_SHNUM_SIZE, ?ELF_HALF_SIZE).
+-define(E_SHSTRNDX_SIZE, ?ELF_HALF_SIZE).
+
+%% Useful arithmetics for computing byte offsets for various File Header
+%% entries from a File Header (erlang) binary
+-define(E_IDENT_OFFSET, 0).
+-define(E_TYPE_OFFSET, (?E_IDENT_OFFSET + ?E_IDENT_SIZE) ).
+-define(E_MACHINE_OFFSET, (?E_TYPE_OFFSET + ?E_TYPE_SIZE) ).
+-define(E_VERSION_OFFSET, (?E_MACHINE_OFFSET + ?E_MACHINE_SIZE) ).
+-define(E_ENTRY_OFFSET, (?E_VERSION_OFFSET + ?E_VERSION_SIZE) ).
+-define(E_PHOFF_OFFSET, (?E_ENTRY_OFFSET + ?E_ENTRY_SIZE) ).
+-define(E_SHOFF_OFFSET, (?E_PHOFF_OFFSET + ?E_PHOFF_SIZE) ).
+-define(E_FLAGS_OFFSET, (?E_SHOFF_OFFSET + ?E_SHOFF_SIZE) ).
+-define(E_EHSIZE_OFFSET, (?E_FLAGS_OFFSET + ?E_FLAGS_SIZE) ).
+-define(E_PHENTSIZE_OFFSET, (?E_EHSIZE_OFFSET + ?E_EHSIZE_SIZE) ).
+-define(E_PHNUM_OFFSET, (?E_PHENTSIZE_OFFSET + ?E_PHENTSIZE_SIZE) ).
+-define(E_SHENTSIZE_OFFSET, (?E_PHNUM_OFFSET + ?E_PHNUM_SIZE) ).
+-define(E_SHNUM_OFFSET, (?E_SHENTSIZE_OFFSET + ?E_SHENTSIZE_SIZE) ).
+-define(E_SHSTRNDX_OFFSET, (?E_SHNUM_OFFSET + ?E_SHNUM_SIZE) ).
+
+%% Name aliases of File Header fields information used in get_header_field
+%% function of elf64_format module.
+-define(E_IDENT, {?E_IDENT_OFFSET, ?E_IDENT_SIZE}).
+-define(E_TYPE, {?E_TYPE_OFFSET, ?E_TYPE_SIZE}).
+-define(E_MACHINE, {?E_MACHINE_OFFSET, ?E_MACHINE_SIZE}).
+-define(E_VERSION, {?E_VERSION_OFFSET, ?E_VERSION_SIZE})
+-define(E_ENTRY, {?E_ENTRY_OFFSET, ?E_ENTRY_SIZE}).
+-define(E_PHOFF, {?E_PHOFF_OFFSET, ?E_PHOFF_SIZE}).
+-define(E_SHOFF, {?E_SHOFF_OFFSET, ?E_SHOFF_SIZE}).
+-define(E_FLAGS, {?E_FLAGS_OFFSET, ?E_FLAGS_SIZE}).
+-define(E_EHSIZE, {?E_EHSIZE_OFFSET, ?E_EHSIZE_SIZE}).
+-define(E_PHENTSIZE, {?E_PHENTSIZE_OFFSET, ?E_PHENTSIZE_SIZE}).
+-define(E_PHNUM, {?E_PHNUM_OFFSET, ?E_PHNUM_SIZE}).
+-define(E_SHENTSIZE, {?E_SHENTSIZE_OFFSET, ?E_SHENTSIZE_SIZE}).
+-define(E_SHNUM, {?E_SHNUM_OFFSET, ?E_SHNUM_SIZE}).
+-define(E_SHSTRNDX, {?E_SHSTRNDX_OFFSET, ?E_SHSTRNDX_SIZE}).
+
+%% ELF Identification (e_ident)
+-define(EI_MAG0, 0).
+-define(EI_MAG1, 1).
+-define(EI_MAG2, 2).
+-define(EI_MAG3, 3).
+-define(EI_CLASS, 4).
+-define(EI_DATA, 5).
+-define(EI_VERSION, 6).
+-define(EI_OSABI, 7).
+-define(EI_ABIVERSION, 8).
+-define(EI_PAD, 9).
+-define(EI_NIDENT, 16).
+
+%% Object File Classes (e_ident[EI_CLASS])
+-define(ELFCLASSNONE, 0).
+-define(ELFCLASS32, 1).
+-define(ELFCLASS64, 2).
+
+%% Data Encodings (e_ident[EI_DATA])
+-define(ELFDATA2LSB, 1).
+-define(ELFDATA2MSB, 2).
+
+%% Operating System and ABI Identifiers (e_ident[EI_OSABI])
+-define(ELFOSABI_SYSV, 0).
+-define(ELFOSABI_HPUX, 1).
+-define(ELFOSABI_STANDALONE, 255).
+
+%% Object File Types (e_type)
+-define(ET_NONE, 0).
+-define(ET_REL, 1).
+-define(ET_EXEC, 2).
+-define(ET_DYN, 3).
+-define(ET_CORE, 4).
+-define(ET_LOOS, 16#FE00).
+-define(ET_HIOS, 16#FEFF).
+-define(ET_LOPROC, 16#FF00).
+-define(ET_HIPROC, 16#FFFF).
+
+%%------------------------------------------------------------------------------
+%% ELF Section Header
+%%------------------------------------------------------------------------------
+-define(ELF_SHDRENTRY_SIZE, (?SH_NAME_SIZE + ?SH_TYPE_SIZE + ?SH_FLAGS_SIZE
+ +?SH_ADDR_SIZE + ?SH_OFFSET_SIZE + ?SH_SIZE_SIZE
+ +?SH_LINK_SIZE + ?SH_INFO_SIZE
+ +?SH_ADDRALIGN_SIZE + ?SH_ENTSIZE_SIZE) ).
+
+-define(SH_NAME_SIZE, ?ELF_WORD_SIZE).
+-define(SH_TYPE_SIZE, ?ELF_WORD_SIZE).
+-define(SH_FLAGS_SIZE, ?ELF_XWORD_SIZE).
+-define(SH_ADDR_SIZE, ?ELF_ADDR_SIZE).
+-define(SH_OFFSET_SIZE, ?ELF_OFF_SIZE).
+-define(SH_SIZE_SIZE, ?ELF_XWORD_SIZE).
+-define(SH_LINK_SIZE, ?ELF_WORD_SIZE).
+-define(SH_INFO_SIZE, ?ELF_WORD_SIZE).
+-define(SH_ADDRALIGN_SIZE, ?ELF_XWORD_SIZE).
+-define(SH_ENTSIZE_SIZE, ?ELF_XWORD_SIZE).
+
+%% Useful arithmetics for computing byte offsets for various fields from a
+%% Section Header Entry (erlang) binary
+-define(SH_NAME_OFFSET, 0).
+-define(SH_TYPE_OFFSET, (?SH_NAME_OFFSET + ?SH_NAME_SIZE) ).
+-define(SH_FLAGS_OFFSET, (?SH_TYPE_OFFSET + ?SH_TYPE_SIZE) ).
+-define(SH_ADDR_OFFSET, (?SH_FLAGS_OFFSET + ?SH_FLAGS_SIZE) ).
+-define(SH_OFFSET_OFFSET, (?SH_ADDR_OFFSET + ?SH_ADDR_SIZE) ).
+-define(SH_SIZE_OFFSET, (?SH_OFFSET_OFFSET + ?SH_OFFSET_SIZE) ).
+-define(SH_LINK_OFFSET, (?SH_SIZE_OFFSET + ?SH_SIZE_SIZE) ).
+-define(SH_INFO_OFFSET, (?SH_LINK_OFFSET + ?SH_LINK_SIZE) ).
+-define(SH_ADDRALIGN_OFFSET, (?SH_INFO_OFFSET + ?SH_INFO_SIZE) ).
+-define(SH_ENTSIZE_OFFSET, (?SH_ADDRALIGN_OFFSET + ?SH_ADDRALIGN_SIZE) ).
+
+%% Name aliases of Section Header Table entry information used in
+%% get_shdrtab_entry function of elf64_format module.
+-define(SH_NAME, {?SH_NAME_OFFSET, ?SH_NAME_SIZE}).
+-define(SH_TYPE, {?SH_TYPE_OFFSET, ?SH_TYPE_SIZE}).
+-define(SH_FLAGS, {?SH_FLAGS_OFFSET, ?SH_FLAGS_SIZE}).
+-define(SH_ADDR, {?SH_ADDR_OFFSET, ?SH_ADDR_SIZE}).
+-define(SH_OFFSET, {?SH_OFFSET_OFFSET, ?SH_OFFSET_SIZE}).
+-define(SH_SIZE, {?SH_SIZE_OFFSET, ?SH_SIZE_SIZE}).
+-define(SH_LINK, {?SH_LINK_OFFSET, ?SH_LINK_SIZE}).
+-define(SH_INFO, {?SH_INFO_OFFSET, ?SH_INFO_SIZE}).
+-define(SH_ADDRALIGN, {?SH_ADDRALIGN_OFFSET, ?SH_ADDRALIGN_SIZE}).
+-define(SH_ENTSIZE, {?SH_ENTSIZE_OFFSET, ?SH_ENTSIZE_SIZE}).
+
+%% Section Indices
+-define(SHN_UNDEF, 0).
+-define(SHN_LOPROC, 16#FF00).
+-define(SHN_HIPROC, 16#FF1F).
+-define(SHN_LOOS, 16#FF20).
+-define(SHN_HIOS, 16#FF3F).
+-define(SHN_ABS, 16#FFF1).
+-define(SHN_COMMON, 16#FFF2).
+
+%% Section Types (sh_type)
+-define(SHT_NULL, 0).
+-define(SHT_PROGBITS, 1).
+-define(SHT_SYMTAB, 2).
+-define(SHT_STRTAB, 3).
+-define(SHT_RELA, 4).
+-define(SHT_HASH, 5).
+-define(SHT_DYNAMIC, 6).
+-define(SHT_NOTE, 7).
+-define(SHT_NOBITS, 8).
+-define(SHT_REL, 9).
+-define(SHT_SHLIB, 10).
+-define(SHT_DYNSYM, 11).
+-define(SHT_LOOS, 16#60000000).
+-define(SHT_HIOS, 16#6FFFFFFF).
+-define(SHT_LOPROC, 16#70000000).
+-define(SHT_HIPROC, 16#7FFFFFFF).
+
+%% Section Attributes (sh_flags)
+-define(SHF_WRITE, 16#1).
+-define(SHF_ALLOC, 16#2).
+-define(SHF_EXECINSTR, 16#4).
+-define(SHF_MASKOS, 16#0F000000).
+-define(SHF_MASKPROC, 16#F0000000).
+
+%%
+%% Standard Section names for Code and Data
+%%
+-define(BSS, ".bss").
+-define(DATA, ".data").
+-define(INTERP, ".interp").
+-define(RODATA, ".rodata").
+-define(TEXT, ".text").
+%% Other Standard Section names
+-define(COMMENT, ".comment").
+-define(DYNAMIC, ".dynamic").
+-define(DYNSTR, ".dynstr").
+-define(GOT, ".got").
+-define(HASH, ".hash").
+-define(NOTE(Name), (".note" ++ Name)).
+-define(PLT, ".plt").
+-define(REL(Name), (".rel" ++ Name) ).
+-define(RELA(Name), (".rela" ++ Name) ).
+-define(SHSTRTAB, ".shstrtab").
+-define(STRTAB, ".strtab").
+-define(SYMTAB, ".symtab").
+-define(GCC_EXN_TAB, ".gcc_except_table").
+
+%%------------------------------------------------------------------------------
+%% ELF Symbol Table Entries
+%%------------------------------------------------------------------------------
+-define(ELF_SYM_SIZE, (?ST_NAME_SIZE + ?ST_INFO_SIZE + ?ST_OTHER_SIZE
+ +?ST_SHNDX_SIZE + ?ST_VALUE_SIZE + ?ST_SIZE_SIZE) ).
+
+-define(ST_NAME_SIZE, ?ELF_WORD_SIZE).
+-define(ST_INFO_SIZE, ?ELF_UNSIGNED_CHAR_SIZE).
+-define(ST_OTHER_SIZE, ?ELF_UNSIGNED_CHAR_SIZE).
+-define(ST_SHNDX_SIZE, ?ELF_HALF_SIZE).
+-define(ST_VALUE_SIZE, ?ELF_ADDR_SIZE).
+-define(ST_SIZE_SIZE, ?ELF_XWORD_SIZE).
+
+%% Precomputed offset for Symbol Table entries in SymTab binary
+%%XXX: Included in either elf32_format or elf64_format.
+
+%% Name aliases for Symbol Table entry information
+-define(ST_NAME, {?ST_NAME_OFFSET, ?ST_NAME_SIZE}).
+-define(ST_INFO, {?ST_INFO_OFFSET, ?ST_INFO_SIZE}).
+-define(ST_OTHER, {?ST_OTHER_OFFSET, ?ST_OTHER_SIZE}).
+-define(ST_SHNDX, {?ST_SHNDX_OFFSET, ?ST_SHNDX_SIZE}).
+-define(ST_VALUE, {?ST_VALUE_OFFSET, ?ST_VALUE_SIZE}).
+-define(ST_SIZE, {?ST_SIZE_OFFSET, ?ST_SIZE_SIZE}).
+
+%% Macros to extract information from st_type
+-define(ELF_ST_BIND(I), (I bsr 4) ).
+-define(ELF_ST_TYPE(I), (I band 16#f) ).
+-define(ELF_ST_INFO(B,T), (B bsl 4 + T band 16#f) ).
+
+%% Symbol Bindings
+-define(STB_LOCAL, 0).
+-define(STB_GLOBAL, 1).
+-define(STB_WEAK, 2).
+-define(STB_LOOS, 10).
+-define(STB_HIOS, 12).
+-define(STB_LOPROC, 13).
+-define(STB_HIPROC, 15).
+
+%% Symbol Types
+-define(STT_NOTYPE, 0).
+-define(STT_OBJECT, 1).
+-define(STT_FUNC, 2).
+-define(STT_SECTION, 3).
+-define(STT_FILE, 4).
+-define(STT_LOOS, 10).
+-define(STT_HIOS, 12).
+-define(STT_LOPROC, 13).
+-define(STT_HIPROC, 15).
+
+%%------------------------------------------------------------------------------
+%% ELF Relocation Entries
+%%------------------------------------------------------------------------------
+-define(ELF_REL_SIZE, (?R_OFFSET_SIZE + ?R_INFO_SIZE) ).
+-define(ELF_RELA_SIZE, (?R_OFFSET_SIZE + ?R_INFO_SIZE + ?R_ADDEND_SIZE) ).
+
+-define(R_OFFSET_SIZE, ?ELF_ADDR_SIZE).
+-define(R_INFO_SIZE, ?ELF_XWORD_SIZE).
+-define(R_ADDEND_SIZE, ?ELF_SXWORD_SIZE).
+
+%% Arithmetics for computing byte offsets in a Relocation entry binary
+-define(R_OFFSET_OFFSET, 0).
+-define(R_INFO_OFFSET, (?R_OFFSET_OFFSET + ?R_OFFSET_SIZE) ).
+-define(R_ADDEND_OFFSET, (?R_INFO_OFFSET + ?R_INFO_SIZE) ).
+
+%% Name aliases for Relocation field information
+-define(R_OFFSET, {?R_OFFSET_OFFSET, ?R_OFFSET_SIZE}).
+-define(R_INFO, {?R_INFO_OFFSET, ?R_INFO_SIZE}).
+-define(R_ADDEND, {?R_ADDEND_OFFSET, ?R_ADDEND_SIZE}).
+
+%% Useful macros to extract information from r_info field
+%%XXX: Included in either elf32_format or elf64_format.
+
+%%------------------------------------------------------------------------------
+%% ELF Program Header Table
+%%------------------------------------------------------------------------------
+-define(ELF_PHDR_SIZE, (?P_TYPE_SIZE + ?P_FLAGS_SIZE + ?P_OFFSET_SIZE
+ +?P_VADDR_SIZE + ?P_PADDR_SIZE + ?P_FILESZ_SIZE
+ +?P_MEMSZ_SIZE + ?P_ALIGN_SIZE) ).
+
+-define(P_TYPE_SIZE, ?ELF_WORD_SIZE).
+-define(P_FLAGS_SIZE, ?ELF_WORD_SIZE).
+-define(P_OFFSET_SIZE, ?ELF_OFF_SIZE).
+-define(P_VADDR_SIZE, ?ELF_ADDR_SIZE).
+-define(P_PADDR_SIZE, ?ELF_ADDR_SIZE).
+-define(P_FILESZ_SIZE, ?ELF_XWORD_SIZE).
+-define(P_MEMSZ_SIZE, ?ELF_XWORD_SIZE).
+-define(P_ALIGN_SIZE, ?ELF_XWORD_SIZE).
+
+%% Offsets of various fields in a Program Header Table entry binary.
+%%XXX: Included in either elf32_format or elf64_format.
+
+%% Name aliases for each Program Header Table entry field information.
+-define(P_TYPE, {?P_TYPE_OFFSET, ?P_TYPE_SIZE} ).
+-define(P_FLAGS, {?P_FLAGS_OFFSET, ?P_FLAGS_SIZE} ).
+-define(P_OFFSET, {?P_OFFSET_OFFSET, ?P_OFFSET_SIZE} ).
+-define(P_VADDR, {?P_VADDR_OFFSET, ?P_VADDR_SIZE} ).
+-define(P_PADDR, {?P_PADDR_OFFSET, ?P_PADDR_SIZE} ).
+-define(P_FILESZ, {?P_FILESZ_OFFSET, ?P_FILESZ_SIZE} ).
+-define(P_MEMSZ, {?P_MEMSZ_OFFSET, ?P_MEMSZ_SIZE} ).
+-define(P_ALIGN, {?P_ALIGN_OFFSET, ?P_ALIGN_SIZE} ).
+
+%% Segment Types (p_type)
+-define(PT_NULL, 0).
+-define(PT_LOAD, 1).
+-define(PT_DYNAMIC, 2).
+-define(PT_INTERP, 3).
+-define(PT_NOTE, 4).
+-define(PT_SHLIB, 5).
+-define(PT_PHDR, 6).
+-define(PT_LOOS, 16#60000000).
+-define(PT_HIOS, 16#6FFFFFFF).
+-define(PT_LOPROC, 16#70000000).
+-define(PT_HIPROC, 16#7FFFFFFF).
+
+%% Segment Attributes (p_flags)
+-define(PF_X, 16#1).
+-define(PF_W, 16#2).
+-define(PF_R, 16#4).
+-define(PF_MASKOS, 16#00FF0000).
+-define(PF_MASKPROC, 16#FF000000).
+
+%%------------------------------------------------------------------------------
+%% ELF Dynamic Table
+%%------------------------------------------------------------------------------
+-define(ELF_DYN_SIZE, (?D_TAG_SIZE + ?D_VAL_PTR_SIZE) ).
+
+-define(D_TAG_SIZE, ?ELF_SXWORD_SIZE).
+-define(D_VAL_PTR_SIZE, ?ELF_ADDR_SIZE).
+
+%% Offsets of each field in Dynamic Table entry in binary
+-define(D_TAG_OFFSET, 0).
+-define(D_VAL_PTR_OFFSET, (?D_TAG_OFFSET + ?D_TAG_SIZE)).
+
+%% Name aliases for each field of a Dynamic Table entry information
+-define(D_TAG, {?D_TAG_OFFSET, ?D_TAG_SIZE} ).
+-define(D_VAL_PTR, {?D_VAL_PTR_OFFSET, ?D_VAL_PTR_SIZE} ).
+
+%% Dynamic Table Entries
+-define(DT_NULL, 0).
+-define(DT_NEEDED, 1).
+-define(DT_PLTRELSZ, 2).
+-define(DT_PLTGOT, 3).
+-define(DT_HASH, 4).
+-define(DT_STRTAB, 5).
+-define(DT_SYMTAB, 6).
+-define(DT_RELA, 7).
+-define(DT_RELASZ, 8).
+-define(DT_RELAENT, 9).
+-define(DT_STRSZ, 10).
+-define(DT_SYMENT, 11).
+-define(DT_INIT, 12).
+-define(DT_FINI, 13).
+-define(DT_SONAME, 14).
+-define(DT_RPATH, 15).
+-define(DT_SYMBOLIC, 16).
+-define(DT_REL, 17).
+-define(DT_RELSZ, 18).
+-define(DT_RELENT, 19).
+-define(DT_PLTREL, 20).
+-define(DT_DEBUG, 21).
+-define(DT_TEXTREL, 22).
+-define(DT_JMPREL, 23).
+-define(DT_BIND_NOW, 24).
+-define(DT_INIT_ARRAY, 25).
+-define(DT_FINI_ARRAY, 26).
+-define(DT_INIT_ARRAYSZ, 27).
+-define(DT_FINI_ARRAYSZ, 28).
+-define(DT_LOOS, 16#60000000).
+-define(DT_HIOS, 16#6FFFFFFF).
+-define(DT_LOPROC, 16#700000000).
+-define(DT_HIPROC, 16#7FFFFFFFF).
+
+%%------------------------------------------------------------------------------
+%% ELF GCC Exception Table
+%%------------------------------------------------------------------------------
+
+%% The DWARF Exception Header Encoding is used to describe the type of data used
+%% in the .eh_frame_hdr (and .gcc_except_table) section. The upper 4 bits
+%% indicate how the value is to be applied. The lower 4 bits indicate the format
+%% of the data.
+
+%% DWARF Exception Header value format
+-define(DW_EH_PE_omit, 16#ff). % No value is present.
+-define(DW_EH_PE_uleb128, 16#01). % Unsigned value encoded using LEB128.
+-define(DW_EH_PE_udata2, 16#02). % A 2 bytes unsigned value.
+-define(DW_EH_PE_udata4, 16#03). % A 4 bytes unsigned value.
+-define(DW_EH_PE_udata8, 16#04). % An 8 bytes unsigned value.
+-define(DW_EH_PE_sleb128, 16#09). % Signed value encoded using LEB128.
+-define(DW_EH_PE_sdata2, 16#0a). % A 2 bytes signed value.
+-define(DW_EH_PE_sdata4, 16#0b). % A 4 bytes signed value.
+-define(DW_EH_PE_sdata8, 16#0c). % An 8 bytes signed value.
+
+%% DWARF Exception Header application
+-define(DW_EH_PE_absptr, 16#00). % Value is used with no modification.
+-define(DW_EH_PE_pcrel, 16#10). % Value is relative to the current PC.
+-define(DW_EH_PE_datarel, 16#30). % Value is relative to the beginning of the
+ % section.
+
+%%------------------------------------------------------------------------------
+%% ELF Read-only data (constants, literlas etc.)
+%%------------------------------------------------------------------------------
+-define(RO_ENTRY_SIZE, 8).
+
+%%------------------------------------------------------------------------------
+%% Custom Note section: ".note.gc" for Erlang GC
+%%------------------------------------------------------------------------------
+
+%% The structure of this section is the following:
+%%
+%% .short <n> # number of safe points in code
+%%
+%% .long .L<label1> # safe point address |
+%% .long .L<label2> # safe point address |-> safe point addrs
+%% ..... |
+%% .long .L<label3> # safe point address |
+%%
+%% .short <n> # stack frame size (in words) |-> fixed-size part
+%% .short <n> # stack arity |
+%% .short <n> # number of live roots that follow |
+%%
+%% .short <n> # live root's stack index |
+%% ..... |-> live root indices
+%% .short <n> # >> |
+
+%% The name of the custom Note Section
+-define(NOTE_ERLGC_NAME, ".gc").
+
+%% The first word of a Note Section for Erlang GC (".note.gc") is always the
+%% number of safepoints in code.
+-define(SP_COUNT, {?SP_COUNT_OFFSET, ?SP_COUNT_SIZE}).
+-define(SP_COUNT_SIZE, ?ELF_HALF_SIZE).
+-define(SP_COUNT_OFFSET, 0). %(always the first entry in sdesc)
+
+%% The fixed-size part of a safe point (SP) entry consists of 4 words: the SP
+%% address (offset in code), the stack frame size of the function (where the SP
+%% is located), the stack arity of the function (the registered values are *not*
+%% counted), the number of live roots in the specific SP.
+-define(SP_FIXED, {?SP_FIXED_OFF, ?SP_FIXED_SIZE}).
+-define(SP_FIXED_OFF, 0).
+%%XXX: Exclude SP_ADDR_SIZE from SP_FIXED_SIZE in lew of new GC layout
+-define(SP_FIXED_SIZE, (?SP_STKFRAME_SIZE + ?SP_STKARITY_SIZE
+ + ?SP_LIVEROOTCNT_SIZE)).
+
+-define(SP_ADDR_SIZE, ?ELF_WORD_SIZE).
+-define(SP_STKFRAME_SIZE, ?ELF_HALF_SIZE).
+-define(SP_STKARITY_SIZE, ?ELF_HALF_SIZE).
+-define(SP_LIVEROOTCNT_SIZE, ?ELF_HALF_SIZE).
+
+%%XXX: SP_STKFRAME is the first piece of information in the new GC layout
+-define(SP_STKFRAME_OFFSET, 0).
+-define(SP_STKARITY_OFFSET, (?SP_STKFRAME_OFFSET + ?SP_STKFRAME_SIZE) ).
+-define(SP_LIVEROOTCNT_OFFSET, (?SP_STKARITY_OFFSET + ?SP_STKARITY_SIZE) ).
+
+%% Name aliases for safepoint fields.
+-define(SP_STKFRAME, {?SP_STKFRAME_OFFSET, ?SP_STKFRAME_SIZE}).
+-define(SP_STKARITY, {?SP_STKARITY_OFFSET, ?SP_STKARITY_SIZE}).
+-define(SP_LIVEROOTCNT, {?SP_LIVEROOTCNT_OFFSET, ?SP_LIVEROOTCNT_SIZE}).
+
+%% After the fixed-size part a variable-size part exists. This part holds the
+%% stack frame index of every live root in the specific SP.
+-define(LR_STKINDEX_SIZE, ?ELF_HALF_SIZE).
+
+%%------------------------------------------------------------------------------
+%% Misc.
+%%------------------------------------------------------------------------------
+-define(bits(Bytes), ((Bytes) bsl 3)).
diff --git a/lib/hipe/llvm/hipe_llvm.erl b/lib/hipe/llvm/hipe_llvm.erl
new file mode 100644
index 0000000000..5e33731a2b
--- /dev/null
+++ b/lib/hipe/llvm/hipe_llvm.erl
@@ -0,0 +1,1131 @@
+%% -*- erlang-indent-level: 2 -*-
+
+-module(hipe_llvm).
+
+-export([
+ mk_ret/1,
+ ret_ret_list/1,
+
+ mk_br/1,
+ br_dst/1,
+
+ mk_br_cond/3,
+ mk_br_cond/4,
+ br_cond_cond/1,
+ br_cond_true_label/1,
+ br_cond_false_label/1,
+ br_cond_meta/1,
+
+ mk_indirectbr/3,
+ indirectbr_type/1,
+ indirectbr_address/1,
+ indirectbr_label_list/1,
+
+ mk_switch/4,
+ switch_type/1,
+ switch_value/1,
+ switch_default_label/1,
+ switch_value_label_list/1,
+
+ mk_invoke/9,
+ invoke_dst/1,
+ invoke_cconv/1,
+ invoke_ret_attrs/1,
+ invoke_type/1,
+ invoke_fnptrval/1,
+ invoke_arglist/1,
+ invoke_fn_attrs/1,
+ invoke_to_label/1,
+ invoke_unwind_label/1,
+
+ mk_operation/6,
+ operation_dst/1,
+ operation_op/1,
+ operation_type/1,
+ operation_src1/1,
+ operation_src2/1,
+ operation_options/1,
+
+ mk_extractvalue/5,
+ extractvalue_dst/1,
+ extractvalue_type/1,
+ extractvalue_val/1,
+ extractvalue_idx/1,
+ extractvalue_idxs/1,
+
+ mk_insertvalue/7,
+ insertvalue_dst/1,
+ insertvalue_val_type/1,
+ insertvalue_val/1,
+ insertvalue_elem_type/1,
+ insertvalue_elem/1,
+ insertvalue_idx/1,
+ insertvalue_idxs/1,
+
+ mk_alloca/4,
+ alloca_dst/1,
+ alloca_type/1,
+ alloca_num/1,
+ alloca_align/1,
+
+ mk_load/6,
+ load_dst/1,
+ load_p_type/1,
+ load_pointer/1,
+ load_alignment/1,
+ load_nontemporal/1,
+ load_volatile/1,
+
+ mk_store/7,
+ store_type/1,
+ store_value/1,
+ store_p_type/1,
+ store_pointer/1,
+ store_alignment/1,
+ store_nontemporal/1,
+ store_volatile/1,
+
+ mk_getelementptr/5,
+ getelementptr_dst/1,
+ getelementptr_p_type/1,
+ getelementptr_value/1,
+ getelementptr_typed_idxs/1,
+ getelementptr_inbounds/1,
+
+ mk_conversion/5,
+ conversion_dst/1,
+ conversion_op/1,
+ conversion_src_type/1,
+ conversion_src/1,
+ conversion_dst_type/1,
+
+ mk_sitofp/4,
+ sitofp_dst/1,
+ sitofp_src_type/1,
+ sitofp_src/1,
+ sitofp_dst_type/1,
+
+ mk_ptrtoint/4,
+ ptrtoint_dst/1,
+ ptrtoint_src_type/1,
+ ptrtoint_src/1,
+ ptrtoint_dst_type/1,
+
+ mk_inttoptr/4,
+ inttoptr_dst/1,
+ inttoptr_src_type/1,
+ inttoptr_src/1,
+ inttoptr_dst_type/1,
+
+ mk_icmp/5,
+ icmp_dst/1,
+ icmp_cond/1,
+ icmp_type/1,
+ icmp_src1/1,
+ icmp_src2/1,
+
+ mk_fcmp/5,
+ fcmp_dst/1,
+ fcmp_cond/1,
+ fcmp_type/1,
+ fcmp_src1/1,
+ fcmp_src2/1,
+
+ mk_phi/3,
+ phi_dst/1,
+ phi_type/1,
+ phi_value_label_list/1,
+
+ mk_select/6,
+ select_dst/1,
+ select_cond/1,
+ select_typ1/1,
+ select_val1/1,
+ select_typ2/1,
+ select_val2/1,
+
+ mk_call/8,
+ call_dst/1,
+ call_is_tail/1,
+ call_cconv/1,
+ call_ret_attrs/1,
+ call_type/1,
+ call_fnptrval/1,
+ call_arglist/1,
+ call_fn_attrs/1,
+
+ mk_fun_def/10,
+ fun_def_linkage/1,
+ fun_def_visibility/1,
+ fun_def_cconv/1,
+ fun_def_ret_attrs/1,
+ fun_def_type/1,
+ fun_def_name/1,
+ fun_def_arglist/1,
+ fun_def_fn_attrs/1,
+ fun_def_align/1,
+ fun_def_body/1,
+
+ mk_fun_decl/8,
+ fun_decl_linkage/1,
+ fun_decl_visibility/1,
+ fun_decl_cconv/1,
+ fun_decl_ret_attrs/1,
+ fun_decl_type/1,
+ fun_decl_name/1,
+ fun_decl_arglist/1,
+ fun_decl_align/1,
+
+ mk_landingpad/0,
+
+ mk_comment/1,
+ comment_text/1,
+
+ mk_label/1,
+ label_label/1,
+ is_label/1,
+
+ mk_const_decl/4,
+ const_decl_dst/1,
+ const_decl_decl_type/1,
+ const_decl_type/1,
+ const_decl_value/1,
+
+ mk_asm/1,
+ asm_instruction/1,
+
+ mk_adj_stack/3,
+ adj_stack_offset/1,
+ adj_stack_register/1,
+ adj_stack_type/1,
+
+ mk_branch_meta/3,
+ branch_meta_id/1,
+ branch_meta_true_weight/1,
+ branch_meta_false_weight/1
+ ]).
+
+-export([
+ mk_void/0,
+
+ mk_label_type/0,
+
+ mk_int/1,
+ int_width/1,
+
+ mk_double/0,
+
+ mk_pointer/1,
+ pointer_type/1,
+
+ mk_array/2,
+ array_size/1,
+ array_type/1,
+
+ mk_vector/2,
+ vector_size/1,
+ vector_type/1,
+
+ mk_struct/1,
+ struct_type_list/1,
+
+ mk_fun/2,
+ function_ret_type/1,
+ function_arg_type_list/1
+ ]).
+
+-export([pp_ins_list/2, pp_ins/2]).
+
+
+%%-----------------------------------------------------------------------------
+%% Abstract Data Types for LLVM Assembly.
+%%-----------------------------------------------------------------------------
+
+%% Terminator Instructions
+-record(llvm_ret, {ret_list=[]}).
+-type llvm_ret() :: #llvm_ret{}.
+
+-record(llvm_br, {dst}).
+-type llvm_br() :: #llvm_br{}.
+
+-record(llvm_br_cond, {'cond', true_label, false_label, meta=[]}).
+-type llvm_br_cond() :: #llvm_br_cond{}.
+
+-record(llvm_indirectbr, {type, address, label_list}).
+-type llvm_indirectbr() :: #llvm_indirectbr{}.
+
+-record(llvm_switch, {type, value, default_label, value_label_list=[]}).
+-type llvm_switch() :: #llvm_switch{}.
+
+-record(llvm_invoke, {dst, cconv=[], ret_attrs=[], type, fnptrval, arglist=[],
+ fn_attrs=[], to_label, unwind_label}).
+-type llvm_invoke() :: #llvm_invoke{}.
+
+%% Binary Operations
+-record(llvm_operation, {dst, op, type, src1, src2, options=[]}).
+-type llvm_operation() :: #llvm_operation{}.
+
+%% Aggregate Operations
+-record(llvm_extractvalue, {dst, type, val, idx, idxs=[]}).
+-type llvm_extractvalue() :: #llvm_extractvalue{}.
+
+-record(llvm_insertvalue, {dst, val_type, val, elem_type, elem, idx, idxs=[]}).
+-type llvm_insertvalue() :: #llvm_insertvalue{}.
+
+%% Memory Access and Addressing Operations
+-record(llvm_alloca, {dst, type, num=[], align=[]}).
+-type llvm_alloca() :: #llvm_alloca{}.
+
+-record(llvm_load, {dst, p_type, pointer, alignment=[], nontemporal=[],
+ volatile=false}).
+-type llvm_load() :: #llvm_load{}.
+
+-record(llvm_store, {type, value, p_type, pointer, alignment=[],
+ nontemporal=[], volatile=false}).
+-type llvm_store() :: #llvm_store{}.
+
+-record(llvm_getelementptr, {dst, p_type, value, typed_idxs, inbounds}).
+-type llvm_getelementptr() :: #llvm_getelementptr{}.
+
+%% Conversion Operations
+-record(llvm_conversion, {dst, op, src_type, src, dst_type}).
+-type llvm_conversion() :: #llvm_conversion{}.
+
+-record(llvm_sitofp, {dst, src_type, src, dst_type}).
+-type llvm_sitofp() :: #llvm_sitofp{}.
+
+-record(llvm_ptrtoint, {dst, src_type, src, dst_type}).
+-type llvm_ptrtoint() :: #llvm_ptrtoint{}.
+
+-record(llvm_inttoptr, {dst, src_type, src, dst_type}).
+-type llvm_inttoptr() :: #llvm_inttoptr{}.
+
+%% Other Operations
+-record(llvm_icmp, {dst, 'cond', type, src1, src2}).
+-type llvm_icmp() :: #llvm_icmp{}.
+
+-record(llvm_fcmp, {dst, 'cond', type, src1, src2}).
+-type llvm_fcmp() :: #llvm_fcmp{}.
+
+-record(llvm_phi, {dst, type, value_label_list}).
+-type llvm_phi() :: #llvm_phi{}.
+
+-record(llvm_select, {dst, 'cond', typ1, val1, typ2, val2}).
+-type llvm_select() :: #llvm_select{}.
+
+-record(llvm_call, {dst=[], is_tail = false, cconv = [], ret_attrs = [], type,
+ fnptrval, arglist = [], fn_attrs = []}).
+-type llvm_call() :: #llvm_call{}.
+
+-record(llvm_fun_def, {linkage=[], visibility=[], cconv=[], ret_attrs=[],
+ type, 'name', arglist=[], fn_attrs=[], align=[], body=[]}).
+-type llvm_fun_def() :: #llvm_fun_def{}.
+
+-record(llvm_fun_decl, {linkage=[], visibility=[], cconv=[], ret_attrs=[],
+ type, 'name', arglist=[], align=[]}).
+-type llvm_fun_decl() :: #llvm_fun_decl{}.
+
+-record(llvm_landingpad, {}).
+-type llvm_landingpad() :: #llvm_landingpad{}.
+
+-record(llvm_comment, {text}).
+-type llvm_comment() :: #llvm_comment{}.
+
+-record(llvm_label, {label}).
+-type llvm_label() :: #llvm_label{}.
+
+-record(llvm_const_decl, {dst, decl_type, type, value}).
+-type llvm_const_decl() :: #llvm_const_decl{}.
+
+-record(llvm_asm, {instruction}).
+-type llvm_asm() :: #llvm_asm{}.
+
+-record(llvm_adj_stack, {offset, 'register', type}).
+-type llvm_adj_stack() :: #llvm_adj_stack{}.
+
+-record(llvm_branch_meta, {id, true_weight, false_weight}).
+-type llvm_branch_meta() :: #llvm_branch_meta{}.
+
+%% A type for any LLVM instruction
+-type llvm_instr() :: llvm_ret() | llvm_br() | llvm_br_cond()
+ | llvm_indirectbr() | llvm_switch() | llvm_invoke()
+ | llvm_operation() | llvm_extractvalue()
+ | llvm_insertvalue() | llvm_alloca() | llvm_load()
+ | llvm_store() | llvm_getelementptr() | llvm_conversion()
+ | llvm_sitofp() | llvm_ptrtoint() | llvm_inttoptr()
+ | llvm_icmp() | llvm_fcmp() | llvm_phi() | llvm_select()
+ | llvm_call() | llvm_fun_def() | llvm_fun_decl()
+ | llvm_landingpad() | llvm_comment() | llvm_label()
+ | llvm_const_decl() | llvm_asm() | llvm_adj_stack()
+ | llvm_branch_meta().
+
+%% Types
+-record(llvm_void, {}).
+%-type llvm_void() :: #llvm_void{}.
+
+-record(llvm_label_type, {}).
+%-type llvm_label_type() :: #llvm_label_type{}.
+
+-record(llvm_int, {width}).
+%-type llvm_int() :: #llvm_int{}.
+
+-record(llvm_float, {}).
+%-type llvm_float() :: #llvm_float{}.
+
+-record(llvm_double, {}).
+%-type llvm_double() :: #llvm_double{}.
+
+-record(llvm_fp80, {}).
+%-type llvm_fp80() :: #llvm_fp80{}.
+
+-record(llvm_fp128, {}).
+%-type llvm_fp128() :: #llvm_fp128{}.
+
+-record(llvm_ppc_fp128, {}).
+%-type llvm_ppc_fp128() :: #llvm_ppc_fp128{}.
+
+-record(llvm_pointer, {type}).
+%-type llvm_pointer() :: #llvm_pointer{}.
+
+-record(llvm_vector, {'size', type}).
+%-type llvm_vector() :: #llvm_vector{}.
+
+-record(llvm_struct, {type_list}).
+%-type llvm_struct() :: #llvm_struct{}.
+
+-record(llvm_array, {'size', type}).
+%-type llvm_array() :: #llvm_array{}.
+
+-record(llvm_fun, {ret_type, arg_type_list}).
+%-type llvm_fun() :: #llvm_fun{}.
+
+%%-----------------------------------------------------------------------------
+%% Accessor Functions
+%%-----------------------------------------------------------------------------
+
+%% ret
+mk_ret(Ret_list) -> #llvm_ret{ret_list=Ret_list}.
+ret_ret_list(#llvm_ret{ret_list=Ret_list}) -> Ret_list.
+
+%% br
+mk_br(Dst) -> #llvm_br{dst=Dst}.
+br_dst(#llvm_br{dst=Dst}) -> Dst.
+
+%% br_cond
+mk_br_cond(Cond, True_label, False_label) ->
+ #llvm_br_cond{'cond'=Cond, true_label=True_label, false_label=False_label}.
+mk_br_cond(Cond, True_label, False_label, Metadata) ->
+ #llvm_br_cond{'cond'=Cond, true_label=True_label, false_label=False_label,
+ meta=Metadata}.
+br_cond_cond(#llvm_br_cond{'cond'=Cond}) -> Cond.
+br_cond_true_label(#llvm_br_cond{true_label=True_label}) -> True_label.
+br_cond_false_label(#llvm_br_cond{false_label=False_label}) ->
+ False_label.
+br_cond_meta(#llvm_br_cond{meta=Metadata}) -> Metadata.
+
+%% indirectbr
+mk_indirectbr(Type, Address, Label_list) -> #llvm_indirectbr{type=Type, address=Address, label_list=Label_list}.
+indirectbr_type(#llvm_indirectbr{type=Type}) -> Type.
+indirectbr_address(#llvm_indirectbr{address=Address}) -> Address.
+indirectbr_label_list(#llvm_indirectbr{label_list=Label_list}) -> Label_list.
+
+%% invoke
+mk_invoke(Dst, Cconv, Ret_attrs, Type, Fnptrval, Arglist, Fn_attrs, To_label, Unwind_label) ->
+ #llvm_invoke{dst=Dst, cconv=Cconv, ret_attrs=Ret_attrs, type=Type,
+ fnptrval=Fnptrval, arglist=Arglist, fn_attrs=Fn_attrs, to_label=To_label,
+ unwind_label=Unwind_label}.
+invoke_dst(#llvm_invoke{dst=Dst}) -> Dst.
+invoke_cconv(#llvm_invoke{cconv=Cconv}) -> Cconv.
+invoke_ret_attrs(#llvm_invoke{ret_attrs=Ret_attrs}) -> Ret_attrs.
+invoke_type(#llvm_invoke{type=Type}) -> Type.
+invoke_fnptrval(#llvm_invoke{fnptrval=Fnptrval}) -> Fnptrval.
+invoke_arglist(#llvm_invoke{arglist=Arglist}) -> Arglist.
+invoke_fn_attrs(#llvm_invoke{fn_attrs=Fn_attrs}) -> Fn_attrs.
+invoke_to_label(#llvm_invoke{to_label=To_label}) -> To_label.
+invoke_unwind_label(#llvm_invoke{unwind_label=Unwind_label}) -> Unwind_label.
+
+%% switch
+mk_switch(Type, Value, Default_label, Value_label_list) ->
+ #llvm_switch{type=Type, value=Value, default_label=Default_label,
+ value_label_list=Value_label_list}.
+switch_type(#llvm_switch{type=Type}) -> Type.
+switch_value(#llvm_switch{value=Value}) -> Value.
+switch_default_label(#llvm_switch{default_label=Default_label}) ->
+ Default_label.
+switch_value_label_list(#llvm_switch{value_label_list=Value_label_list}) ->
+ Value_label_list.
+
+%% operation
+mk_operation(Dst, Op, Type, Src1, Src2, Options) ->
+ #llvm_operation{dst=Dst, op=Op, type=Type, src1=Src1, src2=Src2,
+ options=Options}.
+operation_dst(#llvm_operation{dst=Dst}) -> Dst.
+operation_op(#llvm_operation{op=Op}) -> Op.
+operation_type(#llvm_operation{type=Type}) -> Type.
+operation_src1(#llvm_operation{src1=Src1}) -> Src1.
+operation_src2(#llvm_operation{src2=Src2}) -> Src2.
+operation_options(#llvm_operation{options=Options}) -> Options.
+
+%% extractvalue
+mk_extractvalue(Dst, Type, Val, Idx, Idxs) ->
+ #llvm_extractvalue{dst=Dst,type=Type,val=Val,idx=Idx,idxs=Idxs}.
+extractvalue_dst(#llvm_extractvalue{dst=Dst}) -> Dst.
+extractvalue_type(#llvm_extractvalue{type=Type}) -> Type.
+extractvalue_val(#llvm_extractvalue{val=Val}) -> Val.
+extractvalue_idx(#llvm_extractvalue{idx=Idx}) -> Idx.
+extractvalue_idxs(#llvm_extractvalue{idxs=Idxs}) -> Idxs.
+
+%% insertvalue
+mk_insertvalue(Dst, Val_type, Val, Elem_type, Elem, Idx, Idxs) ->
+ #llvm_insertvalue{dst=Dst, val_type=Val_type, val=Val, elem_type=Elem_type,
+ elem=Elem, idx=Idx, idxs=Idxs}.
+insertvalue_dst(#llvm_insertvalue{dst=Dst}) -> Dst.
+insertvalue_val_type(#llvm_insertvalue{val_type=Val_type}) -> Val_type.
+insertvalue_val(#llvm_insertvalue{val=Val}) -> Val.
+insertvalue_elem_type(#llvm_insertvalue{elem_type=Elem_type}) -> Elem_type.
+insertvalue_elem(#llvm_insertvalue{elem=Elem}) -> Elem.
+insertvalue_idx(#llvm_insertvalue{idx=Idx}) -> Idx.
+insertvalue_idxs(#llvm_insertvalue{idxs=Idxs}) -> Idxs.
+
+%% alloca
+mk_alloca(Dst, Type, Num, Align) ->
+ #llvm_alloca{dst=Dst, type=Type, num=Num, align=Align}.
+alloca_dst(#llvm_alloca{dst=Dst}) -> Dst.
+alloca_type(#llvm_alloca{type=Type}) -> Type.
+alloca_num(#llvm_alloca{num=Num}) -> Num.
+alloca_align(#llvm_alloca{align=Align}) -> Align.
+
+%% load
+mk_load(Dst, Type, Pointer, Alignment, Nontemporal, Volatile) ->
+ #llvm_load{dst=Dst, p_type=Type, pointer=Pointer, alignment=Alignment,
+ nontemporal=Nontemporal, volatile=Volatile}.
+load_dst(#llvm_load{dst=Dst}) -> Dst.
+load_p_type(#llvm_load{p_type=Type}) -> Type.
+load_pointer(#llvm_load{pointer=Pointer}) -> Pointer.
+load_alignment(#llvm_load{alignment=Alignment}) -> Alignment.
+load_nontemporal(#llvm_load{nontemporal=Nontemporal}) -> Nontemporal.
+load_volatile(#llvm_load{volatile=Volatile}) -> Volatile.
+
+%% store
+mk_store(Type, Value, P_Type, Pointer, Alignment, Nontemporal, Volatile) ->
+ #llvm_store{type=Type, value=Value, p_type=P_Type, pointer=Pointer, alignment=Alignment,
+ nontemporal=Nontemporal, volatile=Volatile}.
+store_type(#llvm_store{type=Type}) -> Type.
+store_value(#llvm_store{value=Value}) -> Value.
+store_p_type(#llvm_store{p_type=P_Type}) -> P_Type.
+store_pointer(#llvm_store{pointer=Pointer}) -> Pointer.
+store_alignment(#llvm_store{alignment=Alignment}) -> Alignment.
+store_nontemporal(#llvm_store{nontemporal=Nontemporal}) -> Nontemporal.
+store_volatile(#llvm_store{volatile=Volatile}) -> Volatile.
+
+%% getelementptr
+mk_getelementptr(Dst, P_Type, Value, Typed_Idxs, Inbounds) ->
+ #llvm_getelementptr{dst=Dst,p_type=P_Type, value=Value,
+ typed_idxs=Typed_Idxs, inbounds=Inbounds}.
+getelementptr_dst(#llvm_getelementptr{dst=Dst}) -> Dst.
+getelementptr_p_type(#llvm_getelementptr{p_type=P_Type}) -> P_Type.
+getelementptr_value(#llvm_getelementptr{value=Value}) -> Value.
+getelementptr_typed_idxs(#llvm_getelementptr{typed_idxs=Typed_Idxs}) -> Typed_Idxs.
+getelementptr_inbounds(#llvm_getelementptr{inbounds=Inbounds}) -> Inbounds.
+
+%% conversion
+mk_conversion(Dst, Op, Src_type, Src, Dst_type) ->
+ #llvm_conversion{dst=Dst, op=Op, src_type=Src_type, src=Src, dst_type=Dst_type}.
+conversion_dst(#llvm_conversion{dst=Dst}) -> Dst.
+conversion_op(#llvm_conversion{op=Op}) -> Op.
+conversion_src_type(#llvm_conversion{src_type=Src_type}) -> Src_type.
+conversion_src(#llvm_conversion{src=Src}) -> Src.
+conversion_dst_type(#llvm_conversion{dst_type=Dst_type}) -> Dst_type.
+
+%% sitofp
+mk_sitofp(Dst, Src_type, Src, Dst_type) ->
+ #llvm_sitofp{dst=Dst, src_type=Src_type, src=Src, dst_type=Dst_type}.
+sitofp_dst(#llvm_sitofp{dst=Dst}) -> Dst.
+sitofp_src_type(#llvm_sitofp{src_type=Src_type}) -> Src_type.
+sitofp_src(#llvm_sitofp{src=Src}) -> Src.
+sitofp_dst_type(#llvm_sitofp{dst_type=Dst_type}) -> Dst_type.
+
+%% ptrtoint
+mk_ptrtoint(Dst, Src_Type, Src, Dst_Type) ->
+ #llvm_ptrtoint{dst=Dst, src_type=Src_Type, src=Src, dst_type=Dst_Type}.
+ptrtoint_dst(#llvm_ptrtoint{dst=Dst}) -> Dst.
+ptrtoint_src_type(#llvm_ptrtoint{src_type=Src_Type}) -> Src_Type.
+ptrtoint_src(#llvm_ptrtoint{src=Src}) -> Src.
+ptrtoint_dst_type(#llvm_ptrtoint{dst_type=Dst_Type}) -> Dst_Type .
+
+%% inttoptr
+mk_inttoptr(Dst, Src_Type, Src, Dst_Type) ->
+ #llvm_inttoptr{dst=Dst, src_type=Src_Type, src=Src, dst_type=Dst_Type}.
+inttoptr_dst(#llvm_inttoptr{dst=Dst}) -> Dst.
+inttoptr_src_type(#llvm_inttoptr{src_type=Src_Type}) -> Src_Type.
+inttoptr_src(#llvm_inttoptr{src=Src}) -> Src.
+inttoptr_dst_type(#llvm_inttoptr{dst_type=Dst_Type}) -> Dst_Type .
+
+%% icmp
+mk_icmp(Dst, Cond, Type, Src1, Src2) ->
+ #llvm_icmp{dst=Dst,'cond'=Cond,type=Type,src1=Src1,src2=Src2}.
+icmp_dst(#llvm_icmp{dst=Dst}) -> Dst.
+icmp_cond(#llvm_icmp{'cond'=Cond}) -> Cond.
+icmp_type(#llvm_icmp{type=Type}) -> Type.
+icmp_src1(#llvm_icmp{src1=Src1}) -> Src1.
+icmp_src2(#llvm_icmp{src2=Src2}) -> Src2.
+
+%% fcmp
+mk_fcmp(Dst, Cond, Type, Src1, Src2) ->
+ #llvm_fcmp{dst=Dst,'cond'=Cond,type=Type,src1=Src1,src2=Src2}.
+fcmp_dst(#llvm_fcmp{dst=Dst}) -> Dst.
+fcmp_cond(#llvm_fcmp{'cond'=Cond}) -> Cond.
+fcmp_type(#llvm_fcmp{type=Type}) -> Type.
+fcmp_src1(#llvm_fcmp{src1=Src1}) -> Src1.
+fcmp_src2(#llvm_fcmp{src2=Src2}) -> Src2.
+
+%% phi
+mk_phi(Dst, Type, Value_label_list) ->
+ #llvm_phi{dst=Dst, type=Type,value_label_list=Value_label_list}.
+phi_dst(#llvm_phi{dst=Dst}) -> Dst.
+phi_type(#llvm_phi{type=Type}) -> Type.
+phi_value_label_list(#llvm_phi{value_label_list=Value_label_list}) ->
+ Value_label_list.
+
+%% select
+mk_select(Dst, Cond, Typ1, Val1, Typ2, Val2) ->
+ #llvm_select{dst=Dst, 'cond'=Cond, typ1=Typ1, val1=Val1, typ2=Typ2, val2=Val2}.
+select_dst(#llvm_select{dst=Dst}) -> Dst.
+select_cond(#llvm_select{'cond'=Cond}) -> Cond.
+select_typ1(#llvm_select{typ1=Typ1}) -> Typ1.
+select_val1(#llvm_select{val1=Val1}) -> Val1.
+select_typ2(#llvm_select{typ2=Typ2}) -> Typ2.
+select_val2(#llvm_select{val2=Val2}) -> Val2.
+
+%% call
+mk_call(Dst, Is_tail, Cconv, Ret_attrs, Type, Fnptrval, Arglist, Fn_attrs) ->
+ #llvm_call{dst=Dst, is_tail=Is_tail, cconv=Cconv, ret_attrs=Ret_attrs,
+ type=Type, fnptrval=Fnptrval, arglist=Arglist, fn_attrs=Fn_attrs}.
+call_dst(#llvm_call{dst=Dst}) -> Dst.
+call_is_tail(#llvm_call{is_tail=Is_tail}) -> Is_tail.
+call_cconv(#llvm_call{cconv=Cconv}) -> Cconv.
+call_ret_attrs(#llvm_call{ret_attrs=Ret_attrs}) -> Ret_attrs.
+call_type(#llvm_call{type=Type}) -> Type.
+call_fnptrval(#llvm_call{fnptrval=Fnptrval}) -> Fnptrval.
+call_arglist(#llvm_call{arglist=Arglist}) -> Arglist.
+call_fn_attrs(#llvm_call{fn_attrs=Fn_attrs}) -> Fn_attrs.
+
+%% fun_def
+mk_fun_def(Linkage, Visibility, Cconv, Ret_attrs, Type, Name, Arglist,
+ Fn_attrs, Align, Body) ->
+ #llvm_fun_def{
+ linkage=Linkage,
+ visibility=Visibility,
+ cconv=Cconv,
+ ret_attrs=Ret_attrs,
+ type=Type,
+ 'name'=Name,
+ arglist=Arglist,
+ fn_attrs=Fn_attrs,
+ align=Align,
+ body=Body
+ }.
+
+fun_def_linkage(#llvm_fun_def{linkage=Linkage}) -> Linkage.
+fun_def_visibility(#llvm_fun_def{visibility=Visibility}) -> Visibility.
+fun_def_cconv(#llvm_fun_def{cconv=Cconv}) -> Cconv .
+fun_def_ret_attrs(#llvm_fun_def{ret_attrs=Ret_attrs}) -> Ret_attrs.
+fun_def_type(#llvm_fun_def{type=Type}) -> Type.
+fun_def_name(#llvm_fun_def{'name'=Name}) -> Name.
+fun_def_arglist(#llvm_fun_def{arglist=Arglist}) -> Arglist.
+fun_def_fn_attrs(#llvm_fun_def{fn_attrs=Fn_attrs}) -> Fn_attrs.
+fun_def_align(#llvm_fun_def{align=Align}) -> Align.
+fun_def_body(#llvm_fun_def{body=Body}) -> Body.
+
+%% fun_decl
+mk_fun_decl(Linkage, Visibility, Cconv, Ret_attrs, Type, Name, Arglist, Align)->
+ #llvm_fun_decl{
+ linkage=Linkage,
+ visibility=Visibility,
+ cconv=Cconv,
+ ret_attrs=Ret_attrs,
+ type=Type,
+ 'name'=Name,
+ arglist=Arglist,
+ align=Align
+ }.
+
+fun_decl_linkage(#llvm_fun_decl{linkage=Linkage}) -> Linkage.
+fun_decl_visibility(#llvm_fun_decl{visibility=Visibility}) -> Visibility.
+fun_decl_cconv(#llvm_fun_decl{cconv=Cconv}) -> Cconv .
+fun_decl_ret_attrs(#llvm_fun_decl{ret_attrs=Ret_attrs}) -> Ret_attrs.
+fun_decl_type(#llvm_fun_decl{type=Type}) -> Type.
+fun_decl_name(#llvm_fun_decl{'name'=Name}) -> Name.
+fun_decl_arglist(#llvm_fun_decl{arglist=Arglist}) -> Arglist.
+fun_decl_align(#llvm_fun_decl{align=Align}) -> Align.
+
+%% landingpad
+mk_landingpad() -> #llvm_landingpad{}.
+
+%% comment
+mk_comment(Text) -> #llvm_comment{text=Text}.
+comment_text(#llvm_comment{text=Text}) -> Text.
+
+%% label
+mk_label(Label) -> #llvm_label{label=Label}.
+label_label(#llvm_label{label=Label}) -> Label.
+
+-spec is_label(llvm_instr()) -> boolean().
+is_label(#llvm_label{}) -> true;
+is_label(#llvm_ret{}) -> false;
+is_label(#llvm_br{}) -> false;
+is_label(#llvm_br_cond{}) -> false;
+is_label(#llvm_indirectbr{}) -> false;
+is_label(#llvm_switch{}) -> false;
+is_label(#llvm_invoke{}) -> false;
+is_label(#llvm_operation{}) -> false;
+is_label(#llvm_extractvalue{}) -> false;
+is_label(#llvm_insertvalue{}) -> false;
+is_label(#llvm_alloca{}) -> false;
+is_label(#llvm_load{}) -> false;
+is_label(#llvm_store{}) -> false;
+is_label(#llvm_getelementptr{}) -> false;
+is_label(#llvm_conversion{}) -> false;
+is_label(#llvm_sitofp{}) -> false;
+is_label(#llvm_ptrtoint{}) -> false;
+is_label(#llvm_inttoptr{}) -> false;
+is_label(#llvm_icmp{}) -> false;
+is_label(#llvm_fcmp{}) -> false;
+is_label(#llvm_phi{}) -> false;
+is_label(#llvm_select{}) -> false;
+is_label(#llvm_call{}) -> false;
+is_label(#llvm_fun_def{}) -> false;
+is_label(#llvm_fun_decl{}) -> false;
+is_label(#llvm_landingpad{}) -> false;
+is_label(#llvm_comment{}) -> false;
+is_label(#llvm_const_decl{}) -> false;
+is_label(#llvm_asm{}) -> false;
+is_label(#llvm_adj_stack{}) -> false;
+is_label(#llvm_branch_meta{}) -> false.
+
+%% const_decl
+mk_const_decl(Dst, Decl_type, Type, Value) ->
+ #llvm_const_decl{dst=Dst, decl_type=Decl_type, type=Type, value=Value}.
+const_decl_dst(#llvm_const_decl{dst=Dst}) -> Dst.
+const_decl_decl_type(#llvm_const_decl{decl_type=Decl_type}) -> Decl_type.
+const_decl_type(#llvm_const_decl{type=Type}) -> Type.
+const_decl_value(#llvm_const_decl{value=Value}) -> Value.
+
+%% asm
+mk_asm(Instruction) -> #llvm_asm{instruction=Instruction}.
+asm_instruction(#llvm_asm{instruction=Instruction}) -> Instruction.
+
+%% adj_stack
+mk_adj_stack(Offset, Register, Type) ->
+ #llvm_adj_stack{offset=Offset, 'register'=Register, type=Type}.
+adj_stack_offset(#llvm_adj_stack{offset=Offset}) -> Offset.
+adj_stack_register(#llvm_adj_stack{'register'=Register}) -> Register.
+adj_stack_type(#llvm_adj_stack{type=Type}) -> Type.
+
+%% branch meta-data
+mk_branch_meta(Id, True_weight, False_weight) ->
+ #llvm_branch_meta{id=Id, true_weight=True_weight, false_weight=False_weight}.
+branch_meta_id(#llvm_branch_meta{id=Id}) -> Id.
+branch_meta_true_weight(#llvm_branch_meta{true_weight=True_weight}) ->
+ True_weight.
+branch_meta_false_weight(#llvm_branch_meta{false_weight=False_weight}) ->
+ False_weight.
+
+%% types
+mk_void() -> #llvm_void{}.
+
+mk_label_type() -> #llvm_label_type{}.
+
+mk_int(Width) -> #llvm_int{width=Width}.
+int_width(#llvm_int{width=Width}) -> Width.
+
+mk_double() -> #llvm_double{}.
+
+mk_pointer(Type) -> #llvm_pointer{type=Type}.
+pointer_type(#llvm_pointer{type=Type}) -> Type.
+
+mk_array(Size, Type) -> #llvm_array{'size'=Size, type=Type}.
+array_size(#llvm_array{'size'=Size}) -> Size.
+array_type(#llvm_array{type=Type}) -> Type.
+
+mk_vector(Size, Type) -> #llvm_vector{'size'=Size, type=Type}.
+vector_size(#llvm_vector{'size'=Size}) -> Size.
+vector_type(#llvm_vector{type=Type}) -> Type.
+
+mk_struct(Type_list) -> #llvm_struct{type_list=Type_list}.
+struct_type_list(#llvm_struct{type_list=Type_list}) -> Type_list.
+
+mk_fun(Ret_type, Arg_type_list) ->
+ #llvm_fun{ret_type=Ret_type, arg_type_list=Arg_type_list}.
+function_ret_type(#llvm_fun{ret_type=Ret_type}) -> Ret_type.
+function_arg_type_list(#llvm_fun{arg_type_list=Arg_type_list}) ->
+ Arg_type_list.
+
+%%----------------------------------------------------------------------------
+%% Pretty-printer Functions
+%%----------------------------------------------------------------------------
+
+%% @doc Pretty-print a list of LLVM instructions to a Device.
+pp_ins_list(_Dev, []) -> ok;
+pp_ins_list(Dev, [I|Is]) ->
+ pp_ins(Dev, I),
+ pp_ins_list(Dev, Is).
+
+pp_ins(Dev, I) ->
+ case indent(I) of
+ true -> write(Dev, " ");
+ false -> ok
+ end,
+ case I of
+ #llvm_ret{} ->
+ write(Dev, "ret "),
+ case ret_ret_list(I) of
+ [] -> write(Dev, "void");
+ List -> pp_args(Dev, List)
+ end,
+ write(Dev, "\n");
+ #llvm_br{} ->
+ write(Dev, ["br label ", br_dst(I), "\n"]);
+ #llvm_switch{} ->
+ write(Dev, "switch "),
+ pp_type(Dev, switch_type(I)),
+ write(Dev, [" ", switch_value(I), ", label ", switch_default_label(I),
+ " \n [\n"]),
+ pp_switch_value_label_list(Dev, switch_type(I),
+ switch_value_label_list(I)),
+ write(Dev, " ]\n");
+ #llvm_invoke{} ->
+ write(Dev, [invoke_dst(I), " = invoke ", invoke_cconv(I), " "]),
+ pp_options(Dev, invoke_ret_attrs(I)),
+ pp_type(Dev, invoke_type(I)),
+ write(Dev, [" ", invoke_fnptrval(I), "("]),
+ pp_args(Dev, invoke_arglist(I)),
+ write(Dev, ") "),
+ pp_options(Dev, invoke_fn_attrs(I)),
+ write(Dev, [" to label ", invoke_to_label(I)," unwind label ",
+ invoke_unwind_label(I), " \n"]);
+ #llvm_br_cond{} ->
+ write(Dev, ["br i1 ", br_cond_cond(I), ", label ", br_cond_true_label(I),
+ ", label ", br_cond_false_label(I)]),
+ case br_cond_meta(I) of
+ [] -> ok;
+ Metadata ->
+ write(Dev, [", !prof !", Metadata])
+ end,
+ write(Dev, "\n");
+ #llvm_indirectbr{} ->
+ write(Dev, "indirectbr "),
+ pp_type(Dev, indirectbr_type(I)),
+ write(Dev, [" ", indirectbr_address(I), ", [ "]),
+ pp_args(Dev, indirectbr_label_list(I)),
+ write(Dev, " ]\n");
+ #llvm_operation{} ->
+ write(Dev, [operation_dst(I), " = ", atom_to_list(operation_op(I)), " "]),
+ case op_has_options(operation_op(I)) of
+ true -> pp_options(Dev, operation_options(I));
+ false -> ok
+ end,
+ pp_type(Dev, operation_type(I)),
+ write(Dev, [" ", operation_src1(I), ", ", operation_src2(I), "\n"]);
+ #llvm_extractvalue{} ->
+ write(Dev, [extractvalue_dst(I), " = extractvalue "]),
+ pp_type(Dev, extractvalue_type(I)),
+ %% TODO Print idxs
+ write(Dev, [" ", extractvalue_val(I), ", ", extractvalue_idx(I), "\n"]);
+ #llvm_insertvalue{} ->
+ write(Dev, [insertvalue_dst(I), " = insertvalue "]),
+ pp_type(Dev, insertvalue_val_type(I)),
+ write(Dev, [" ", insertvalue_val(I), ", "]),
+ pp_type(Dev, insertvalue_elem_type(I)),
+ %%TODO Print idxs
+ write(Dev, [" ", insertvalue_elem(I), ", ", insertvalue_idx(I), "\n"]);
+ #llvm_alloca{} ->
+ write(Dev, [alloca_dst(I), " = alloca "]),
+ pp_type(Dev, alloca_type(I)),
+ case alloca_num(I) of
+ [] -> ok;
+ Num ->
+ write(Dev, ", "),
+ pp_type(Dev, alloca_type(I)),
+ write(Dev, [" ", Num, " "])
+ end,
+ case alloca_align(I) of
+ [] -> ok;
+ Align -> write(Dev, [",align ", Align])
+ end,
+ write(Dev, "\n");
+ #llvm_load{} ->
+ write(Dev, [load_dst(I), " = "]),
+ write(Dev, "load "),
+ case load_volatile(I) of
+ true -> write(Dev, "volatile ");
+ false -> ok
+ end,
+ pp_type(Dev, load_p_type(I)),
+ write(Dev, [" ", load_pointer(I), " "]),
+ case load_alignment(I) of
+ [] -> ok;
+ Al -> write(Dev, [", align ", Al, " "])
+ end,
+ case load_nontemporal(I) of
+ [] -> ok;
+ In -> write(Dev, [", !nontemporal !", In])
+ end,
+ write(Dev, "\n");
+ #llvm_store{} ->
+ write(Dev, "store "),
+ case store_volatile(I) of
+ true -> write(Dev, "volatile ");
+ false -> ok
+ end,
+ pp_type(Dev, store_type(I)),
+ write(Dev, [" ", store_value(I), ", "]),
+ pp_type(Dev, store_p_type(I)),
+ write(Dev, [" ", store_pointer(I), " "]),
+ case store_alignment(I) of
+ [] -> ok;
+ Al -> write(Dev, [", align ", Al, " "])
+ end,
+ case store_nontemporal(I) of
+ [] -> ok;
+ In -> write(Dev, [", !nontemporal !", In])
+ end,
+ write(Dev, "\n");
+ #llvm_getelementptr{} ->
+ write(Dev, [getelementptr_dst(I), " = getelementptr "]),
+ case getelementptr_inbounds(I) of
+ true -> write(Dev, "inbounds ");
+ false -> ok
+ end,
+ pp_type(Dev, getelementptr_p_type(I)),
+ write(Dev, [" ", getelementptr_value(I)]),
+ pp_typed_idxs(Dev, getelementptr_typed_idxs(I)),
+ write(Dev, "\n");
+ #llvm_conversion{} ->
+ write(Dev, [conversion_dst(I), " = ", atom_to_list(conversion_op(I)), " "]),
+ pp_type(Dev, conversion_src_type(I)),
+ write(Dev, [" ", conversion_src(I), " to "]),
+ pp_type(Dev, conversion_dst_type(I)),
+ write(Dev, "\n");
+ #llvm_icmp{} ->
+ write(Dev, [icmp_dst(I), " = icmp ", atom_to_list(icmp_cond(I)), " "]),
+ pp_type(Dev, icmp_type(I)),
+ write(Dev, [" ", icmp_src1(I), ", ", icmp_src2(I), "\n"]);
+ #llvm_fcmp{} ->
+ write(Dev, [fcmp_dst(I), " = fcmp ", atom_to_list(fcmp_cond(I)), " "]),
+ pp_type(Dev, fcmp_type(I)),
+ write(Dev, [" ", fcmp_src1(I), ", ", fcmp_src2(I), "\n"]);
+ #llvm_phi{} ->
+ write(Dev, [phi_dst(I), " = phi "]),
+ pp_type(Dev, phi_type(I)),
+ pp_phi_value_labels(Dev, phi_value_label_list(I)),
+ write(Dev, "\n");
+ #llvm_select{} ->
+ write(Dev, [select_dst(I), " = select i1 ", select_cond(I), ", "]),
+ pp_type(Dev, select_typ1(I)),
+ write(Dev, [" ", select_val1(I), ", "]),
+ pp_type(Dev, select_typ2(I)),
+ write(Dev, [" ", select_val2(I), "\n"]);
+ #llvm_call{} ->
+ case call_dst(I) of
+ [] -> ok;
+ Dst -> write(Dev, [Dst, " = "])
+ end,
+ case call_is_tail(I) of
+ true -> write(Dev, "tail ");
+ false -> ok
+ end,
+ write(Dev, ["call ", call_cconv(I), " "]),
+ pp_options(Dev, call_ret_attrs(I)),
+ pp_type(Dev, call_type(I)),
+ write(Dev, [" ", call_fnptrval(I), "("]),
+ pp_args(Dev, call_arglist(I)),
+ write(Dev, ") "),
+ pp_options(Dev, call_fn_attrs(I)),
+ write(Dev, "\n");
+ #llvm_fun_def{} ->
+ write(Dev, "define "),
+ pp_options(Dev, fun_def_linkage(I)),
+ pp_options(Dev, fun_def_visibility(I)),
+ case fun_def_cconv(I) of
+ [] -> ok;
+ Cc -> write(Dev, [Cc, " "])
+ end,
+ pp_options(Dev, fun_def_ret_attrs(I)),
+ write(Dev, " "),
+ pp_type(Dev, fun_def_type(I)),
+ write(Dev, [" @", fun_def_name(I), "("]),
+ pp_args(Dev, fun_def_arglist(I)),
+ write(Dev, ") "),
+ pp_options(Dev, fun_def_fn_attrs(I)),
+ case fun_def_align(I) of
+ [] -> ok;
+ N -> write(Dev, ["align ", N])
+ end,
+ write(Dev, "{\n"),
+ pp_ins_list(Dev, fun_def_body(I)),
+ write(Dev, "}\n");
+ #llvm_fun_decl{} ->
+ write(Dev, "declare "),
+ pp_options(Dev, fun_decl_linkage(I)),
+ pp_options(Dev, fun_decl_visibility(I)),
+ case fun_decl_cconv(I) of
+ [] -> ok;
+ Cc -> write(Dev, [Cc, " "])
+ end,
+ pp_options(Dev, fun_decl_ret_attrs(I)),
+ pp_type(Dev, fun_decl_type(I)),
+ write(Dev, [" ", fun_decl_name(I), "("]),
+ pp_type_list(Dev, fun_decl_arglist(I)),
+ write(Dev, ") "),
+ case fun_decl_align(I) of
+ [] -> ok;
+ N -> write(Dev, ["align ", N])
+ end,
+ write(Dev, "\n");
+ #llvm_comment{} ->
+ write(Dev, ["; ", atom_to_list(comment_text(I)), "\n"]);
+ #llvm_label{} ->
+ write(Dev, [label_label(I), ":\n"]);
+ #llvm_const_decl{} ->
+ write(Dev, [const_decl_dst(I), " = ", const_decl_decl_type(I), " "]),
+ pp_type(Dev, const_decl_type(I)),
+ write(Dev, [" ", const_decl_value(I), "\n"]);
+ #llvm_landingpad{} ->
+ write(Dev, "landingpad { i8*, i32 } personality i32 (i32, i64, i8*,i8*)*
+ @__gcc_personality_v0 cleanup\n");
+ #llvm_asm{} ->
+ write(Dev, [asm_instruction(I), "\n"]);
+ #llvm_adj_stack{} ->
+ write(Dev, ["call void asm sideeffect \"sub $0, ",
+ adj_stack_register(I), "\", \"r\"("]),
+ pp_type(Dev, adj_stack_type(I)),
+ write(Dev, [" ", adj_stack_offset(I),")\n"]);
+ #llvm_branch_meta{} ->
+ write(Dev, ["!", branch_meta_id(I), " = metadata !{metadata !\"branch_weights\",
+ i32 ", branch_meta_true_weight(I), ", i32 ",
+ branch_meta_false_weight(I), "}\n"]);
+ Other ->
+ exit({?MODULE, pp_ins, {"Unknown LLVM instruction", Other}})
+ end.
+
+%% @doc Pretty-print a list of types
+pp_type_list(_Dev, []) -> ok;
+pp_type_list(Dev, [T]) ->
+ pp_type(Dev, T);
+pp_type_list(Dev, [T|Ts]) ->
+ pp_type(Dev, T),
+ write(Dev, ", "),
+ pp_type_list(Dev, Ts).
+
+pp_type(Dev, Type) ->
+ case Type of
+ #llvm_void{} ->
+ write(Dev, "void");
+ #llvm_label_type{} ->
+ write(Dev, "label");
+ %% Integer
+ #llvm_int{} ->
+ write(Dev, ["i", integer_to_list(int_width(Type))]);
+ %% Float
+ #llvm_float{} ->
+ write(Dev, "float");
+ #llvm_double{} ->
+ write(Dev, "double");
+ #llvm_fp80{} ->
+ write(Dev, "x86_fp80");
+ #llvm_fp128{} ->
+ write(Dev, "fp128");
+ #llvm_ppc_fp128{} ->
+ write(Dev, "ppc_fp128");
+ %% Pointer
+ #llvm_pointer{} ->
+ pp_type(Dev, pointer_type(Type)),
+ write(Dev, "*");
+ %% Function
+ #llvm_fun{} ->
+ pp_type(Dev, function_ret_type(Type)),
+ write(Dev, " ("),
+ pp_type_list(Dev, function_arg_type_list(Type)),
+ write(Dev, ")");
+ %% Aggregate
+ #llvm_array{} ->
+ write(Dev, ["[", integer_to_list(array_size(Type)), " x "]),
+ pp_type(Dev, array_type(Type)),
+ write(Dev, "]");
+ #llvm_struct{} ->
+ write(Dev, "{"),
+ pp_type_list(Dev, struct_type_list(Type)),
+ write(Dev, "}");
+ #llvm_vector{} ->
+ write(Dev, ["{", integer_to_list(vector_size(Type)), " x "]),
+ pp_type(Dev, vector_type(Type)),
+ write(Dev, "}")
+ end.
+
+%% @doc Pretty-print a list of typed arguments
+pp_args(_Dev, []) -> ok;
+pp_args(Dev, [{Type, Arg} | []]) ->
+ pp_type(Dev, Type),
+ write(Dev, [" ", Arg]);
+pp_args(Dev, [{Type, Arg} | Args]) ->
+ pp_type(Dev, Type),
+ write(Dev, [" ", Arg, ", "]),
+ pp_args(Dev, Args).
+
+%% @doc Pretty-print a list of options
+pp_options(_Dev, []) -> ok;
+pp_options(Dev, [O|Os]) ->
+ write(Dev, [atom_to_list(O), " "]),
+ pp_options(Dev, Os).
+
+%% @doc Pretty-print a list of phi value-labels
+pp_phi_value_labels(_Dev, []) -> ok;
+pp_phi_value_labels(Dev, [{Value, Label}|[]]) ->
+ write(Dev, ["[ ", Value, ", ", Label, " ]"]);
+pp_phi_value_labels(Dev,[{Value, Label}|VL]) ->
+ write(Dev, ["[ ", Value, ", ", Label, " ], "]),
+ pp_phi_value_labels(Dev, VL).
+
+%% @doc Pretty-print a list of typed indexes
+pp_typed_idxs(_Dev, []) -> ok;
+pp_typed_idxs(Dev, [{Type, Id} | Tids]) ->
+ write(Dev, ", "),
+ pp_type(Dev, Type),
+ write(Dev, [" ", Id]),
+ pp_typed_idxs(Dev, Tids).
+
+%% @doc Pretty-print a switch label list
+pp_switch_value_label_list(_Dev, _Type, []) -> ok;
+pp_switch_value_label_list(Dev, Type, [{Value, Label} | VLs]) ->
+ write(Dev, " "),
+ pp_type(Dev, Type),
+ write(Dev, [" ", Value, ", label ", Label, "\n"]),
+ pp_switch_value_label_list(Dev, Type, VLs).
+
+%%----------------------------------------------------------------------------
+%% Auxiliary Functions
+%%----------------------------------------------------------------------------
+
+%% @doc Returns if an instruction needs to be intended
+indent(I) ->
+ case I of
+ #llvm_label{} -> false;
+ #llvm_fun_def{} -> false;
+ #llvm_fun_decl{} -> false;
+ #llvm_const_decl{} -> false;
+ #llvm_branch_meta{} -> false;
+ _ -> true
+ end.
+
+op_has_options(Op) ->
+ case Op of
+ 'and' -> false;
+ 'or' -> false;
+ 'xor' -> false;
+ _ -> true
+ end.
+
+%% @doc Abstracts actual writing to file operations
+write(Dev, Msg) ->
+ ok = file:write(Dev, Msg).
diff --git a/lib/hipe/llvm/hipe_llvm_arch.hrl b/lib/hipe/llvm/hipe_llvm_arch.hrl
new file mode 100644
index 0000000000..689a5a52ea
--- /dev/null
+++ b/lib/hipe/llvm/hipe_llvm_arch.hrl
@@ -0,0 +1,11 @@
+-ifdef(BIT32).
+-define(NR_PINNED_REGS, 2).
+-define(NR_ARG_REGS, 3).
+-define(ARCH_REGISTERS, hipe_x86_registers).
+-define(FLOAT_OFFSET, 2).
+-else.
+-define(NR_PINNED_REGS, 2).
+-define(NR_ARG_REGS, 4).
+-define(ARCH_REGISTERS, hipe_amd64_registers).
+-define(FLOAT_OFFSET, 6).
+-endif.
diff --git a/lib/hipe/llvm/hipe_llvm_liveness.erl b/lib/hipe/llvm/hipe_llvm_liveness.erl
new file mode 100644
index 0000000000..d1c90ed4c9
--- /dev/null
+++ b/lib/hipe/llvm/hipe_llvm_liveness.erl
@@ -0,0 +1,112 @@
+-module(hipe_llvm_liveness).
+
+-export([analyze/1]).
+
+%% @doc Find gc roots and explicitly mark when they go out of scope, based
+%% on the liveness analyzis performed by the hipe_rtl_liveness:analyze/1.
+analyze(RtlCfg) ->
+ Liveness = hipe_rtl_liveness:analyze(RtlCfg),
+ Roots = find_roots(RtlCfg, Liveness),
+ %% erlang:display(Roots),
+ NewRtlCfg = mark_dead_roots(RtlCfg, Liveness, Roots),
+ {NewRtlCfg, Roots}.
+
+%% @doc Determine which are the GC Roots.Possible roots are all
+%% RTL variables (rtl_var). However, since safe points are function calls, we
+%% consider as possible GC roots only RTL variables that are live around
+%% function calls.
+find_roots(Cfg, Liveness) ->
+ Labels = hipe_rtl_cfg:postorder(Cfg),
+ Roots = find_roots_bb(Labels, Cfg, Liveness, []),
+ lists:usort(lists:flatten(Roots)).
+
+find_roots_bb([], _Cfg, _Liveness, RootAcc) ->
+ RootAcc;
+find_roots_bb([L|Ls], Cfg, Liveness, RootAcc) ->
+ Block = hipe_rtl_cfg:bb(Cfg, L),
+ BlockCode = hipe_bb:code(Block),
+ LiveIn = ordsets:from_list(strip(hipe_rtl_liveness:livein(Liveness, L))),
+ LiveOut = ordsets:from_list(strip(hipe_rtl_liveness:liveout(Liveness, L))),
+ Roots = do_find_roots_bb(BlockCode, L, LiveOut, LiveIn, []),
+ find_roots_bb(Ls, Cfg, Liveness, Roots++RootAcc).
+
+%% For each call inside a BB the GC roots are those RTL variables that
+%% are live before and after the call.
+%% --> Live Before Call: These are the RTL variables that belong to the
+%% LiveIn list or are initialized inside the BB before the call
+%% --> Live After Call: These are the RTL variables that belong to the
+%% LiveOut list or are used after the call inside the BB (they die
+%% inside the BB and so do not belong to the LiveOut list)
+do_find_roots_bb([], _Label, _LiveOut, _LiveBefore, RootAcc) ->
+ RootAcc;
+do_find_roots_bb([I|Is], L, LiveOut, LiveBefore, RootAcc) ->
+ case hipe_rtl:is_call(I) of
+ true ->
+ %% Used inside the BB after the call
+ UsedAfterCall_ = strip(lists:flatten([hipe_rtl:uses(V) || V <- Is])),
+ UsedAfterCall = ordsets:from_list(UsedAfterCall_),
+ LiveAfter = ordsets:union(UsedAfterCall, LiveOut),
+ %% The Actual Roots
+ Roots = ordsets:intersection(LiveBefore, LiveAfter),
+ %% The result of the instruction
+ Defines = ordsets:from_list(strip(hipe_rtl:defines(I))),
+ LiveBefore1 = ordsets:union(LiveBefore, Defines),
+ do_find_roots_bb(Is, L, LiveOut, LiveBefore1, [Roots|RootAcc]);
+ false ->
+ %% The result of the instruction
+ Defines = ordsets:from_list(strip(hipe_rtl:defines(I))),
+ LiveBefore1 = ordsets:union(LiveBefore, Defines),
+ do_find_roots_bb(Is, L, LiveOut, LiveBefore1, RootAcc)
+ end.
+
+%% @doc This function is responsible for marking when GC Roots, which can be
+%% only RTL variables go out of scope (dead). This pass is needed for the LLVM
+%% back end because the LLVM framework forces us to explicit mark when gc roots
+%% are no longer live.
+mark_dead_roots(CFG, Liveness, Roots) ->
+ Labels = hipe_rtl_cfg:postorder(CFG),
+ mark_dead_bb(Labels, CFG, Liveness, Roots).
+
+mark_dead_bb([], Cfg, _Liveness, _Roots) ->
+ Cfg;
+mark_dead_bb([L|Ls], Cfg, Liveness, Roots) ->
+ Block = hipe_rtl_cfg:bb(Cfg, L),
+ BlockCode = hipe_bb:code(Block),
+ LiveOut = ordsets:from_list(strip(hipe_rtl_liveness:liveout(Liveness, L))),
+ NewBlockCode = do_mark_dead_bb(BlockCode, LiveOut, Roots, []),
+ %% Update the CFG
+ NewBB = hipe_bb:code_update(Block, NewBlockCode),
+ NewCFG = hipe_rtl_cfg:bb_add(Cfg, L, NewBB),
+ mark_dead_bb(Ls, NewCFG, Liveness, Roots).
+
+do_mark_dead_bb([], _LiveOut, _Roots, NewBlockCode) ->
+ lists:reverse(NewBlockCode);
+do_mark_dead_bb([I|Is], LiveOut ,Roots, NewBlockCode) ->
+ Uses = ordsets:from_list(strip(hipe_rtl:uses(I))),
+ %% GC roots that are used in this instruction
+ RootsUsed = ordsets:intersection(Roots, Uses),
+ UsedAfter_ = strip(lists:flatten([hipe_rtl:uses(V) || V <- Is])),
+ UsedAfter = ordsets:from_list(UsedAfter_),
+ %% GC roots that are live after this instruction
+ LiveAfter = ordsets:union(LiveOut, UsedAfter),
+ %% GC roots that their last use is in this instruction
+ DeadRoots = ordsets:subtract(RootsUsed, LiveAfter),
+ %% Recreate the RTL variable from the corresponding Index
+ OldVars = [hipe_rtl:mk_var(V1) || V1 <- DeadRoots],
+ %% Mark the RTL variable as DEAD (last use)
+ NewVars = [kill_var(V2) || V2 <- OldVars],
+ %% Create a list with the substitution of the old vars with the new
+ %% ones which are marked with the dead keyword
+ Subtitution = lists:zip(OldVars, NewVars),
+ NewI = case Subtitution of
+ [] -> I;
+ _ -> hipe_rtl:subst_uses_llvm(Subtitution, I)
+ end,
+ do_mark_dead_bb(Is, LiveOut, Roots, [NewI|NewBlockCode]).
+
+%% Update the liveness of a var,in order to mark that this is the last use.
+kill_var(Var) -> hipe_rtl:var_liveness_update(Var, dead).
+
+%% We are only interested for rtl_vars, since only rtl_vars are possible gc
+%% roots.
+strip(L) -> [Y || {rtl_var, Y, _} <- L].
diff --git a/lib/hipe/llvm/hipe_llvm_main.erl b/lib/hipe/llvm/hipe_llvm_main.erl
new file mode 100644
index 0000000000..e911fb89c9
--- /dev/null
+++ b/lib/hipe/llvm/hipe_llvm_main.erl
@@ -0,0 +1,514 @@
+%% -*- erlang-indent-level: 2 -*-
+-module(hipe_llvm_main).
+
+-export([rtl_to_native/4]).
+
+-include("../../kernel/src/hipe_ext_format.hrl").
+-include("hipe_llvm_arch.hrl").
+-include("elf_format.hrl").
+
+%% @doc Translation of RTL to a loadable object. This function takes the RTL
+%% code and calls hipe_rtl_to_llvm:translate/2 to translate the RTL code to
+%% LLVM code. After this, LLVM asm is printed to a file and the LLVM tool
+%% chain is invoked in order to produce an object file.
+rtl_to_native(MFA, RTL, Roots, Options) ->
+ %% Compile to LLVM and get Instruction List (along with infos)
+ {LLVMCode, RelocsDict, ConstTab} =
+ hipe_rtl_to_llvm:translate(RTL, Roots),
+ %% Fix function name to an acceptable LLVM identifier (needed for closures)
+ {_Module, Fun, Arity} = hipe_rtl_to_llvm:fix_mfa_name(MFA),
+ %% Write LLVM Assembly to intermediate file (on disk)
+ {ok, Dir, ObjectFile} =
+ compile_with_llvm(Fun, Arity, LLVMCode, Options, false),
+ %%
+ %% Extract information from object file
+ %%
+ ObjBin = open_object_file(ObjectFile),
+ %% Read and set the ELF class
+ elf_format:set_architecture_flag(ObjBin),
+ %% Get labels info (for switches and jump tables)
+ Labels = elf_format:get_rodata_relocs(ObjBin),
+ {Switches, Closures} = get_tables(ObjBin),
+ %% Associate Labels with Switches and Closures with stack args
+ {SwitchInfos, ExposedClosures} =
+ correlate_labels(Switches ++ Closures, Labels),
+ %% SwitchInfos: [{"table_50", [Labels]}]
+ %% ExposedClosures: [{"table_closures", [Labels]}]
+
+ %% Labelmap contains the offsets of the labels in the code that are
+ %% used for switch's jump tables
+ LabelMap = create_labelmap(MFA, SwitchInfos, RelocsDict),
+ %% Get relocation info
+ TextRelocs = elf_format:get_text_relocs(ObjBin),
+ %% AccRefs contains the offsets of all references to relocatable symbols in
+ %% the code:
+ AccRefs = fix_relocations(TextRelocs, RelocsDict, MFA),
+ %% Get stack descriptors
+ SDescs = get_sdescs(ObjBin),
+ %% FixedSDescs are the stack descriptors after correcting calls that have
+ %% arguments in the stack
+ FixedSDescs =
+ fix_stack_descriptors(RelocsDict, AccRefs, SDescs, ExposedClosures),
+ Refs = AccRefs ++ FixedSDescs,
+ %% Get binary code from object file
+ BinCode = elf_format:extract_text(ObjBin),
+ %% Remove temp files (if needed)
+ ok = remove_temp_folder(Dir, Options),
+ %% Return the code together with information that will be used in the
+ %% hipe_llvm_merge module to produce the final binary that will be loaded
+ %% by the hipe unified loader.
+ {MFA, BinCode, byte_size(BinCode), ConstTab, Refs, LabelMap}.
+
+%%------------------------------------------------------------------------------
+%% LLVM tool chain
+%%------------------------------------------------------------------------------
+
+%% @doc Compile function FunName/Arity to LLVM. Return Dir (in order to remove
+%% it if we do not want to store temporary files) and ObjectFile name that
+%% is created by the LLVM tools.
+compile_with_llvm(FunName, Arity, LLVMCode, Options, UseBuffer) ->
+ Filename = atom_to_list(FunName) ++ "_" ++ integer_to_list(Arity),
+ %% Save temp files in a unique folder
+ Dir = unique_folder(FunName, Arity, Options),
+ ok = file:make_dir(Dir),
+ %% Print LLVM assembly to file
+ OpenOpts = [append, raw] ++
+ case UseBuffer of
+ %% true -> [delayed_write]; % Use delayed_write!
+ false -> []
+ end,
+ {ok, File_llvm} = file:open(Dir ++ Filename ++ ".ll", OpenOpts),
+ hipe_llvm:pp_ins_list(File_llvm, LLVMCode),
+ %% delayed_write can cause file:close not to do a close, hence the two calls
+ ok = file:close(File_llvm),
+ __ = file:close(File_llvm),
+ %% Invoke LLVM compiler tools to produce an object file
+ llvm_opt(Dir, Filename, Options),
+ llvm_llc(Dir, Filename, Options),
+ compile(Dir, Filename, "gcc"), %%FIXME: use llc -filetype=obj and skip this!
+ {ok, Dir, Dir ++ Filename ++ ".o"}.
+
+%% @doc Invoke opt tool to optimize the bitcode (_name.ll -> _name.bc).
+llvm_opt(Dir, Filename, Options) ->
+ Source = Dir ++ Filename ++ ".ll",
+ Dest = Dir ++ Filename ++ ".bc",
+ OptLevel = trans_optlev_flag(opt, Options),
+ OptFlags = [OptLevel, "-mem2reg", "-strip"],
+ Command = "opt " ++ fix_opts(OptFlags) ++ " " ++ Source ++ " -o " ++ Dest,
+ %% io:format("OPT: ~s~n", [Command]),
+ case os:cmd(Command) of
+ "" -> ok;
+ Error -> exit({?MODULE, opt, Error})
+ end.
+
+%% @doc Invoke llc tool to compile the bitcode to object file
+%% (_name.bc -> _name.o).
+llvm_llc(Dir, Filename, Options) ->
+ Source = Dir ++ Filename ++ ".bc",
+ OptLevel = trans_optlev_flag(llc, Options),
+ Align = find_stack_alignment(),
+ LlcFlags = [OptLevel, "-code-model=medium", "-stack-alignment=" ++ Align
+ , "-tailcallopt", "-filetype=asm"], %%FIXME
+ Command = "llc " ++ fix_opts(LlcFlags) ++ " " ++ Source,
+ %% io:format("LLC: ~s~n", [Command]),
+ case os:cmd(Command) of
+ "" -> ok;
+ Error -> exit({?MODULE, llc, Error})
+ end.
+
+%% @doc Invoke the compiler tool ("gcc", "llvmc", etc.) to generate an object
+%% file from native assembly.
+compile(Dir, Fun_Name, Compiler) ->
+ Source = Dir ++ Fun_Name ++ ".s",
+ Dest = Dir ++ Fun_Name ++ ".o",
+ Command = Compiler ++ " -c " ++ Source ++ " -o " ++ Dest,
+ %% io:format("~s: ~s~n", [Compiler, Command]),
+ case os:cmd(Command) of
+ "" -> ok;
+ Error -> exit({?MODULE, cc, Error})
+ end.
+
+find_stack_alignment() ->
+ case get(hipe_target_arch) of
+ x86 -> "4";
+ amd64 -> "8";
+ _ -> exit({?MODULE, find_stack_alignment, "Unimplemented architecture"})
+ end.
+
+%% @doc Join options.
+fix_opts(Opts) ->
+ string:join(Opts, " ").
+
+%% @doc Translate optimization-level flag (default is "O2").
+trans_optlev_flag(Tool, Options) ->
+ Flag = case Tool of
+ opt -> llvm_opt;
+ llc -> llvm_llc
+ end,
+ case proplists:get_value(Flag, Options) of
+ o0 -> ""; % "-O0" does not exist in opt tool
+ o1 -> "-O1";
+ o2 -> "-O2";
+ o3 -> "-O3";
+ undefined -> "-O2"
+ end.
+
+%%------------------------------------------------------------------------------
+%% Functions to manage Relocations
+%%------------------------------------------------------------------------------
+
+%% @doc Get switch table and closure table.
+get_tables(Elf) ->
+ %% Search Symbol Table for an entry with name prefixed with "table_":
+ Triples = elf_format:get_tab_entries(Elf),
+ Switches = [T || T={"table_" ++ _, _, _} <- Triples],
+ Closures = [T || T={"table_closures" ++ _, _, _} <- Switches],
+ {Switches, Closures}.
+
+%% @doc This function associates symbols who point to some table of labels with
+%% the corresponding offsets of the labels in the code. These tables can
+%% either be jump tables for switches or a table which contains the labels
+%% of blocks that contain closure calls with more than ?NR_ARG_REGS.
+correlate_labels([], _L) -> {[], []};
+correlate_labels(Tables, Labels) ->
+ %% Sort "Tables" based on "ValueOffsets"
+ OffsetSortedTb = lists:ukeysort(2, Tables),
+ %% Unzip offset-sorted list of "Switches"
+ {Names, _Offsets, TablesSizeList} = lists:unzip3(OffsetSortedTb),
+ %% Associate switch names with labels
+ L = split_list(Labels, TablesSizeList),
+ %% Zip back! (to [{SwitchName, Values}])
+ NamesValues = lists:zip(Names, L),
+ case lists:keytake("table_closures", 1, NamesValues) of
+ false -> %% No closures in the code, no closure table
+ {NamesValues, []};
+ {value, ClosureTableNV, SwitchesNV} ->
+ {SwitchesNV, ClosureTableNV}
+ end.
+
+%% @doc Create a gb_tree which contains information about the labels that used
+%% for switch's jump tables. The keys of the gb_tree are of the form
+%% {MFA, Label} and the values are the actual Offsets.
+create_labelmap(MFA, SwitchInfos, RelocsDict) ->
+ create_labelmap(MFA, SwitchInfos, RelocsDict, gb_trees:empty()).
+
+create_labelmap(_, [], _, LabelMap) -> LabelMap;
+create_labelmap(MFA, [{Name, Offsets} | Rest], RelocsDict, LabelMap) ->
+ case dict:fetch(Name, RelocsDict) of
+ {switch, {_TableType, LabelList, _NrLabels, _SortOrder}, _JTabLab} ->
+ KVDict = lists:ukeysort(1, lists:zip(LabelList, Offsets)),
+ NewLabelMap = insert_to_labelmap(KVDict, LabelMap),
+ create_labelmap(MFA, Rest, RelocsDict, NewLabelMap);
+ _ ->
+ exit({?MODULE, create_labelmap, "Not a jump table!"})
+ end.
+
+%% @doc Insert a list of [{Key,Value}] to a LabelMap (gb_tree).
+insert_to_labelmap([], LabelMap) -> LabelMap;
+insert_to_labelmap([{Key, Value}|Rest], LabelMap) ->
+ case gb_trees:lookup(Key, LabelMap) of
+ none ->
+ insert_to_labelmap(Rest, gb_trees:insert(Key, Value, LabelMap));
+ {value, Value} -> %% Exists with the *exact* same Value.
+ insert_to_labelmap(Rest, LabelMap)
+ end.
+
+%% @doc Correlate object file relocation symbols with info from translation to
+%% llvm code.
+fix_relocations(Relocs, RelocsDict, MFA) ->
+ fix_relocs(Relocs, RelocsDict, MFA, []).
+
+fix_relocs([], _, _, RelocAcc) -> RelocAcc;
+fix_relocs([{Name, Offset}|Rs], RelocsDict, {ModName,_,_}=MFA, RelocAcc) ->
+ case dict:fetch(Name, RelocsDict) of
+ {atom, AtomName} ->
+ fix_relocs(Rs, RelocsDict, MFA,
+ [{?LOAD_ATOM, Offset, AtomName}|RelocAcc]);
+ {constant, Label} ->
+ fix_relocs(Rs, RelocsDict, MFA,
+ [{?LOAD_ADDRESS, Offset, {constant, Label}}|RelocAcc]);
+ {switch, _, JTabLab} -> %% Treat switch exactly as constant
+ fix_relocs(Rs, RelocsDict, MFA,
+ [{?LOAD_ADDRESS, Offset, {constant, JTabLab}}|RelocAcc]);
+ {closure, _}=Closure ->
+ fix_relocs(Rs, RelocsDict, MFA,
+ [{?LOAD_ADDRESS, Offset, Closure}|RelocAcc]);
+ {call, {bif, BifName, _}} ->
+ fix_relocs(Rs, RelocsDict, MFA,
+ [{?CALL_LOCAL, Offset, BifName}|RelocAcc]);
+ %% MFA calls to functions in the same module are of type 3, while all
+ %% other MFA calls are of type 2.
+ {call, {ModName,_F,_A}=CallMFA} ->
+ fix_relocs(Rs, RelocsDict, MFA,
+ [{?CALL_LOCAL, Offset, CallMFA}|RelocAcc]);
+ {call, CallMFA} ->
+ fix_relocs(Rs, RelocsDict, MFA,
+ [{?CALL_REMOTE, Offset, CallMFA}|RelocAcc]);
+ Other ->
+ exit({?MODULE, fix_relocs,
+ {"Relocation not in relocation dictionary", Other}})
+ end.
+
+%%------------------------------------------------------------------------------
+%% Functions to manage Stack Descriptors
+%%------------------------------------------------------------------------------
+
+%% @doc This function takes an ELF Object File binary and returns a proper sdesc
+%% list for Erlang/OTP System's loader. The return value should be of the
+%% form:
+%% {
+%% 4, Safepoint Address,
+%% {ExnLabel OR [], FrameSize, StackArity, {Liveroot stack frame indexes}},
+%% }
+get_sdescs(Elf) ->
+ case elf_format:extract_note(Elf, ?NOTE_ERLGC_NAME) of
+ <<>> -> % Object file has no ".note.gc" section!
+ [];
+ NoteGC_bin ->
+ %% Get safe point addresses (stored in ".rela.note.gc" section):
+ RelaNoteGC = elf_format:extract_rela(Elf, ?NOTE(?NOTE_ERLGC_NAME)),
+ SPCount = length(RelaNoteGC),
+ T = SPCount * ?SP_ADDR_SIZE,
+ %% Pattern match fields of ".note.gc":
+ <<SPCount:(?bits(?SP_COUNT_SIZE))/integer-little, % Sanity check!
+ SPAddrs:T/binary, % NOTE: In 64bit they are relocs!
+ StkFrameSize:(?bits(?SP_STKFRAME_SIZE))/integer-little,
+ StkArity:(?bits(?SP_STKARITY_SIZE))/integer-little,
+ _LiveRootCount:(?bits(?SP_LIVEROOTCNT_SIZE))/integer-little, % Skip
+ Roots/binary>> = NoteGC_bin,
+ LiveRoots = get_liveroots(Roots, []),
+ %% Extract information about the safe point addresses:
+ SPOffs =
+ case elf_format:is64bit() of
+ true -> %% Find offsets in ".rela.note.gc":
+ elf_format:get_rela_addends(RelaNoteGC);
+ false -> %% Find offsets in SPAddrs (in ".note.gc"):
+ get_spoffs(SPAddrs, [])
+ end,
+ %% Extract Exception Handler labels:
+ ExnHandlers = elf_format:get_exn_handlers(Elf),
+ %% Combine ExnHandlers and Safe point addresses (return addresses):
+ ExnAndSPOffs = combine_ras_and_exns(ExnHandlers, SPOffs, []),
+ create_sdesc_list(ExnAndSPOffs, StkFrameSize, StkArity, LiveRoots, [])
+ end.
+
+%% @doc Extracts a bunch of integers (live roots) from a binary. Returns a tuple
+%% as need for stack descriptors.
+get_liveroots(<<>>, Acc) ->
+ list_to_tuple(Acc);
+get_liveroots(<<Root:?bits(?LR_STKINDEX_SIZE)/integer-little,
+ MoreRoots/binary>>, Acc) ->
+ get_liveroots(MoreRoots, [Root | Acc]).
+
+%% @doc Extracts a bunch of integers (safepoint offsets) from a binary. Returns
+%% a tuple as need for stack descriptors.
+get_spoffs(<<>>, Acc) ->
+ lists:reverse(Acc);
+get_spoffs(<<SPOff:?bits(?SP_ADDR_SIZE)/integer-little, More/binary>>, Acc) ->
+ get_spoffs(More, [SPOff | Acc]).
+
+combine_ras_and_exns(_, [], Acc) ->
+ lists:reverse(Acc);
+combine_ras_and_exns(ExnHandlers, [RA | MoreRAs], Acc) ->
+ %% FIXME: do something better than O(n^2) by taking advantage of the property
+ %% ||ExnHandlers|| <= ||RAs||
+ Handler = find_exn_handler(RA, ExnHandlers),
+ combine_ras_and_exns(ExnHandlers, MoreRAs, [{Handler, RA} | Acc]).
+
+find_exn_handler(_, []) ->
+ [];
+find_exn_handler(RA, [{Start, End, Handler} | MoreExnHandlers]) ->
+ case (RA >= Start andalso RA =< End) of
+ true ->
+ Handler;
+ false ->
+ find_exn_handler(RA, MoreExnHandlers)
+ end.
+
+create_sdesc_list([], _, _, _, Acc) ->
+ lists:reverse(Acc);
+create_sdesc_list([{ExnLbl, SPOff} | MoreExnAndSPOffs],
+ StkFrameSize, StkArity, LiveRoots, Acc) ->
+ Hdlr = case ExnLbl of
+ 0 -> [];
+ N -> N
+ end,
+ create_sdesc_list(MoreExnAndSPOffs, StkFrameSize, StkArity, LiveRoots,
+ [{?SDESC, SPOff, {Hdlr, StkFrameSize, StkArity, LiveRoots}}
+ | Acc]).
+
+%% @doc This function is responsible for correcting the stack descriptors of
+%% the calls that are found in the code and have more than NR_ARG_REGS
+%% (thus, some of their arguments are passed to the stack). Because of the
+%% Reserved Call Frame feature that the LLVM uses, the stack descriptors
+%% are not correct since at the point of call the frame size is reduced
+%% proportionally to the number of arguments that are passed on the stack.
+%% Also the offsets of the roots need to be re-adjusted.
+fix_stack_descriptors(_, _, [], _) ->
+ [];
+fix_stack_descriptors(RelocsDict, Relocs, SDescs, ExposedClosures) ->
+ %% NamedCalls are MFA and BIF calls that need fix
+ NamedCalls = calls_with_stack_args(RelocsDict),
+ NamedCallsOffs = calls_offsets_arity(Relocs, NamedCalls),
+ ExposedClosures1 =
+ case dict:is_key("table_closures", RelocsDict) of
+ true -> %% A Table with closures exists
+ {table_closures, ArityList} = dict:fetch("table_closures", RelocsDict),
+ case ExposedClosures of
+ {_, Offsets} ->
+ lists:zip(Offsets, ArityList);
+ _ ->
+ exit({?MODULE, fix_stack_descriptors,
+ {"Wrong exposed closures", ExposedClosures}})
+ end;
+ false ->
+ []
+ end,
+ ClosuresOffs = closures_offsets_arity(ExposedClosures1, SDescs),
+ fix_sdescs(NamedCallsOffs ++ ClosuresOffs, SDescs).
+
+%% @doc This function takes as argument the relocation dictionary as produced by
+%% the translation of RTL code to LLVM and finds the names of the calls
+%% (MFA and BIF calls) that have more than NR_ARG_REGS.
+calls_with_stack_args(Dict) ->
+ calls_with_stack_args(dict:to_list(Dict), []).
+
+calls_with_stack_args([], Calls) -> Calls;
+calls_with_stack_args([ {_Name, {call, {M, F, A}}} | Rest], Calls)
+ when A > ?NR_ARG_REGS ->
+ Call =
+ case M of
+ bif -> {F,A};
+ _ -> {M,F,A}
+ end,
+ calls_with_stack_args(Rest, [Call|Calls]);
+calls_with_stack_args([_|Rest], Calls) ->
+ calls_with_stack_args(Rest, Calls).
+
+%% @doc This function extracts the stack arity and the offset in the code of
+%% the named calls (MFAs, BIFs) that have stack arguments.
+calls_offsets_arity(AccRefs, CallsWithStackArgs) ->
+ calls_offsets_arity(AccRefs, CallsWithStackArgs, []).
+
+calls_offsets_arity([], _, Acc) -> Acc;
+calls_offsets_arity([{Type, Offset, Term} | Rest], CallsWithStackArgs, Acc)
+ when Type =:= ?CALL_REMOTE orelse Type =:= ?CALL_LOCAL ->
+ case lists:member(Term, CallsWithStackArgs) of
+ true ->
+ Arity =
+ case Term of
+ {_M, _F, A} -> A;
+ {_F, A} -> A
+ end,
+ calls_offsets_arity(Rest, CallsWithStackArgs,
+ [{Offset + 4, Arity - ?NR_ARG_REGS} | Acc]);
+ false ->
+ calls_offsets_arity(Rest, CallsWithStackArgs, Acc)
+ end;
+calls_offsets_arity([_|Rest], CallsWithStackArgs, Acc) ->
+ calls_offsets_arity(Rest, CallsWithStackArgs, Acc).
+
+%% @doc This function extracts the stack arity and the offsets of closures that
+%% have stack arity. The Closures argument represents the
+%% hipe_bifs:llvm_exposure_closure/0 calls in the code. The actual closure
+%% is the next call in the code, so the offset of the next call must be
+%% calculated from the stack descriptors.
+closures_offsets_arity([], _) ->
+ [];
+closures_offsets_arity(ExposedClosures, SDescs) ->
+ Offsets = [Offset || {_, Offset, _} <- SDescs],
+ %% Offsets and closures must be sorted in order for find_offsets/3 to work
+ SortedOffsets = lists:sort(Offsets),
+ SortedExposedClosures = lists:keysort(1, ExposedClosures),
+ find_offsets(SortedExposedClosures, SortedOffsets, []).
+
+find_offsets([], _, Acc) -> Acc;
+find_offsets([{Off,Arity}|Rest], Offsets, Acc) ->
+ [I | RestOffsets] = lists:dropwhile(fun (Y) -> Y<Off end, Offsets),
+ find_offsets(Rest, RestOffsets, [{I, Arity}|Acc]).
+
+%% The functions below correct the arity of calls, that are identified
+%% by offset, in the stack descriptors.
+fix_sdescs([], SDescs) -> SDescs;
+fix_sdescs([{Offset, Arity} | Rest], SDescs) ->
+ case lists:keyfind(Offset, 2, SDescs) of
+ false ->
+ fix_sdescs(Rest, SDescs);
+ {?SDESC, Offset, SDesc} ->
+ {ExnHandler, FrameSize, StkArity, Roots} = SDesc,
+ DecRoot = fun(X) -> X-Arity end,
+ NewRootsList = lists:map(DecRoot, tuple_to_list(Roots)),
+ NewSDesc =
+ case length(NewRootsList) > 0 andalso hd(NewRootsList) >= 0 of
+ true ->
+ {?SDESC, Offset, {ExnHandler, FrameSize-Arity, StkArity,
+ list_to_tuple(NewRootsList)}};
+ false ->
+ {?SDESC, Offset, {ExnHandler, FrameSize, StkArity, Roots}}
+ end,
+ RestSDescs = lists:keydelete(Offset, 2, SDescs),
+ fix_sdescs(Rest, [NewSDesc | RestSDescs])
+ end.
+
+
+%%------------------------------------------------------------------------------
+%% Miscellaneous functions
+%%------------------------------------------------------------------------------
+
+%% @doc A function that opens a file as binary. The function takes as argument
+%% the name of the file and returns an Erlang binary.
+-spec open_object_file(string()) -> binary().
+open_object_file(ObjFile) ->
+ case file:read_file(ObjFile) of
+ {ok, Binary} ->
+ Binary;
+ {error, Reason} ->
+ exit({?MODULE, open_file, Reason})
+ end.
+
+remove_temp_folder(Dir, Options) ->
+ case proplists:get_bool(llvm_save_temps, Options) of
+ true -> ok;
+ false -> spawn(fun () -> "" = os:cmd("rm -rf " ++ Dir) end), ok
+ end.
+
+unique_id(FunName, Arity) ->
+ integer_to_list(erlang:phash2({FunName, Arity, now()})).
+
+unique_folder(FunName, Arity, Options) ->
+ DirName = "llvm_" ++ unique_id(FunName, Arity) ++ "/",
+ Dir =
+ case proplists:get_bool(llvm_save_temps, Options) of
+ true -> %% Store folder in current directory
+ DirName;
+ false -> %% Temporarily store folder in tempfs (/dev/shm/)
+ "/dev/shm/" ++ DirName
+ end,
+ %% Make sure it does not exist
+ case dir_exists(Dir) of
+ true -> %% Dir already exists! Generate again.
+ unique_folder(FunName, Arity, Options);
+ false ->
+ Dir
+ end.
+
+%% @doc Function that checks that a given Filename is an existing Directory
+%% Name (from http://rosettacode.org/wiki/Ensure_that_a_file_exists#Erlang)
+dir_exists(Filename) ->
+ {Flag, Info} = file:read_file_info(Filename),
+ (Flag =:= ok) andalso (element(3, Info) =:= directory).
+
+%% @doc Function that takes as arguments a list of integers and a list with
+%% numbers indicating how many items should each tuple have and splits
+%% the original list to a list of lists of integers (with the specified
+%% number of elements), i.e. [ [...], [...] ].
+-spec split_list([integer()], [integer()]) -> [ [integer()] ].
+split_list(List, ElemsPerTuple) ->
+ split_list(List, ElemsPerTuple, []).
+
+-spec split_list([integer()], [integer()], [ [integer()] ]) -> [ [integer()] ].
+split_list([], [], Acc) ->
+ lists:reverse(Acc);
+split_list(List, [NumOfElems | MoreNums], Acc) ->
+ {L1, L2} = lists:split(NumOfElems, List),
+ split_list(L2, MoreNums, [ L1 | Acc]).
diff --git a/lib/hipe/llvm/hipe_llvm_merge.erl b/lib/hipe/llvm/hipe_llvm_merge.erl
new file mode 100644
index 0000000000..3ababfc21a
--- /dev/null
+++ b/lib/hipe/llvm/hipe_llvm_merge.erl
@@ -0,0 +1,114 @@
+%%% -*- erlang-indent-level: 2 -*-
+-module(hipe_llvm_merge).
+
+-export([finalize/3]).
+
+-include("hipe_llvm_arch.hrl").
+-include("../../kernel/src/hipe_ext_format.hrl").
+-include("../rtl/hipe_literals.hrl").
+-include("../main/hipe.hrl").
+
+finalize(CompiledCode, Closures, Exports) ->
+ CompiledCode1 = [CodePack || {_, CodePack} <- CompiledCode],
+ Code = [{MFA, [], ConstTab}
+ || {MFA, _, _ , ConstTab, _, _} <- CompiledCode1],
+ {ConstAlign, ConstSize, ConstMap, RefsFromConsts} =
+ hipe_pack_constants:pack_constants(Code, ?ARCH_REGISTERS:alignment()),
+ %% Compute total code size separately as a sanity check for alignment
+ CodeSize = compute_code_size(CompiledCode1, 0),
+ %% io:format("Code Size (pre-computed): ~w~n", [CodeSize]),
+ {CodeBinary, ExportMap} = merge_mfas(CompiledCode1, 0, <<>>, []),
+ %% io:format("Code Size (post-computed): ~w~n", [byte_size(CodeBinary)]),
+ ?VERBOSE_ASSERT(CodeSize =:= byte_size(CodeBinary)),
+ AccRefs = merge_refs(CompiledCode1, ConstMap, 0, []),
+ %% Bring CompiledCode to a combine_label_maps-acceptable form.
+ LabelMap = combine_label_maps(CompiledCode1, 0, gb_trees:empty()),
+ SC = hipe_pack_constants:slim_constmap(ConstMap),
+ DataRelocs = hipe_pack_constants:mk_data_relocs(RefsFromConsts, LabelMap),
+ SSE = hipe_pack_constants:slim_sorted_exportmap(ExportMap, Closures, Exports),
+ SlimRefs = hipe_pack_constants:slim_refs(AccRefs),
+ term_to_binary([{?VERSION_STRING(),?HIPE_SYSTEM_CRC},
+ ConstAlign, ConstSize,
+ SC, % ConstMap
+ DataRelocs, % LabelMap
+ SSE, % ExportMap
+ CodeSize, CodeBinary, SlimRefs,
+ 0,[] % ColdCodeSize, SlimColdRefs
+ ]).
+
+%% Copied from hipe_x86_assemble.erl
+nr_pad_bytes(Address) ->
+ (4 - (Address rem 4)) rem 4. % XXX: 16 or 32 instead?
+
+align_entry(Address) ->
+ Address + nr_pad_bytes(Address).
+
+compute_code_size([{_MFA, _BinaryCode, CodeSize, _, _, _}|Code], Size) ->
+ compute_code_size(Code, align_entry(Size+CodeSize));
+compute_code_size([], Size) -> Size.
+
+combine_label_maps([{MFA, _, CodeSize, _, _, LabelMap}|Code], Address, CLM) ->
+ NewCLM = merge_label_map(gb_trees:to_list(LabelMap), MFA, Address, CLM),
+ combine_label_maps(Code, align_entry(Address+CodeSize), NewCLM);
+combine_label_maps([], _Address, CLM) -> CLM.
+
+merge_label_map([{Label,Offset}|Rest], MFA, Address, CLM) ->
+ NewCLM = gb_trees:insert({MFA,Label}, Address+Offset, CLM),
+ merge_label_map(Rest, MFA, Address, NewCLM);
+merge_label_map([], _MFA, _Address, CLM) -> CLM.
+
+%% @doc Merge the MFAs' binary code to one continuous binary and compute the
+%% size of this binary. At the same time create an exportmap in a form
+%% of {Address, M, F, A}.
+%% XXX: Is alignment correct/optimal for X86/AMD64?
+merge_mfas([{{M,F,A}, CodeBinary, CodeSize, _, _, _}|Code],
+ Address, AccCode, AccExportMap) ->
+ ?VERBOSE_ASSERT(CodeSize =:= byte_size(CodeBinary)),
+ {Address1, Code1} =
+ case nr_pad_bytes(Address + CodeSize) of
+ 0 -> %% Retains alignment:
+ {Address + CodeSize, CodeBinary};
+ NrPadBytes -> %% Needs padding!
+ Padding = list_to_binary(lists:duplicate(NrPadBytes, 0)),
+ {Address + CodeSize + NrPadBytes, % =:= align_entry(Address+CodeSize)
+ <<CodeBinary/binary, Padding/binary>>}
+ end,
+ ?VERBOSE_ASSERT(Address1 =:=
+ align_entry(Address + CodeSize)), %XXX: Should address be aligned?
+ AccCode1 = <<AccCode/binary, Code1/binary>>,
+ merge_mfas(Code, Address1, AccCode1, [{Address, M, F, A}|AccExportMap]);
+merge_mfas([], _Address, AccCode, AccExportMap) ->
+ {AccCode, AccExportMap}.
+
+%% @doc Merge the references of relocatable symbols in the binary code. The
+%% offsets must be updated because of the merging of the code binaries!
+merge_refs([], _ConstMap, _Addr, AccRefs) -> AccRefs;
+merge_refs([{MFA, _, CodeSize, _, Refs, _}|Rest], ConstMap, Address, AccRefs) ->
+ %% Important!: The hipe_pack_constants:pack_constants/2 function assignes
+ %% unique numbers to constants (ConstNo). This numbers are used from now on,
+ %% instead of labels that were used before. So, in order to be compatible, we
+ %% must change all the constant labels in the Refs to the corresponding
+ %% ConstNo, that can be found in the ConstMap (#pcm_entry{}).
+ UpdatedRefs = [update_ref(label_to_constno(Ref, MFA, ConstMap), Address)
+ || Ref <- Refs],
+ merge_refs(Rest, ConstMap, align_entry(Address+CodeSize),
+ UpdatedRefs++AccRefs).
+
+label_to_constno({Type, Offset, {constant, Label}}, MFA, ConstMap) ->
+ ConstNo = hipe_pack_constants:find_const({MFA, Label}, ConstMap),
+ {Type, Offset, {constant, ConstNo}};
+label_to_constno(Other, _MFA, _ConstMap) ->
+ Other.
+
+%% @doc Update offset to a reference. In case of stack descriptors we must check
+%% if there exists an exception handler, because it must also be updated.
+update_ref({?SDESC, Offset, SDesc}, CodeAddr) ->
+ NewRefAddr = Offset+CodeAddr,
+ case SDesc of
+ {[], _, _, _} -> % No handler; only update offset
+ {?SDESC, NewRefAddr, SDesc};
+ {ExnHandler, FrameSize, StackArity, Roots} -> % Update exception handler
+ {?SDESC, NewRefAddr, {ExnHandler+CodeAddr, FrameSize, StackArity, Roots}}
+ end;
+update_ref({Type, Offset, Term}, CodeAddr) ->
+ {Type, Offset+CodeAddr, Term}.
diff --git a/lib/hipe/llvm/hipe_rtl_to_llvm.erl b/lib/hipe/llvm/hipe_rtl_to_llvm.erl
new file mode 100644
index 0000000000..ba76e1d815
--- /dev/null
+++ b/lib/hipe/llvm/hipe_rtl_to_llvm.erl
@@ -0,0 +1,1612 @@
+%% -*- erlang-indent-level: 2 -*-
+
+-module(hipe_rtl_to_llvm).
+-author("Chris Stavrakakis, Yiannis Tsiouris").
+
+-export([translate/2]). % the main function of this module
+-export([fix_mfa_name/1]). % a help function used in hipe_llvm_main
+
+-include("../rtl/hipe_rtl.hrl").
+-include("../rtl/hipe_literals.hrl").
+-include("hipe_llvm_arch.hrl").
+
+-define(WORD_WIDTH, (?bytes_to_bits(hipe_rtl_arch:word_size()))).
+-define(BRANCH_META_TAKEN, "0").
+-define(BRANCH_META_NOT_TAKEN, "1").
+
+%%------------------------------------------------------------------------------
+%% @doc Main function for translating an RTL function to LLVM Assembly. Takes as
+%% input the RTL code and the variable indexes of possible garbage
+%% collection roots and returns the corresponing LLVM, a dictionary with
+%% all the relocations in the code and a hipe_consttab() with informaton
+%% about data.
+%%------------------------------------------------------------------------------
+translate(RTL, Roots) ->
+ Fun = hipe_rtl:rtl_fun(RTL),
+ Params = hipe_rtl:rtl_params(RTL),
+ Data = hipe_rtl:rtl_data(RTL),
+ Code = hipe_rtl:rtl_code(RTL),
+ %% Init unique symbol generator and initialize the label counter to the last
+ %% RTL label.
+ hipe_gensym:init(llvm),
+ {_, MaxLabel} = hipe_rtl:rtl_label_range(RTL),
+ put({llvm,label_count}, MaxLabel + 1),
+ %% Put first label of RTL code in process dictionary
+ find_code_entry_label(Code),
+ %% Initialize relocations symbol dictionary
+ Relocs = dict:new(),
+ %% Print RTL to file
+ %% {ok, File_rtl} = file:open("rtl_" ++integer_to_list(random:uniform(2000))
+ %% ++ ".rtl", [write]),
+ %% hipe_rtl:pp(File_rtl, RTL),
+ %% file:close(File_rtl),
+
+ %% Pass on RTL code to handle exception handling and identify labels of Fail
+ %% Blocks
+ {Code1, FailLabels} = fix_code(Code),
+ %% Allocate stack slots for each virtual register and declare gc roots
+ AllocaStackCode = alloca_stack(Code1, Params, Roots),
+ %% Translate Code
+ {LLVM_Code1, Relocs1, NewData} =
+ translate_instr_list(Code1, [], Relocs, Data),
+ %% Create LLVM code to declare relocation symbols as external symbols along
+ %% with local variables in order to use them as just any other variable
+ {FinalRelocs, ExternalDecl, LocalVars} =
+ handle_relocations(Relocs1, Data, Fun),
+ %% Pass on LLVM code in order to create Fail blocks and a landingpad
+ %% instruction to each one
+ LLVM_Code2 = add_landingpads(LLVM_Code1, FailLabels),
+ %% Create LLVM Code for the compiled function
+ LLVM_Code3 = create_function_definition(Fun, Params, LLVM_Code2,
+ AllocaStackCode ++ LocalVars),
+ %% Final Code = CompiledFunction + External Declarations
+ FinalLLVMCode = [LLVM_Code3 | ExternalDecl],
+ {FinalLLVMCode, FinalRelocs, NewData}.
+
+find_code_entry_label([]) ->
+ exit({?MODULE, find_code_entry_label, "Empty code"});
+find_code_entry_label([I|_]) ->
+ case hipe_rtl:is_label(I) of
+ true ->
+ put(first_label, hipe_rtl:label_name(I));
+ false ->
+ exit({?MODULE, find_code_entry_label, "First instruction is not a label"})
+ end.
+
+%% @doc Create a stack slot for each virtual register. The stack slots
+%% that correspond to possible garbage collection roots must be
+%% marked as such.
+alloca_stack(Code, Params, Roots) ->
+ %% Find all assigned virtual registers
+ Destinations = collect_destinations(Code),
+ %% Declare virtual registers, and declare garbage collection roots
+ do_alloca_stack(Destinations++Params, Params, Roots).
+
+collect_destinations(Code) ->
+ lists:usort(lists:flatmap(fun insn_dst/1, Code)).
+
+do_alloca_stack(Destinations, Params, Roots) ->
+ do_alloca_stack(Destinations, Params, Roots, []).
+
+do_alloca_stack([], _, _, Acc) ->
+ Acc;
+do_alloca_stack([D|Ds], Params, Roots, Acc) ->
+ {Name, _I} = trans_dst(D),
+ WordTy = hipe_llvm:mk_int(?WORD_WIDTH),
+ WordTyPtr = hipe_llvm:mk_pointer(WordTy),
+ ByteTyPtr = hipe_llvm:mk_pointer(hipe_llvm:mk_int(8)),
+ case hipe_rtl:is_var(D) of
+ true ->
+ Num = hipe_rtl:var_index(D),
+ I1 = hipe_llvm:mk_alloca(Name, WordTy, [], []),
+ case lists:member(Num, Roots) of
+ true -> %% Variable is a possible Root
+ T1 = mk_temp(),
+ BYTE_TYPE_PP = hipe_llvm:mk_pointer(ByteTyPtr),
+ I2 =
+ hipe_llvm:mk_conversion(T1, bitcast, WordTyPtr, Name, BYTE_TYPE_PP),
+ GcRootArgs = [{BYTE_TYPE_PP, T1}, {ByteTyPtr, "@gc_metadata"}],
+ I3 = hipe_llvm:mk_call([], false, [], [], hipe_llvm:mk_void(),
+ "@llvm.gcroot", GcRootArgs, []),
+ I4 = case lists:member(D, Params) of
+ false ->
+ hipe_llvm:mk_store(WordTy, "-5", WordTyPtr, Name,
+ [], [], false);
+ true -> []
+ end,
+ do_alloca_stack(Ds, Params, Roots, [I1, I2, I3, I4 | Acc]);
+ false ->
+ do_alloca_stack(Ds, Params, Roots, [I1|Acc])
+ end;
+ false ->
+ case hipe_rtl:is_reg(D) andalso isPrecoloured(D) of
+ true -> %% Precoloured registers are mapped to "special" stack slots
+ do_alloca_stack(Ds, Params, Roots, Acc);
+ false ->
+ I1 = case hipe_rtl:is_fpreg(D) of
+ true ->
+ FloatTy = hipe_llvm:mk_double(),
+ hipe_llvm:mk_alloca(Name, FloatTy, [], []);
+ false -> hipe_llvm:mk_alloca(Name, WordTy, [], [])
+ end,
+ do_alloca_stack(Ds, Params, Roots, [I1|Acc])
+ end
+ end.
+
+%%------------------------------------------------------------------------------
+%% @doc Translation of the linearized RTL Code. Each RTL instruction is
+%% translated to a list of LLVM Assembly instructions. The relocation
+%% dictionary is updated when needed.
+%%------------------------------------------------------------------------------
+translate_instr_list([], Acc, Relocs, Data) ->
+ {lists:reverse(lists:flatten(Acc)), Relocs, Data};
+translate_instr_list([I | Is], Acc, Relocs, Data) ->
+ {Acc1, NewRelocs, NewData} = translate_instr(I, Relocs, Data),
+ translate_instr_list(Is, [Acc1 | Acc], NewRelocs, NewData).
+
+translate_instr(I, Relocs, Data) ->
+ case I of
+ #alu{} ->
+ {I2, Relocs2} = trans_alu(I, Relocs),
+ {I2, Relocs2, Data};
+ #alub{} ->
+ {I2, Relocs2} = trans_alub(I, Relocs),
+ {I2, Relocs2, Data};
+ #branch{} ->
+ {I2, Relocs2} = trans_branch(I, Relocs),
+ {I2, Relocs2, Data};
+ #call{} ->
+ {I2, Relocs2} =
+ case hipe_rtl:call_fun(I) of
+ %% In AMD64 this instruction does nothing!
+ %% TODO: chech use of fwait in other architectures!
+ fwait ->
+ {[], Relocs};
+ _ ->
+ trans_call(I, Relocs)
+ end,
+ {I2, Relocs2, Data};
+ #comment{} ->
+ {I2, Relocs2} = trans_comment(I, Relocs),
+ {I2, Relocs2, Data};
+ #enter{} ->
+ {I2, Relocs2} = trans_enter(I, Relocs),
+ {I2, Relocs2, Data};
+ #fconv{} ->
+ {I2, Relocs2} = trans_fconv(I, Relocs),
+ {I2, Relocs2, Data};
+ #fload{} ->
+ {I2, Relocs2} = trans_fload(I, Relocs),
+ {I2, Relocs2, Data};
+ #fmove{} ->
+ {I2, Relocs2} = trans_fmove(I, Relocs),
+ {I2, Relocs2, Data};
+ #fp{} ->
+ {I2, Relocs2} = trans_fp(I, Relocs),
+ {I2, Relocs2, Data};
+ #fp_unop{} ->
+ {I2, Relocs2} = trans_fp_unop(I, Relocs),
+ {I2, Relocs2, Data};
+ #fstore{} ->
+ {I2, Relocs2} = trans_fstore(I, Relocs),
+ {I2, Relocs2, Data};
+ #goto{} ->
+ {I2, Relocs2} = trans_goto(I, Relocs),
+ {I2, Relocs2, Data};
+ #label{} ->
+ {I2, Relocs2} = trans_label(I, Relocs),
+ {I2, Relocs2, Data};
+ #load{} ->
+ {I2, Relocs2} = trans_load(I, Relocs),
+ {I2, Relocs2, Data};
+ #load_address{} ->
+ {I2, Relocs2} = trans_load_address(I, Relocs),
+ {I2, Relocs2, Data};
+ #load_atom{} ->
+ {I2, Relocs2} = trans_load_atom(I, Relocs),
+ {I2, Relocs2, Data};
+ #move{} ->
+ {I2, Relocs2} = trans_move(I, Relocs),
+ {I2, Relocs2, Data};
+ #return{} ->
+ {I2, Relocs2} = trans_return(I, Relocs),
+ {I2, Relocs2, Data};
+ #store{} ->
+ {I2, Relocs2} = trans_store(I, Relocs),
+ {I2, Relocs2, Data};
+ #switch{} -> %% Only switch instruction updates Data
+ {I2, Relocs2, NewData} = trans_switch(I, Relocs, Data),
+ {I2, Relocs2, NewData};
+ Other ->
+ exit({?MODULE, translate_instr, {"Unknown RTL instruction", Other}})
+ end.
+
+%%
+%% alu
+%%
+trans_alu(I, Relocs) ->
+ RtlDst = hipe_rtl:alu_dst(I),
+ TmpDst = mk_temp(),
+ {Src1, I1} = trans_src(hipe_rtl:alu_src1(I)),
+ {Src2, I2} = trans_src(hipe_rtl:alu_src2(I)),
+ Op = trans_op(hipe_rtl:alu_op(I)),
+ WordTy = hipe_llvm:mk_int(?WORD_WIDTH),
+ I3 = hipe_llvm:mk_operation(TmpDst, Op, WordTy, Src1, Src2, []),
+ I4 = store_stack_dst(TmpDst, RtlDst),
+ {[I4, I3, I2, I1], Relocs}.
+
+%%
+%% alub
+%%
+trans_alub(I, Relocs) ->
+ case hipe_rtl:alub_cond(I) of
+ Op when Op =:= overflow orelse Op =:= not_overflow ->
+ trans_alub_overflow(I, signed, Relocs);
+ ltu -> %% ltu means unsigned overflow
+ trans_alub_overflow(I, unsigned, Relocs);
+ _ ->
+ trans_alub_no_overflow(I, Relocs)
+ end.
+
+trans_alub_overflow(I, Sign, Relocs) ->
+ {Src1, I1} = trans_src(hipe_rtl:alub_src1(I)),
+ {Src2, I2} = trans_src(hipe_rtl:alub_src2(I)),
+ RtlDst = hipe_rtl:alub_dst(I),
+ TmpDst = mk_temp(),
+ Name = trans_alub_op(I, Sign),
+ NewRelocs = relocs_store(Name, {call, {llvm, Name, 2}}, Relocs),
+ WordTy = hipe_llvm:mk_int(?WORD_WIDTH),
+ ReturnType = hipe_llvm:mk_struct([WordTy, hipe_llvm:mk_int(1)]),
+ T1 = mk_temp(),
+ I3 = hipe_llvm:mk_call(T1, false, [], [], ReturnType, "@" ++ Name,
+ [{WordTy, Src1}, {WordTy, Src2}], []),
+ %% T1{0}: result of the operation
+ I4 = hipe_llvm:mk_extractvalue(TmpDst, ReturnType, T1 , "0", []),
+ I5 = store_stack_dst(TmpDst, RtlDst),
+ T2 = mk_temp(),
+ %% T1{1}: Boolean variable indicating overflow
+ I6 = hipe_llvm:mk_extractvalue(T2, ReturnType, T1, "1", []),
+ case hipe_rtl:alub_cond(I) of
+ Op when Op =:= overflow orelse Op =:= ltu ->
+ True_label = mk_jump_label(hipe_rtl:alub_true_label(I)),
+ False_label = mk_jump_label(hipe_rtl:alub_false_label(I)),
+ MetaData = branch_metadata(hipe_rtl:alub_pred(I));
+ not_overflow ->
+ True_label = mk_jump_label(hipe_rtl:alub_false_label(I)),
+ False_label = mk_jump_label(hipe_rtl:alub_true_label(I)),
+ MetaData = branch_metadata(1 - hipe_rtl:alub_pred(I))
+ end,
+ I7 = hipe_llvm:mk_br_cond(T2, True_label, False_label, MetaData),
+ {[I7, I6, I5, I4, I3, I2, I1], NewRelocs}.
+
+trans_alub_op(I, Sign) ->
+ Name =
+ case Sign of
+ signed ->
+ case hipe_rtl:alub_op(I) of
+ add -> "llvm.sadd.with.overflow.";
+ mul -> "llvm.smul.with.overflow.";
+ sub -> "llvm.ssub.with.overflow.";
+ Op -> exit({?MODULE, trans_alub_op, {"Unknown alub operator", Op}})
+ end;
+ unsigned ->
+ case hipe_rtl:alub_op(I) of
+ add -> "llvm.uadd.with.overflow.";
+ mul -> "llvm.umul.with.overflow.";
+ sub -> "llvm.usub.with.overflow.";
+ Op -> exit({?MODULE, trans_alub_op, {"Unknown alub operator", Op}})
+ end
+ end,
+ Type =
+ case hipe_rtl_arch:word_size() of
+ 4 -> "i32";
+ 8 -> "i64"
+ %% Other -> exit({?MODULE, trans_alub_op, {"Unknown type", Other}})
+ end,
+ Name ++ Type.
+
+trans_alub_no_overflow(I, Relocs) ->
+ %% alu
+ T = hipe_rtl:mk_alu(hipe_rtl:alub_dst(I), hipe_rtl:alub_src1(I),
+ hipe_rtl:alub_op(I), hipe_rtl:alub_src2(I)),
+ %% A trans_alu instruction cannot change relocations
+ {I1, _} = trans_alu(T, Relocs),
+ %% icmp
+ %% Translate destination as src, to match with the semantics of instruction
+ {Dst, I2} = trans_src(hipe_rtl:alub_dst(I)),
+ Cond = trans_rel_op(hipe_rtl:alub_cond(I)),
+ T3 = mk_temp(),
+ WordTy = hipe_llvm:mk_int(?WORD_WIDTH),
+ I5 = hipe_llvm:mk_icmp(T3, Cond, WordTy, Dst, "0"),
+ %% br
+ Metadata = branch_metadata(hipe_rtl:alub_pred(I)),
+ True_label = mk_jump_label(hipe_rtl:alub_true_label(I)),
+ False_label = mk_jump_label(hipe_rtl:alub_false_label(I)),
+ I6 = hipe_llvm:mk_br_cond(T3, True_label, False_label, Metadata),
+ {[I6, I5, I2, I1], Relocs}.
+
+%%
+%% branch
+%%
+trans_branch(I, Relocs) ->
+ {Src1, I1} = trans_src(hipe_rtl:branch_src1(I)),
+ {Src2, I2} = trans_src(hipe_rtl:branch_src2(I)),
+ Cond = trans_rel_op(hipe_rtl:branch_cond(I)),
+ %% icmp
+ T1 = mk_temp(),
+ WordTy = hipe_llvm:mk_int(?WORD_WIDTH),
+ I3 = hipe_llvm:mk_icmp(T1, Cond, WordTy, Src1, Src2),
+ %% br
+ True_label = mk_jump_label(hipe_rtl:branch_true_label(I)),
+ False_label = mk_jump_label(hipe_rtl:branch_false_label(I)),
+ Metadata = branch_metadata(hipe_rtl:branch_pred(I)),
+ I4 = hipe_llvm:mk_br_cond(T1, True_label, False_label, Metadata),
+ {[I4, I3, I2, I1], Relocs}.
+
+branch_metadata(X) when X =:= 0.5 -> [];
+branch_metadata(X) when X > 0.5 -> ?BRANCH_META_TAKEN;
+branch_metadata(X) when X < 0.5 -> ?BRANCH_META_NOT_TAKEN.
+
+%%
+%% call
+%%
+trans_call(I, Relocs) ->
+ RtlCallArgList= hipe_rtl:call_arglist(I),
+ RtlCallName = hipe_rtl:call_fun(I),
+ {I0, Relocs1} = expose_closure(RtlCallName, RtlCallArgList, Relocs),
+ TmpDst = mk_temp(),
+ {CallArgs, I1} = trans_call_args(RtlCallArgList),
+ FixedRegs = fixed_registers(),
+ {LoadedFixedRegs, I2} = load_fixed_regs(FixedRegs),
+ FinalArgs = fix_reg_args(LoadedFixedRegs) ++ CallArgs,
+ {Name, I3, Relocs2} =
+ trans_call_name(RtlCallName, Relocs1, CallArgs, FinalArgs),
+ T1 = mk_temp(),
+ WordTy = hipe_llvm:mk_int(?WORD_WIDTH),
+ FunRetTy = hipe_llvm:mk_struct(lists:duplicate(?NR_PINNED_REGS + 1, WordTy)),
+ I4 =
+ case hipe_rtl:call_fail(I) of
+ %% Normal Call
+ [] ->
+ hipe_llvm:mk_call(T1, false, "cc 11", [], FunRetTy, Name, FinalArgs,
+ []);
+ %% Call With Exception
+ FailLabelNum ->
+ TrueLabel = "L" ++ integer_to_list(hipe_rtl:call_normal(I)),
+ FailLabel = "%FL" ++ integer_to_list(FailLabelNum),
+ II1 =
+ hipe_llvm:mk_invoke(T1, "cc 11", [], FunRetTy, Name, FinalArgs, [],
+ "%" ++ TrueLabel, FailLabel),
+ II2 = hipe_llvm:mk_label(TrueLabel),
+ [II2, II1]
+ end,
+ I5 = store_fixed_regs(FixedRegs, T1),
+ I6 =
+ case hipe_rtl:call_dstlist(I) of
+ [] -> []; %% No return value
+ [Destination] ->
+ II3 =
+ hipe_llvm:mk_extractvalue(TmpDst, FunRetTy, T1,
+ integer_to_list(?NR_PINNED_REGS), []),
+ II4 = store_stack_dst(TmpDst, Destination),
+ [II4, II3]
+ end,
+ I7 =
+ case hipe_rtl:call_continuation(I) of
+ [] -> []; %% No continuation
+ CC ->
+ {II5, _} = trans_goto(hipe_rtl:mk_goto(CC), Relocs2),
+ II5
+ end,
+ {[I7, I6, I5, I4, I3, I2, I1, I0], Relocs2}.
+
+%% In case of call to a register (closure call) with more than ?NR_ARG_REGS
+%% arguments we must track the offset this call in the code, in order to
+%% to correct the stack descriptor. So, we insert a new Label and add this label
+%% to the "table_closures"
+%% --------------------------------|--------------------------------------------
+%% Old Code | New Code
+%% --------------------------------|--------------------------------------------
+%% | br %ClosureLabel
+%% call %reg(Args) | ClosureLabel:
+%% | call %reg(Args)
+expose_closure(CallName, CallArgs, Relocs) ->
+ CallArgsNr = length(CallArgs),
+ case hipe_rtl:is_reg(CallName) andalso CallArgsNr > ?NR_ARG_REGS of
+ true ->
+ LabelNum = hipe_gensym:new_label(llvm),
+ ClosureLabel = hipe_llvm:mk_label(mk_label(LabelNum)),
+ JumpIns = hipe_llvm:mk_br(mk_jump_label(LabelNum)),
+ Relocs1 =
+ relocs_store({CallName, LabelNum},
+ {closure_label, LabelNum, CallArgsNr - ?NR_ARG_REGS},
+ Relocs),
+ {[ClosureLabel, JumpIns], Relocs1};
+ false ->
+ {[], Relocs}
+ end.
+
+trans_call_name(RtlCallName, Relocs, CallArgs, FinalArgs) ->
+ case RtlCallName of
+ PrimOp when is_atom(PrimOp) ->
+ LlvmName = trans_prim_op(PrimOp),
+ Relocs1 = relocs_store(LlvmName, {call, {bif, PrimOp, length(CallArgs)}},
+ Relocs),
+ {"@" ++ LlvmName, [], Relocs1};
+ {M, F, A} when is_atom(M), is_atom(F), is_integer(A) ->
+ LlvmName = trans_mfa_name({M,F,A}),
+ Relocs1 = relocs_store(LlvmName, {call, {M,F,A}}, Relocs),
+ {"@" ++ LlvmName, [], Relocs1};
+ Reg ->
+ case hipe_rtl:is_reg(Reg) of
+ true ->
+ %% In case of a closure call, the register holding the address
+ %% of the closure must be converted to function type in
+ %% order to make the call
+ TT1 = mk_temp(),
+ {RegName, II1} = trans_src(Reg),
+ WordTy = hipe_llvm:mk_int(?WORD_WIDTH),
+ WordTyPtr = hipe_llvm:mk_pointer(WordTy),
+ II2 =
+ hipe_llvm:mk_conversion(TT1, inttoptr, WordTy, RegName, WordTyPtr),
+ TT2 = mk_temp(),
+ ArgsTypeList = lists:duplicate(length(FinalArgs), WordTy),
+ FunRetTy =
+ hipe_llvm:mk_struct(lists:duplicate(?NR_PINNED_REGS + 1, WordTy)),
+ FunType = hipe_llvm:mk_fun(FunRetTy, ArgsTypeList),
+ FunTypeP = hipe_llvm:mk_pointer(FunType),
+ II3 = hipe_llvm:mk_conversion(TT2, bitcast, WordTyPtr, TT1, FunTypeP),
+ {TT2, [II3, II2, II1], Relocs};
+ false ->
+ exit({?MODULE, trans_call, {"Unimplemented call to", RtlCallName}})
+ end
+ end.
+
+%%
+trans_call_args(ArgList) ->
+ {Args, I} = lists:unzip(trans_args(ArgList)),
+ %% Reverse arguments that are passed to stack to match with the Erlang
+ %% calling convention. (Propably not needed in prim calls.)
+ ReversedArgs =
+ case erlang:length(Args) > ?NR_ARG_REGS of
+ false ->
+ Args;
+ true ->
+ {ArgsInRegs, ArgsInStack} = lists:split(?NR_ARG_REGS, Args),
+ ArgsInRegs ++ lists:reverse(ArgsInStack)
+ end,
+ %% Reverse I, because some of the arguments may go out of scope and
+ %% should be killed(store -5). When two or more arguments are they
+ %% same, then order matters!
+ {ReversedArgs, lists:reverse(I)}.
+
+%%
+%% trans_comment
+%%
+trans_comment(I, Relocs) ->
+ I1 = hipe_llvm:mk_comment(hipe_rtl:comment_text(I)),
+ {I1, Relocs}.
+
+%%
+%% enter
+%%
+trans_enter(I, Relocs) ->
+ {CallArgs, I0} = trans_call_args(hipe_rtl:enter_arglist(I)),
+ FixedRegs = fixed_registers(),
+ {LoadedFixedRegs, I1} = load_fixed_regs(FixedRegs),
+ FinalArgs = fix_reg_args(LoadedFixedRegs) ++ CallArgs,
+ {Name, I2, NewRelocs} =
+ trans_call_name(hipe_rtl:enter_fun(I), Relocs, CallArgs, FinalArgs),
+ T1 = mk_temp(),
+ WordTy = hipe_llvm:mk_int(?WORD_WIDTH),
+ FunRetTy = hipe_llvm:mk_struct(lists:duplicate(?NR_PINNED_REGS + 1, WordTy)),
+ I3 = hipe_llvm:mk_call(T1, true, "cc 11", [], FunRetTy, Name, FinalArgs, []),
+ I4 = hipe_llvm:mk_ret([{FunRetTy, T1}]),
+ {[I4, I3, I2, I1, I0], NewRelocs}.
+
+%%
+%% fconv
+%%
+trans_fconv(I, Relocs) ->
+ %% XXX: Can a fconv destination be a precoloured reg?
+ RtlDst = hipe_rtl:fconv_dst(I),
+ TmpDst = mk_temp(),
+ {Src, I1} = trans_float_src(hipe_rtl:fconv_src(I)),
+ FloatTy = hipe_llvm:mk_double(),
+ WordTy = hipe_llvm:mk_int(?WORD_WIDTH),
+ I2 = hipe_llvm:mk_conversion(TmpDst, sitofp, WordTy, Src, FloatTy),
+ I3 = store_float_stack(TmpDst, RtlDst),
+ {[I3, I2, I1], Relocs}.
+
+
+%% TODO: fload, fstore, fmove, and fp are almost the same with load, store, move
+%% and alu. Maybe we should join them.
+
+%%
+%% fload
+%%
+trans_fload(I, Relocs) ->
+ RtlDst = hipe_rtl:fload_dst(I),
+ RtlSrc = hipe_rtl:fload_src(I),
+ _Offset = hipe_rtl:fload_offset(I),
+ TmpDst = mk_temp(),
+ {Src, I1} = trans_float_src(RtlSrc),
+ {Offset, I2} = trans_float_src(_Offset),
+ T1 = mk_temp(),
+ WordTy = hipe_llvm:mk_int(?WORD_WIDTH),
+ FloatTyPtr = hipe_llvm:mk_pointer(hipe_llvm:mk_double()),
+ I3 = hipe_llvm:mk_operation(T1, add, WordTy, Src, Offset, []),
+ T2 = mk_temp(),
+ I4 = hipe_llvm:mk_conversion(T2, inttoptr, WordTy, T1, FloatTyPtr),
+ I5 = hipe_llvm:mk_load(TmpDst, FloatTyPtr, T2, [], [], false),
+ I6 = store_float_stack(TmpDst, RtlDst),
+ {[I6, I5, I4, I3, I2, I1], Relocs}.
+
+%%
+%% fmove
+%%
+trans_fmove(I, Relocs) ->
+ RtlDst = hipe_rtl:fmove_dst(I),
+ RtlSrc = hipe_rtl:fmove_src(I),
+ {Src, I1} = trans_float_src(RtlSrc),
+ I2 = store_float_stack(Src, RtlDst),
+ {[I2, I1], Relocs}.
+
+%%
+%% fp
+%%
+trans_fp(I, Relocs) ->
+ %% XXX: Just copied trans_alu...think again..
+ RtlDst = hipe_rtl:fp_dst(I),
+ RtlSrc1 = hipe_rtl:fp_src1(I),
+ RtlSrc2 = hipe_rtl:fp_src2(I),
+ %% Destination cannot be a precoloured register
+ FloatTy = hipe_llvm:mk_double(),
+ FloatTyPtr = hipe_llvm:mk_pointer(FloatTy),
+ TmpDst = mk_temp(),
+ {Src1, I1} = trans_float_src(RtlSrc1),
+ {Src2, I2} = trans_float_src(RtlSrc2),
+ Op = trans_fp_op(hipe_rtl:fp_op(I)),
+ I3 = hipe_llvm:mk_operation(TmpDst, Op, FloatTy, Src1, Src2, []),
+ I4 = store_float_stack(TmpDst, RtlDst),
+ %% Synchronization for floating point exceptions
+ I5 = hipe_llvm:mk_store(FloatTy, TmpDst, FloatTyPtr, "%exception_sync", [],
+ [], true),
+ T1 = mk_temp(),
+ I6 = hipe_llvm:mk_load(T1, FloatTyPtr, "%exception_sync", [], [], true),
+ {[I6, I5, I4, I3, I2, I1], Relocs}.
+
+%%
+%% fp_unop
+%%
+trans_fp_unop(I, Relocs) ->
+ RtlDst = hipe_rtl:fp_unop_dst(I),
+ RtlSrc = hipe_rtl:fp_unop_src(I),
+ %% Destination cannot be a precoloured register
+ TmpDst = mk_temp(),
+ {Src, I1} = trans_float_src(RtlSrc),
+ Op = trans_fp_op(hipe_rtl:fp_unop_op(I)),
+ FloatTy = hipe_llvm:mk_double(),
+ I2 = hipe_llvm:mk_operation(TmpDst, Op, FloatTy, "0.0", Src, []),
+ I3 = store_float_stack(TmpDst, RtlDst),
+ {[I3, I2, I1], Relocs}.
+%% TODO: Fix fp_unop in a way like the following. You must change trans_dest,
+%% in order to call float_to_list in a case of float constant. Maybe the type
+%% check is expensive...
+%% Dst = hipe_rtl:fp_unop_dst(I),
+%% Src = hipe_rtl:fp_unop_src(I),
+%% Op = hipe_rtl:fp_unop_op(I),
+%% Zero = hipe_rtl:mk_imm(0.0),
+%% I1 = hipe_rtl:mk_fp(Dst, Zero, Op, Src),
+%% trans_fp(I, Relocs1).
+
+%%
+%% fstore
+%%
+trans_fstore(I, Relocs) ->
+ Base = hipe_rtl:fstore_base(I),
+ case isPrecoloured(Base) of
+ true ->
+ trans_fstore_reg(I, Relocs);
+ false ->
+ exit({?MODULE, trans_fstore ,{"Not implemented yet", false}})
+ end.
+
+trans_fstore_reg(I, Relocs) ->
+ {Base, I0} = trans_reg(hipe_rtl:fstore_base(I), dst),
+ WordTy = hipe_llvm:mk_int(?WORD_WIDTH),
+ WordTyPtr = hipe_llvm:mk_pointer(WordTy),
+ FloatTy = hipe_llvm:mk_double(),
+ FloatTyPtr = hipe_llvm:mk_pointer(FloatTy),
+ T1 = mk_temp(),
+ I1 = hipe_llvm:mk_load(T1, WordTyPtr, Base, [], [], false),
+ {Offset, I2} = trans_src(hipe_rtl:fstore_offset(I)),
+ T2 = mk_temp(),
+ I3 = hipe_llvm:mk_operation(T2, add, WordTy, T1, Offset, []),
+ T3 = mk_temp(),
+ I4 = hipe_llvm:mk_conversion(T3, inttoptr, WordTy, T2, FloatTyPtr),
+ {Value, I5} = trans_src(hipe_rtl:fstore_src(I)),
+ I6 = hipe_llvm:mk_store(FloatTy, Value, FloatTyPtr, T3, [], [], false),
+ {[I6, I5, I4, I3, I2, I1, I0], Relocs}.
+
+%%
+%% goto
+%%
+trans_goto(I, Relocs) ->
+ I1 = hipe_llvm:mk_br(mk_jump_label(hipe_rtl:goto_label(I))),
+ {I1, Relocs}.
+
+%%
+%% label
+%%
+trans_label(I, Relocs) ->
+ Label = mk_label(hipe_rtl:label_name(I)),
+ I1 = hipe_llvm:mk_label(Label),
+ {I1, Relocs}.
+
+%%
+%% load
+%%
+trans_load(I, Relocs) ->
+ RtlDst = hipe_rtl:load_dst(I),
+ TmpDst = mk_temp(),
+ %% XXX: Why translate them independently? ------------------------
+ {Src, I1} = trans_src(hipe_rtl:load_src(I)),
+ {Offset, I2} = trans_src(hipe_rtl:load_offset(I)),
+ T1 = mk_temp(),
+ WordTy = hipe_llvm:mk_int(?WORD_WIDTH),
+ WordTyPtr = hipe_llvm:mk_pointer(WordTy),
+ I3 = hipe_llvm:mk_operation(T1, add, WordTy, Src, Offset, []),
+ %%----------------------------------------------------------------
+ I4 = case hipe_rtl:load_size(I) of
+ word ->
+ T2 = mk_temp(),
+ II1 = hipe_llvm:mk_conversion(T2, inttoptr, WordTy, T1, WordTyPtr),
+ II2 = hipe_llvm:mk_load(TmpDst, WordTyPtr, T2, [], [], false),
+ [II2, II1];
+ Size ->
+ LoadType = llvm_type_from_size(Size),
+ LoadTypeP = hipe_llvm:mk_pointer(LoadType),
+ T2 = mk_temp(),
+ II1 = hipe_llvm:mk_conversion(T2, inttoptr, WordTy, T1, LoadTypeP),
+ T3 = mk_temp(),
+ LoadTypePointer = hipe_llvm:mk_pointer(LoadType),
+ II2 = hipe_llvm:mk_load(T3, LoadTypePointer, T2, [], [], false),
+ Conversion =
+ case hipe_rtl:load_sign(I) of
+ signed -> sext;
+ unsigned -> zext
+ end,
+ II3 =
+ hipe_llvm:mk_conversion(TmpDst, Conversion, LoadType, T3, WordTy),
+ [II3, II2, II1]
+ end,
+ I5 = store_stack_dst(TmpDst, RtlDst),
+ {[I5, I4, I3, I2, I1], Relocs}.
+
+%%
+%% load_address
+%%
+trans_load_address(I, Relocs) ->
+ RtlDst = hipe_rtl:load_address_dst(I),
+ RtlAddr = hipe_rtl:load_address_addr(I),
+ {Addr, NewRelocs} =
+ case hipe_rtl:load_address_type(I) of
+ constant ->
+ {"%DL" ++ integer_to_list(RtlAddr) ++ "_var", Relocs};
+ closure ->
+ {{_, ClosureName, _}, _, _} = RtlAddr,
+ FixedClosureName = fix_closure_name(ClosureName),
+ Relocs1 = relocs_store(FixedClosureName, {closure, RtlAddr}, Relocs),
+ {"%" ++ FixedClosureName ++ "_var", Relocs1};
+ type ->
+ exit({?MODULE, trans_load_address,
+ {"Type not implemented in load_address", RtlAddr}})
+ end,
+ I1 = store_stack_dst(Addr, RtlDst),
+ {[I1], NewRelocs}.
+
+%%
+%% load_atom
+%%
+trans_load_atom(I, Relocs) ->
+ RtlDst = hipe_rtl:load_atom_dst(I),
+ RtlAtom = hipe_rtl:load_atom_atom(I),
+ AtomName = "atom_" ++ make_llvm_id(atom_to_list(RtlAtom)),
+ AtomVar = "%" ++ AtomName ++ "_var",
+ NewRelocs = relocs_store(AtomName, {atom, RtlAtom}, Relocs),
+ I1 = store_stack_dst(AtomVar, RtlDst),
+ {[I1], NewRelocs}.
+
+%%
+%% move
+%%
+trans_move(I, Relocs) ->
+ RtlDst = hipe_rtl:move_dst(I),
+ RtlSrc = hipe_rtl:move_src(I),
+ {Src, I1} = trans_src(RtlSrc),
+ I2 = store_stack_dst(Src, RtlDst),
+ {[I2, I1], Relocs}.
+
+%%
+%% return
+%%
+trans_return(I, Relocs) ->
+ WordTy = hipe_llvm:mk_int(?WORD_WIDTH),
+ {VarRet, I1} =
+ case hipe_rtl:return_varlist(I) of
+ [] ->
+ {[], []};
+ [A] ->
+ {Name, II1} = trans_src(A),
+ {[{WordTy, Name}], II1}
+ end,
+ FixedRegs = fixed_registers(),
+ {LoadedFixedRegs, I2} = load_fixed_regs(FixedRegs),
+ FixedRet = [{WordTy, X} || X <- LoadedFixedRegs],
+ Ret = FixedRet ++ VarRet,
+ {RetTypes, _RetNames} = lists:unzip(Ret),
+ Type = hipe_llvm:mk_struct(RetTypes),
+ {RetStruct, I3} = mk_return_struct(Ret, Type),
+ I4 = hipe_llvm:mk_ret([{Type, RetStruct}]),
+ {[I4, I3, I2, I1], Relocs}.
+
+%% @doc Create a structure to hold the return value and the precoloured
+%% registers.
+mk_return_struct(RetValues, Type) ->
+ mk_return_struct(RetValues, Type, [], "undef", 0).
+
+mk_return_struct([], _, Acc, StructName, _) ->
+ {StructName, Acc};
+mk_return_struct([{ElemType, ElemName}|Rest], Type, Acc, StructName, Index) ->
+ T1 = mk_temp(),
+ I1 = hipe_llvm:mk_insertvalue(T1, Type, StructName, ElemType, ElemName,
+ integer_to_list(Index), []),
+ mk_return_struct(Rest, Type, [I1 | Acc], T1, Index+1).
+
+%%
+%% store
+%%
+trans_store(I, Relocs) ->
+ {Base, I1} = trans_src(hipe_rtl:store_base(I)),
+ {Offset, I2} = trans_src(hipe_rtl:store_offset(I)),
+ {Value, I3} = trans_src(hipe_rtl:store_src(I)),
+ T1 = mk_temp(),
+ WordTy = hipe_llvm:mk_int(?WORD_WIDTH),
+ WordTyPtr = hipe_llvm:mk_pointer(WordTy),
+ I4 = hipe_llvm:mk_operation(T1, add, WordTy, Base, Offset, []),
+ I5 =
+ case hipe_rtl:store_size(I) of
+ word ->
+ T2 = mk_temp(),
+ II1 = hipe_llvm:mk_conversion(T2, inttoptr, WordTy, T1, WordTyPtr),
+ II2 = hipe_llvm:mk_store(WordTy, Value, WordTyPtr, T2, [], [],
+ false),
+ [II2, II1];
+ Size ->
+ %% XXX: Is always trunc correct ?
+ LoadType = llvm_type_from_size(Size),
+ LoadTypePointer = hipe_llvm:mk_pointer(LoadType),
+ T2 = mk_temp(),
+ II1 = hipe_llvm:mk_conversion(T2, inttoptr, WordTy, T1, LoadTypePointer),
+ T3 = mk_temp(),
+ II2 = hipe_llvm:mk_conversion(T3, 'trunc', WordTy, Value, LoadType),
+ II3 = hipe_llvm:mk_store(LoadType, T3, LoadTypePointer, T2, [], [], false),
+ [II3, II2, II1]
+ end,
+ {[I5, I4, I3, I2, I1], Relocs}.
+
+%%
+%% switch
+%%
+trans_switch(I, Relocs, Data) ->
+ RtlSrc = hipe_rtl:switch_src(I),
+ {Src, I1} = trans_src(RtlSrc),
+ Labels = hipe_rtl:switch_labels(I),
+ JumpLabels = [mk_jump_label(L) || L <- Labels],
+ SortOrder = hipe_rtl:switch_sort_order(I),
+ NrLabels = length(Labels),
+ ByteTyPtr = hipe_llvm:mk_pointer(hipe_llvm:mk_int(8)),
+ TableType = hipe_llvm:mk_array(NrLabels, ByteTyPtr),
+ TableTypeP = hipe_llvm:mk_pointer(TableType),
+ TypedJumpLabels = [{hipe_llvm:mk_label_type(), X} || X <- JumpLabels],
+ T1 = mk_temp(),
+ {Src2, []} = trans_dst(RtlSrc),
+ TableName = "table_" ++ tl(Src2),
+ WordTy = hipe_llvm:mk_int(?WORD_WIDTH),
+ I2 = hipe_llvm:mk_getelementptr(T1, TableTypeP, "@"++TableName,
+ [{WordTy, "0"}, {WordTy, Src}], false),
+ T2 = mk_temp(),
+ BYTE_TYPE_PP = hipe_llvm:mk_pointer(ByteTyPtr),
+ I3 = hipe_llvm:mk_load(T2, BYTE_TYPE_PP, T1, [], [], false),
+ I4 = hipe_llvm:mk_indirectbr(ByteTyPtr, T2, TypedJumpLabels),
+ LMap = [{label, L} || L <- Labels],
+ %% Update data with the info for the jump table
+ {NewData, JTabLab} =
+ case hipe_rtl:switch_sort_order(I) of
+ [] ->
+ hipe_consttab:insert_block(Data, word, LMap);
+ SortOrder ->
+ hipe_consttab:insert_sorted_block(Data, word, LMap, SortOrder)
+ end,
+ Relocs2 = relocs_store(TableName, {switch, {TableType, Labels, NrLabels,
+ SortOrder}, JTabLab}, Relocs),
+ {[I4, I3, I2, I1], Relocs2, NewData}.
+
+%% @doc Pass on RTL code in order to fix invoke and closure calls.
+fix_code(Code) ->
+ fix_calls(Code).
+
+%% @doc Fix invoke calls and closure calls with more than ?NR_ARG_REGS
+%% arguments.
+fix_calls(Code) ->
+ fix_calls(Code, [], []).
+
+fix_calls([], Acc, FailLabels) ->
+ {lists:reverse(Acc), FailLabels};
+fix_calls([I | Is], Acc, FailLabels) ->
+ case hipe_rtl:is_call(I) of
+ true ->
+ {NewCall, NewFailLabels} =
+ case hipe_rtl:call_fail(I) of
+ [] ->
+ {I, FailLabels};
+ FailLabel ->
+ fix_invoke_call(I, FailLabel, FailLabels)
+ end,
+ fix_calls(Is, [NewCall|Acc], NewFailLabels);
+ false ->
+ fix_calls(Is, [I|Acc], FailLabels)
+ end.
+
+%% @doc When a call has a fail continuation label it must be extended with a
+%% normal continuation label to go with the LLVM's invoke instruction.
+%% FailLabels is the list of labels of all fail blocks, which are needed to
+%% be declared as landing pads. Furtermore, we must add to fail labels a
+%% call to hipe_bifs:llvm_fix_pinned_regs/0 in order to avoid reloading old
+%% values of pinned registers. This may happen because the result of an
+%% invoke instruction is not available at fail-labels, and, thus, we cannot
+%% get the correct values of pinned registers. Finally, the stack needs to
+%% be re-adjusted when there are stack arguments.
+fix_invoke_call(I, FailLabel, FailLabels) ->
+ NewLabel = hipe_gensym:new_label(llvm),
+ NewCall1 = hipe_rtl:call_normal_update(I, NewLabel),
+ SpAdj = find_sp_adj(hipe_rtl:call_arglist(I)),
+ case lists:keyfind(FailLabel, 1, FailLabels) of
+ %% Same fail label with same Stack Pointer adjustment
+ {FailLabel, NewFailLabel, SpAdj} ->
+ NewCall2 = hipe_rtl:call_fail_update(NewCall1, NewFailLabel),
+ {NewCall2, FailLabels};
+ %% Same fail label but with different Stack Pointer adjustment
+ {_, _, _} ->
+ NewFailLabel = hipe_gensym:new_label(llvm),
+ NewCall2 = hipe_rtl:call_fail_update(NewCall1, NewFailLabel),
+ {NewCall2, [{FailLabel, NewFailLabel, SpAdj} | FailLabels]};
+ %% New Fail label
+ false ->
+ NewFailLabel = hipe_gensym:new_label(llvm),
+ NewCall2 = hipe_rtl:call_fail_update(NewCall1, NewFailLabel),
+ {NewCall2, [{FailLabel, NewFailLabel, SpAdj} | FailLabels]}
+ end.
+
+find_sp_adj(ArgList) ->
+ NrArgs = length(ArgList),
+ case NrArgs > ?NR_ARG_REGS of
+ true ->
+ (NrArgs - ?NR_ARG_REGS) * hipe_rtl_arch:word_size();
+ false ->
+ 0
+ end.
+
+%% @doc Add landingpad instruction in Fail Blocks.
+add_landingpads(LLVM_Code, FailLabels) ->
+ FailLabels2 = [convert_label(T) || T <- FailLabels],
+ add_landingpads(LLVM_Code, FailLabels2, []).
+
+add_landingpads([], _, Acc) ->
+ lists:reverse(Acc);
+add_landingpads([I | Is], FailLabels, Acc) ->
+ case hipe_llvm:is_label(I) of
+ true ->
+ Label = hipe_llvm:label_label(I),
+ Ins = create_fail_blocks(Label, FailLabels),
+ add_landingpads(Is, FailLabels, [I | Ins] ++ Acc);
+ false ->
+ add_landingpads(Is, FailLabels, [I | Acc])
+ end.
+
+convert_label({X,Y,Z}) ->
+ {"L" ++ integer_to_list(X), "FL" ++ integer_to_list(Y), Z}.
+
+%% @doc Create a fail block wich.
+create_fail_blocks(_, []) -> [];
+create_fail_blocks(Label, FailLabels) ->
+ create_fail_blocks(Label, FailLabels, []).
+
+create_fail_blocks(Label, FailLabels, Acc) ->
+ case lists:keytake(Label, 1, FailLabels) of
+ false ->
+ Acc;
+ {value, {Label, FailLabel, SpAdj}, RestFailLabels} ->
+ WordTy = hipe_llvm:mk_int(?WORD_WIDTH),
+ I1 = hipe_llvm:mk_label(FailLabel),
+ LP = hipe_llvm:mk_landingpad(),
+ I2 =
+ case SpAdj > 0 of
+ true ->
+ StackPointer = ?ARCH_REGISTERS:reg_name(?ARCH_REGISTERS:sp()),
+ hipe_llvm:mk_adj_stack(integer_to_list(SpAdj), StackPointer,
+ WordTy);
+ false -> []
+ end,
+ T1 = mk_temp(),
+ FixedRegs = fixed_registers(),
+ FunRetTy =
+ hipe_llvm:mk_struct(lists:duplicate(?NR_PINNED_REGS + 1, WordTy)),
+ I3 = hipe_llvm:mk_call(T1, false, "cc 11", [], FunRetTy,
+ "@hipe_bifs.llvm_fix_pinned_regs.0", [], []),
+ I4 = store_fixed_regs(FixedRegs, T1),
+ I5 = hipe_llvm:mk_br("%" ++ Label),
+ Ins = lists:flatten([I5, I4, I3, I2, LP,I1]),
+ create_fail_blocks(Label, RestFailLabels, Ins ++ Acc)
+ end.
+
+%%------------------------------------------------------------------------------
+%% Miscellaneous Functions
+%%------------------------------------------------------------------------------
+
+%% @doc Convert RTL argument list to LLVM argument list.
+trans_args(ArgList) ->
+ WordTy = hipe_llvm:mk_int(?WORD_WIDTH),
+ MakeArg =
+ fun(A) ->
+ {Name, I1} = trans_src(A),
+ {{WordTy, Name}, I1}
+ end,
+ [MakeArg(A) || A <- ArgList].
+
+%% @doc Convert a list of Precoloured registers to LLVM argument list.
+fix_reg_args(ArgList) ->
+ WordTy = hipe_llvm:mk_int(?WORD_WIDTH),
+ [{WordTy, A} || A <- ArgList].
+
+%% @doc Load Precoloured registers.
+load_fixed_regs(RegList) ->
+ Names = [mk_temp_reg(R) || R <- RegList],
+ WordTy = hipe_llvm:mk_int(?WORD_WIDTH),
+ WordTyPtr = hipe_llvm:mk_pointer(WordTy),
+ Fun1 =
+ fun (X, Y) ->
+ hipe_llvm:mk_load(X, WordTyPtr, "%" ++ Y ++ "_reg_var", [], [], false)
+ end,
+ Ins = lists:zipwith(Fun1, Names, RegList),
+ {Names, Ins}.
+
+%% @doc Store Precoloured registers.
+store_fixed_regs(RegList, Name) ->
+ Names = [mk_temp_reg(R) || R <- RegList],
+ Indexes = lists:seq(0, erlang:length(RegList) - 1),
+ WordTy = hipe_llvm:mk_int(?WORD_WIDTH),
+ WordTyPtr = hipe_llvm:mk_pointer(WordTy),
+ FunRetTy = hipe_llvm:mk_struct(lists:duplicate(?NR_PINNED_REGS + 1, WordTy)),
+ Fun1 =
+ fun(X,Y) ->
+ hipe_llvm:mk_extractvalue(X, FunRetTy, Name, integer_to_list(Y), [])
+ end,
+ I1 = lists:zipwith(Fun1, Names, Indexes),
+ Fun2 =
+ fun (X, Y) ->
+ hipe_llvm:mk_store(WordTy, X, WordTyPtr, "%" ++ Y ++ "_reg_var", [], [],
+ false)
+ end,
+ I2 = lists:zipwith(Fun2, Names, RegList),
+ [I2, I1].
+
+%%------------------------------------------------------------------------------
+%% Translation of Names
+%%------------------------------------------------------------------------------
+
+%% @doc Fix F in MFA tuple to acceptable LLVM identifier (case of closure).
+-spec fix_mfa_name(mfa()) -> mfa().
+fix_mfa_name({Mod_Name, Closure_Name, Arity}) ->
+ Fun_Name = list_to_atom(fix_closure_name(Closure_Name)),
+ {Mod_Name, Fun_Name, Arity}.
+
+%% @doc Make an acceptable LLVM identifier for a closure name.
+fix_closure_name(ClosureName) ->
+ make_llvm_id(atom_to_list(ClosureName)).
+
+%% @doc Create an acceptable LLVM identifier.
+make_llvm_id(Name) ->
+ case Name of
+ "" -> "Empty";
+ Other -> lists:flatten([llvm_id(C) || C <- Other])
+ end.
+
+llvm_id(C) when C=:=46; C>47 andalso C<58; C>64 andalso C<91; C=:=95;
+ C>96 andalso C<123 ->
+ C;
+llvm_id(C) ->
+ io_lib:format("_~2.16.0B_",[C]).
+
+%% @doc Create an acceptable LLVM identifier for an MFA.
+trans_mfa_name({M,F,A}) ->
+ N = atom_to_list(M) ++ "." ++ atom_to_list(F) ++ "." ++ integer_to_list(A),
+ make_llvm_id(N).
+
+%%------------------------------------------------------------------------------
+%% Creation of Labels and Temporaries
+%%------------------------------------------------------------------------------
+mk_label(N) ->
+ "L" ++ integer_to_list(N).
+
+mk_jump_label(N) ->
+ "%L" ++ integer_to_list(N).
+
+mk_temp() ->
+ "%t" ++ integer_to_list(hipe_gensym:new_var(llvm)).
+
+mk_temp_reg(Name) ->
+ "%" ++ Name ++ integer_to_list(hipe_gensym:new_var(llvm)).
+
+%%----------------------------------------------------------------------------
+%% Translation of Operands
+%%----------------------------------------------------------------------------
+
+store_stack_dst(TempDst, Dst) ->
+ {Dst2, II1} = trans_dst(Dst),
+ WordTy = hipe_llvm:mk_int(?WORD_WIDTH),
+ WordTyPtr = hipe_llvm:mk_pointer(WordTy),
+ II2 = hipe_llvm:mk_store(WordTy, TempDst, WordTyPtr, Dst2, [], [], false),
+ [II2, II1].
+
+store_float_stack(TempDst, Dst) ->
+ {Dst2, II1} = trans_dst(Dst),
+ FloatTy = hipe_llvm:mk_double(),
+ FloatTyPtr = hipe_llvm:mk_pointer(FloatTy),
+ II2 = hipe_llvm:mk_store(FloatTy, TempDst, FloatTyPtr, Dst2, [], [], false),
+ [II2, II1].
+
+trans_float_src(Src) ->
+ case hipe_rtl:is_const_label(Src) of
+ true ->
+ Name = "@DL" ++ integer_to_list(hipe_rtl:const_label_label(Src)),
+ T1 = mk_temp(),
+ %% XXX: Hardcoded offset
+ ByteTy = hipe_llvm:mk_int(8),
+ ByteTyPtr = hipe_llvm:mk_pointer(ByteTy),
+ I1 = hipe_llvm:mk_getelementptr(T1, ByteTyPtr, Name,
+ [{ByteTy, integer_to_list(?FLOAT_OFFSET)}], true),
+ T2 = mk_temp(),
+ FloatTy = hipe_llvm:mk_double(),
+ FloatTyPtr = hipe_llvm:mk_pointer(FloatTy),
+ I2 = hipe_llvm:mk_conversion(T2, bitcast, ByteTyPtr, T1, FloatTyPtr),
+ T3 = mk_temp(),
+ I3 = hipe_llvm:mk_load(T3, FloatTyPtr, T2, [], [], false),
+ {T3, [I3, I2, I1]};
+ false ->
+ trans_src(Src)
+ end.
+
+trans_src(A) ->
+ WordTy = hipe_llvm:mk_int(?WORD_WIDTH),
+ WordTyPtr = hipe_llvm:mk_pointer(WordTy),
+ case hipe_rtl:is_imm(A) of
+ true ->
+ Value = integer_to_list(hipe_rtl:imm_value(A)),
+ {Value, []};
+ false ->
+ case hipe_rtl:is_reg(A) of
+ true ->
+ case isPrecoloured(A) of
+ true -> trans_reg(A, src);
+ false ->
+ {Name, []} = trans_reg(A, src),
+ T1 = mk_temp(),
+ I1 = hipe_llvm:mk_load(T1, WordTyPtr, Name, [], [], false),
+ {T1, [I1]}
+ end;
+ false ->
+ case hipe_rtl:is_var(A) of
+ true ->
+ RootName = "%vr" ++ integer_to_list(hipe_rtl:var_index(A)),
+ T1 = mk_temp(),
+ I1 = hipe_llvm:mk_load(T1, WordTyPtr, RootName, [], [], false),
+ I2 =
+ case hipe_rtl:var_liveness(A) of
+ live ->
+ [];
+ dead ->
+ NilValue = hipe_tagscheme:mk_nil(),
+ hipe_llvm:mk_store(WordTy, integer_to_list(NilValue), WordTyPtr, RootName,
+ [], [], false)
+ end,
+ {T1, [I2, I1]};
+ false ->
+ case hipe_rtl:is_fpreg(A) of
+ true ->
+ {Name, []} = trans_dst(A),
+ T1 = mk_temp(),
+ FloatTyPtr = hipe_llvm:mk_pointer(hipe_llvm:mk_double()),
+ I1 = hipe_llvm:mk_load(T1, FloatTyPtr, Name, [], [], false),
+ {T1, [I1]};
+ false -> trans_dst(A)
+ end
+ end
+ end
+ end.
+
+trans_dst(A) ->
+ case hipe_rtl:is_reg(A) of
+ true ->
+ trans_reg(A, dst);
+ false ->
+ Name = case hipe_rtl:is_var(A) of
+ true ->
+ "%vr" ++ integer_to_list(hipe_rtl:var_index(A));
+ false ->
+ case hipe_rtl:is_fpreg(A) of
+ true -> "%fr" ++ integer_to_list(hipe_rtl:fpreg_index(A));
+ false ->
+ case hipe_rtl:is_const_label(A) of
+ true ->
+ "%DL" ++ integer_to_list(hipe_rtl:const_label_label(A)) ++ "_var";
+ false ->
+ exit({?MODULE, trans_dst, {"Bad RTL argument",A}})
+ end
+ end
+ end,
+ {Name, []}
+ end.
+
+%% @doc Translate a register. If it is precoloured it must be mapped to the
+%% correct stack slot that holds the precoloured register value.
+trans_reg(Arg, Position) ->
+ Index = hipe_rtl:reg_index(Arg),
+ case isPrecoloured(Arg) of
+ true ->
+ Name = map_precoloured_reg(Index),
+ case Position of
+ src -> fix_reg_src(Name);
+ dst -> fix_reg_dst(Name)
+ end;
+ false ->
+ {hipe_rtl_arch:reg_name(Index), []}
+ end.
+
+map_precoloured_reg(Index) ->
+ case hipe_rtl_arch:reg_name(Index) of
+ "%r15" -> "%hp_reg_var";
+ "%rbp" -> "%p_reg_var";
+ "%esi" -> "%hp_reg_var";
+ "%ebp" -> "%p_reg_var";
+ "%fcalls" ->
+ {"%p_reg_var", ?ARCH_REGISTERS:proc_offset(?ARCH_REGISTERS:fcalls())};
+ "%hplim" ->
+ {"%p_reg_var", ?ARCH_REGISTERS:proc_offset(?ARCH_REGISTERS:heap_limit())};
+ _ ->
+ exit({?MODULE, map_precoloured_reg, {"Register not mapped yet", Index}})
+ end.
+
+%% @doc Load precoloured dst register.
+fix_reg_dst(Register) ->
+ case Register of
+ {Name, Offset} -> %% Case of %fcalls, %hplim
+ WordTy = hipe_llvm:mk_int(?WORD_WIDTH),
+ pointer_from_reg(Name, WordTy, Offset);
+ Name -> %% Case of %p and %hp
+ {Name, []}
+ end.
+
+%% @doc Load precoloured src register.
+fix_reg_src(Register) ->
+ WordTy = hipe_llvm:mk_int(?WORD_WIDTH),
+ WordTyPtr = hipe_llvm:mk_pointer(WordTy),
+ case Register of
+ {Name, Offset} -> %% Case of %fcalls, %hplim
+ {T1, I1} = pointer_from_reg(Name, WordTy, Offset),
+ T2 = mk_temp(),
+ I2 = hipe_llvm:mk_load(T2, WordTyPtr, T1, [], [] , false),
+ {T2, [I2, I1]};
+ Name -> %% Case of %p and %hp
+ T1 = mk_temp(),
+ {T1, hipe_llvm:mk_load(T1, WordTyPtr, Name, [], [], false)}
+ end.
+
+%% @doc Load %fcalls and %hplim.
+pointer_from_reg(RegName, Type, Offset) ->
+ PointerType = hipe_llvm:mk_pointer(Type),
+ T1 = mk_temp(),
+ I1 = hipe_llvm:mk_load(T1, PointerType, RegName, [], [] ,false),
+ T2 = mk_temp(),
+ I2 = hipe_llvm:mk_conversion(T2, inttoptr, Type, T1, PointerType),
+ T3 = mk_temp(),
+ %% XXX: Offsets should be a power of 2.
+ I3 = hipe_llvm:mk_getelementptr(T3, PointerType, T2,
+ [{Type, integer_to_list(Offset div hipe_rtl_arch:word_size())}], true),
+ {T3, [I3, I2, I1]}.
+
+isPrecoloured(X) ->
+ hipe_rtl_arch:is_precoloured(X).
+
+%%------------------------------------------------------------------------------
+%% Translation of operators
+%%------------------------------------------------------------------------------
+
+trans_op(Op) ->
+ case Op of
+ add -> add;
+ sub -> sub;
+ 'or' -> 'or';
+ 'and' -> 'and';
+ 'xor' -> 'xor';
+ sll -> shl;
+ srl -> lshr;
+ sra -> ashr;
+ mul -> mul;
+ 'fdiv' -> fdiv;
+ 'sdiv' -> sdiv;
+ 'srem' -> srem;
+ Other -> exit({?MODULE, trans_op, {"Unknown RTL operator", Other}})
+ end.
+
+trans_rel_op(Op) ->
+ case Op of
+ eq -> eq;
+ ne -> ne;
+ gtu -> ugt;
+ geu -> uge;
+ ltu -> ult;
+ leu -> ule;
+ gt -> sgt;
+ ge -> sge;
+ lt -> slt;
+ le -> sle
+ end.
+
+trans_prim_op(Op) ->
+ case Op of
+ '+' -> "bif_add";
+ '-' -> "bif_sub";
+ '*' -> "bif_mul";
+ 'div' -> "bif_div";
+ '/' -> "bif_div";
+ Other -> atom_to_list(Other)
+ end.
+
+trans_fp_op(Op) ->
+ case Op of
+ fadd -> fadd;
+ fsub -> fsub;
+ fdiv -> fdiv;
+ fmul -> fmul;
+ fchs -> fsub;
+ Other -> exit({?MODULE, trans_fp_op, {"Unknown RTL float operator",Other}})
+ end.
+
+%% Misc.
+insn_dst(I) ->
+ case I of
+ #alu{} ->
+ [hipe_rtl:alu_dst(I)];
+ #alub{} ->
+ [hipe_rtl:alub_dst(I)];
+ #call{} ->
+ case hipe_rtl:call_dstlist(I) of
+ [] -> [];
+ [Dst] -> [Dst]
+ end;
+ #load{} ->
+ [hipe_rtl:load_dst(I)];
+ #load_address{} ->
+ [hipe_rtl:load_address_dst(I)];
+ #load_atom{} ->
+ [hipe_rtl:load_atom_dst(I)];
+ #move{} ->
+ [hipe_rtl:move_dst(I)];
+ #phi{} ->
+ [hipe_rtl:phi_dst(I)];
+ #fconv{} ->
+ [hipe_rtl:fconv_dst(I)];
+ #fload{} ->
+ [hipe_rtl:fload_dst(I)];
+ #fmove{} ->
+ [hipe_rtl:fmove_dst(I)];
+ #fp{} ->
+ [hipe_rtl:fp_dst(I)];
+ #fp_unop{} ->
+ [hipe_rtl:fp_unop_dst(I)];
+ _ ->
+ []
+ end.
+
+llvm_type_from_size(Size) ->
+ case Size of
+ byte -> hipe_llvm:mk_int(8);
+ int16 -> hipe_llvm:mk_int(16);
+ int32 -> hipe_llvm:mk_int(32);
+ word -> hipe_llvm:mk_int(64)
+ end.
+
+%% @doc Create definition for the compiled function. The parameters that are
+%% passed to the stack must be reversed to match with the CC. Also
+%% precoloured registers that are passed as arguments must be stored to
+%% the corresonding stack slots.
+create_function_definition(Fun, Params, Code, LocalVars) ->
+ FunctionName = trans_mfa_name(Fun),
+ FixedRegs = fixed_registers(),
+ %% Reverse parameters to match with the Erlang calling convention
+ ReversedParams =
+ case erlang:length(Params) > ?NR_ARG_REGS of
+ false ->
+ Params;
+ true ->
+ {ParamsInRegs, ParamsInStack} = lists:split(?NR_ARG_REGS, Params),
+ ParamsInRegs ++ lists:reverse(ParamsInStack)
+ end,
+ Args = header_regs(FixedRegs) ++ header_params(ReversedParams),
+ EntryLabel = hipe_llvm:mk_label("Entry"),
+ FloatTy = hipe_llvm:mk_double(),
+ ExceptionSync = hipe_llvm:mk_alloca("%exception_sync", FloatTy, [], []),
+ I2 = load_regs(FixedRegs),
+ I3 = hipe_llvm:mk_br(mk_jump_label(get(first_label))),
+ StoredParams = store_params(Params),
+ EntryBlock =
+ lists:flatten([EntryLabel, ExceptionSync, I2, LocalVars, StoredParams, I3]),
+ Final_Code = EntryBlock ++ Code,
+ FunctionOptions = [nounwind, noredzone, list_to_atom("gc \"erlang\"")],
+ WordTy = hipe_llvm:mk_int(?WORD_WIDTH),
+ FunRetTy = hipe_llvm:mk_struct(lists:duplicate(?NR_PINNED_REGS + 1, WordTy)),
+ hipe_llvm:mk_fun_def([], [], "cc 11", [], FunRetTy, FunctionName, Args,
+ FunctionOptions, [], Final_Code).
+
+header_params(Params) ->
+ WordTy = hipe_llvm:mk_int(?WORD_WIDTH),
+ [{WordTy, "%v" ++ integer_to_list(hipe_rtl:var_index(P))} || P <- Params].
+
+store_params(Params) ->
+ Fun1 =
+ fun(X) ->
+ Index = hipe_rtl:var_index(X),
+ {Name, _} = trans_dst(X),
+ ParamName = "%v" ++ integer_to_list(Index),
+ WordTy = hipe_llvm:mk_int(?WORD_WIDTH),
+ WordTyPtr = hipe_llvm:mk_pointer(WordTy),
+ hipe_llvm:mk_store(WordTy, ParamName, WordTyPtr, Name, [], [], false)
+ end,
+ lists:map(Fun1, Params).
+
+fixed_registers() ->
+ case get(hipe_target_arch) of
+ x86 ->
+ ["hp", "p"];
+ amd64 ->
+ ["hp", "p"];
+ Other ->
+ exit({?MODULE, map_registers, {"Unknown architecture", Other}})
+ end.
+
+header_regs(Registers) ->
+ WordTy = hipe_llvm:mk_int(?WORD_WIDTH),
+ [{WordTy, "%" ++ X ++ "_in"} || X <- Registers].
+
+load_regs(Registers) ->
+ WordTy = hipe_llvm:mk_int(?WORD_WIDTH),
+ WordTyPtr = hipe_llvm:mk_pointer(WordTy),
+ Fun1 =
+ fun(X) ->
+ I1 = hipe_llvm:mk_alloca("%" ++ X ++ "_reg_var", WordTy, [], []),
+ I2 = hipe_llvm:mk_store(WordTy, "%" ++ X ++ "_in", WordTyPtr,
+ "%" ++ X ++ "_reg_var", [], [], false),
+ [I1, I2]
+ end,
+ lists:map(Fun1, Registers).
+
+%%------------------------------------------------------------------------------
+%% Relocation-specific Stuff
+%%------------------------------------------------------------------------------
+
+relocs_store(Key, Value, Relocs) ->
+ dict:store(Key, Value, Relocs).
+
+relocs_to_list(Relocs) ->
+ dict:to_list(Relocs).
+
+%% @doc This function is responsible for the actions needed to handle
+%% relocations:
+%% 1) Updates relocations with constants and switch jump tables.
+%% 2) Creates LLVM code to declare relocations as external
+%% functions/constants.
+%% 3) Creates LLVM code in order to create local variables for the external
+%% constants/labels.
+handle_relocations(Relocs, Data, Fun) ->
+ RelocsList = relocs_to_list(Relocs),
+ %% Seperate Relocations according to their type
+ {CallList, AtomList, ClosureList, ClosureLabels, SwitchList} =
+ seperate_relocs(RelocsList),
+ %% Create code to declare atoms
+ AtomDecl = [declare_atom(A) || A <- AtomList],
+ %% Create code to create local name for atoms
+ AtomLoad = [load_atom(A) || A <- AtomList],
+ %% Create code to declare closures
+ ClosureDecl = [declare_closure(C) || C <- ClosureList],
+ %% Create code to create local name for closures
+ ClosureLoad = [load_closure(C) || C <- ClosureList],
+ %% Find function calls
+ IsExternalCall = fun (X) -> is_external_call(X, Fun) end,
+ ExternalCallList = lists:filter(IsExternalCall, CallList),
+ %% Create code to declare external function
+ FunDecl = fixed_fun_decl() ++ [call_to_decl(C) || C <- ExternalCallList],
+ %% Extract constant labels from Constant Map (remove duplicates)
+ ConstLabels = hipe_consttab:labels(Data),
+ %% Create code to declare constants
+ ConstDecl = [declare_constant(C) || C <- ConstLabels],
+ %% Create code to create local name for constants
+ ConstLoad = [load_constant(C) || C <- ConstLabels],
+ %% Create code to create jump tables
+ SwitchDecl = declare_switches(SwitchList, Fun),
+ %% Create code to create a table with the labels of all closure calls
+ {ClosureLabelDecl, Relocs1} =
+ declare_closure_labels(ClosureLabels, Relocs, Fun),
+ %% Enter constants to relocations
+ Relocs2 = lists:foldl(fun const_to_dict/2, Relocs1, ConstLabels),
+ %% Temporary Store inc_stack and llvm_fix_pinned_regs to Dictionary
+ %% TODO: Remove this
+ Relocs3 = dict:store("inc_stack_0", {call, {bif, inc_stack_0, 0}}, Relocs2),
+ Relocs4 = dict:store("hipe_bifs.llvm_fix_pinned_regs.0",
+ {call, {hipe_bifs, llvm_fix_pinned_regs, 0}}, Relocs3),
+ BranchMetaData = [
+ hipe_llvm:mk_branch_meta(?BRANCH_META_TAKEN, "99", "1")
+ , hipe_llvm:mk_branch_meta(?BRANCH_META_NOT_TAKEN, "1", "99")
+ ],
+ ExternalDeclarations = AtomDecl ++ ClosureDecl ++ ConstDecl ++ FunDecl ++
+ ClosureLabelDecl ++ SwitchDecl ++ BranchMetaData,
+ LocalVariables = AtomLoad ++ ClosureLoad ++ ConstLoad,
+ {Relocs4, ExternalDeclarations, LocalVariables}.
+
+%% @doc Seperate relocations according to their type.
+seperate_relocs(Relocs) ->
+ seperate_relocs(Relocs, [], [], [], [], []).
+
+seperate_relocs([], CallAcc, AtomAcc, ClosureAcc, LabelAcc, JmpTableAcc) ->
+ {CallAcc, AtomAcc, ClosureAcc, LabelAcc, JmpTableAcc};
+seperate_relocs([R|Rs], CallAcc, AtomAcc, ClosureAcc, LabelAcc, JmpTableAcc) ->
+ case R of
+ {_, {call, _}} ->
+ seperate_relocs(Rs, [R | CallAcc], AtomAcc, ClosureAcc, LabelAcc,
+ JmpTableAcc);
+ {_, {atom, _}} ->
+ seperate_relocs(Rs, CallAcc, [R | AtomAcc], ClosureAcc, LabelAcc,
+ JmpTableAcc);
+ {_, {closure, _}} ->
+ seperate_relocs(Rs, CallAcc, AtomAcc, [R | ClosureAcc], LabelAcc,
+ JmpTableAcc);
+ {_, {switch, _, _}} ->
+ seperate_relocs(Rs, CallAcc, AtomAcc, ClosureAcc, LabelAcc,
+ [R | JmpTableAcc]);
+ {_, {closure_label, _, _}} ->
+ seperate_relocs(Rs, CallAcc, AtomAcc, ClosureAcc, [R | LabelAcc],
+ JmpTableAcc)
+ end.
+
+%% @doc External declaration of an atom.
+declare_atom({AtomName, _}) ->
+ WordTy = hipe_llvm:mk_int(?WORD_WIDTH),
+ hipe_llvm:mk_const_decl("@" ++ AtomName, "external constant", WordTy, "").
+
+%% @doc Creation of local variable for an atom.
+load_atom({AtomName, _}) ->
+ Dst = "%" ++ AtomName ++ "_var",
+ Name = "@" ++ AtomName,
+ WordTy = hipe_llvm:mk_int(?WORD_WIDTH),
+ WordTyPtr = hipe_llvm:mk_pointer(WordTy),
+ hipe_llvm:mk_conversion(Dst, ptrtoint, WordTyPtr, Name, WordTy).
+
+%% @doc External declaration of a closure.
+declare_closure({ClosureName, _})->
+ ByteTy = hipe_llvm:mk_int(8),
+ hipe_llvm:mk_const_decl("@" ++ ClosureName, "external constant", ByteTy, "").
+
+%% @doc Creation of local variable for a closure.
+load_closure({ClosureName, _})->
+ Dst = "%" ++ ClosureName ++ "_var",
+ Name = "@" ++ ClosureName,
+ WordTy = hipe_llvm:mk_int(?WORD_WIDTH),
+ ByteTyPtr = hipe_llvm:mk_pointer(hipe_llvm:mk_int(8)),
+ hipe_llvm:mk_conversion(Dst, ptrtoint, ByteTyPtr, Name, WordTy).
+
+%% @doc Declaration of a local variable for a switch jump table.
+declare_switches(JumpTableList, Fun) ->
+ FunName = trans_mfa_name(Fun),
+ [declare_switch_table(X, FunName) || X <- JumpTableList].
+
+declare_switch_table({Name, {switch, {TableType, Labels, _, _}, _}}, FunName) ->
+ LabelList = [mk_jump_label(L) || L <- Labels],
+ Fun1 = fun(X) -> "i8* blockaddress(@" ++ FunName ++ ", " ++ X ++ ")" end,
+ List2 = lists:map(Fun1, LabelList),
+ List3 = string:join(List2, ",\n"),
+ List4 = "[\n" ++ List3 ++ "\n]\n",
+ hipe_llvm:mk_const_decl("@" ++ Name, "constant", TableType, List4).
+
+%% @doc Declaration of a variable for a table with the labels of all closure
+%% calls in the code.
+declare_closure_labels([], Relocs, _Fun) ->
+ {[], Relocs};
+declare_closure_labels(ClosureLabels, Relocs, Fun) ->
+ FunName = trans_mfa_name(Fun),
+ {LabelList, ArityList} =
+ lists:unzip([{mk_jump_label(Label), A} ||
+ {_, {closure_label, Label, A}} <- ClosureLabels]),
+ Relocs1 = relocs_store("table_closures", {table_closures, ArityList}, Relocs),
+ List2 =
+ ["i8* blockaddress(@" ++ FunName ++ ", " ++ L ++ ")" || L <- LabelList],
+ List3 = string:join(List2, ",\n"),
+ List4 = "[\n" ++ List3 ++ "\n]\n",
+ NrLabels = length(LabelList),
+ ByteTyPtr = hipe_llvm:mk_pointer(hipe_llvm:mk_int(8)),
+ TableType = hipe_llvm:mk_array(NrLabels, ByteTyPtr),
+ ConstDecl =
+ hipe_llvm:mk_const_decl("@table_closures", "constant", TableType, List4),
+ {[ConstDecl], Relocs1}.
+
+%% @doc A call is treated as non external only in a case of a recursive
+%% function.
+is_external_call({_, {call, Fun}}, Fun) -> false;
+is_external_call(_, _) -> true.
+
+%% @doc External declaration of a function.
+call_to_decl({Name, {call, MFA}}) ->
+ {M, _F, A} = MFA,
+ CConv = "cc 11",
+ WordTy = hipe_llvm:mk_int(?WORD_WIDTH),
+ FunRetTy = hipe_llvm:mk_struct(lists:duplicate(?NR_PINNED_REGS + 1, WordTy)),
+ {Type, Args} =
+ case M of
+ llvm ->
+ {hipe_llvm:mk_struct([WordTy, hipe_llvm:mk_int(1)]), [1, 2]};
+ %% +precoloured regs
+ _ ->
+ {FunRetTy, lists:seq(1, A + ?NR_PINNED_REGS)}
+ end,
+ ArgsTypes = lists:duplicate(length(Args), WordTy),
+ hipe_llvm:mk_fun_decl([], [], CConv, [], Type, "@" ++ Name, ArgsTypes, []).
+
+%% @doc These functions are always declared, even if not used.
+fixed_fun_decl() ->
+ ByteTy = hipe_llvm:mk_int(8),
+ ByteTyPtr = hipe_llvm:mk_pointer(ByteTy),
+ LandPad = hipe_llvm:mk_fun_decl([], [], [], [], hipe_llvm:mk_int(32),
+ "@__gcc_personality_v0", [hipe_llvm:mk_int(32), hipe_llvm:mk_int(64),
+ ByteTyPtr, ByteTyPtr], []),
+ GCROOTDecl = hipe_llvm:mk_fun_decl([], [], [], [], hipe_llvm:mk_void(),
+ "@llvm.gcroot", [hipe_llvm:mk_pointer(ByteTyPtr), ByteTyPtr], []),
+ WordTy = hipe_llvm:mk_int(?WORD_WIDTH),
+ FunRetTy = hipe_llvm:mk_struct(lists:duplicate(?NR_PINNED_REGS + 1, WordTy)),
+ FixPinnedRegs = hipe_llvm:mk_fun_decl([], [], [], [], FunRetTy,
+ "@hipe_bifs.llvm_fix_pinned_regs.0", [], []),
+ GcMetadata = hipe_llvm:mk_const_decl("@gc_metadata", "external constant",
+ ByteTy, ""),
+ [LandPad, GCROOTDecl, FixPinnedRegs, GcMetadata].
+
+%% @doc Declare an External Consant. We declare all constants as i8 in order to
+%% be able to calcucate pointers of the form DL+6, with the getelementptr
+%% instruction. Otherwise we have to convert constants form pointers to
+%% values, add the offset and convert them again to pointers.
+declare_constant(Label) ->
+ Name = "@DL" ++ integer_to_list(Label),
+ ByteTy = hipe_llvm:mk_int(8),
+ hipe_llvm:mk_const_decl(Name, "external constant", ByteTy, "").
+
+%% @doc Load a constant is achieved by converting a pointer to an integer of
+%% the correct width.
+load_constant(Label) ->
+ Dst = "%DL" ++ integer_to_list(Label) ++ "_var",
+ Name = "@DL" ++ integer_to_list(Label),
+ WordTy = hipe_llvm:mk_int(?WORD_WIDTH),
+ ByteTyPtr = hipe_llvm:mk_pointer(hipe_llvm:mk_int(8)),
+ hipe_llvm:mk_conversion(Dst, ptrtoint, ByteTyPtr, Name, WordTy).
+
+%% @doc Store external constants and calls to dictionary.
+const_to_dict(Elem, Dict) ->
+ Name = "DL" ++ integer_to_list(Elem),
+ dict:store(Name, {'constant', Elem}, Dict).
diff --git a/lib/hipe/main/hipe.app.src b/lib/hipe/main/hipe.app.src
index bcdfcb0e03..e81212d4dc 100644
--- a/lib/hipe/main/hipe.app.src
+++ b/lib/hipe/main/hipe.app.src
@@ -30,6 +30,7 @@
cerl_prettypr,
cerl_to_icode,
cerl_typean,
+ elf_format,
erl_bif_types,
erl_types,
hipe,
@@ -108,6 +109,10 @@
hipe_ig,
hipe_ig_moves,
hipe_jit,
+ hipe_llvm,
+ hipe_llvm_liveness,
+ hipe_llvm_main,
+ hipe_llvm_merge,
hipe_ls_regalloc,
hipe_main,
hipe_moves,
@@ -159,6 +164,7 @@
hipe_rtl_symbolic,
hipe_rtl_to_amd64,
hipe_rtl_to_arm,
+ hipe_rtl_to_llvm,
hipe_rtl_to_ppc,
hipe_rtl_to_sparc,
hipe_rtl_to_x86,
@@ -216,4 +222,6 @@
hipe_x86_x87]},
{registered,[]},
{applications, [kernel,stdlib]},
- {env, []}]}.
+ {env, []},
+ {runtime_dependencies, ["syntax_tools-1.6.14","stdlib-2.0","kernel-3.0",
+ "erts-6.0","compiler-5.0"]}]}.
diff --git a/lib/hipe/main/hipe.erl b/lib/hipe/main/hipe.erl
index 434d5c3061..d47eced6d8 100644
--- a/lib/hipe/main/hipe.erl
+++ b/lib/hipe/main/hipe.erl
@@ -821,7 +821,9 @@ finalize_fun_sequential({MFA, Icode}, Opts, Servers) ->
?debug_msg("Compiled ~w in ~.2f s\n", [MFA,(T2-T1)/1000])),
{MFA, Code};
{rtl, LinearRtl} ->
- {MFA, LinearRtl}
+ {MFA, LinearRtl};
+ {llvm_binary, Binary} ->
+ {MFA, Binary}
catch
error:Error ->
?when_option(verbose, Opts, ?debug_untagged_msg("\n", [])),
@@ -890,21 +892,27 @@ do_load(Mod, Bin, BeamBinOrPath) when is_binary(BeamBinOrPath);
end.
assemble(CompiledCode, Closures, Exports, Options) ->
- case get(hipe_target_arch) of
- ultrasparc ->
- hipe_sparc_assemble:assemble(CompiledCode, Closures, Exports, Options);
- powerpc ->
- hipe_ppc_assemble:assemble(CompiledCode, Closures, Exports, Options);
- ppc64 ->
- hipe_ppc_assemble:assemble(CompiledCode, Closures, Exports, Options);
- arm ->
- hipe_arm_assemble:assemble(CompiledCode, Closures, Exports, Options);
- x86 ->
- hipe_x86_assemble:assemble(CompiledCode, Closures, Exports, Options);
- amd64 ->
- hipe_amd64_assemble:assemble(CompiledCode, Closures, Exports, Options);
- Arch ->
- ?EXIT({executing_on_an_unsupported_architecture, Arch})
+ case proplists:get_bool(to_llvm, Options) of
+ false ->
+ case get(hipe_target_arch) of
+ ultrasparc ->
+ hipe_sparc_assemble:assemble(CompiledCode, Closures, Exports, Options);
+ powerpc ->
+ hipe_ppc_assemble:assemble(CompiledCode, Closures, Exports, Options);
+ ppc64 ->
+ hipe_ppc_assemble:assemble(CompiledCode, Closures, Exports, Options);
+ arm ->
+ hipe_arm_assemble:assemble(CompiledCode, Closures, Exports, Options);
+ x86 ->
+ hipe_x86_assemble:assemble(CompiledCode, Closures, Exports, Options);
+ amd64 ->
+ hipe_amd64_assemble:assemble(CompiledCode, Closures, Exports, Options);
+ Arch ->
+ ?EXIT({executing_on_an_unsupported_architecture, Arch})
+ end;
+ true ->
+ %% Merge already compiled code (per MFA) to a single binary.
+ hipe_llvm_merge:finalize(CompiledCode, Closures, Exports)
end.
%% --------------------------------------------------------------------
@@ -1330,6 +1338,11 @@ opt_keys() ->
timeregalloc,
timers,
to_rtl,
+ to_llvm, % Use the LLVM backend for compilation.
+ llvm_save_temps, % Save the LLVM intermediate files in the current
+ % directory; useful for debugging.
+ llvm_llc, % Specify llc optimization-level: o1, o2, o3, undefined.
+ llvm_opt, % Specify opt optimization-level: o1, o2, o3, undefined.
use_indexing,
use_inline_atom_search,
use_callgraph,
@@ -1468,11 +1481,19 @@ opt_expansions() ->
[{o1, o1_opts()},
{o2, o2_opts()},
{o3, o3_opts()},
+ {to_llvm, llvm_opts(o3)},
+ {{to_llvm, o0}, llvm_opts(o0)},
+ {{to_llvm, o1}, llvm_opts(o1)},
+ {{to_llvm, o2}, llvm_opts(o2)},
+ {{to_llvm, o3}, llvm_opts(o3)},
{x87, [x87, inline_fp]},
{inline_fp, case get(hipe_target_arch) of %% XXX: Temporary until x86
x86 -> [x87, inline_fp]; %% has sse2
_ -> [inline_fp] end}].
+llvm_opts(O) ->
+ [to_llvm, {llvm_opt, O}, {llvm_llc, O}].
+
%% This expands "basic" options, which may be tested early and cannot be
%% in conflict with options found in the source code.
diff --git a/lib/hipe/main/hipe_main.erl b/lib/hipe/main/hipe_main.erl
index 99028cc3c1..89b79998be 100644
--- a/lib/hipe/main/hipe_main.erl
+++ b/lib/hipe/main/hipe_main.erl
@@ -49,7 +49,7 @@
%%=====================================================================
-type comp_icode_ret() :: {'native',hipe_architecture(),{'unprofiled',_}}
- | {'rtl',tuple()}.
+ | {'rtl',tuple()} | {'llvm_binary',term()}.
%%=====================================================================
@@ -115,11 +115,18 @@ compile_icode(MFA, LinearIcode0, Options, Servers, DebugState) ->
pp(IcodeCfg7, MFA, icode_liveness, pp_icode_liveness, Options, Servers),
FinalIcode = hipe_icode_cfg:cfg_to_linear(IcodeCfg7),
?opt_stop_timer("Icode"),
- LinearRTL = ?option_time(icode_to_rtl(MFA,FinalIcode,Options, Servers),
- "RTL", Options),
+ {LinearRTL, Roots} = ?option_time(icode_to_rtl(MFA, FinalIcode, Options, Servers),
+ "RTL", Options),
case proplists:get_bool(to_rtl, Options) of
false ->
- rtl_to_native(MFA, LinearRTL, Options, DebugState);
+ case proplists:get_bool(to_llvm, Options) of
+ false ->
+ rtl_to_native(MFA, LinearRTL, Options, DebugState);
+ true ->
+ %% The LLVM backend returns binary code, unlike the rest of the HiPE
+ %% backends which return native assembly.
+ rtl_to_llvm_to_binary(MFA, LinearRTL, Roots, Options, DebugState)
+ end;
true ->
put(hipe_debug, DebugState),
{rtl, LinearRTL}
@@ -385,11 +392,21 @@ icode_to_rtl(MFA, Icode, Options, Servers) ->
%% hipe_rtl_cfg:pp(RtlCfg3),
pp(RtlCfg3, MFA, rtl_liveness, pp_rtl_liveness, Options, Servers),
RtlCfg4 = rtl_lcm(RtlCfg3, Options),
- pp(RtlCfg4, MFA, rtl, pp_rtl, Options, Servers),
- LinearRTL1 = hipe_rtl_cfg:linearize(RtlCfg4),
+ %% LLVM: A liveness analysis on RTL must be performed in order to find the GC
+ %% roots and explicitly mark them (in RTL) when they go out of scope (only
+ %% when the LLVM backend is used).
+ {RtlCfg5, Roots} =
+ case proplists:get_bool(to_llvm, Options) of
+ false ->
+ {RtlCfg4, []};
+ true ->
+ hipe_llvm_liveness:analyze(RtlCfg4)
+ end,
+ pp(RtlCfg5, MFA, rtl, pp_rtl, Options, Servers),
+ LinearRTL1 = hipe_rtl_cfg:linearize(RtlCfg5),
LinearRTL2 = hipe_rtl_cleanup_const:cleanup(LinearRTL1),
%% hipe_rtl:pp(standard_io, LinearRTL2),
- LinearRTL2.
+ {LinearRTL2, Roots}.
translate_to_rtl(Icode, Options) ->
%% GC tests should have been added in the conversion to Icode.
@@ -540,6 +557,17 @@ rtl_to_native(MFA, LinearRTL, Options, DebugState) ->
put(hipe_debug, DebugState),
LinearNativeCode.
+%% Translate Linear RTL to binary code using LLVM.
+rtl_to_llvm_to_binary(MFA, LinearRTL, Roots, Options, DebugState) ->
+ ?opt_start_timer("LLVM native code"),
+ %% BinaryCode is a tuple, as defined in llvm/hipe_llvm_main module, which
+ %% contains the binary code together with info needed by the loader, e.g.
+ %% ConstTab, Refs, LabelMap, etc.
+ BinaryCode = hipe_llvm_main:rtl_to_native(MFA, LinearRTL, Roots, Options),
+ ?opt_stop_timer("LLVM native code"),
+ put(hipe_debug, DebugState),
+ {llvm_binary, BinaryCode}.
+
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Debugging stuff ...
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
diff --git a/lib/hipe/misc/hipe_gensym.erl b/lib/hipe/misc/hipe_gensym.erl
index 84fc8fa7e8..4d2a237188 100644
--- a/lib/hipe/misc/hipe_gensym.erl
+++ b/lib/hipe/misc/hipe_gensym.erl
@@ -44,7 +44,7 @@
%% Types of allowable entities to set global variables for
%%-----------------------------------------------------------------------
--type gvarname() :: 'icode' | 'rtl' | 'arm' | 'ppc' | 'sparc' | 'x86'.
+-type gvarname() :: 'icode' | 'rtl' | 'arm' | 'ppc' | 'sparc' | 'x86' | 'llvm'.
%%-----------------------------------------------------------------------
diff --git a/lib/hipe/misc/hipe_pack_constants.erl b/lib/hipe/misc/hipe_pack_constants.erl
index ca8a9e6bf7..300f9ae43a 100644
--- a/lib/hipe/misc/hipe_pack_constants.erl
+++ b/lib/hipe/misc/hipe_pack_constants.erl
@@ -20,30 +20,48 @@
%%
-module(hipe_pack_constants).
--export([pack_constants/2, slim_refs/1, slim_constmap/1]).
+-export([pack_constants/2, slim_refs/1, slim_constmap/1,
+ find_const/2, mk_data_relocs/2, slim_sorted_exportmap/3]).
-include("hipe_consttab.hrl").
-include("../../kernel/src/hipe_ext_format.hrl").
+-include("../main/hipe.hrl"). % Needed for the EXIT macro in find_const/2.
%%-----------------------------------------------------------------------------
--type raw_data() :: binary() | number() | list() | tuple().
--type tbl_ref() :: {hipe_constlbl(), non_neg_integer()}.
+-type const_num() :: non_neg_integer().
+-type raw_data() :: binary() | number() | list() | tuple().
+
+-type addr() :: non_neg_integer().
+-type ref_p() :: {DataPos :: hipe_constlbl(), CodeOffset :: addr()}.
+-type ref() :: ref_p() | {'sorted', Base :: addr(), [ref_p()]}.
+
+-type mfa_refs() :: {mfa(), [ref()]}.
+
+%% XXX: these types may not belong here: FIX!
+-type fa() :: {atom(), arity()}.
+-type export_map() :: [{addr(), module(), atom(), arity()}].
-record(pcm_entry, {mfa :: mfa(),
label :: hipe_constlbl(),
- const_num :: non_neg_integer(),
- start :: non_neg_integer(),
+ const_num :: const_num(),
+ start :: addr(),
type :: 0 | 1 | 2,
raw_data :: raw_data()}).
+-type pcm_entry() :: #pcm_entry{}.
+
+-type label_map() :: gb_trees:tree({mfa(), hipe_constlbl()}, addr()).
+
+%% Some of the following types may possibly need to be exported
+-type data_relocs() :: [ref()].
+-type packed_const_map() :: [pcm_entry()].
+-type mfa_refs_map() :: [mfa_refs()].
+-type slim_export_map() :: [addr() | module() | atom() | arity() | boolean()].
%%-----------------------------------------------------------------------------
-spec pack_constants([{mfa(),[_],hipe_consttab()}], ct_alignment()) ->
- {ct_alignment(),
- non_neg_integer(),
- [#pcm_entry{}],
- [{mfa(),[tbl_ref() | {'sorted',non_neg_integer(),[tbl_ref()]}]}]}.
+ {ct_alignment(), non_neg_integer(), packed_const_map(), mfa_refs_map()}.
pack_constants(Data, Align) ->
pack_constants(Data, 0, Align, 0, [], []).
@@ -194,13 +212,12 @@ compact_dests([], Dest, AccofDest, Acc) ->
%% to the slimmed and flattened format ConstMap which is put in object
%% files.
%%
--spec slim_constmap([#pcm_entry{}]) -> [raw_data()].
+-spec slim_constmap(packed_const_map()) -> [raw_data()].
slim_constmap(Map) ->
slim_constmap(Map, gb_sets:new(), []).
--spec slim_constmap([#pcm_entry{}], gb_sets:set(), [raw_data()]) -> [raw_data()].
-slim_constmap([#pcm_entry{const_num=ConstNo, start=Offset,
- type=Type, raw_data=Term}|Rest], Inserted, Acc) ->
+slim_constmap([#pcm_entry{const_num = ConstNo, start = Offset,
+ type = Type, raw_data = Term}|Rest], Inserted, Acc) ->
case gb_sets:is_member(ConstNo, Inserted) of
true ->
slim_constmap(Rest, Inserted, Acc);
@@ -209,3 +226,60 @@ slim_constmap([#pcm_entry{const_num=ConstNo, start=Offset,
slim_constmap(Rest, NewInserted, [ConstNo, Offset, Type, Term|Acc])
end;
slim_constmap([], _Inserted, Acc) -> Acc.
+
+%%
+%% Lookup a constant in a ConstMap.
+%%
+-spec find_const({mfa(), hipe_constlbl()}, packed_const_map()) -> const_num().
+
+find_const({MFA, Label}, [E = #pcm_entry{mfa = MFA, label = Label}|_]) ->
+ E#pcm_entry.const_num;
+find_const(N, [_|R]) ->
+ find_const(N, R);
+find_const(C, []) ->
+ ?EXIT({constant_not_found, C}).
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%%
+%% Functions to build and handle Refs, ExportMap and LabelMap.
+%% Note: Moved here because they are used by all backends in
+%% hipe_{arm,sparc,ppc,x86}_assemble.erl
+%% XXX: Is this the right place for them?
+%%
+
+-spec mk_data_relocs(mfa_refs_map(), label_map()) -> data_relocs().
+
+mk_data_relocs(RefsFromConsts, LabelMap) ->
+ lists:flatten(mk_data_relocs(RefsFromConsts, LabelMap, [])).
+
+mk_data_relocs([{MFA, Labels} | Rest], LabelMap, Acc) ->
+ Map = [case Label of
+ {L,Pos} ->
+ Offset = find({MFA,L}, LabelMap),
+ {Pos,Offset};
+ {sorted,Base,OrderedLabels} ->
+ {sorted, Base, [begin
+ Offset = find({MFA,L}, LabelMap),
+ {Order, Offset}
+ end
+ || {L,Order} <- OrderedLabels]}
+ end
+ || Label <- Labels],
+ %% msg("Map: ~w Map\n", [Map]),
+ mk_data_relocs(Rest, LabelMap, [Map,Acc]);
+mk_data_relocs([], _, Acc) -> Acc.
+
+find({MFA,L}, LabelMap) ->
+ gb_trees:get({MFA,L}, LabelMap).
+
+-spec slim_sorted_exportmap(export_map(), [mfa()], [fa()]) -> slim_export_map().
+
+slim_sorted_exportmap([{Addr,M,F,A}|Rest], Closures, Exports) ->
+ IsClosure = lists:member({M,F,A}, Closures),
+ IsExported = is_exported(F, A, Exports),
+ [Addr,M,F,A,IsClosure,IsExported | slim_sorted_exportmap(Rest, Closures, Exports)];
+slim_sorted_exportmap([], _, _) -> [].
+
+is_exported(F, A, Exports) ->
+ lists:member({F,A}, Exports).
diff --git a/lib/hipe/ppc/hipe_ppc_assemble.erl b/lib/hipe/ppc/hipe_ppc_assemble.erl
index b2fd50517b..3ad91f4051 100644
--- a/lib/hipe/ppc/hipe_ppc_assemble.erl
+++ b/lib/hipe/ppc/hipe_ppc_assemble.erl
@@ -46,8 +46,8 @@ assemble(CompiledCode, Closures, Exports, Options) ->
print("Total num bytes=~w\n", [CodeSize], Options),
%%
SC = hipe_pack_constants:slim_constmap(ConstMap),
- DataRelocs = mk_data_relocs(RefsFromConsts, LabelMap),
- SSE = slim_sorted_exportmap(ExportMap,Closures,Exports),
+ DataRelocs = hipe_pack_constants:mk_data_relocs(RefsFromConsts, LabelMap),
+ SSE = hipe_pack_constants:slim_sorted_exportmap(ExportMap,Closures,Exports),
SlimRefs = hipe_pack_constants:slim_refs(AccRefs),
Bin = term_to_binary([{?VERSION_STRING(),?HIPE_SYSTEM_CRC},
ConstAlign, ConstSize,
@@ -288,7 +288,7 @@ do_pseudo_li(I, MFA, ConstMap) ->
%%% end,
%%% {load_address, {Tag,untag_mfa_or_prim(MFAorPrim)}};
{Label,constant} ->
- ConstNo = find_const({MFA,Label}, ConstMap),
+ ConstNo = hipe_pack_constants:find_const({MFA,Label}, ConstMap),
{load_address, {constant,ConstNo}};
{Label,closure} ->
{load_address, {closure,Label}};
@@ -574,37 +574,6 @@ mk_y(Pred, BD) ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-mk_data_relocs(RefsFromConsts, LabelMap) ->
- lists:flatten(mk_data_relocs(RefsFromConsts, LabelMap, [])).
-
-mk_data_relocs([{MFA,Labels} | Rest], LabelMap, Acc) ->
- Map = [case Label of
- {L,Pos} ->
- Offset = find({MFA,L}, LabelMap),
- {Pos,Offset};
- {sorted,Base,OrderedLabels} ->
- {sorted, Base, [begin
- Offset = find({MFA,L}, LabelMap),
- {Order, Offset}
- end
- || {L,Order} <- OrderedLabels]}
- end
- || Label <- Labels],
- %% msg("Map: ~w Map\n",[Map]),
- mk_data_relocs(Rest, LabelMap, [Map,Acc]);
-mk_data_relocs([],_,Acc) -> Acc.
-
-find({_MFA,_L} = MFAL,LabelMap) ->
- gb_trees:get(MFAL, LabelMap).
-
-slim_sorted_exportmap([{Addr,M,F,A}|Rest], Closures, Exports) ->
- IsClosure = lists:member({M,F,A}, Closures),
- IsExported = is_exported(F, A, Exports),
- [Addr,M,F,A,IsClosure,IsExported | slim_sorted_exportmap(Rest, Closures, Exports)];
-slim_sorted_exportmap([],_,_) -> [].
-
-is_exported(F, A, Exports) -> lists:member({F,A}, Exports).
-
%%%
%%% Assembly listing support (pp_asm option).
%%%
@@ -642,14 +611,3 @@ fill_spaces(N) when N > 0 ->
fill_spaces(N-1);
fill_spaces(0) ->
[].
-
-%%%
-%%% Lookup a constant in a ConstMap.
-%%%
-
-find_const({MFA,Label}, [{pcm_entry,MFA,Label,ConstNo,_,_,_}|_]) ->
- ConstNo;
-find_const(N, [_|R]) ->
- find_const(N, R);
-find_const(C, []) ->
- ?EXIT({constant_not_found,C}).
diff --git a/lib/hipe/regalloc/hipe_ls_regalloc.erl b/lib/hipe/regalloc/hipe_ls_regalloc.erl
index 4276b8f968..7a00a0534a 100644
--- a/lib/hipe/regalloc/hipe_ls_regalloc.erl
+++ b/lib/hipe/regalloc/hipe_ls_regalloc.erl
@@ -722,7 +722,7 @@ is_free(R, Free) ->
is_free(R, Free, []).
is_free(R, [{R,_}|Rest], Acc) ->
- {true,lists:reverse(Acc)++Rest};
+ {true, lists:reverse(Acc, Rest)};
is_free(R, [X|Rs],Acc) ->
is_free(R, Rs, [X|Acc]);
is_free(_, [], _) ->
@@ -733,7 +733,7 @@ exists_free_register(Start, Regs) ->
exists_free_register(Start, [{Phys, Start0}|Rest], Acc)
when Start > Start0 ->
- {true, Phys, lists:reverse(Acc)++Rest};
+ {true, Phys, lists:reverse(Acc, Rest)};
exists_free_register(Start, [Free|Rest], Acc) ->
exists_free_register(Start, Rest, [Free|Acc]);
exists_free_register(_, [], _) ->
diff --git a/lib/hipe/regalloc/hipe_optimistic_regalloc.erl b/lib/hipe/regalloc/hipe_optimistic_regalloc.erl
index 5bad31ade9..0278a896d2 100644
--- a/lib/hipe/regalloc/hipe_optimistic_regalloc.erl
+++ b/lib/hipe/regalloc/hipe_optimistic_regalloc.erl
@@ -958,9 +958,9 @@ splits_2({Cols, NonCols, OldSpillCost}, L, SpillCost) ->
%% Merge two ordered sub-splits into one.
spillCostOrderedMerge(Spl1, [], Spl) ->
- lists:reverse(Spl) ++ Spl1;
+ lists:reverse(Spl, Spl1);
spillCostOrderedMerge([], Spl2, Spl) ->
- lists:reverse(Spl) ++ Spl2;
+ lists:reverse(Spl, Spl2);
spillCostOrderedMerge(Spl1, Spl2, Spl) ->
{_, _, SpillCost1} = hd(Spl1),
{_, _, SpillCost2} = hd(Spl2),
diff --git a/lib/hipe/rtl/hipe_icode2rtl.erl b/lib/hipe/rtl/hipe_icode2rtl.erl
index 034153a3cb..483d0b37f7 100644
--- a/lib/hipe/rtl/hipe_icode2rtl.erl
+++ b/lib/hipe/rtl/hipe_icode2rtl.erl
@@ -427,8 +427,6 @@ gen_type_test([X], Type, TrueLbl, FalseLbl, Pred, ConstTab) ->
hipe_rtl:mk_branch(X, eq, TmpF, TrueLbl, FalseLbl, Pred)], ConstTab};
cons ->
{hipe_tagscheme:test_cons(X, TrueLbl, FalseLbl, Pred), ConstTab};
- constant ->
- {hipe_tagscheme:test_constant(X, TrueLbl, FalseLbl, Pred), ConstTab};
fixnum ->
{hipe_tagscheme:test_fixnum(X, TrueLbl, FalseLbl, Pred), ConstTab};
float ->
@@ -439,6 +437,8 @@ gen_type_test([X], Type, TrueLbl, FalseLbl, Pred, ConstTab) ->
{hipe_tagscheme:test_integer(X, TrueLbl, FalseLbl, Pred), ConstTab};
list ->
{hipe_tagscheme:test_list(X, TrueLbl, FalseLbl, Pred), ConstTab};
+ map ->
+ {hipe_tagscheme:test_map(X, TrueLbl, FalseLbl, Pred), ConstTab};
nil ->
{hipe_tagscheme:test_nil(X, TrueLbl, FalseLbl, Pred), ConstTab};
number ->
diff --git a/lib/hipe/rtl/hipe_rtl.erl b/lib/hipe/rtl/hipe_rtl.erl
index 4bf4eb6bd7..bc61bec0bd 100644
--- a/lib/hipe/rtl/hipe_rtl.erl
+++ b/lib/hipe/rtl/hipe_rtl.erl
@@ -29,7 +29,7 @@
%% <li> {alu, Dst, Src1, Op, Src2} </li>
%% <li> {alub, Dst, Src1, Op, Src2, RelOp, TrueLabel, FalseLabel, P} </li>
%% <li> {branch, Src1, Src2, RelOp, TrueLabel, FalseLabel, P} </li>
-%% <li> {call, DsListt, Fun, ArgList, Type, Continuation, FailContinuation}
+%% <li> {call, DsListt, Fun, ArgList, Type, Continuation, FailContinuation, NormalContinuation}
%% Type is one of {local, remote, primop, closure} </li>
%% <li> {comment, Text} </li>
%% <li> {enter, Fun, ArgList, Type}
@@ -106,7 +106,7 @@
%% rtl_data_update/2,
%% rtl_var_range/1,
%% rtl_var_range_update/2,
- %% rtl_label_range/1,
+ rtl_label_range/1,
%% rtl_label_range_update/2,
rtl_info/1,
rtl_info_update/2]).
@@ -226,6 +226,7 @@
%% goto_label_update/2,
mk_call/6,
+ mk_call/7,
call_fun/1,
call_dstlist/1,
call_dstlist_update/2,
@@ -233,8 +234,10 @@
call_continuation/1,
call_fail/1,
call_type/1,
+ call_normal/1,
+ call_normal_update/2,
%% call_continuation_update/2,
- %% call_fail_update/2,
+ call_fail_update/2,
is_call/1,
mk_enter/3,
@@ -290,10 +293,13 @@
%% fconv_src_update/2,
%% is_fconv/1,
- %% mk_var/1,
+ mk_var/1,
+ mk_var/2,
mk_new_var/0,
is_var/1,
var_index/1,
+ var_liveness/1,
+ var_liveness_update/2,
%% change_vars_to_regs/1,
@@ -350,10 +356,15 @@
%% move_dst_update/2,
fixnumop_dst_update/2,
pp_instr/2,
- %% pp_arg/2,
+ %% Uber hack!
+ pp_var/2,
+ pp_reg/2,
+ pp_arg/2,
phi_arglist_update/2,
phi_redirect_pred/3]).
+-export([subst_uses_llvm/2]).
+
-export_type([alub_cond/0]).
%%
@@ -387,7 +398,7 @@ rtl_data(#rtl{data=Data}) -> Data.
%% rtl_data_update(Rtl, Data) -> Rtl#rtl{data=Data}.
%% rtl_var_range(#rtl{var_range=VarRange}) -> VarRange.
%% rtl_var_range_update(Rtl, VarRange) -> Rtl#rtl{var_range=VarRange}.
-%% rtl_label_range(#rtl{label_range=LabelRange}) -> LabelRange.
+rtl_label_range(#rtl{label_range=LabelRange}) -> LabelRange.
%% rtl_label_range_update(Rtl, LabelRange) -> Rtl#rtl{label_range=LabelRange}.
rtl_info(#rtl{info=Info}) -> Info.
rtl_info_update(Rtl, Info) -> Rtl#rtl{info=Info}.
@@ -643,6 +654,17 @@ is_goto(_) -> false.
%% call
%%
+%% LLVM: Call with normal continuation
+mk_call(DstList, Fun, ArgList, Continuation, FailContinuation,
+ NormalContinuation, Type) ->
+ case Type of
+ remote -> ok;
+ not_remote -> ok
+ end,
+ #call{dstlist=DstList, 'fun'=Fun, arglist=ArgList, type=Type,
+ continuation=Continuation, failcontinuation=FailContinuation,
+ normalcontinuation=NormalContinuation}.
+
mk_call(DstList, Fun, ArgList, Continuation, FailContinuation, Type) ->
case Type of
remote -> ok;
@@ -651,6 +673,10 @@ mk_call(DstList, Fun, ArgList, Continuation, FailContinuation, Type) ->
#call{dstlist=DstList, 'fun'=Fun, arglist=ArgList, type=Type,
continuation=Continuation,
failcontinuation=FailContinuation}.
+
+call_normal(#call{normalcontinuation=NormalContinuation}) -> NormalContinuation.
+call_normal_update(C, NewNormalContinuation) ->
+ C#call{normalcontinuation=NewNormalContinuation}.
call_dstlist(#call{dstlist=DstList}) -> DstList.
call_dstlist_update(C, NewDstList) -> C#call{dstlist=NewDstList}.
call_fun(#call{'fun'=Fun}) -> Fun.
@@ -853,11 +879,14 @@ reg_is_gcsafe(#rtl_reg{is_gc_safe=IsGcSafe}) -> IsGcSafe.
is_reg(#rtl_reg{}) -> true;
is_reg(_) -> false.
--record(rtl_var, {index :: non_neg_integer()}).
+-record(rtl_var, {index :: non_neg_integer(), liveness=live :: dead | live}).
mk_var(Num) when is_integer(Num), Num >= 0 -> #rtl_var{index=Num}.
+mk_var(Num, Liveness) when is_integer(Num), Num>=0 -> #rtl_var{index=Num, liveness=Liveness}.
mk_new_var() -> mk_var(hipe_gensym:get_next_var(rtl)).
var_index(#rtl_var{index=Index}) -> Index.
+var_liveness(#rtl_var{liveness=Liveness}) -> Liveness.
+var_liveness_update(RtlVar, Liveness) -> RtlVar#rtl_var{liveness=Liveness}.
is_var(#rtl_var{}) -> true;
is_var(_) -> false.
@@ -1077,6 +1106,131 @@ subst_uses(Subst, I) ->
switch_src_update(I, subst1(Subst, switch_src(I)))
end.
+subst_uses_llvm(Subst, I) ->
+ case I of
+ #alu{} ->
+ {NewSrc2, Subst1} = subst1_llvm(Subst, alu_src2(I)),
+ {NewSrc1, _ } = subst1_llvm(Subst1, alu_src1(I)),
+ I0 = alu_src1_update(I, NewSrc1),
+ alu_src2_update(I0, NewSrc2);
+ #alub{} ->
+ {NewSrc2, Subst1} = subst1_llvm(Subst, alub_src2(I)),
+ {NewSrc1, _ } = subst1_llvm(Subst1, alub_src1(I)),
+ I0 = alub_src1_update(I, NewSrc1),
+ alub_src2_update(I0, NewSrc2);
+ #branch{} ->
+ {NewSrc2, Subst1} = subst1_llvm(Subst, branch_src2(I)),
+ {NewSrc1, _ } = subst1_llvm(Subst1, branch_src1(I)),
+ I0 = branch_src1_update(I, NewSrc1),
+ branch_src2_update(I0, NewSrc2);
+ #call{} ->
+ case call_is_known(I) of
+ false ->
+ {NewFun, Subst1} = subst1_llvm(Subst, call_fun(I)),
+ {NewArgList, _} = subst_list_llvm(Subst1, call_arglist(I)),
+ I0 = call_fun_update(I, NewFun),
+ call_arglist_update(I0, NewArgList);
+ true ->
+ {NewArgList, _} = subst_list_llvm(Subst, call_arglist(I)),
+ call_arglist_update(I, NewArgList)
+ end;
+ #comment{} ->
+ I;
+ #enter{} ->
+ case enter_is_known(I) of
+ false ->
+ {NewFun, Subst1} = subst1_llvm(Subst, enter_fun(I)),
+ {NewArgList, _} = subst_list_llvm(Subst1, enter_arglist(I)),
+ I0 = enter_fun_update(I, NewFun),
+ enter_arglist_update(I0, NewArgList);
+ true ->
+ {NewArgList, _} = subst_list_llvm(Subst, enter_arglist(I)),
+ enter_arglist_update(I, NewArgList)
+ end;
+ #fconv{} ->
+ {NewSrc, _ } = subst1_llvm(Subst, fconv_src(I)),
+ fconv_src_update(I, NewSrc);
+ #fixnumop{} ->
+ {NewSrc, _ } = subst1_llvm(Subst, fixnumop_src(I)),
+ fixnumop_src_update(I, NewSrc);
+ #fload{} ->
+ {NewSrc, Subst1} = subst1_llvm(Subst, fload_src(I)),
+ {NewOffset, _ } = subst1_llvm(Subst1, fload_offset(I)),
+ I0 = fload_src_update(I, NewSrc),
+ fload_offset_update(I0, NewOffset);
+ #fmove{} ->
+ {NewSrc, _ } = subst1_llvm(Subst, fmove_src(I)),
+ fmove_src_update(I, NewSrc);
+ #fp{} ->
+ {NewSrc2, Subst1} = subst1_llvm(Subst, fp_src2(I)),
+ {NewSrc1, _ } = subst1_llvm(Subst1, fp_src1(I)),
+ I0 = fp_src1_update(I, NewSrc1),
+ fp_src2_update(I0, NewSrc2);
+ #fp_unop{} ->
+ {NewSrc, _ } = subst1_llvm(Subst, fp_unop_src(I)),
+ fp_unop_src_update(I, NewSrc);
+ #fstore{} ->
+ {NewSrc, Subst1} = subst1_llvm(Subst, fstore_src(I)),
+ {NewBase, Subst2} = subst1_llvm(Subst1, fstore_base(I)),
+ {NewOffset, _ } = subst1_llvm(Subst2, fstore_offset(I)),
+ I0 = fstore_src_update(I, NewSrc),
+ I1 = fstore_base_update(I0, NewBase),
+ fstore_offset_update(I1, NewOffset);
+ #goto{} ->
+ I;
+ #goto_index{} ->
+ I;
+ #gctest{} ->
+ {NewWords, _ } = subst1_llvm(Subst, gctest_words(I)),
+ gctest_words_update(I, NewWords);
+ #label{} ->
+ I;
+ #load{} ->
+ {NewSrc, Subst1} = subst1_llvm(Subst, load_src(I)),
+ {NewOffset, _ } = subst1_llvm(Subst1, load_offset(I)),
+ I0 = load_src_update(I, NewSrc),
+ load_offset_update(I0, NewOffset);
+ #load_address{} ->
+ I;
+ #load_atom{} ->
+ I;
+ #load_word_index{} ->
+ I;
+ #move{} ->
+ {NewSrc, _ } = subst1_llvm(Subst, move_src(I)),
+ move_src_update(I, NewSrc);
+ #multimove{} ->
+ {NewSrcList, _} = subst_list_llvm(Subst, multimove_srclist(I)),
+ multimove_srclist_update(I, NewSrcList);
+ #phi{} ->
+ phi_argvar_subst(I, Subst);
+ #return{} ->
+ {NewVarList, _} = subst_list_llvm(Subst, return_varlist(I)),
+ return_varlist_update(I, NewVarList);
+ #store{} ->
+ {NewSrc, Subst1} = subst1_llvm(Subst, store_src(I)),
+ {NewBase, Subst2} = subst1_llvm(Subst1, store_base(I)),
+ {NewOffset, _ } = subst1_llvm(Subst2, store_offset(I)),
+ I0 = store_src_update(I, NewSrc),
+ I1 = store_base_update(I0, NewBase),
+ store_offset_update(I1, NewOffset);
+ #switch{} ->
+ {NewSrc, _ } = subst1_llvm(Subst, switch_src(I)),
+ switch_src_update(I, NewSrc)
+ end.
+
+subst_list_llvm(S,X) -> subst_list_llvm(S, lists:reverse(X), []).
+subst_list_llvm(S, [], Acc) -> {Acc, S};
+subst_list_llvm(S, [X|Xs], Acc) ->
+ {NewX, RestS} = subst1_llvm(S, X),
+ subst_list_llvm(RestS, Xs, [NewX|Acc]).
+
+subst1_llvm(A,B) -> subst1_llvm(A,B,[]).
+
+subst1_llvm([], X, Acc) -> {X, Acc};
+subst1_llvm([{X,Y}|Rs], X, Acc) -> {Y, Acc++Rs};
+subst1_llvm([R|Xs], X, Acc) -> subst1_llvm(Xs,X,[R|Acc]).
+
subst_defines(Subst, I)->
case I of
#alu{} ->
@@ -1614,7 +1768,11 @@ pp_var(Dev, Arg) ->
true ->
pp_hard_reg(Dev, var_index(Arg));
false ->
- io:format(Dev, "v~w", [var_index(Arg)])
+ io:format(Dev, "v~w", [var_index(Arg)]),
+ case var_liveness(Arg) of
+ dead -> io:format(Dev, "(dead)", []);
+ _ -> ok
+ end
end.
pp_arg(Dev, A) ->
diff --git a/lib/hipe/rtl/hipe_rtl.hrl b/lib/hipe/rtl/hipe_rtl.hrl
index 974e40f830..fbdf9ac524 100644
--- a/lib/hipe/rtl/hipe_rtl.hrl
+++ b/lib/hipe/rtl/hipe_rtl.hrl
@@ -28,7 +28,8 @@
-record(alu, {dst, src1, op, src2}).
-record(alub, {dst, src1, op, src2, 'cond', true_label, false_label, p}).
-record(branch, {src1, src2, 'cond', true_label, false_label, p}).
--record(call, {dstlist, 'fun', arglist, type, continuation, failcontinuation}).
+-record(call, {dstlist, 'fun', arglist, type, continuation,
+ failcontinuation, normalcontinuation = []}).
-record(comment, {text}).
-record(enter, {'fun', arglist, type}).
-record(fconv, {dst, src}).
diff --git a/lib/hipe/rtl/hipe_rtl_liveness.erl b/lib/hipe/rtl/hipe_rtl_liveness.erl
index 3cfada9d6c..0c4b6b2e11 100644
--- a/lib/hipe/rtl/hipe_rtl_liveness.erl
+++ b/lib/hipe/rtl/hipe_rtl_liveness.erl
@@ -34,7 +34,8 @@
-module(hipe_rtl_liveness).
-%% -define(LIVEOUT_NEEDED,true). % needed for liveness.inc below.
+%% -define(DEBUG_LIVENESS,true).
+-define(LIVEOUT_NEEDED,true). % needed for liveness.inc below.
-define(PRETTY_PRINT,false).
-include("hipe_rtl.hrl").
diff --git a/lib/hipe/rtl/hipe_tagscheme.erl b/lib/hipe/rtl/hipe_tagscheme.erl
index f1e8d1ef41..c27c682915 100644
--- a/lib/hipe/rtl/hipe_tagscheme.erl
+++ b/lib/hipe/rtl/hipe_tagscheme.erl
@@ -39,14 +39,13 @@
test_tuple/4, test_atom/4, test_bignum/4, test_pos_bignum/4,
test_any_pid/4, test_any_port/4,
test_ref/4, test_fun/4, test_fun2/5, test_matchstate/4,
- test_binary/4, test_bitstr/4, test_list/4,
- test_integer/4, test_number/4, test_constant/4, test_tuple_N/5]).
+ test_binary/4, test_bitstr/4, test_list/4, test_map/4,
+ test_integer/4, test_number/4, test_tuple_N/5]).
-export([realtag_fixnum/2, tag_fixnum/2, realuntag_fixnum/2, untag_fixnum/2]).
-export([test_two_fixnums/3, test_fixnums/4, unsafe_fixnum_add/3,
unsafe_fixnum_sub/3,
fixnum_gt/5, fixnum_lt/5, fixnum_ge/5, fixnum_le/5, fixnum_val/1,
- fixnum_mul/4,
- fixnum_addsub/5, fixnum_andorxor/4, fixnum_not/2,
+ fixnum_mul/4, fixnum_addsub/5, fixnum_andorxor/4, fixnum_not/2,
fixnum_bsr/3, fixnum_bsl/3]).
-export([unsafe_car/2, unsafe_cdr/2,
unsafe_constant_element/3, unsafe_update_element/3, element/6]).
@@ -113,13 +112,15 @@
-define(TAG_HEADER_EXTERNAL_PID, ((16#C bsl ?TAG_PRIMARY_SIZE) bor ?TAG_PRIMARY_HEADER)).
-define(TAG_HEADER_EXTERNAL_PORT,((16#D bsl ?TAG_PRIMARY_SIZE) bor ?TAG_PRIMARY_HEADER)).
-define(TAG_HEADER_EXTERNAL_REF, ((16#E bsl ?TAG_PRIMARY_SIZE) bor ?TAG_PRIMARY_HEADER)).
+-define(TAG_HEADER_MAP, ((16#F bsl ?TAG_PRIMARY_SIZE) bor ?TAG_PRIMARY_HEADER)).
-define(TAG_HEADER_MASK, 16#3F).
-define(HEADER_ARITY_OFFS, 6).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-mk_header(SZ,TAG) -> (SZ bsl ?HEADER_ARITY_OFFS) + TAG.
+mk_header(SZ, TAG) -> (SZ bsl ?HEADER_ARITY_OFFS) + TAG.
+
mk_arityval(SZ) -> mk_header(SZ, ?TAG_HEADER_ARITYVAL).
size_from_header(Sz, Header) ->
@@ -133,9 +134,9 @@ mk_var_header(Header, Size, Tag) ->
mk_fixnum(X) -> (X bsl ?TAG_IMMED1_SIZE) + ?TAG_IMMED1_SMALL.
-define(NIL, ((-1 bsl ?TAG_IMMED2_SIZE) bor ?TAG_IMMED2_NIL)).
-mk_nil() -> ?NIL.
-%% mk_atom(X) -> (X bsl ?TAG_IMMED2_SIZE) + ?TAG_IMMED2_ATOM.
-mk_non_value() -> ?THE_NON_VALUE.
+mk_nil() -> ?NIL.
+%% mk_atom(X) -> (X bsl ?TAG_IMMED2_SIZE) + ?TAG_IMMED2_ATOM.
+mk_non_value() -> ?THE_NON_VALUE.
-spec is_fixnum(integer()) -> boolean().
is_fixnum(N) when is_integer(N) ->
@@ -253,6 +254,15 @@ test_tuple_N(X, N, TrueLab, FalseLab, Pred) ->
hipe_rtl:mk_branch(Tmp, 'eq', hipe_rtl:mk_imm(mk_arityval(N)),
TrueLab, FalseLab, Pred)].
+test_map(X, TrueLab, FalseLab, Pred) ->
+ Tmp = hipe_rtl:mk_new_reg_gcsafe(),
+ HalfTrueLab = hipe_rtl:mk_new_label(),
+ MapMask = ?TAG_HEADER_MASK,
+ [test_is_boxed(X, hipe_rtl:label_name(HalfTrueLab), FalseLab, Pred),
+ HalfTrueLab,
+ get_header(Tmp, X),
+ mask_and_compare(Tmp, MapMask, ?TAG_HEADER_MAP, TrueLab, FalseLab, Pred)].
+
test_ref(X, TrueLab, FalseLab, Pred) ->
Hdr = hipe_rtl:mk_new_reg_gcsafe(),
Tag = hipe_rtl:mk_new_reg_gcsafe(),
@@ -405,17 +415,6 @@ test_number(X, TrueLab, FalseLab, Pred) ->
hipe_rtl:mk_branch(Tmp, 'eq', hipe_rtl:mk_imm(HeaderFlonum),
TrueLab, FalseLab, Pred)].
-%% CONS, NIL, and TUPLE are not constants, everything else is
-test_constant(X, TrueLab, FalseLab, Pred) ->
- Lab1 = hipe_rtl:mk_new_label(),
- Lab2 = hipe_rtl:mk_new_label(),
- Pred1 = 1-Pred,
- [test_cons(X, FalseLab, hipe_rtl:label_name(Lab1), Pred1),
- Lab1,
- test_nil(X, FalseLab, hipe_rtl:label_name(Lab2), Pred1),
- Lab2,
- test_tuple(X, FalseLab, TrueLab, Pred1)].
-
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
tag_fixnum(DestVar, SrcReg) ->
diff --git a/lib/hipe/sparc/hipe_sparc_assemble.erl b/lib/hipe/sparc/hipe_sparc_assemble.erl
index b534fe20ec..68a4e1b349 100644
--- a/lib/hipe/sparc/hipe_sparc_assemble.erl
+++ b/lib/hipe/sparc/hipe_sparc_assemble.erl
@@ -45,8 +45,8 @@ assemble(CompiledCode, Closures, Exports, Options) ->
print("Total num bytes=~w\n", [CodeSize], Options),
%%
SC = hipe_pack_constants:slim_constmap(ConstMap),
- DataRelocs = mk_data_relocs(RefsFromConsts, LabelMap),
- SSE = slim_sorted_exportmap(ExportMap,Closures,Exports),
+ DataRelocs = hipe_pack_constants:mk_data_relocs(RefsFromConsts, LabelMap),
+ SSE = hipe_pack_constants:slim_sorted_exportmap(ExportMap,Closures,Exports),
SlimRefs = hipe_pack_constants:slim_refs(AccRefs),
Bin = term_to_binary([{?VERSION_STRING(),?HIPE_SYSTEM_CRC},
ConstAlign, ConstSize,
@@ -222,7 +222,7 @@ do_pseudo_set(I, MFA, ConstMap) ->
%%% end,
%%% {load_address, {Tag,untag_mfa_or_prim(MFAorPrim)}};
{Label,constant} ->
- ConstNo = find_const({MFA,Label}, ConstMap),
+ ConstNo = hipe_pack_constants:find_const({MFA,Label}, ConstMap),
{load_address, {constant,ConstNo}};
{Label,closure} ->
{load_address, {closure,Label}};
@@ -507,37 +507,6 @@ px({pred,Pred}) -> % XXX: use pt/pn throughout entire backend
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-mk_data_relocs(RefsFromConsts, LabelMap) ->
- lists:flatten(mk_data_relocs(RefsFromConsts, LabelMap, [])).
-
-mk_data_relocs([{MFA,Labels} | Rest], LabelMap, Acc) ->
- Map = [case Label of
- {L,Pos} ->
- Offset = find({MFA,L}, LabelMap),
- {Pos,Offset};
- {sorted,Base,OrderedLabels} ->
- {sorted, Base, [begin
- Offset = find({MFA,L}, LabelMap),
- {Order, Offset}
- end
- || {L,Order} <- OrderedLabels]}
- end
- || Label <- Labels],
- %% msg("Map: ~w Map\n",[Map]),
- mk_data_relocs(Rest, LabelMap, [Map,Acc]);
-mk_data_relocs([],_,Acc) -> Acc.
-
-find({_MFA,_L} = MFAL, LabelMap) ->
- gb_trees:get(MFAL, LabelMap).
-
-slim_sorted_exportmap([{Addr,M,F,A}|Rest], Closures, Exports) ->
- IsClosure = lists:member({M,F,A}, Closures),
- IsExported = is_exported(F, A, Exports),
- [Addr,M,F,A,IsClosure,IsExported | slim_sorted_exportmap(Rest, Closures, Exports)];
-slim_sorted_exportmap([],_,_) -> [].
-
-is_exported(F, A, Exports) -> lists:member({F,A}, Exports).
-
%%%
%%% Assembly listing support (pp_asm option).
%%%
@@ -575,14 +544,3 @@ fill_spaces(N) when N > 0 ->
fill_spaces(N-1);
fill_spaces(0) ->
[].
-
-%%%
-%%% Lookup a constant in a ConstMap.
-%%%
-
-find_const({MFA,Label},[{pcm_entry,MFA,Label,ConstNo,_,_,_}|_]) ->
- ConstNo;
-find_const(N,[_|R]) ->
- find_const(N,R);
-find_const(C,[]) ->
- ?EXIT({constant_not_found,C}).
diff --git a/lib/hipe/test/Makefile b/lib/hipe/test/Makefile
index cedb150b5d..acb2849d0d 100644
--- a/lib/hipe/test/Makefile
+++ b/lib/hipe/test/Makefile
@@ -8,6 +8,10 @@ include $(ERL_TOP)/make/$(TARGET)/otp.mk
MODULES= \
hipe_SUITE
+# .erl files for these modules are automatically generated
+GEN_MODULES= \
+ bs_SUITE
+
ERL_FILES= $(MODULES:%=%.erl)
TARGET_FILES= $(MODULES:%=$(EBIN)/%.$(EMULATOR))
@@ -40,6 +44,8 @@ EBIN = .
make_emakefile:
$(ERL_TOP)/make/make_emakefile $(ERL_COMPILE_FLAGS) -o$(EBIN) $(MODULES) \
> $(EMAKEFILE)
+ $(ERL_TOP)/make/make_emakefile $(ERL_COMPILE_FLAGS) -o$(EBIN) $(GEN_MODULES) \
+ >> $(EMAKEFILE)
$(ERL_TOP)/make/make_emakefile $(ERL_COMPILE_FLAGS) -o$(EBIN) '*_SUITE_make' \
>> $(EMAKEFILE)
diff --git a/lib/hipe/test/hipe_testsuite_driver.erl b/lib/hipe/test/hipe_testsuite_driver.erl
index c8fdf1600c..5f05a716bc 100644
--- a/lib/hipe/test/hipe_testsuite_driver.erl
+++ b/lib/hipe/test/hipe_testsuite_driver.erl
@@ -85,7 +85,7 @@ list_testcases(Dirname) ->
list_dir(Dir, Extension, Dirs) ->
case file:list_dir(Dir) of
- {error, _} = Error-> Error;
+ {error, _} = Error -> Error;
{ok, Filenames} ->
FullFilenames = [filename:join(Dir, F) || F <- Filenames],
Matches1 = case Dirs of
@@ -173,10 +173,29 @@ run(TestCase, Dir, _OutDir) ->
%% end, DataFiles),
%% try
ok = TestCase:test(),
- HiPEOpts = try TestCase:hipe_options() catch _:_ -> [] end,
+ HiPEOpts = try TestCase:hipe_options() catch error:undef -> [] end,
{ok, TestCase} = hipe:c(TestCase, HiPEOpts),
- ok = TestCase:test().
+ ok = TestCase:test(),
+ case is_llvm_opt_available() of
+ true ->
+ {ok, TestCase} = hipe:c(TestCase, [to_llvm|HiPEOpts]),
+ ok = TestCase:test();
+ false -> ok
+ end.
%% after
%% lists:foreach(fun (DF) -> ok end, % = file:delete(DF) end,
%% [filename:join(OutDir, D) || D <- DataFiles])
%% end.
+
+
+%% This function, which is supposed to check whether the right LLVM
+%% infrastructure is available, should be probably written in a better
+%% and more portable way and moved to the hipe application.
+
+is_llvm_opt_available() ->
+ OptStr = os:cmd("opt -version"),
+ SubStr = "LLVM version ", N = length(SubStr),
+ case string:str(OptStr, SubStr) of
+ 0 -> false;
+ S -> P = S + N, string:sub_string(OptStr, P, P + 2) >= "3.4"
+ end.
diff --git a/lib/hipe/vsn.mk b/lib/hipe/vsn.mk
index ed4b4dc8d2..fb7e4b91a0 100644
--- a/lib/hipe/vsn.mk
+++ b/lib/hipe/vsn.mk
@@ -1 +1 @@
-HIPE_VSN = 3.10.2.2
+HIPE_VSN = 3.10.3
diff --git a/lib/hipe/x86/hipe_x86_assemble.erl b/lib/hipe/x86/hipe_x86_assemble.erl
index 7878c7219d..3f756769c4 100644
--- a/lib/hipe/x86/hipe_x86_assemble.erl
+++ b/lib/hipe/x86/hipe_x86_assemble.erl
@@ -21,7 +21,6 @@
%%%
%%% TODO:
%%% - Simplify combine_label_maps and mk_data_relocs.
-%%% - Move find_const to hipe_pack_constants?
-ifdef(HIPE_AMD64).
-define(HIPE_X86_ASSEMBLE, hipe_amd64_assemble).
@@ -80,8 +79,8 @@ assemble(CompiledCode, Closures, Exports, Options) ->
%% ?debug_msg("Constants are ~w bytes\n",[ConstSize])),
%%
SC = hipe_pack_constants:slim_constmap(ConstMap),
- DataRelocs = mk_data_relocs(RefsFromConsts, LabelMap),
- SSE = slim_sorted_exportmap(ExportMap,Closures,Exports),
+ DataRelocs = hipe_pack_constants:mk_data_relocs(RefsFromConsts, LabelMap),
+ SSE = hipe_pack_constants:slim_sorted_exportmap(ExportMap,Closures,Exports),
SlimRefs = hipe_pack_constants:slim_refs(AccRefs),
Bin = term_to_binary([{?VERSION_STRING(),?HIPE_SYSTEM_CRC},
ConstAlign, ConstSize,
@@ -442,7 +441,7 @@ translate_imm(#x86_imm{value=Imm}, Context, MayTrunc8) ->
case Imm of
{Label,constant} ->
{MFA,ConstMap} = Context,
- ConstNo = find_const({MFA,Label}, ConstMap),
+ ConstNo = hipe_pack_constants:find_const({MFA,Label}, ConstMap),
{constant,ConstNo};
{Label,closure} ->
{closure,Label};
@@ -712,7 +711,7 @@ resolve_jmp_switch_arg(I, _Context) ->
{rm64,hipe_amd64_encode:rm_mem(EA)}.
-else.
resolve_jmp_switch_arg(I, {MFA,ConstMap}) ->
- ConstNo = find_const({MFA,hipe_x86:jmp_switch_jtab(I)}, ConstMap),
+ ConstNo = hipe_pack_constants:find_const({MFA,hipe_x86:jmp_switch_jtab(I)}, ConstMap),
Disp32 = {?LOAD_ADDRESS,{constant,ConstNo}},
SINDEX = ?HIPE_X86_ENCODE:sindex(2, hipe_x86:temp_reg(hipe_x86:jmp_switch_temp(I))),
EA = ?HIPE_X86_ENCODE:ea_disp32_sindex(Disp32, SINDEX), % this creates a SIB implicitly
@@ -932,37 +931,6 @@ resolve_x87_binop_args(Src=#x86_fpreg{}, Dst=#x86_fpreg{})->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-mk_data_relocs(RefsFromConsts, LabelMap) ->
- lists:flatten(mk_data_relocs(RefsFromConsts, LabelMap, [])).
-
-mk_data_relocs([{MFA,Labels} | Rest], LabelMap, Acc) ->
- Map = [case Label of
- {L,Pos} ->
- Offset = find({MFA,L}, LabelMap),
- {Pos,Offset};
- {sorted,Base,OrderedLabels} ->
- {sorted, Base, [begin
- Offset = find({MFA,L}, LabelMap),
- {Order, Offset}
- end
- || {L,Order} <- OrderedLabels]}
- end
- || Label <- Labels],
- %% msg("Map: ~w Map\n",[Map]),
- mk_data_relocs(Rest, LabelMap, [Map,Acc]);
-mk_data_relocs([],_,Acc) -> Acc.
-
-find({MFA,L},LabelMap) ->
- gb_trees:get({MFA,L}, LabelMap).
-
-slim_sorted_exportmap([{Addr,M,F,A}|Rest], Closures, Exports) ->
- IsClosure = lists:member({M,F,A}, Closures),
- IsExported = is_exported(F, A, Exports),
- [Addr,M,F,A,IsClosure,IsExported | slim_sorted_exportmap(Rest, Closures, Exports)];
-slim_sorted_exportmap([],_,_) -> [].
-
-is_exported(F, A, Exports) -> lists:member({F,A}, Exports).
-
%%%
%%% Assembly listing support (pp_asm option).
%%%
@@ -1001,14 +969,3 @@ fill_spaces(N) when N > 0 ->
fill_spaces(N-1);
fill_spaces(0) ->
[].
-
-%%%
-%%% Lookup a constant in a ConstMap.
-%%%
-
-find_const({MFA,Label},[{pcm_entry,MFA,Label,ConstNo,_,_,_}|_]) ->
- ConstNo;
-find_const(N,[_|R]) ->
- find_const(N,R);
-find_const(C,[]) ->
- ?EXIT({constant_not_found,C}).
diff --git a/lib/ic/src/ic.app.src b/lib/ic/src/ic.app.src
index 29aa6def00..7dd47ac9c6 100644
--- a/lib/ic/src/ic.app.src
+++ b/lib/ic/src/ic.app.src
@@ -46,7 +46,8 @@
{registered, []},
{applications, [stdlib, kernel]},
{env, []},
- {mod, {ic, []}}
+ {mod, {ic, []}},
+ {runtime_dependencies, ["stdlib-2.0","kernel-3.0","erts-6.0"]}
]}.
diff --git a/lib/ic/src/ic.erl b/lib/ic/src/ic.erl
index c0742cf7bd..4f3e8d180c 100644
--- a/lib/ic/src/ic.erl
+++ b/lib/ic/src/ic.erl
@@ -250,7 +250,7 @@ make_erl_options(Opts) ->
Optimize = Opts#options.optimize,
PreProc =
lists:flatten(
- lists:map(fun(D) -> io_lib:format("-I\"~s\" ", [ic_util:to_list(D)]) end,
+ lists:map(fun(D) -> io_lib:format("-I\"~ts\" ", [ic_util:to_list(D)]) end,
Includes1)++
lists:map(
fun ({Name, Value}) ->
diff --git a/lib/ic/src/ic_codegen.erl b/lib/ic/src/ic_codegen.erl
index f611c69bea..82431b79a2 100644
--- a/lib/ic/src/ic_codegen.erl
+++ b/lib/ic/src/ic_codegen.erl
@@ -216,12 +216,14 @@ exp_to_string({F,N}) -> io_lib:format("~p/~p", [ic_util:to_atom(F), N]).
%%--------------------------------------------------------------------
emit_stub_head(_G, ignore, _Name, _) -> ignore;
emit_stub_head(G, F1, Name, erlang) ->
+ comment(F1, " coding: latin-1", []),
mcomment(F1, stub_header(G, Name)),
nl(F1),
emit(F1, "-module(~p).\n", [list_to_atom(Name)]),
emit(F1, "-ic_compiled(~p).\n", [compiler_vsn(?COMPILERVSN)]),
emit(F1, "\n\n"), F1;
emit_stub_head(G, F1, Name, erlang_template) ->
+ comment(F1, " coding: latin-1", []),
ic_erl_template:emit_header(G, F1, Name),
F1;
emit_stub_head(_G, F1, _Name, erlang_template_no_gen) ->
@@ -259,6 +261,7 @@ compiler_vsn(Vsn) ->
%% Name is Fully scoped (undescore) name of interface or module
emit_hrl_head(_G, ignore, _Name, _) -> ignore;
emit_hrl_head(G, Fd, Name, erlang) ->
+ comment(Fd, " coding: latin-1", []),
mcomment(Fd, ["Erlang header file" |
hrl_header(G, Name)]),
nl(Fd),
diff --git a/lib/ic/src/ic_pp.erl b/lib/ic/src/ic_pp.erl
index 54701f7438..e54304ebaa 100644
--- a/lib/ic/src/ic_pp.erl
+++ b/lib/ic/src/ic_pp.erl
@@ -257,15 +257,15 @@ run_include(FileName, FileList, _Out, Defs, Err, War, IncLine, IncFile, IncDir,
tokenise(File, FileName) ->
{Result, _L} = token(File, 2, [], not_set, 0),
- FI_start = lists:reverse(lists:flatten(io_lib:format("# 1 ~p~n",[FileName]))),
+ FI_start = lists:reverse(lists:flatten(io_lib:format("# 1 \"~ts\"~n",[FileName]))),
FileInfoStart = {file_info, FI_start},
[FileInfoStart | Result].
tokenise(File, FileName, IncLine, PrevFile) ->
{Result, _L} = token(File, 2, [], not_set, 0),
- FI_start = lists:reverse(lists:flatten(io_lib:format("# 1 ~p 1~n",[FileName]))),
+ FI_start = lists:reverse(lists:flatten(io_lib:format("# 1 \"~ts\" 1~n",[FileName]))),
FileInfoStart = {file_info, FI_start},
- FI_end = lists:reverse(lists:flatten(io_lib:format("# ~p ~p 2~n~n",[IncLine-1,PrevFile]))),
+ FI_end = lists:reverse(lists:flatten(io_lib:format("# ~p \"~ts\" 2~n~n",[IncLine-1,PrevFile]))),
FileInfoEnd = [{file_info, FI_end}],
{Result, FileInfoStart, FileInfoEnd}.
% [FileInfoStart | Result] ++ FileInfoEnd.
@@ -1942,7 +1942,7 @@ read_inc_file(FileName, IncDir, Mio) ->
FileList = binary_to_list(Bin),
{ok, AbsFile, FileList};
{error, Text} ->
- {error, Text}
+ {error, Text}
end;
true ->
skip
diff --git a/lib/ic/test/java_client_erl_server_SUITE.erl b/lib/ic/test/java_client_erl_server_SUITE.erl
index 9e49305c3c..cbcf32515e 100644
--- a/lib/ic/test/java_client_erl_server_SUITE.erl
+++ b/lib/ic/test/java_client_erl_server_SUITE.erl
@@ -288,7 +288,7 @@ classpath(Dir) ->
cmd(Cmd) ->
PortOpts = [{line,80},eof,exit_status,stderr_to_stdout],
- io:format("<cmd> ~s~n", [Cmd]),
+ io:format("<cmd> ~ts~n", [Cmd]),
case catch open_port({spawn,Cmd}, PortOpts) of
Port when is_port(Port) ->
Result = cmd_loop(Port, []),
diff --git a/lib/ic/vsn.mk b/lib/ic/vsn.mk
index fe27d095d3..2ffbbad444 100644
--- a/lib/ic/vsn.mk
+++ b/lib/ic/vsn.mk
@@ -1 +1 @@
-IC_VSN = 4.3.4
+IC_VSN = 4.3.5
diff --git a/lib/inets/src/http_client/httpc_cookie.erl b/lib/inets/src/http_client/httpc_cookie.erl
index 69900bae65..134115bdfa 100644
--- a/lib/inets/src/http_client/httpc_cookie.erl
+++ b/lib/inets/src/http_client/httpc_cookie.erl
@@ -335,7 +335,8 @@ add_domain(Str, #http_cookie{domain = Domain}) ->
Str ++ "; $Domain=" ++ Domain.
parse_set_cookies(CookieHeaders, DefaultPathDomain) ->
- SetCookieHeaders = [Value || {"set-cookie", Value} <- CookieHeaders],
+ %% empty Set-Cookie header is invalid according to RFC but some sites violate it
+ SetCookieHeaders = [Value || {"set-cookie", Value} <- CookieHeaders, Value /= ""],
Cookies = [parse_set_cookie(SetCookieHeader, DefaultPathDomain) ||
SetCookieHeader <- SetCookieHeaders],
%% print_cookies("Parsed Cookies", Cookies),
diff --git a/lib/inets/src/http_client/httpc_handler.erl b/lib/inets/src/http_client/httpc_handler.erl
index a89a457a51..88e08be789 100644
--- a/lib/inets/src/http_client/httpc_handler.erl
+++ b/lib/inets/src/http_client/httpc_handler.erl
@@ -1119,15 +1119,8 @@ handle_http_body(Body, #state{headers = Headers,
handle_response(State#state{headers = NewHeaders,
body = NewBody})
end;
- Encoding when is_list(Encoding) ->
- ?hcrt("handle_http_body - encoding", [{encoding, Encoding}]),
- NewState = answer_request(Request,
- httpc_response:error(Request,
- unknown_encoding),
- State),
- {stop, normal, NewState};
- _ ->
- ?hcrt("handle_http_body - other", []),
+ Enc when Enc =:= "identity"; Enc =:= undefined ->
+ ?hcrt("handle_http_body - identity", []),
Length =
list_to_integer(Headers#http_response_h.'content-length'),
case ((Length =< MaxBodySize) orelse (MaxBodySize =:= nolimit)) of
@@ -1149,12 +1142,19 @@ handle_http_body(Body, #state{headers = Headers,
body_too_big),
State),
{stop, normal, NewState}
- end
+ end;
+ Encoding when is_list(Encoding) ->
+ ?hcrt("handle_http_body - other", [{encoding, Encoding}]),
+ NewState = answer_request(Request,
+ httpc_response:error(Request,
+ unknown_encoding),
+ State),
+ {stop, normal, NewState}
end.
handle_response(#state{status = new} = State) ->
?hcrd("handle response - status = new", []),
- handle_response(check_persistent(State));
+ handle_response(try_to_enable_pipeline_or_keep_alive(State));
handle_response(#state{request = Request,
status = Status,
@@ -1429,22 +1429,39 @@ is_keep_alive_enabled_server(_,_) ->
is_keep_alive_connection(Headers, #session{client_close = ClientClose}) ->
(not ((ClientClose) orelse httpc_response:is_server_closing(Headers))).
-check_persistent(
- #state{session = #session{type = Type} = Session,
+try_to_enable_pipeline_or_keep_alive(
+ #state{session = Session,
+ request = #request{method = Method},
status_line = {Version, _, _},
headers = Headers,
- profile_name = ProfileName} = State) ->
+ profile_name = ProfileName} = State) ->
+ ?hcrd("try to enable pipeline or keep-alive",
+ [{version, Version},
+ {headers, Headers},
+ {session, Session}]),
case is_keep_alive_enabled_server(Version, Headers) andalso
- is_keep_alive_connection(Headers, Session) of
+ is_keep_alive_connection(Headers, Session) of
true ->
- mark_persistent(ProfileName, Session),
- State#state{status = Type};
+ case (is_pipeline_enabled_client(Session) andalso
+ httpc_request:is_idempotent(Method)) of
+ true ->
+ insert_session(Session, ProfileName),
+ State#state{status = pipeline};
+ false ->
+ insert_session(Session, ProfileName),
+ %% Make sure type is keep_alive in session
+ %% as it in this case might be pipeline
+ NewSession = Session#session{type = keep_alive},
+ State#state{status = keep_alive,
+ session = NewSession}
+ end;
false ->
State#state{status = close}
end.
answer_request(#request{id = RequestId, from = From} = Request, Msg,
- #state{timers = Timers,
+ #state{session = Session,
+ timers = Timers,
profile_name = ProfileName} = State) ->
?hcrt("answer request", [{request, Request}, {msg, Msg}]),
httpc_response:send(From, Msg),
@@ -1454,14 +1471,19 @@ answer_request(#request{id = RequestId, from = From} = Request, Msg,
Timer = {RequestId, TimerRef},
cancel_timer(TimerRef, {timeout, Request#request.id}),
httpc_manager:request_done(RequestId, ProfileName),
+ NewSession = maybe_make_session_available(ProfileName, Session),
Timers2 = Timers#timers{request_timers = lists:delete(Timer,
RequestTimers)},
State#state{request = Request#request{from = answer_sent},
+ session = NewSession,
timers = Timers2}.
-mark_persistent(ProfileName, Session) ->
- update_session(ProfileName, Session, #session.persistent, true),
- Session#session{persistent = true}.
+maybe_make_session_available(ProfileName,
+ #session{available = false} = Session) ->
+ update_session(ProfileName, Session, #session.available, true),
+ Session#session{available = true};
+maybe_make_session_available(_ProfileName, Session) ->
+ Session.
cancel_timers(#timers{request_timers = ReqTmrs, queue_timer = QTmr}) ->
cancel_timer(QTmr, timeout_queue),
@@ -1829,7 +1851,7 @@ update_session(ProfileName, #session{id = SessionId} = Session, Pos, Value) ->
[ProfileName, SessionId, Pos, Value,
(catch httpc_manager:which_session_info(ProfileName)),
Session,
- (catch httpc_manager:lookup_session(ProfileName, SessionId)),
+ (catch httpc_manager:lookup_session(SessionId, ProfileName)),
T, E]),
exit({failed_updating_session,
[{profile, ProfileName},
diff --git a/lib/inets/src/http_client/httpc_internal.hrl b/lib/inets/src/http_client/httpc_internal.hrl
index d5b3dd2a2a..add5d11dfa 100644
--- a/lib/inets/src/http_client/httpc_internal.hrl
+++ b/lib/inets/src/http_client/httpc_internal.hrl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2005-2013. All Rights Reserved.
+%% Copyright Ericsson AB 2005-2014. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -143,8 +143,8 @@
%% true | false
%% This will be true, when a response has been received for
- %% the first request and the server has not closed the connection
- persistent = false
+ %% the first request. See type above.
+ available = false
}).
diff --git a/lib/inets/src/http_client/httpc_manager.erl b/lib/inets/src/http_client/httpc_manager.erl
index a3ed371e61..48a9c32454 100644
--- a/lib/inets/src/http_client/httpc_manager.erl
+++ b/lib/inets/src/http_client/httpc_manager.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2002-2013. All Rights Reserved.
+%% Copyright Ericsson AB 2002-2014. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -451,7 +451,7 @@ do_init(ProfileName, CookiesDir) ->
%%--------------------------------------------------------------------
handle_call({request, Request}, _, State) ->
?hcri("request", [{request, Request}]),
- case (catch handle_request(Request, State, false)) of
+ case (catch handle_request(Request, State)) of
{reply, Msg, NewState} ->
{reply, Msg, NewState};
Error ->
@@ -511,7 +511,7 @@ handle_cast({retry_or_redirect_request, {Time, Request}},
{noreply, State};
handle_cast({retry_or_redirect_request, Request}, State) ->
- case (catch handle_request(Request, State, true)) of
+ case (catch handle_request(Request, State)) of
{reply, {ok, _}, NewState} ->
{noreply, NewState};
Error ->
@@ -724,7 +724,7 @@ get_handler_info(Tab) ->
handle_request(#request{settings =
#http_options{version = "HTTP/0.9"}} = Request,
- State, _) ->
+ State) ->
%% Act as an HTTP/0.9 client that does not know anything
%% about persistent connections
@@ -737,7 +737,7 @@ handle_request(#request{settings =
handle_request(#request{settings =
#http_options{version = "HTTP/1.0"}} = Request,
- State, _) ->
+ State) ->
%% Act as an HTTP/1.0 client that does not
%% use persistent connections
@@ -748,13 +748,13 @@ handle_request(#request{settings =
start_handler(NewRequest#request{headers = NewHeaders}, State),
{reply, {ok, NewRequest#request.id}, State};
-handle_request(Request, State = #state{options = Options}, Retry) ->
+handle_request(Request, State = #state{options = Options}) ->
NewRequest = handle_cookies(generate_request_id(Request), State),
SessionType = session_type(Options),
case select_session(Request#request.method,
Request#request.address,
- Request#request.scheme, SessionType, State, Retry) of
+ Request#request.scheme, SessionType, State) of
{ok, HandlerPid} ->
pipeline_or_keep_alive(NewRequest, HandlerPid, State);
no_connection ->
@@ -778,7 +778,6 @@ start_handler(#request{id = Id,
#state{profile_name = ProfileName,
handler_db = HandlerDb,
options = Options}) ->
- ClientClose = httpc_request:is_client_closing(Request#request.headers),
{ok, Pid} =
case is_inets_manager() of
true ->
@@ -789,18 +788,13 @@ start_handler(#request{id = Id,
end,
HandlerInfo = {Id, Pid, From},
ets:insert(HandlerDb, HandlerInfo),
- insert_session(#session{id = {Request#request.address, Pid},
- scheme = Request#request.scheme,
- client_close = ClientClose,
- type = session_type(Options)
- }, ProfileName),
erlang:monitor(process, Pid).
select_session(Method, HostPort, Scheme, SessionType,
#state{options = #options{max_pipeline_length = MaxPipe,
max_keep_alive_length = MaxKeepAlive},
- session_db = SessionDb}, Retry) ->
+ session_db = SessionDb}) ->
?hcrd("select session", [{session_type, SessionType},
{max_pipeline_length, MaxPipe},
{max_keep_alive_length, MaxKeepAlive}]),
@@ -813,23 +807,13 @@ select_session(Method, HostPort, Scheme, SessionType,
%% client_close, scheme and type specified.
%% The fields id (part of: HandlerPid) and queue_length
%% specified.
- Pattern = case (Retry andalso SessionType == pipeline) of
- true ->
- #session{id = {HostPort, '$1'},
- client_close = false,
- scheme = Scheme,
- queue_length = '$2',
- type = SessionType,
- persistent = true,
- _ = '_'};
- false ->
- #session{id = {HostPort, '$1'},
- client_close = false,
- scheme = Scheme,
- queue_length = '$2',
- type = SessionType,
- _ = '_'}
- end,
+ Pattern = #session{id = {HostPort, '$1'},
+ client_close = false,
+ scheme = Scheme,
+ queue_length = '$2',
+ type = SessionType,
+ available = true,
+ _ = '_'},
%% {'_', {HostPort, '$1'}, false, Scheme, '_', '$2', SessionTyp},
Candidates = ets:match(SessionDb, Pattern),
?hcrd("select session", [{host_port, HostPort},
diff --git a/lib/inets/src/http_server/httpd_example.erl b/lib/inets/src/http_server/httpd_example.erl
index 16a080f8e2..6fc07f033c 100644
--- a/lib/inets/src/http_server/httpd_example.erl
+++ b/lib/inets/src/http_server/httpd_example.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2009. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2014. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -66,7 +66,7 @@ get_bin(_Env,_Input) ->
<INPUT TYPE=\"text\" NAME=\"input2\">
<INPUT TYPE=\"submit\"><BR>
</FORM>" ++ "\n"),
- footer()].
+ list_to_binary(footer())].
post(_Env,[]) ->
[header(),
diff --git a/lib/inets/src/http_server/httpd_util.erl b/lib/inets/src/http_server/httpd_util.erl
index b0b18b9c3d..0d04a75205 100644
--- a/lib/inets/src/http_server/httpd_util.erl
+++ b/lib/inets/src/http_server/httpd_util.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2011. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2014. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -206,9 +206,6 @@ message(413, Reason,_) ->
"Entity: " ++ html_encode(Reason);
message(414,ReasonPhrase,_) ->
"Message " ++ html_encode(ReasonPhrase) ++ ".";
-message(416,ReasonPhrase,_) ->
- html_encode(ReasonPhrase);
-
message(500,_,ConfigDB) ->
ServerAdmin=lookup(ConfigDB,server_admin,"unknown@unknown"),
"The server encountered an internal error or "
@@ -233,7 +230,9 @@ message(501,{Method, RequestURI, HTTPVersion}, _ConfigDB) ->
end;
message(503, String, _ConfigDB) ->
- "This service in unavailable due to: " ++ html_encode(String).
+ "This service in unavailable due to: " ++ html_encode(String);
+message(_, ReasonPhrase, _) ->
+ html_encode(ReasonPhrase).
maybe_encode(URI) ->
Decoded = try http_uri:decode(URI) of
diff --git a/lib/inets/src/inets_app/inets.app.src b/lib/inets/src/inets_app/inets.app.src
index a6dd364c2d..9eae962d03 100644
--- a/lib/inets/src/inets_app/inets.app.src
+++ b/lib/inets/src/inets_app/inets.app.src
@@ -110,4 +110,6 @@
{registered,[inets_sup, httpc_manager]},
%% If the "new" ssl is used then 'crypto' must be started before inets.
{applications,[kernel,stdlib]},
- {mod,{inets_app,[]}}]}.
+ {mod,{inets_app,[]}},
+ {runtime_dependencies, ["stdlib-2.0","ssl-5.3.4","runtime_tools-1.8.14",
+ "mnesia-4.12","kernel-3.0","erts-6.0"]}]}.
diff --git a/lib/inets/test/Makefile b/lib/inets/test/Makefile
index c156b34406..609396273d 100644
--- a/lib/inets/test/Makefile
+++ b/lib/inets/test/Makefile
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 1997-2013. All Rights Reserved.
+# Copyright Ericsson AB 1997-2014. All Rights Reserved.
#
# The contents of this file are subject to the Erlang Public License,
# Version 1.1, (the "License"); you may not use this file except in
diff --git a/lib/inets/test/httpc_SUITE.erl b/lib/inets/test/httpc_SUITE.erl
index fe6edd504e..b1b799c953 100644
--- a/lib/inets/test/httpc_SUITE.erl
+++ b/lib/inets/test/httpc_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2013. All Rights Reserved.
+%% Copyright Ericsson AB 2004-2014. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -91,6 +91,7 @@ only_simulated() ->
[
cookie,
cookie_profile,
+ empty_set_cookie,
trace,
stream_once,
no_content_204,
@@ -104,6 +105,7 @@ only_simulated() ->
remote_socket_close,
remote_socket_close_async,
transfer_encoding,
+ transfer_encoding_identity,
redirect_loop,
redirect_moved_permanently,
redirect_multiple_choises,
@@ -296,6 +298,9 @@ trace(Config) when is_list(Config) ->
pipeline(Config) when is_list(Config) ->
Request = {url(group_name(Config), "/dummy.html", Config), []},
{ok, _} = httpc:request(get, Request, [], [], pipeline),
+
+ %% Make sure pipeline session is registerd
+ test_server:sleep(4000),
keep_alive_requests(Request, pipeline).
%%--------------------------------------------------------------------
@@ -303,6 +308,9 @@ pipeline(Config) when is_list(Config) ->
persistent_connection(Config) when is_list(Config) ->
Request = {url(group_name(Config), "/dummy.html", Config), []},
{ok, _} = httpc:request(get, Request, [], [], persistent),
+
+ %% Make sure pipeline session is registerd
+ test_server:sleep(4000),
keep_alive_requests(Request, persistent).
%%-------------------------------------------------------------------------
@@ -530,6 +538,19 @@ cookie_profile(Config) when is_list(Config) ->
inets:stop(httpc, cookie_test).
%%-------------------------------------------------------------------------
+empty_set_cookie() ->
+ [{doc, "Test empty Set-Cookie header."}].
+empty_set_cookie(Config) when is_list(Config) ->
+ ok = httpc:set_options([{cookies, enabled}]),
+
+ Request0 = {url(group_name(Config), "/empty_set_cookie.html", Config), []},
+
+ {ok, {{_,200,_}, [_ | _], [_|_]}}
+ = httpc:request(get, Request0, [], []),
+
+ ok = httpc:set_options([{cookies, disabled}]).
+
+%%-------------------------------------------------------------------------
headers_as_is(doc) ->
["Test the option headers_as_is"];
headers_as_is(Config) when is_list(Config) ->
@@ -624,6 +645,12 @@ transfer_encoding(Config) when is_list(Config) ->
%%-------------------------------------------------------------------------
+transfer_encoding_identity(Config) when is_list(Config) ->
+ URL = url(group_name(Config), "/identity_transfer_encoding.html", Config),
+ {ok, {{_,200,_}, [_|_], "IDENTITY"}} = httpc:request(URL).
+
+%%-------------------------------------------------------------------------
+
empty_response_header() ->
[{doc, "Test the case that the HTTP server does not send any headers. Solves OTP-6830"}].
empty_response_header(Config) when is_list(Config) ->
@@ -1609,6 +1636,13 @@ handle_uri(_,"/capital_transfer_encoding.html",_,_,Socket,_) ->
send(Socket, http_chunk:encode("obar</BODY></HTML>")),
http_chunk:encode_last();
+handle_uri(_,"/identity_transfer_encoding.html",_,_,_,_) ->
+ "HTTP/1.0 200 OK\r\n"
+ "Transfer-Encoding:identity\r\n"
+ "Content-Length:8\r\n"
+ "\r\n"
+ "IDENTITY";
+
handle_uri(_,"/cookie.html",_,_,_,_) ->
"HTTP/1.1 200 ok\r\n" ++
"set-cookie:" ++ "test_cookie=true; path=/;" ++
@@ -1616,6 +1650,12 @@ handle_uri(_,"/cookie.html",_,_,_,_) ->
"Content-Length:32\r\n\r\n"++
"<HTML><BODY>foobar</BODY></HTML>";
+handle_uri(_,"/empty_set_cookie.html",_,_,_,_) ->
+ "HTTP/1.1 200 ok\r\n" ++
+ "set-cookie: \r\n" ++
+ "Content-Length:32\r\n\r\n"++
+ "<HTML><BODY>foobar</BODY></HTML>";
+
handle_uri(_,"/missing_crlf.html",_,_,_,_) ->
"HTTP/1.1 200 ok" ++
"Content-Length:32\r\n" ++
diff --git a/lib/inets/test/httpd_1_0.erl b/lib/inets/test/httpd_1_0.erl
index 53f23b12e0..0836c9e881 100644
--- a/lib/inets/test/httpd_1_0.erl
+++ b/lib/inets/test/httpd_1_0.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2013-2013. All Rights Reserved.
+%% Copyright Ericsson AB 2013-2014. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -20,7 +20,7 @@
-module(httpd_1_0).
--export([host/4]).
+-export([host/4, trace/4]).
%%-------------------------------------------------------------------------
%% Test cases
@@ -31,3 +31,8 @@ host(Type, Port, Host, Node) ->
"GET / HTTP/1.0\r\n\r\n",
[{statuscode, 200},
{version, "HTTP/1.0"}]).
+trace(Type, Port, Host, Node)->
+ ok = httpd_test_lib:verify_request(Type, Host, Port, Node,
+ "TRACE / HTTP/1.0\r\n\r\n",
+ [{statuscode, 501},
+ {version, "HTTP/1.0"}]).
diff --git a/lib/inets/test/httpd_1_1.erl b/lib/inets/test/httpd_1_1.erl
index 4b2a5f619d..6a5fc4a18f 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-2013. All Rights Reserved.
+%% Copyright Ericsson AB 2005-2014. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -22,7 +22,7 @@
-include_lib("kernel/include/file.hrl").
--export([host/4, chunked/4, expect/4, range/4, if_test/5, http_trace/4,
+-export([host/4, chunked/4, expect/4, range/4, if_test/5, trace/4,
head/4, mod_cgi_chunked_encoding_test/5]).
%% -define(all_keys_lower_case,true).
@@ -152,13 +152,13 @@ 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",
+ "\r\nIf-Modified-Since:" ++
+ Mod ++ "\r\n\r\n",
[{statuscode, 200}]),
Mod1 = httpd_util:rfc1123_date(calendar:gregorian_seconds_to_datetime(
CreatedSec+100)),
@@ -168,74 +168,69 @@ if_test(Type, Port, Host, Node, DocRoot)->
++ 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",
+ "\r\nIf-Modified-Since:" ++
+ "AAA[...]AAAA" ++ "\r\n\r\n",
[{statuscode, 400}]),
-
-
- Mod2 = httpd_util:rfc1123_date(calendar:gregorian_seconds_to_datetime(
+
+ Mod2 = httpd_util:rfc1123_date(calendar:gregorian_seconds_to_datetime(
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}]),
- Mod3 = httpd_util:rfc1123_date(calendar:gregorian_seconds_to_datetime(
+ %% 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}]),
+ Mod3 = httpd_util:rfc1123_date(calendar:gregorian_seconds_to_datetime(
CreatedSec-1)),
ok = httpd_test_lib:verify_request(Type, Host, Port, Node,
- "GET / HTTP/1.1\r\nHost:"
- ++ Host ++
- "\r\nIf-Unmodified-Since:"++ Mod3
+ "GET / HTTP/1.1\r\nHost:"
+ ++ Host ++
+ "\r\nIf-Unmodified-Since:"++ Mod3
++"\r\n\r\n",
- [{statuscode, 412}]),
+ [{statuscode, 412}]),
- %% Control that we get the body when the etag match
+ %% 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}]),
- 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:"++
+ 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}]),
- %% 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}]),
+ %% 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}]),
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",
+ ++ Host ++ "\r\n"++
+ "If-None-Match:NotEtag,"
+ "NeihterEtag\r\n\r\n",
[{statuscode,200}]),
ok.
-
-http_trace(Type, Port, Host, Node)->
+
+trace(Type, Port, Host, Node)->
ok = httpd_test_lib:verify_request(Type, Host, Port, Node,
"TRACE / HTTP/1.1\r\n" ++
"Host:" ++ Host ++ "\r\n" ++
"Max-Forwards:2\r\n\r\n",
- [{statuscode, 200}]),
- ok = httpd_test_lib:verify_request(Type, Host, Port, Node,
- "TRACE / HTTP/1.0\r\n\r\n",
- [{statuscode, 501},
- {version, "HTTP/1.0"}]).
+ [{statuscode, 200}]).
head(Type, Port, Host, Node)->
%% mod_include
ok = httpd_test_lib:verify_request(Type, Host, Port, Node,
@@ -283,7 +278,7 @@ mod_cgi_chunked_encoding_test(Type, Port, Host, Node, [Request| Rest])->
%%--------------------------------------------------------------------
validateRangeRequest(Socket,Response,ValidBody,C,O,DE)->
receive
- {tcp,Socket,Data} ->
+ {_,Socket,Data} ->
case string:str(Data,"\r\n") of
0->
validateRangeRequest(Socket,
@@ -312,7 +307,7 @@ validateRangeRequest1(Socket, Response, ValidBody) ->
case end_of_header(Response) of
false ->
receive
- {tcp,Socket,Data} ->
+ {_,Socket,Data} ->
validateRangeRequest1(Socket, Response ++ Data,
ValidBody);
_->
@@ -331,10 +326,10 @@ validateRangeRequest2(Socket, Head, Body, ValidBody, {multiPart,Boundary})->
validateMultiPartRangeRequest(Body, ValidBody, Boundary);
false->
receive
- {tcp, Socket, Data} ->
+ {_, Socket, Data} ->
validateRangeRequest2(Socket, Head, Body ++ Data,
ValidBody, {multiPart, Boundary});
- {tcp_closed, Socket} ->
+ {_, Socket} ->
error;
_ ->
error
@@ -353,7 +348,7 @@ validateRangeRequest2(Socket, Head, Body, ValidBody, BodySize)
end;
Size when Size < BodySize ->
receive
- {tcp, Socket, Data} ->
+ {_, Socket, Data} ->
validateRangeRequest2(Socket, Head,
Body ++ Data, ValidBody, BodySize);
_ ->
diff --git a/lib/inets/test/httpd_SUITE.erl b/lib/inets/test/httpd_SUITE.erl
index c0d73663d3..4be20d3a69 100644
--- a/lib/inets/test/httpd_SUITE.erl
+++ b/lib/inets/test/httpd_SUITE.erl
@@ -26,6 +26,7 @@
-include_lib("kernel/include/file.hrl").
-include_lib("common_test/include/ct.hrl").
+-include_lib("public_key/include/public_key.hrl").
-include("inets_test_lib.hrl").
%% Note: This directive should only be used in test suites.
@@ -33,6 +34,11 @@
-record(httpd_user, {user_name, password, user_data}).
-record(httpd_group, {group_name, userlist}).
+-define(MAX_HEADER_SIZE, 256).
+%% Minutes before failed auths timeout.
+-define(FAIL_EXPIRE_TIME,1).
+%% Seconds before successful auths timeout.
+-define(AUTH_TIMEOUT,5).
%%--------------------------------------------------------------------
%% Common Test interface functions -----------------------------------
@@ -42,22 +48,59 @@ suite() ->
all() ->
[
- {group, http},
- {group, http_limit}
- %%{group, https}
+ {group, http_basic},
+ {group, https_basic},
+ {group, http_limit},
+ {group, https_limit},
+ {group, http_basic_auth},
+ {group, https_basic_auth},
+ {group, http_auth_api},
+ {group, https_auth_api},
+ {group, http_auth_api_dets},
+ {group, https_auth_api_dets},
+ {group, http_auth_api_mnesia},
+ {group, https_auth_api_mnesia},
+ {group, http_htaccess},
+ {group, https_htaccess},
+ {group, http_security},
+ {group, https_security}
].
groups() ->
[
- {http, [], all_groups()},
- %%{https, [], all_groups()},
- {http_limit, [], [max_clients_1_1, max_clients_1_0, max_clients_0_9]},
- {http_1_1, [], [host, chunked, expect, cgi] ++ http_head() ++ http_get()},
- {http_1_0, [], [host, cgi] ++ http_head() ++ http_get()},
- {http_0_9, [], http_head() ++ http_get()}
+ {http_basic, [], basic_groups()},
+ {https_basic, [], basic_groups()},
+ {http_limit, [], [{group, limit}]},
+ {https_limit, [], [{group, limit}]},
+ {http_basic_auth, [], [{group, basic_auth}]},
+ {https_basic_auth, [], [{group, basic_auth}]},
+ {http_auth_api, [], [{group, auth_api}]},
+ {https_auth_api, [], [{group, auth_api}]},
+ {http_auth_api_dets, [], [{group, auth_api_dets}]},
+ {https_auth_api_dets, [], [{group, auth_api_dets}]},
+ {http_auth_api_mnesia, [], [{group, auth_api_mnesia}]},
+ {https_auth_api_mnesia, [], [{group, auth_api_mnesia}]},
+ {http_htaccess, [], [{group, htaccess}]},
+ {https_htaccess, [], [{group, htaccess}]},
+ {http_security, [], [{group, security}]},
+ {https_security, [], [{group, security}]},
+ {limit, [], [max_clients_1_1, max_clients_1_0, max_clients_0_9]},
+ {basic_auth, [], [basic_auth_1_1, basic_auth_1_0, basic_auth_0_9]},
+ {auth_api, [], [auth_api_1_1, auth_api_1_0, auth_api_0_9
+ ]},
+ {auth_api_dets, [], [auth_api_1_1, auth_api_1_0, auth_api_0_9
+ ]},
+ {auth_api_mnesia, [], [auth_api_1_1, auth_api_1_0, auth_api_0_9
+ ]},
+ {htaccess, [], [htaccess_1_1, htaccess_1_0, htaccess_0_9]},
+ {security, [], [security_1_1, security_1_0]}, %% Skip 0.9 as causes timing issus in test code
+ {http_1_1, [], [host, chunked, expect, cgi, cgi_chunked_encoding_test,
+ trace, range, if_modified_since] ++ http_head() ++ http_get() ++ load()},
+ {http_1_0, [], [host, cgi, trace] ++ http_head() ++ http_get() ++ load()},
+ {http_0_9, [], http_head() ++ http_get() ++ load()}
].
-all_groups ()->
+basic_groups ()->
[{group, http_1_1},
{group, http_1_0},
{group, http_0_9}
@@ -66,15 +109,27 @@ all_groups ()->
http_head() ->
[head].
http_get() ->
- [alias, get,
- basic_auth,
- esi, ssi].
+ [alias,
+ get,
+ %%actions, Add configuration so that this test mod_action
+ esi,
+ ssi,
+ content_length,
+ bad_hex,
+ missing_CR,
+ max_header,
+ ipv6
+ ].
+load() ->
+ [light, medium
+ %%,heavy
+ ].
+
init_per_suite(Config) ->
PrivDir = ?config(priv_dir, Config),
DataDir = ?config(data_dir, Config),
inets_test_lib:stop_apps([inets]),
- inets_test_lib:start_apps([inets]),
ServerRoot = filename:join(PrivDir, "server_root"),
inets_test_lib:del_dirs(ServerRoot),
DocRoot = filename:join(ServerRoot, "htdocs"),
@@ -82,44 +137,94 @@ init_per_suite(Config) ->
[{server_root, ServerRoot},
{doc_root, DocRoot},
{node, node()},
- {host, inets_test_lib:hostname()} | Config].
+ {host, inets_test_lib:hostname()},
+ {address, getaddr()} | Config].
end_per_suite(_Config) ->
ok.
%%--------------------------------------------------------------------
-init_per_group(https = Group, Config0) ->
- case start_apps(Group) of
- ok ->
- init_httpd(Group, [{type, ssl} | Config0]);
- _ ->
- {skip, "Could not start https apps"}
- end;
-
-init_per_group(Group, Config0) when Group == http; Group == http_limit ->
+init_per_group(Group, Config0) when Group == https_basic;
+ Group == https_limit;
+ Group == https_basic_auth;
+ Group == https_auth_api;
+ Group == https_auth_api_dets;
+ Group == https_auth_api_mnesia;
+ Group == https_security
+ ->
+ init_ssl(Group, Config0);
+init_per_group(Group, Config0) when Group == http_basic;
+ Group == http_limit;
+ Group == http_basic_auth;
+ Group == http_auth_api;
+ Group == http_auth_api_dets;
+ Group == http_auth_api_mnesia;
+ Group == http_security
+ ->
+ ok = start_apps(Group),
init_httpd(Group, [{type, ip_comm} | Config0]);
init_per_group(http_1_1, Config) ->
[{http_version, "HTTP/1.1"} | Config];
init_per_group(http_1_0, Config) ->
[{http_version, "HTTP/1.0"} | Config];
init_per_group(http_0_9, Config) ->
- [{http_version, "HTTP/0.9"} | Config];
+ case {os:type(), os:version()} of
+ {{win32, _}, {5,1,2600}} ->
+ {skip, "eaddrinuse XP problem"};
+ _ ->
+ [{http_version, "HTTP/0.9"} | Config]
+ end;
+init_per_group(http_htaccess = Group, Config) ->
+ Path = ?config(doc_root, Config),
+ catch remove_htaccess(Path),
+ create_htaccess_data(Path, ?config(address, Config)),
+ ok = start_apps(Group),
+ init_httpd(Group, [{type, ip_comm} | Config]);
+init_per_group(https_htaccess = Group, Config) ->
+ Path = ?config(doc_root, Config),
+ catch remove_htaccess(Path),
+ create_htaccess_data(Path, ?config(address, Config)),
+ init_ssl(Group, Config);
+init_per_group(auth_api, Config) ->
+ [{auth_prefix, ""} | Config];
+init_per_group(auth_api_dets, Config) ->
+ [{auth_prefix, "dets_"} | Config];
+init_per_group(auth_api_mnesia, Config) ->
+ start_mnesia(?config(node, Config)),
+ [{auth_prefix, "mnesia_"} | Config];
init_per_group(_, Config) ->
Config.
-end_per_group(http, _Config) ->
- ok;
-end_per_group(https, _Config) ->
- ssl:stop();
+
+end_per_group(Group, _Config) when Group == http_basic;
+ Group == http_limit;
+ Group == http_basic_auth;
+ Group == http_auth_api;
+ Group == http_auth_api_dets;
+ Group == http_auth_api_mnesia;
+ Group == http_htaccess;
+ Group == http_security
+ ->
+ inets:stop();
+end_per_group(Group, _Config) when Group == https_basic;
+ Group == https_limit;
+ Group == https_basic_auth;
+ Group == https_auth_api;
+ Group == http_auth_api_dets;
+ Group == http_auth_api_mnesia;
+ Group == https_htaccess;
+ Group == http_security
+ ->
+ ssl:stop(),
+ inets:stop();
+
+end_per_group(auth_api_mnesia, _) ->
+ cleanup_mnesia();
+
end_per_group(_, _) ->
ok.
-init_httpd(Group, Config0) ->
- Config1 = proplists:delete(port, Config0),
- Config = proplists:delete(server_pid, Config1),
- {Pid, Port} = server_start(Group, server_config(Group, Config)),
- [{server_pid, Pid}, {port, Port} | Config].
%%--------------------------------------------------------------------
-init_per_testcase(host, Config) ->
+init_per_testcase(Case, Config) when Case == host; Case == trace ->
Prop = ?config(tc_group_properties, Config),
Name = proplists:get_value(name, Prop),
Cb = case Name of
@@ -129,15 +234,15 @@ init_per_testcase(host, Config) ->
httpd_1_1
end,
[{version_cb, Cb} | proplists:delete(version_cb, Config)];
+
+init_per_testcase(range, Config) ->
+ DocRoot = ?config(doc_root, Config),
+ create_range_data(DocRoot),
+ Config;
+
init_per_testcase(_, Config) ->
Config.
-%% init_per_testcase(basic_auth = Case, Config) ->
-%% start_mnesia(?config(node, Config)),
-%% common_init_per_test_case(Case, Config);
-
-%% end_per_testcase(basic_auth, Config) ->
-%% cleanup_mnesia();
end_per_testcase(_Case, _Config) ->
ok.
@@ -163,8 +268,11 @@ get() ->
get(Config) when is_list(Config) ->
Version = ?config(http_version, Config),
Host = ?config(host, Config),
+ Type = ?config(type, Config),
ok = httpd_test_lib:verify_request(?config(type, Config), Host,
- ?config(port, Config), ?config(node, Config),
+ ?config(port, Config),
+ transport_opts(Type, Config),
+ ?config(node, Config),
http_request("GET /index.html ", Version, Host),
[{statuscode, 200},
{header, "Content-Type", "text/html"},
@@ -172,6 +280,15 @@ get(Config) when is_list(Config) ->
{header, "Server"},
{version, Version}]).
+basic_auth_1_1(Config) when is_list(Config) ->
+ basic_auth([{http_version, "HTTP/1.1"} | Config]).
+
+basic_auth_1_0(Config) when is_list(Config) ->
+ basic_auth([{http_version, "HTTP/1.0"} | Config]).
+
+basic_auth_0_9(Config) when is_list(Config) ->
+ basic_auth([{http_version, "HTTP/0.9"} | Config]).
+
basic_auth() ->
[{doc, "Test Basic authentication with WWW-Authenticate header"}].
@@ -203,13 +320,211 @@ basic_auth(Config) ->
Config, [{statuscode, 200}]),
%% Authentication still required!
basic_auth_requiered(Config).
-
+
+auth_api_1_1(Config) when is_list(Config) ->
+ auth_api([{http_version, "HTTP/1.1"} | Config]).
+
+auth_api_1_0(Config) when is_list(Config) ->
+ auth_api([{http_version, "HTTP/1.0"} | Config]).
+
+auth_api_0_9(Config) when is_list(Config) ->
+ auth_api([{http_version, "HTTP/0.9"} | Config]).
+
+auth_api() ->
+ [{doc, "Test mod_auth API"}].
+
+auth_api(Config) when is_list(Config) ->
+ Prefix = ?config(auth_prefix, Config),
+ do_auth_api(Prefix, Config).
+
+do_auth_api(AuthPrefix, Config) ->
+ Version = ?config(http_version, Config),
+ Host = ?config(host, Config),
+ Port = ?config(port, Config),
+ Node = ?config(node, Config),
+ ServerRoot = ?config(server_root, Config),
+ ok = http_status("GET / ", Config,
+ [{statuscode, 200}]),
+ ok = auth_status(auth_request("/", "one", "WrongPassword", Version, Host), Config,
+ [{statuscode, 200}]),
+
+ %% Make sure Authenticate header is received even the second time
+ %% we try a incorrect password! Otherwise a browser client will hang!
+ ok = auth_status(auth_request("/" ++ AuthPrefix ++ "open/",
+ "dummy", "WrongPassword", Version, Host), Config,
+ [{statuscode, 401},
+ {header, "WWW-Authenticate"}]),
+ ok = auth_status(auth_request("/" ++ AuthPrefix ++ "open/", "dummy", "WrongPassword",
+ Version, Host), Config, [{statuscode, 401},
+ {header, "WWW-Authenticate"}]),
+
+ %% Change the password to DummyPassword then try to add a user
+ %% Get an error and set it to NoPassword
+ ok = update_password(Node, ServerRoot, Host, Port, AuthPrefix,
+ "open", "NoPassword", "DummyPassword"),
+ {error,bad_password} =
+ add_user(Node, ServerRoot, Port, AuthPrefix, "open", "one",
+ "onePassword", []),
+ ok = update_password(Node, ServerRoot, Host, Port, AuthPrefix, "open",
+ "DummyPassword", "NoPassword"),
+
+ %% Test /*open, require user one Aladdin
+ remove_users(Node, ServerRoot, Host, Port, AuthPrefix, "open"),
+
+ ok = auth_status(auth_request("/" ++ AuthPrefix ++ "open/",
+ "one", "onePassword", Version, Host), Config,
+ [{statuscode, 401}]),
+
+ ok = auth_status(auth_request("/" ++ AuthPrefix ++ "open/",
+ "two", "twoPassword", Version, Host), Config,
+ [{statuscode, 401}]),
+
+ ok = auth_status(auth_request("/" ++ AuthPrefix ++ "open/",
+ "Aladdin", "onePassword", Version, Host),
+ Config, [{statuscode, 401}]),
+
+ true = add_user(Node, ServerRoot, Port, AuthPrefix, "open", "one",
+ "onePassword", []),
+ true = add_user(Node, ServerRoot, Port, AuthPrefix, "open", "two",
+ "twoPassword", []),
+ true = add_user(Node, ServerRoot, Port, AuthPrefix, "open", "Aladdin",
+ "AladdinPassword", []),
+ {ok, [_|_]} = list_users(Node, ServerRoot, Host, Port,
+ AuthPrefix, "open"),
+ ok = auth_status(auth_request("/" ++ AuthPrefix ++ "open/",
+ "one", "WrongPassword", Version, Host),
+ Config, [{statuscode, 401}]),
+ ok = auth_status(auth_request("/" ++ AuthPrefix ++ "open/",
+ "one", "onePassword", Version, Host),
+ Config, [{statuscode, 200}]),
+ ok = auth_status(auth_request("/" ++ AuthPrefix ++ "open/",
+ "two", "twoPassword", Version, Host),
+ Config,[{statuscode, 401}]),
+ ok = auth_status(auth_request("/" ++ AuthPrefix ++ "open/",
+ "Aladdin", "WrongPassword", Version, Host),
+ Config,[{statuscode, 401}]),
+ ok = auth_status(auth_request("/" ++ AuthPrefix ++ "open/",
+ "Aladdin", "AladdinPassword", Version, Host),
+ Config, [{statuscode, 200}]),
+
+ remove_users(Node, ServerRoot, Host, Port, AuthPrefix, "open"),
+ {ok, []} = list_users(Node, ServerRoot, Host, Port,
+ AuthPrefix, "open"),
+
+ %% Phase 2
+ remove_users(Node, ServerRoot, Host, Port, AuthPrefix, "secret"),
+ {ok, []} = list_users(Node, ServerRoot, Host, Port, AuthPrefix,
+ "secret"),
+ ok = auth_status(auth_request("/" ++ AuthPrefix ++ "secret/",
+ "one", "onePassword", Version, Host),
+ Config, [{statuscode, 401}]),
+ ok = auth_status(auth_request("/" ++ AuthPrefix ++ "secret/",
+ "two", "twoPassword", Version, Host),
+ Config, [{statuscode, 401}]),
+ ok = auth_status(auth_request("/" ++ AuthPrefix ++ "secret/",
+ "three", "threePassword", Version, Host),
+ Config, [{statuscode, 401}]),
+ add_user(Node, ServerRoot, Port, AuthPrefix, "secret", "one",
+ "onePassword",
+ []),
+ add_user(Node, ServerRoot, Port, AuthPrefix, "secret",
+ "two", "twoPassword", []),
+ add_user(Node, ServerRoot, Port, AuthPrefix, "secret", "Aladdin",
+ "AladdinPassword",[]),
+ add_group_member(Node, ServerRoot, Port, AuthPrefix, "secret",
+ "one", "group1"),
+ add_group_member(Node, ServerRoot, Port, AuthPrefix, "secret",
+ "two", "group1"),
+ add_group_member(Node, ServerRoot, Port, AuthPrefix,
+ "secret", "Aladdin", "group2"),
+ ok = auth_status(auth_request("/" ++ AuthPrefix ++ "secret/",
+ "one", "onePassword", Version, Host),
+ Config, [{statuscode, 200}]),
+ ok = auth_status(auth_request("/" ++ AuthPrefix ++ "secret/",
+ "two", "twoPassword", Version, Host),
+ Config,[{statuscode, 200}]),
+ ok = auth_status(auth_request("/" ++ AuthPrefix ++ "secret/",
+ "Aladdin", "AladdinPassword", Version, Host),
+ Config, [{statuscode, 200}]),
+ ok = auth_status(auth_request("/" ++ AuthPrefix ++ "secret/",
+ "three", "threePassword", Version, Host),
+ Config, [{statuscode, 401}]),
+ remove_users(Node, ServerRoot, Host, Port, AuthPrefix, "secret"),
+ {ok, []} = list_users(Node, ServerRoot, Host, Port,
+ AuthPrefix, "secret"),
+ remove_groups(Node, ServerRoot, Host, Port, AuthPrefix, "secret"),
+
+ {ok, []} = list_groups(Node, ServerRoot, Host, Port, AuthPrefix, "secret"),
+
+ %% Phase 3
+ remove_users(Node, ServerRoot, Host, Port, AuthPrefix, "secret/top_secret"),
+ remove_groups(Node, ServerRoot, Host, Port, AuthPrefix, "secret/top_secret"),
+
+ ok = auth_status(auth_request("/" ++ AuthPrefix ++
+ "secret/top_secret/",
+ "three", "threePassword", Version, Host),
+ Config, [{statuscode, 401}]),
+ ok = auth_status(auth_request("/" ++ AuthPrefix ++
+ "secret/top_secret/", "two", "twoPassword", Version, Host),
+ Config, [{statuscode, 401}]),
+ add_user(Node, ServerRoot, Port, AuthPrefix,
+ "secret/top_secret","three",
+ "threePassword",[]),
+ add_user(Node, ServerRoot, Port, AuthPrefix, "secret/top_secret",
+ "two","twoPassword", []),
+ add_group_member(Node, ServerRoot, Port, AuthPrefix, "secret/top_secret", "three", "group3"),
+ ok = auth_status(auth_request("/" ++ AuthPrefix ++
+ "secret/top_secret/", "three", "threePassword",
+ Version, Host),
+ Config, [{statuscode, 200}]),
+ ok = auth_status(auth_request("/" ++ AuthPrefix ++
+ "secret/top_secret/", "two", "twoPassword", Version, Host),
+ Config, [{statuscode, 401}]),
+ add_group_member(Node, ServerRoot, Port, AuthPrefix, "secret/top_secret", "two", "group3"),
+ ok = auth_status(auth_request("/" ++ AuthPrefix ++
+ "secret/top_secret/",
+ "two", "twoPassword", Version, Host),
+ Config, [{statuscode, 200}]),
+ remove_users(Node, ServerRoot, Host, Port, AuthPrefix, "secret/top_secret"),
+ {ok, []} = list_users(Node, ServerRoot, Host, Port,
+ AuthPrefix, "secret/top_secret"),
+ remove_groups(Node, ServerRoot, Host, Port, AuthPrefix, "secret/top_secret"),
+ {ok, []} = list_groups(Node, ServerRoot, Host, Port, AuthPrefix, "secret/top_secret"),
+ ok = auth_status(auth_request("/" ++ AuthPrefix ++
+ "secret/top_secret/", "two", "twoPassword", Version, Host),
+ Config, [{statuscode, 401}]),
+ ok = auth_status(auth_request("/" ++ AuthPrefix ++
+ "secret/top_secret/","three", "threePassword", Version, Host),
+ Config, [{statuscde, 401}]).
+%%-------------------------------------------------------------------------
+ipv6() ->
+ [{require, ipv6_hosts},
+ {doc,"Test ipv6."}].
+ipv6(Config) when is_list(Config) ->
+ {ok, Hostname0} = inet:gethostname(),
+ case lists:member(list_to_atom(Hostname0), ct:get_config(ipv6_hosts)) of
+ true ->
+ Version = ?config(http_version, Config),
+ Host = ?config(host, Config),
+ URI = http_request("GET /", Version, Host),
+ httpd_test_lib:verify_request(?config(type, Config), Host,
+ ?config(port, Config), [inet6],
+ ?config(code, Config),
+ URI,
+ [{statuscode, 200}, {version, Version}]);
+ false ->
+ {skip, "Host does not support IPv6"}
+ end.
+
+%%-------------------------------------------------------------------------
ssi() ->
[{doc, "HTTP GET server side include test"}].
ssi(Config) when is_list(Config) ->
Version = ?config(http_version, Config),
Host = ?config(host, Config),
+ Type = ?config(type, Config),
ok = httpd_test_lib:verify_request(?config(type, Config), Host, ?config(port, Config),
+ transport_opts(Type, Config),
?config(node, Config),
http_request("GET /fsize.shtml ", Version, Host),
[{statuscode, 200},
@@ -217,6 +532,131 @@ ssi(Config) when is_list(Config) ->
{header, "Date"},
{header, "Server"},
{version, Version}]).
+%%-------------------------------------------------------------------------
+htaccess_1_1(Config) when is_list(Config) ->
+ htaccess([{http_version, "HTTP/1.1"} | Config]).
+
+htaccess_1_0(Config) when is_list(Config) ->
+ htaccess([{http_version, "HTTP/1.0"} | Config]).
+
+htaccess_0_9(Config) when is_list(Config) ->
+ htaccess([{http_version, "HTTP/0.9"} | Config]).
+
+htaccess() ->
+ [{doc, "Test mod_auth API"}].
+
+htaccess(Config) when is_list(Config) ->
+ Version = ?config(http_version, Config),
+ Host = ?config(host, Config),
+ Type = ?config(type, Config),
+ Port = ?config(port, Config),
+ Node = ?config(node, Config),
+ %% Control that authentication required!
+ %% Control that the pages that shall be
+ %% authenticated really need authenticatin
+ ok = httpd_test_lib:verify_request(Type, Host, Port, Node,
+ http_request("GET /ht/open/ ", Version, Host),
+ [{statuscode, 401},
+ {version, Version},
+ {header, "WWW-Authenticate"}]),
+ ok = httpd_test_lib:verify_request(Type, Host, Port, Node,
+ http_request("GET /ht/secret/ ", Version, Host),
+ [{statuscode, 401},
+ {version, Version},
+ {header, "WWW-Authenticate"}]),
+ ok = httpd_test_lib:verify_request(Type, Host, Port, Node,
+ http_request("GET /ht/secret/top_secret/ ",
+ Version, Host),
+ [{statuscode, 401},
+ {version, Version},
+ {header, "WWW-Authenticate"}]),
+
+ %% Make sure Authenticate header is received even the second time
+ %% we try a incorrect password! Otherwise a browser client will hang!
+ ok = auth_status(auth_request("/ht/open/",
+ "dummy", "WrongPassword", Version, Host), Config,
+ [{statuscode, 401},
+ {header, "WWW-Authenticate"}]),
+ ok = auth_status(auth_request("/ht/open/",
+ "dummy", "WrongPassword", Version, Host), Config,
+ [{statuscode, 401},
+ {header, "WWW-Authenticate"}]),
+
+ %% Control that not just the first user in the list is valid
+ %% Control the first user
+ %% Authennticating ["one:OnePassword" user first in user list]
+ ok = auth_status(auth_request("/ht/open/dummy.html", "one", "OnePassword",
+ Version, Host), Config,
+ [{statuscode, 200}]),
+
+ %% Control the second user
+ %% Authentication OK and a directory listing is supplied!
+ %% ["Aladdin:open sesame" user second in user list]
+ ok = auth_status(auth_request("/ht/open/","Aladdin",
+ "AladdinPassword", Version, Host), Config,
+ [{statuscode, 200}]),
+
+ %% Contro that bad passwords and userids get a good denial
+ %% User correct but wrong password! ["one:one" user first in user list]
+ ok = auth_status(auth_request("/ht/open/", "one", "one", Version, Host), Config,
+ [{statuscode, 401}]),
+ %% Neither user or password correct! ["dummy:dummy"]
+ ok = auth_status(auth_request("/ht/open/", "dummy", "dummy", Version, Host), Config,
+ [{statuscode, 401}]),
+
+ %% Control that authetication still works, even if its a member in a group
+ %% Authentication OK! ["two:TwoPassword" user in first group]
+ ok = auth_status(auth_request("/ht/secret/dummy.html", "two",
+ "TwoPassword", Version, Host), Config,
+ [{statuscode, 200}]),
+
+ %% Authentication OK and a directory listing is supplied!
+ %% ["three:ThreePassword" user in second group]
+ ok = auth_status(auth_request("/ht/secret/", "three",
+ "ThreePassword", Version, Host), Config,
+ [{statuscode, 200}]),
+
+ %% Deny users with bad passwords even if the user is a group member
+ %% User correct but wrong password! ["two:two" user in first group]
+ ok = auth_status(auth_request("/ht/secret/", "two", "two", Version, Host), Config,
+ [{statuscode, 401}]),
+ %% Neither user or password correct! ["dummy:dummy"]
+ ok = auth_status(auth_request("/ht/secret/", "dummy", "dummy", Version, Host), Config,
+ [{statuscode, 401}]),
+
+ %% control that we deny the users that are in subnet above the allowed
+ ok = auth_status(auth_request("/ht/blocknet/dummy.html", "four",
+ "FourPassword", Version, Host), Config,
+ [{statuscode, 403}]),
+ %% Control that we only applies the rules to the right methods
+ ok = httpd_test_lib:verify_request(Type, Host, Port, Node,
+ http_request("HEAD /ht/blocknet/dummy.html ", Version, Host),
+ [{statuscode, head_status(Version)},
+ {version, Version}]),
+
+ %% Control that the rerquire directive can be overrideen
+ ok = auth_status(auth_request("/ht/secret/top_secret/ ", "Aladdin", "AladdinPassword",
+ Version, Host), Config,
+ [{statuscode, 401}]),
+
+ %% Authentication still required!
+ ok = httpd_test_lib:verify_request(Type, Host, Port, Node,
+ http_request("GET /ht/open/ ", Version, Host),
+ [{statuscode, 401},
+ {version, Version},
+ {header, "WWW-Authenticate"}]),
+ ok = httpd_test_lib:verify_request(Type, Host, Port, Node,
+ http_request("GET /ht/secret/ ", Version, Host),
+ [{statuscode, 401},
+ {version, Version},
+ {header, "WWW-Authenticate"}]),
+ ok = httpd_test_lib:verify_request(Type, Host, Port, Node,
+ http_request("GET /ht/secret/top_secret/ ", Version, Host),
+ [{statuscode, 401},
+ {version, Version},
+ {header, "WWW-Authenticate"}]).
+
+%%-------------------------------------------------------------------------
host() ->
[{doc, "Test host header"}].
@@ -224,21 +664,21 @@ host(Config) when is_list(Config) ->
Cb = ?config(version_cb, Config),
Cb:host(?config(type, Config), ?config(port, Config),
?config(host, Config), ?config(node, Config)).
-
+%%-------------------------------------------------------------------------
chunked() ->
[{doc, "Check that the server accepts chunked requests."}].
chunked(Config) when is_list(Config) ->
httpd_1_1:chunked(?config(type, Config), ?config(port, Config),
?config(host, Config), ?config(node, Config)).
-
+%%-------------------------------------------------------------------------
expect() ->
["Check that the server handles request with the expect header "
"field appropiate"].
expect(Config) when is_list(Config) ->
httpd_1_1:expect(?config(type, Config), ?config(port, Config),
?config(host, Config), ?config(node, Config)).
-
+%%-------------------------------------------------------------------------
max_clients_1_1() ->
[{doc, "Test max clients limit"}].
@@ -256,7 +696,7 @@ max_clients_0_9() ->
max_clients_0_9(Config) when is_list(Config) ->
do_max_clients([{http_version, "HTTP/0.9"} | Config]).
-
+%%-------------------------------------------------------------------------
esi() ->
[{doc, "Test mod_esi"}].
@@ -286,7 +726,7 @@ esi(Config) when is_list(Config) ->
ok = http_status("GET /cgi-bin/erl/httpd_example:get ",
Config, [{statuscode, 200},
{no_header, "cache-control"}]).
-
+%%-------------------------------------------------------------------------
cgi() ->
[{doc, "Test mod_cgi"}].
@@ -361,7 +801,27 @@ cgi(Config) when is_list(Config) ->
ok = http_status("GET /cgi-bin/" ++ Script ++ " ", Config,
[{statuscode, 200},
{no_header, "cache-control"}]).
-
+%%-------------------------------------------------------------------------
+cgi_chunked_encoding_test() ->
+ [{doc, "Test chunked encoding together with mod_cgi "}].
+cgi_chunked_encoding_test(Config) when is_list(Config) ->
+ Host = ?config(host, Config),
+ Script =
+ case test_server:os_type() of
+ {win32, _} ->
+ "/cgi-bin/printenv.bat";
+ _ ->
+ "/cgi-bin/printenv.sh"
+ end,
+ Requests =
+ ["GET " ++ Script ++ " HTTP/1.1\r\nHost:"++ Host ++"\r\n\r\n",
+ "GET /cgi-bin/erl/httpd_example/newformat HTTP/1.1\r\nHost:"
+ ++ Host ++"\r\n\r\n"],
+ httpd_1_1:mod_cgi_chunked_encoding_test(?config(type, Config), ?config(port, Config),
+ Host,
+ ?config(node, Config),
+ Requests).
+%%-------------------------------------------------------------------------
alias() ->
[{doc, "Test mod_alias"}].
@@ -389,160 +849,246 @@ alias(Config) when is_list(Config) ->
[{statuscode, 301},
{header, "Location"},
{header, "Content-Type","text/html"}]).
+%%-------------------------------------------------------------------------
+actions() ->
+ [{doc, "Test mod_actions"}].
+actions(Config) when is_list(Config) ->
+ ok = http_status("GET /", Config, [{statuscode, 200}]).
-%% auth_api() ->
-%% [{doc, "Test mod_auth API"}].
-
-%% auth_api(Config) when is_list(Config) ->
-%% Version = ?config(http_version, Config),
-%% Host = ?config(host, Config),
-%% ok = http_status("GET / ", Config,
-%% [{statuscode, 200}]),
-%% ok = auth_status(auth_request("/", "one", "WrongPassword", Version, Host), Config,
-%% [{statuscode, 200}]),
-
-%% %% Make sure Authenticate header is received even the second time
-%% %% we try a incorrect password! Otherwise a browser client will hang!
-%% ok = auth_status(auth_request("/" ++ AuthStoreType ++ "open/",
-%% "dummy", "WrongPassword", Host), Config,
-%% [{statuscode, 401},
-%% {header, "WWW-Authenticate"}]),
-%% ok = auth_status(auth_request("/" ++ AuthStoreType ++ "open/", "dummy", "WrongPassword",
-%% Host), Config, [{statuscode, 401},
-%% {header, "WWW-Authenticate"}]),
-
-%% %% Change the password to DummyPassword then try to add a user
-%% %% Get an error and set it to NoPassword
-%% ok = update_password(Node, ServerRoot, Host, Port, AuthStoreType ++
-%% "open", "NoPassword", "DummyPassword"),
-%% {error,bad_password} =
-%% add_user(Node, ServerRoot, Port, AuthStoreType ++ "open", "one",
-%% "onePassword", []),
-%% ok = update_password(Node, ServerRoot, Host, Port, AuthStoreType ++"open",
-%% "DummyPassword", "NoPassword"),
-
-%% %% Test /*open, require user one Aladdin
-%% remove_users(Node, ServerRoot, Host, Port, AuthStoreType ++ "open"),
+%%-------------------------------------------------------------------------
+range() ->
+ [{doc, "Test Range header"}].
+
+range(Config) when is_list(Config) ->
+ httpd_1_1:range(?config(type, Config), ?config(port, Config),
+ ?config(host, Config), ?config(node, Config)).
+
+%%-------------------------------------------------------------------------
+if_modified_since() ->
+ [{doc, "Test If-Modified-Since header"}].
+
+if_modified_since(Config) when is_list(Config) ->
+ httpd_1_1:if_test(?config(type, Config), ?config(port, Config),
+ ?config(host, Config), ?config(node, Config),
+ ?config(doc_root, Config)).
+%%-------------------------------------------------------------------------
+trace() ->
+ [{doc, "Test TRACE method"}].
+
+trace(Config) when is_list(Config) ->
+ Cb = ?config(version_cb, Config),
+ Cb:trace(?config(type, Config), ?config(port, Config),
+ ?config(host, Config), ?config(node, Config)).
+
+%%-------------------------------------------------------------------------
+light() ->
+ ["Test light load"].
+light(Config) when is_list(Config) ->
+ httpd_load:load_test(?config(type, Config), ?config(port, Config), ?config(host, Config),
+ ?config(node, Config), 10).
+%%-------------------------------------------------------------------------
+medium() ->
+ ["Test medium load"].
+medium(Config) when is_list(Config) ->
+ httpd_load:load_test(?config(type, Config), ?config(port, Config), ?config(host, Config),
+ ?config(node, Config), 100).
+%%-------------------------------------------------------------------------
+heavy() ->
+ ["Test heavy load"].
+heavy(Config) when is_list(Config) ->
+ httpd_load:load_test(?config(type, Config), ?config(port, Config), ?config(host, Config),
+ ?config(node, Config),
+ 1000).
+%%-------------------------------------------------------------------------
+content_length() ->
+ ["Tests that content-length is correct OTP-5775"].
+content_length(Config) ->
+ Version = ?config(http_version, Config),
+ Host = ?config(host, Config),
+ ok = httpd_test_lib:verify_request(?config(type, Config), Host,
+ ?config(port, Config), ?config(node, Config),
+ http_request("GET /cgi-bin/erl/httpd_example:get_bin ",
+ Version, Host),
+ [{statuscode, 200},
+ {content_length, 274},
+ {version, Version}]).
+%%-------------------------------------------------------------------------
+bad_hex() ->
+ ["Tests that a URI with a bad hexadecimal code is handled OTP-6003"].
+bad_hex(Config) ->
+ Version = ?config(http_version, Config),
+ Host = ?config(host, Config),
+ ok = httpd_test_lib:verify_request(?config(type, Config), Host,
+ ?config(port, Config), ?config(node, Config),
+ http_request("GET http://www.erlang.org/%skalle ",
+ Version, Host),
+ [{statuscode, 400},
+ {version, Version}]).
+%%-------------------------------------------------------------------------
+missing_CR() ->
+ ["Tests missing CR in delimiter OTP-7304"].
+missing_CR(Config) ->
+ Version = ?config(http_version, Config),
+ Host = ?config(host, Config),
+ ok = httpd_test_lib:verify_request(?config(type, Config), Host,
+ ?config(port, Config), ?config(node, Config),
+ http_request_missing_CR("GET /index.html ", Version, Host),
+ [{statuscode, 200},
+ {version, Version}]).
+
+%%-------------------------------------------------------------------------
+max_header() ->
+ ["Denial Of Service (DOS) attack, prevented by max_header"].
+max_header(Config) when is_list(Config) ->
+ Version = ?config(http_version, Config),
+ Host = ?config(host, Config),
+ case Version of
+ "HTTP/0.9" ->
+ {skip, no_implemented};
+ _ ->
+ dos_hostname(?config(type, Config), ?config(port, Config), Host,
+ ?config(node, Config), Version, ?MAX_HEADER_SIZE)
+ end.
+
+%%-------------------------------------------------------------------------
+security_1_1(Config) when is_list(Config) ->
+ security([{http_version, "HTTP/1.1"} | Config]).
+
+security_1_0(Config) when is_list(Config) ->
+ security([{http_version, "HTTP/1.0"} | Config]).
+
+security() ->
+ ["Test mod_security"].
+security(Config) ->
+ Version = ?config(http_version, Config),
+ Host = ?config(host, Config),
+ Port = ?config(port, Config),
+ Node = ?config(node, Config),
+ ServerRoot = ?config(server_root, Config),
+
+ global:register_name(mod_security_test, self()), % Receive events
+
+ test_server:sleep(5000),
+
+ OpenDir = filename:join([ServerRoot, "htdocs", "open"]),
-%% auth_request(Type, Host, Port, Node,"/" ++ AuthStoreType ++ "open/",
-%% "one", "onePassword", [{statuscode, 401}]),
+ %% Test blocking / unblocking of users.
+
+ %% /open, require user one Aladdin
+ remove_users(Node, ServerRoot, Host, Port, "", "open"),
+
+ ok = auth_status(auth_request("/open/",
+ "one", "onePassword", Version, Host), Config,
+ [{statuscode, 401}]),
-%% auth_request(Type, Host, Port, Node,"/" ++ AuthStoreType ++ "open/",
-%% "two", "twoPassword", [{statuscode, 401}]),
+ receive_security_event({event, auth_fail, Port, OpenDir,
+ [{user, "one"}, {password, "onePassword"}]},
+ Node, Port),
+
+ ok = auth_status(auth_request("/open/",
+ "two", "twoPassword", Version, Host), Config,
+ [{statuscode, 401}]),
-%% auth_request(Type, Host, Port, Node,"/" ++ AuthStoreType ++ "open/",
-%% "Aladdin", "onePassword", [{statuscode, 401}]),
-
-%% add_user(Node, ServerRoot, Port, AuthStoreType ++ "open", "one",
-%% "onePassword", []),
-%% add_user(Node, ServerRoot, Port, AuthStoreType ++ "open", "two",
-%% "twoPassword", []),
-%% add_user(Node, ServerRoot, Port, AuthStoreType ++ "open", "Aladdin",
-%% "AladdinPassword", []),
+ receive_security_event({event, auth_fail, Port, OpenDir,
+ [{user, "two"}, {password, "twoPassword"}]},
+ Node, Port),
+
+ ok = auth_status(auth_request("/open/",
+ "Aladdin", "AladdinPassword", Version, Host),
+ Config, [{statuscode, 401}]),
+
+ receive_security_event({event, auth_fail, Port, OpenDir,
+ [{user, "Aladdin"},
+ {password, "AladdinPassword"}]},
+ Node, Port),
+
+ add_user(Node, ServerRoot, Port, "", "open", "one", "onePassword", []),
+ add_user(Node, ServerRoot, Port, "", "open", "two", "twoPassword", []),
+
+ ok = auth_status(auth_request("/open/", "one", "WrongPassword", Version, Host), Config,
+ [{statuscode, 401}]),
+
+ receive_security_event({event, auth_fail, Port, OpenDir,
+ [{user, "one"}, {password, "WrongPassword"}]},
+ Node, Port),
+
+ ok = auth_status(auth_request("/open/", "one", "WrongPassword", Version, Host), Config,
+ [{statuscode, 401}]),
+
+ receive_security_event({event, auth_fail, Port, OpenDir,
+ [{user, "one"}, {password, "WrongPassword"}]},
+ Node, Port),
+ receive_security_event({event, user_block, Port, OpenDir,
+ [{user, "one"}]}, Node, Port),
+
+ global:unregister_name(mod_security_test), % No more events.
+
+ ok = auth_status(auth_request("/open/", "one", "WrongPassword", Version, Host), Config,
+ [{statuscode, 401}]),
+
+ %% User "one" should be blocked now..
+ case list_blocked_users(Node, Port) of
+ [{"one",_, Port, OpenDir,_}] ->
+ ok;
+ Blocked ->
+ ct:fail({unexpected_blocked, Blocked})
+ end,
+
+ [{"one",_, Port, OpenDir,_}] = list_blocked_users(Node, Port, OpenDir),
+
+ true = unblock_user(Node, "one", Port, OpenDir),
+ %% User "one" should not be blocked any more.
+
+ [] = list_blocked_users(Node, Port),
+
+ ok = auth_status(auth_request("/open/", "one", "onePassword", Version, Host), Config,
+ [{statuscode, 200}]),
+
+ %% Test list_auth_users & auth_timeout
+
+ ["one"] = list_auth_users(Node, Port),
+
+ ok = auth_status(auth_request("/open/", "two", "onePassword", Version, Host), Config,
+ [{statuscode, 401}]),
+
+ ["one"] = list_auth_users(Node, Port),
+
-%% {ok, [_|_]} = list_users(Node, ServerRoot, Host, Port,
-%% AuthStoreType++"open"),
-%% auth_request(Type, Host, Port, Node, "/" ++ AuthStoreType ++ "open/",
-%% "one", "WrongPassword", [{statuscode, 401}]),
-%% auth_request(Type, Host, Port, Node, "/" ++ AuthStoreType ++ "open/",
-%% "one", "onePassword", [{statuscode, 200}]),
-%% auth_request(Type, Host, Port, Node,"/" ++ AuthStoreType ++ "open/",
-%% "two", "twoPassword", [{statuscode, 401}]),
-%% auth_request(Type, Host, Port, Node, "/" ++ AuthStoreType ++ "open/",
-%% "Aladdin", "WrongPassword", [{statuscode, 401}]),
-%% auth_request(Type, Host, Port, Node,"/" ++ AuthStoreType ++ "open/",
-%% "Aladdin", "AladdinPassword", [{statuscode, 200}]),
+ ["one"] = list_auth_users(Node, Port, OpenDir),
+
-%% remove_users(Node, ServerRoot, Host, Port, AuthStoreType++"open"),
-%% {ok, []} = list_users(Node, ServerRoot, Host, Port,
-%% AuthStoreType++"open"),
-
-%% %% Phase 2
-%% remove_users(Node, ServerRoot, Host, Port, AuthStoreType++"secret"),
-%% {ok, []} = list_users(Node, ServerRoot, Host, Port, AuthStoreType ++
-%% "secret"),
-%% auth_request(Type, Host, Port, Node,"/" ++ AuthStoreType ++ "secret/",
-%% "one", "onePassword", [{statuscode, 401}]),
-%% auth_request(Type, Host, Port, Node,"/" ++ AuthStoreType ++ "secret/",
-%% "two", "twoPassword", [{statuscode, 401}]),
-%% auth_request(Type, Host, Port, Node, "/" ++ AuthStoreType ++ "secret/",
-%% "three", "threePassword", [{statuscode, 401}]),
-%% add_user(Node, ServerRoot, Port, AuthStoreType ++ "secret", "one",
-%% "onePassword",
-%% []),
-%% add_user(Node, ServerRoot, Port, AuthStoreType ++ "secret",
-%% "two", "twoPassword", []),
-%% add_user(Node, ServerRoot, Port, AuthStoreType++"secret", "Aladdin",
-%% "AladdinPassword",[]),
-%% add_group_member(Node, ServerRoot, Port, AuthStoreType ++ "secret",
-%% "one", "group1"),
-%% add_group_member(Node, ServerRoot, Port, AuthStoreType ++ "secret",
-%% "two", "group1"),
-%% add_group_member(Node, ServerRoot, Port, AuthStoreType ++
-%% "secret", "Aladdin", "group2"),
-%% auth_request(Type, Host, Port, Node,"/" ++ AuthStoreType ++ "secret/",
-%% "one", "onePassword", [{statuscode, 200}]),
-%% auth_request(Type, Host, Port, Node,"/" ++ AuthStoreType ++ "secret/",
-%% "two", "twoPassword", [{statuscode, 200}]),
-%% auth_request(Type, Host, Port, Node,"/" ++ AuthStoreType ++ "secret/",
-%% "Aladdin", "AladdinPassword", [{statuscode, 200}]),
-%% auth_request(Type, Host, Port, Node,"/" ++ AuthStoreType ++ "secret/",
-%% "three", "threePassword", [{statuscode, 401}]),
-%% remove_users(Node, ServerRoot, Host, Port, AuthStoreType ++ "secret"),
-%% {ok, []} = list_users(Node, ServerRoot, Host, Port,
-%% AuthStoreType ++ "secret"),
-%% remove_groups(Node, ServerRoot, Host, Port, AuthStoreType ++ "secret"),
-%% Directory = filename:join([ServerRoot, "htdocs", AuthStoreType ++
-%% "secret"]),
-%% {ok, []} = list_groups(Node, ServerRoot, Host, Port, Directory),
-
-%% %% Phase 3
-%% remove_users(Node, ServerRoot, Host, Port, AuthStoreType ++
-%% "secret/top_secret"),
-%% remove_groups(Node, ServerRoot, Host, Port, AuthStoreType ++
-%% "secret/top_secret"),
-%% auth_request(Type, Host, Port, Node,"/" ++ AuthStoreType ++
-%% "secret/top_secret/",
-%% "three", "threePassword", [{statuscode, 401}]),
-%% auth_request(Type, Host, Port, Node,"/" ++ AuthStoreType ++
-%% "secret/top_secret/", "two", "twoPassword",
-%% [{statuscode, 401}]),
-%% add_user(Node, ServerRoot, Port, AuthStoreType ++
-%% "secret/top_secret","three",
-%% "threePassword",[]),
-%% add_user(Node, ServerRoot, Port, AuthStoreType ++ "secret/top_secret",
-%% "two","twoPassword", []),
-%% add_group_member(Node, ServerRoot, Port, AuthStoreType ++
-%% "secret/top_secret",
-%% "three", "group3"),
-%% auth_request(Type, Host, Port, Node,"/" ++ AuthStoreType ++
-%% "secret/top_secret/", "three", "threePassword",
-%% [{statuscode, 200}]),
-%% auth_request(Type, Host, Port, Node,"/" ++ AuthStoreType ++
-%% "secret/top_secret/", "two", "twoPassword",
-%% [{statuscode, 401}]),
-%% add_group_member(Node, ServerRoot, Port, AuthStoreType ++
-%% "secret/top_secret",
-%% "two", "group3"),
-%% auth_request(Type,Host,Port,Node,"/" ++ AuthStoreType ++
-%% "secret/top_secret/",
-%% "two", "twoPassword", [{statuscode, 200}]),
-%% remove_users(Node, ServerRoot, Host, Port, AuthStoreType ++
-%% "secret/top_secret"),
-%% {ok, []} = list_users(Node, ServerRoot, Host, Port,
-%% AuthStoreType ++ "secret/top_secret"),
-%% remove_groups(Node, ServerRoot, Host, Port, AuthStoreType ++
-%% "secret/top_secret"),
-%% Directory2 = filename:join([ServerRoot, "htdocs",
-%% AuthStoreType ++ "secret/top_secret"]),
-%% {ok, []} = list_groups(Node, ServerRoot, Host, Port, Directory2),
-%% auth_request(Type, Host, Port, Node, "/" ++ AuthStoreType ++
-%% "secret/top_secret/", "two", "twoPassword",
-%% [{statuscode, 401}]),
-%% auth_request(Type, Host, Port, Node, "/" ++ AuthStoreType ++
-%% "secret/top_secret/","three", "threePassword",
-%% [{statuscode, 401}]).
+ ok = auth_status(auth_request("/open/", "two", "twoPassword", Version, Host), Config,
+ [{statuscode, 401}]),
+
+ ["one"] = list_auth_users(Node, Port),
+
+
+ ["one"] = list_auth_users(Node, Port, OpenDir),
+
+ %% Wait for successful auth to timeout.
+ test_server:sleep(?AUTH_TIMEOUT*1001),
+
+ [] = list_auth_users(Node, Port),
+
+ [] = list_auth_users(Node, Port, OpenDir),
+
+ %% "two" is blocked.
+
+ true = unblock_user(Node, "two", Port, OpenDir),
+
+
+ %% Test explicit blocking. Block user 'two'.
+
+ [] = list_blocked_users(Node,Port,OpenDir),
+
+ true = block_user(Node, "two", Port, OpenDir, 10),
+
+ ok = auth_status(auth_request("/open/", "two", "twoPassword", Version, Host), Config,
+ [{statuscode, 401}]),
+
+ true = unblock_user(Node, "two", Port, OpenDir).
+
%%--------------------------------------------------------------------
@@ -550,21 +1096,35 @@ alias(Config) when is_list(Config) ->
%%--------------------------------------------------------------------
do_max_clients(Config) ->
Version = ?config(http_version, Config),
- Host = ?config(host, Config),
- start_blocker(Config),
- ok = httpd_test_lib:verify_request(?config(type, Config), Host,
- ?config(port, Config), ?config(node, Config),
- http_request("GET /index.html ", Version, Host),
+ Host = ?config(host, Config),
+ Port = ?config(port, Config),
+ Type = ?config(type, Config),
+
+ Request = http_request("GET /index.html ", Version, Host),
+ BlockRequest = http_request("GET /eval?httpd_example:delay(2000) ", Version, Host),
+ {ok, Socket} = inets_test_lib:connect_bin(Type, Host, Port, transport_opts(Type, Config)),
+ inets_test_lib:send(Type, Socket, BlockRequest),
+ ct:sleep(100), %% Avoid possible timing issues
+ ok = httpd_test_lib:verify_request(Type, Host,
+ Port,
+ transport_opts(Type, Config),
+ ?config(node, Config),
+ Request,
[{statuscode, 503},
{version, Version}]),
receive
- after 2000 ->
- ok = httpd_test_lib:verify_request(?config(type, Config), Host,
- ?config(port, Config), ?config(node, Config),
- http_request("GET /index.html ", Version, Host),
- [{statuscode, 200},
- {version, Version}])
- end.
+ {_, Socket, _Msg} ->
+ ok
+ end,
+ inets_test_lib:close(Type, Socket),
+ ct:sleep(100), %% Avoid possible timing issues
+ ok = httpd_test_lib:verify_request(Type, Host,
+ Port,
+ transport_opts(Type, Config),
+ ?config(node, Config),
+ Request,
+ [{statuscode, 200},
+ {version, Version}]).
setup_server_dirs(ServerRoot, DocRoot, DataDir) ->
CgiDir = filename:join(ServerRoot, "cgi-bin"),
@@ -604,10 +1164,24 @@ setup_server_dirs(ServerRoot, DocRoot, DataDir) ->
ok = file:write_file_info(EnvCGI,
FileInfo1#file_info{mode = 8#00755}).
-start_apps(https) ->
- inets_test_lib:start_apps([crypto, public_key, ssl]);
-start_apps(_) ->
- ok.
+start_apps(Group) when Group == https_basic;
+ Group == https_limit;
+ Group == https_basic_auth;
+ Group == https_auth_api;
+ Group == https_auth_api_dets;
+ Group == https_auth_api_mnesia;
+ Group == http_htaccess;
+ Group == http_security ->
+ inets_test_lib:start_apps([inets, asn1, crypto, public_key, ssl]);
+start_apps(Group) when Group == http_basic;
+ Group == http_limit;
+ Group == http_basic_auth;
+ Group == http_auth_api;
+ Group == http_auth_api_dets;
+ Group == http_auth_api_mnesia;
+ Group == https_htaccess;
+ Group == https_security ->
+ inets_test_lib:start_apps([inets]).
server_start(_, HttpdConfig) ->
{ok, Pid} = inets:start(httpd, HttpdConfig),
@@ -615,6 +1189,80 @@ server_start(_, HttpdConfig) ->
{value, {_, _, Info}} = lists:keysearch(Pid, 2, Serv),
{Pid, proplists:get_value(port, Info)}.
+init_ssl(Group, Config) ->
+ PrivDir = ?config(priv_dir, Config),
+ CaKey = {_Trusted,_} =
+ erl_make_certs:make_cert([{key, dsa},
+ {subject,
+ [{name, "Public Key"},
+ {?'id-at-name',
+ {printableString, "public_key"}},
+ {?'id-at-pseudonym',
+ {printableString, "pubkey"}},
+ {city, "Stockholm"},
+ {country, "SE"},
+ {org, "erlang"},
+ {org_unit, "testing dep"}
+ ]}
+ ]),
+ ok = erl_make_certs:write_pem(PrivDir, "public_key_cacert", CaKey),
+
+ CertK1 = {_Cert1, _} = erl_make_certs:make_cert([{issuer, CaKey}]),
+ CertK2 = {_Cert2,_} = erl_make_certs:make_cert([{issuer, CertK1},
+ {digest, md5},
+ {extensions, false}]),
+ ok = erl_make_certs:write_pem(PrivDir, "public_key_cert", CertK2),
+
+ case start_apps(Group) of
+ ok ->
+ init_httpd(Group, [{type, ssl} | Config]);
+ _ ->
+ {skip, "Could not start https apps"}
+ end.
+
+server_config(http_basic, Config) ->
+ basic_conf() ++ server_config(http, Config);
+server_config(https_basic, Config) ->
+ basic_conf() ++ server_config(https, Config);
+server_config(http_limit, Config) ->
+ [{max_clients, 1}] ++ server_config(http, Config);
+server_config(https_limit, Config) ->
+ [{max_clients, 1}] ++ server_config(https, Config);
+server_config(http_basic_auth, Config) ->
+ ServerRoot = ?config(server_root, Config),
+ auth_conf(ServerRoot) ++ server_config(http, Config);
+server_config(https_basic_auth, Config) ->
+ ServerRoot = ?config(server_root, Config),
+ auth_conf(ServerRoot) ++ server_config(https, Config);
+server_config(http_auth_api, Config) ->
+ ServerRoot = ?config(server_root, Config),
+ auth_api_conf(ServerRoot, plain) ++ server_config(http, Config);
+server_config(https_auth_api, Config) ->
+ ServerRoot = ?config(server_root, Config),
+ auth_api_conf(ServerRoot, plain) ++ server_config(https, Config);
+server_config(http_auth_api_dets, Config) ->
+ ServerRoot = ?config(server_root, Config),
+ auth_api_conf(ServerRoot, dets) ++ server_config(http, Config);
+server_config(https_auth_api_dets, Config) ->
+ ServerRoot = ?config(server_root, Config),
+ auth_api_conf(ServerRoot, dets) ++ server_config(https, Config);
+server_config(http_auth_api_mnesia, Config) ->
+ ServerRoot = ?config(server_root, Config),
+ auth_api_conf(ServerRoot, mnesia) ++ server_config(http, Config);
+server_config(https_auth_api_mnesia, Config) ->
+ ServerRoot = ?config(server_root, Config),
+ auth_api_conf(ServerRoot, mnesia) ++ server_config(https, Config);
+server_config(http_htaccess, Config) ->
+ auth_access_conf() ++ server_config(http, Config);
+server_config(https_htaccess, Config) ->
+ auth_access_conf() ++ server_config(https, Config);
+server_config(http_security, Config) ->
+ ServerRoot = ?config(server_root, Config),
+ tl(auth_conf(ServerRoot)) ++ security_conf(ServerRoot) ++ server_config(http, Config);
+server_config(https_security, Config) ->
+ ServerRoot = ?config(server_root, Config),
+ tl(auth_conf(ServerRoot)) ++ security_conf(ServerRoot) ++ server_config(https, Config);
+
server_config(http, Config) ->
ServerRoot = ?config(server_root, Config),
[{port, 0},
@@ -625,6 +1273,7 @@ server_config(http, Config) ->
{ipfamily, inet},
{max_header_size, 256},
{max_header_action, close},
+ {directory_index, ["index.html", "welcome.html"]},
{mime_types, [{"html","text/html"},{"htm","text/html"}, {"shtml","text/html"},
{"gif", "image/gif"}]},
{alias, {"/icons/", filename:join(ServerRoot,"icons") ++ "/"}},
@@ -633,13 +1282,24 @@ server_config(http, Config) ->
{script_alias, {"/htbin/", filename:join(ServerRoot, "cgi-bin") ++ "/"}},
{erl_script_alias, {"/cgi-bin/erl", [httpd_example, io]}},
{eval_script_alias, {"/eval", [httpd_example, io]}}
- ] ++ auth_conf(ServerRoot);
+ ];
-server_config(http_limit, Config) ->
- [{max_clients, 1}] ++ server_config(http, Config);
-
-server_config(_, _) ->
- [].
+server_config(https, Config) ->
+ PrivDir = ?config(priv_dir, Config),
+ [{socket_type, {essl,
+ [{cacertfile,
+ filename:join(PrivDir, "public_key_cacert.pem")},
+ {certfile,
+ filename:join(PrivDir, "public_key_cert.pem")},
+ {keyfile,
+ filename:join(PrivDir, "public_key_cert_key.pem")}
+ ]}}] ++ server_config(http, Config).
+
+init_httpd(Group, Config0) ->
+ Config1 = proplists:delete(port, Config0),
+ Config = proplists:delete(server_pid, Config1),
+ {Pid, Port} = server_start(Group, server_config(Group, Config)),
+ [{server_pid, Pid}, {port, Port} | Config].
http_request(Request, "HTTP/1.1" = Version, Host, {Headers, Body}) ->
Request ++ Version ++ "\r\nhost:" ++ Host ++ "\r\n" ++ Headers ++ "\r\n" ++ Body;
@@ -662,19 +1322,33 @@ auth_request(Path, User, Passwd, Version, _Host) ->
base64:encode_to_string(User++":"++Passwd) ++
"\r\n\r\n".
+http_request_missing_CR(Request, "HTTP/1.1" = Version, Host) ->
+ Request ++ Version ++ "\r\nhost:" ++ Host ++ "\r\n\r\n\n";
+http_request_missing_CR(Request, Version, _) ->
+ Request ++ Version ++ "\r\n\n".
+
head_status("HTTP/0.9") ->
501; %% Not implemented in HTTP/0.9
head_status(_) ->
200.
+basic_conf() ->
+ [{modules, [mod_alias, mod_range, mod_responsecontrol,
+ mod_trace, mod_esi, mod_cgi, mod_dir, mod_get, mod_head]}].
+
+auth_access_conf() ->
+ [{modules, [mod_alias, mod_htaccess, mod_dir, mod_get, mod_head]},
+ {access_files, [".htaccess"]}].
+
auth_conf(Root) ->
- [{directory, {filename:join(Root, "htdocs/open"),
+ [{modules, [mod_alias, mod_auth, mod_dir, mod_get, mod_head]},
+ {directory, {filename:join(Root, "htdocs/open"),
[{auth_type, plain},
{auth_name, "Open Area"},
{auth_user_file, filename:join(Root, "auth/passwd")},
{auth_group_file, filename:join(Root, "auth/group")},
{require_user, ["one", "Aladdin"]}]}},
- {directory, {filename:join(Root, "htdocs/secret"),
+ {directory, {filename:join(Root, "htdocs/secret"),
[{auth_type, plain},
{auth_name, "Secret Area"},
{auth_user_file, filename:join(Root, "auth/passwd")},
@@ -685,43 +1359,134 @@ auth_conf(Root) ->
{auth_name, "Top Secret Area"},
{auth_user_file, filename:join(Root, "auth/passwd")},
{auth_group_file, filename:join(Root, "auth/group")},
- {require_group, ["group3"]}]}},
+ {require_group, ["group3"]}]}}].
+
+auth_api_conf(Root, plain) ->
+ [{modules, [mod_alias, mod_auth, mod_dir, mod_get, mod_head]},
{directory, {filename:join(Root, "htdocs/open"),
- [{auth_type, mnesia},
+ [{auth_type, plain},
{auth_name, "Open Area"},
{auth_user_file, filename:join(Root, "auth/passwd")},
{auth_group_file, filename:join(Root, "auth/group")},
{require_user, ["one", "Aladdin"]}]}},
{directory, {filename:join(Root, "htdocs/secret"),
- [{auth_type, mnesia},
+ [{auth_type, plain},
{auth_name, "Secret Area"},
{auth_user_file, filename:join(Root, "auth/passwd")},
{auth_group_file, filename:join(Root, "auth/group")},
- {require_group, ["group1", "group2"]}]}}
- ].
+ {require_group, ["group1", "group2"]}]}},
+ {directory, {filename:join(Root, "htdocs/secret/top_secret"),
+ [{auth_type, plain},
+ {auth_name, "Top Secret Area"},
+ {auth_user_file, filename:join(Root, "auth/passwd")},
+ {auth_group_file, filename:join(Root, "auth/group")},
+ {require_group, ["group3"]}]}}];
+auth_api_conf(Root, dets) ->
+ [
+ {modules, [mod_alias, mod_auth, mod_dir, mod_get, mod_head]},
+ {directory, {filename:join(Root, "htdocs/dets_open"),
+ [{auth_type, dets},
+ {auth_name, "Dets Open Area"},
+ {auth_user_file, filename:join(Root, "passwd")},
+ {auth_group_file, filename:join(Root, "group")},
+ {require_user, ["one", "Aladdin"]}]}},
+ {directory, {filename:join(Root, "htdocs/dets_secret"),
+ [{auth_type, dets},
+ {auth_name, "Dests Secret Area"},
+ {auth_user_file, filename:join(Root, "passwd")},
+ {auth_group_file, filename:join(Root, "group")},
+ {require_group, ["group1", "group2"]}]}},
+ {directory, {filename:join(Root, "htdocs/dets_secret/top_secret"),
+ [{auth_type, dets},
+ {auth_name, "Dets Top Secret Area"},
+ {auth_user_file, filename:join(Root, "passwd")},
+ {auth_group_file, filename:join(Root, "group")},
+ {require_group, ["group3"]}]}}
+ ];
+
+auth_api_conf(Root, mnesia) ->
+ [{modules, [mod_alias, mod_auth, mod_dir, mod_get, mod_head]},
+ {directory, {filename:join(Root, "htdocs/mnesia_open"),
+ [{auth_type, mnesia},
+ {auth_name, "Mnesia Open Area"},
+ {require_user, ["one", "Aladdin"]}]}},
+ {directory, {filename:join(Root, "htdocs/mnesia_secret"),
+ [{auth_type, mnesia},
+ {auth_name, "Mnesia Secret Area"},
+ {require_group, ["group1", "group2"]}]}},
+ {directory, {filename:join(Root, "htdocs/mnesia_secret/top_secret"),
+ [{auth_type, mnesia},
+ {auth_name, "Mnesia Top Secret Area"},
+ {require_group, ["group3"]}]}}].
+
+security_conf(Root) ->
+ SecFile = filename:join(Root, "security_data"),
+ Open = filename:join(Root, "htdocs/open"),
+ Secret = filename:join(Root, "htdocs/secret"),
+ TopSecret = filename:join(Root, "htdocs/secret/top_secret"),
+
+ [{modules, [mod_alias, mod_auth, mod_security, mod_dir, mod_get, mod_head]},
+ {security_directory, {Open,
+ [{auth_name, "Open Area"},
+ {auth_user_file, filename:join(Root, "auth/passwd")},
+ {auth_group_file, filename:join(Root, "auth/group")},
+ {require_user, ["one", "Aladdin"]} |
+ mod_security_conf(SecFile, Open)]}},
+ {security_directory, {Secret,
+ [{auth_name, "Secret Area"},
+ {auth_user_file, filename:join(Root, "auth/passwd")},
+ {auth_group_file, filename:join(Root, "auth/group")},
+ {require_group, ["group1", "group2"]} |
+ mod_security_conf(SecFile, Secret)]}},
+ {security_directory, {TopSecret,
+ [{auth_name, "Top Secret Area"},
+ {auth_user_file, filename:join(Root, "auth/passwd")},
+ {auth_group_file, filename:join(Root, "auth/group")},
+ {require_group, ["group3"]} |
+ mod_security_conf(SecFile, TopSecret)]}}].
+
+mod_security_conf(SecFile, Dir) ->
+ [{data_file, SecFile},
+ {max_retries, 3},
+ {fail_expire_time, ?FAIL_EXPIRE_TIME},
+ {block_time, 1},
+ {auth_timeout, ?AUTH_TIMEOUT},
+ {callback_module, ?MODULE},
+ {path, Dir} %% This is should not be needed, but is atm, awful design!
+ ].
+
http_status(Request, Config, Expected) ->
Version = ?config(http_version, Config),
Host = ?config(host, Config),
+ Type = ?config(type, Config),
httpd_test_lib:verify_request(?config(type, Config), Host,
- ?config(port, Config), ?config(node, Config),
+ ?config(port, Config),
+ transport_opts(Type, Config),
+ ?config(node, Config),
http_request(Request, Version, Host),
Expected ++ [{version, Version}]).
http_status(Request, HeadersAndBody, Config, Expected) ->
Version = ?config(http_version, Config),
- Host = ?config(host, Config),
+ Host = ?config(host, Config),
+ Type = ?config(type, Config),
httpd_test_lib:verify_request(?config(type, Config), Host,
- ?config(port, Config), ?config(node, Config),
+ ?config(port, Config),
+ transport_opts(Type, Config),
+ ?config(node, Config),
http_request(Request, Version, Host, HeadersAndBody),
Expected ++ [{version, Version}]).
auth_status(AuthRequest, Config, Expected) ->
Version = ?config(http_version, Config),
Host = ?config(host, Config),
+ Type = ?config(type, Config),
httpd_test_lib:verify_request(?config(type, Config), Host,
- ?config(port, Config), ?config(node, Config),
+ ?config(port, Config),
+ transport_opts(Type, Config),
+ ?config(node, Config),
AuthRequest,
Expected ++ [{version, Version}]).
@@ -772,23 +1537,258 @@ cleanup_mnesia() ->
mnesia:delete_schema([node()]),
ok.
-start_blocker(Config) ->
- spawn(httpd_SUITE, init_blocker, [self(), Config]),
- receive
- blocker_start ->
+transport_opts(ssl, Config) ->
+ PrivDir = ?config(priv_dir, Config),
+ [{cacertfile, filename:join(PrivDir, "public_key_cacert.pem")}];
+transport_opts(_, _) ->
+ [].
+
+
+%%% mod_range
+create_range_data(Path) ->
+ PathAndFileName=filename:join([Path,"range.txt"]),
+ case file:read_file(PathAndFileName) of
+ {error, enoent} ->
+ file:write_file(PathAndFileName,list_to_binary(["12345678901234567890",
+ "12345678901234567890",
+ "12345678901234567890",
+ "12345678901234567890",
+ "12345678901234567890"]));
+ _ ->
ok
end.
+
+%%% mod_htaccess
+create_htaccess_data(Path, IpAddress)->
+ create_htaccess_dirs(Path),
+
+ create_html_file(filename:join([Path,"ht/open/dummy.html"])),
+ create_html_file(filename:join([Path,"ht/blocknet/dummy.html"])),
+ create_html_file(filename:join([Path,"ht/secret/dummy.html"])),
+ create_html_file(filename:join([Path,"ht/secret/top_secret/dummy.html"])),
-init_blocker(From, Config) ->
- From ! blocker_start,
- block(Config).
+ create_htaccess_file(filename:join([Path,"ht/open/.htaccess"]),
+ Path, "user one Aladdin"),
+ create_htaccess_file(filename:join([Path,"ht/secret/.htaccess"]),
+ Path, "group group1 group2"),
+ create_htaccess_file(filename:join([Path,
+ "ht/secret/top_secret/.htaccess"]),
+ Path, "user four"),
+ create_htaccess_file(filename:join([Path,"ht/blocknet/.htaccess"]),
+ Path, nouser, IpAddress),
+
+ create_user_group_file(filename:join([Path,"ht","users.file"]),
+ "one:OnePassword\ntwo:TwoPassword\nthree:"
+ "ThreePassword\nfour:FourPassword\nAladdin:"
+ "AladdinPassword"),
+ create_user_group_file(filename:join([Path,"ht","groups.file"]),
+ "group1: two one\ngroup2: two three").
+
+create_html_file(PathAndFileName)->
+ file:write_file(PathAndFileName,list_to_binary(
+ "<html><head><title>test</title></head>
+ <body>testar</body></html>")).
+
+create_htaccess_file(PathAndFileName, BaseDir, RequireData)->
+ file:write_file(PathAndFileName,
+ list_to_binary(
+ "AuthUserFile "++ BaseDir ++
+ "/ht/users.file\nAuthGroupFile "++ BaseDir
+ ++ "/ht/groups.file\nAuthName Test\nAuthType"
+ " Basic\n<Limit>\nrequire " ++ RequireData ++
+ "\n</Limit>")).
+
+create_htaccess_file(PathAndFileName, BaseDir, nouser, IpAddress)->
+ file:write_file(PathAndFileName,list_to_binary(
+ "AuthUserFile "++ BaseDir ++
+ "/ht/users.file\nAuthGroupFile " ++
+ BaseDir ++ "/ht/groups.file\nAuthName"
+ " Test\nAuthType"
+ " Basic\n<Limit GET>\n\tallow from " ++
+ format_ip(IpAddress,
+ string:rchr(IpAddress,$.)) ++
+ "\n</Limit>")).
+
+create_user_group_file(PathAndFileName, Data)->
+ file:write_file(PathAndFileName, list_to_binary(Data)).
+
+create_htaccess_dirs(Path)->
+ ok = file:make_dir(filename:join([Path,"ht"])),
+ ok = file:make_dir(filename:join([Path,"ht/open"])),
+ ok = file:make_dir(filename:join([Path,"ht/blocknet"])),
+ ok = file:make_dir(filename:join([Path,"ht/secret"])),
+ ok = file:make_dir(filename:join([Path,"ht/secret/top_secret"])).
+
+remove_htaccess_dirs(Path)->
+ file:del_dir(filename:join([Path,"ht/secret/top_secret"])),
+ file:del_dir(filename:join([Path,"ht/secret"])),
+ file:del_dir(filename:join([Path,"ht/blocknet"])),
+ file:del_dir(filename:join([Path,"ht/open"])),
+ file:del_dir(filename:join([Path,"ht"])).
+
+format_ip(IpAddress,Pos)when Pos > 0->
+ case lists:nth(Pos,IpAddress) of
+ $.->
+ case lists:nth(Pos-2,IpAddress) of
+ $.->
+ format_ip(IpAddress,Pos-3);
+ _->
+ lists:sublist(IpAddress,Pos-2) ++ "."
+ end;
+ _ ->
+ format_ip(IpAddress,Pos-1)
+ end;
+
+format_ip(IpAddress, _Pos)->
+ "1" ++ IpAddress.
+
+remove_htaccess(Path)->
+ file:delete(filename:join([Path,"ht/open/dummy.html"])),
+ file:delete(filename:join([Path,"ht/secret/dummy.html"])),
+ file:delete(filename:join([Path,"ht/secret/top_secret/dummy.html"])),
+ file:delete(filename:join([Path,"ht/blocknet/dummy.html"])),
+ file:delete(filename:join([Path,"ht/blocknet/.htaccess"])),
+ file:delete(filename:join([Path,"ht/open/.htaccess"])),
+ file:delete(filename:join([Path,"ht/secret/.htaccess"])),
+ file:delete(filename:join([Path,"ht/secret/top_secret/.htaccess"])),
+ file:delete(filename:join([Path,"ht","users.file"])),
+ file:delete(filename:join([Path,"ht","groups.file"])),
+ remove_htaccess_dirs(Path).
+
+dos_hostname(Type, Port, Host, Node, Version, Max) ->
+ TooLongHeader = lists:append(lists:duplicate(Max + 1, "a")),
+
+ ok = httpd_test_lib:verify_request(Type, Host, Port, Node,
+ dos_hostname_request("", Version),
+ [{statuscode, 200},
+ {version, Version}]),
+
+ ok = httpd_test_lib:verify_request(Type, Host, Port, Node,
+ dos_hostname_request("dummy-host.ericsson.se", Version),
+ [{statuscode, 200},
+ {version, Version}]),
+
+ ok = httpd_test_lib:verify_request(Type, Host, Port, Node,
+ dos_hostname_request(TooLongHeader, Version),
+ [{statuscode, dos_code(Version)},
+ {version, Version}]).
+dos_hostname_request(Host, Version) ->
+ dos_http_request("GET / ", Version, Host).
+
+dos_http_request(Request, "HTTP/1.1" = Version, Host) ->
+ http_request(Request, Version, Host);
+dos_http_request(Request, Version, Host) ->
+ Request ++ Version ++ "\r\nhost:" ++ Host ++ "\r\n\r\n".
+
+dos_code("HTTP/1.0") ->
+ 403; %% 413 not defined in HTTP/1.0
+dos_code(_) ->
+ 413.
+
+update_password(Node, ServerRoot, _Address, Port, AuthPrefix, Dir, Old, New)->
+ Directory = filename:join([ServerRoot, "htdocs", AuthPrefix ++ Dir]),
+ rpc:call(Node, mod_auth, update_password,
+ [undefined, Port, Directory, Old, New, New]).
+
+add_user(Node, Root, Port, AuthPrefix, Dir, User, Password, UserData) ->
+ Addr = undefined,
+ Directory = filename:join([Root, "htdocs", AuthPrefix ++ Dir]),
+ rpc:call(Node, mod_auth, add_user,
+ [User, Password, UserData, Addr, Port, Directory]).
+
+
+delete_user(Node, Root, _Host, Port, AuthPrefix, Dir, User) ->
+ Addr = undefined,
+ Directory = filename:join([Root, "htdocs", AuthPrefix ++ Dir]),
+ rpc:call(Node, mod_auth, delete_user, [User, Addr, Port, Directory]).
+remove_users(Node, ServerRoot, Host, Port, AuthPrefix, Dir) ->
+ %% List users, delete them, and make sure they are gone.
+ case list_users(Node, ServerRoot, Host, Port, AuthPrefix, Dir) of
+ {ok, Users} ->
+ lists:foreach(fun(User) ->
+ delete_user(Node, ServerRoot, Host,
+ Port, AuthPrefix, Dir, User)
+ end,
+ Users),
+ {ok, []} = list_users(Node, ServerRoot, Host, Port, AuthPrefix, Dir);
+ _ ->
+ ok
+ end.
+
+list_users(Node, Root, _Host, Port, AuthPrefix, Dir) ->
+ Addr = undefined,
+ Directory = filename:join([Root, "htdocs", AuthPrefix ++ Dir]),
+ rpc:call(Node, mod_auth, list_users, [Addr, Port, Directory]).
+
+remove_groups(Node, ServerRoot, Host, Port, AuthPrefix, Dir) ->
+ {ok, Groups} = list_groups(Node, ServerRoot, Host, Port, AuthPrefix, Dir),
+ lists:foreach(fun(Group) ->
+ delete_group(Node, Group, Port, ServerRoot, AuthPrefix, Dir)
+ end,
+ Groups),
+ {ok, []} = list_groups(Node, ServerRoot, Host, Port, AuthPrefix, Dir).
+
+delete_group(Node, Group, Port, Root, AuthPrefix, Dir) ->
+ Addr = undefined,
+ Directory = filename:join([Root, "htdocs", AuthPrefix ++ Dir]),
+ rpc:call(Node, mod_auth, delete_group, [Group, Addr, Port, Directory]).
+
+list_groups(Node, Root, _, Port, AuthPrefix, Dir) ->
+ Addr = undefined,
+ Directory = filename:join([Root, "htdocs", AuthPrefix ++ Dir]),
+ rpc:call(Node, mod_auth, list_groups, [Addr, Port, Directory]).
+
+add_group_member(Node, Root, Port, AuthPrefix, Dir, User, Group) ->
+ Addr = undefined,
+ Directory = filename:join([Root, "htdocs", AuthPrefix ++ Dir]),
+ rpc:call(Node, mod_auth, add_group_member, [Group, User, Addr, Port,
+ Directory]).
+getaddr() ->
+ {ok,HostName} = inet:gethostname(),
+ {ok,{A1,A2,A3,A4}} = inet:getaddr(HostName,inet),
+ lists:flatten(io_lib:format("~p.~p.~p.~p",[A1,A2,A3,A4])).
+
+receive_security_event(Event, Node, Port) ->
+ receive
+ Event ->
+ ok;
+ {'EXIT', _, _} ->
+ receive_security_event(Event, Node, Port)
+ after 5000 ->
+ %% Flush the message queue, to see if we got something...
+ inets_test_lib:flush()
+ end.
+
+list_blocked_users(Node,Port) ->
+ Addr = undefined, % Assumed to be on the same host
+ rpc:call(Node, mod_security, list_blocked_users, [Addr,Port]).
+
+list_blocked_users(Node,Port,Dir) ->
+ Addr = undefined, % Assumed to be on the same host
+ rpc:call(Node, mod_security, list_blocked_users, [Addr,Port,Dir]).
+
+block_user(Node,User,Port,Dir,Sec) ->
+ Addr = undefined, % Assumed to be on the same host
+ rpc:call(Node, mod_security, block_user, [User, Addr, Port, Dir, Sec]).
+
+unblock_user(Node,User,Port,Dir) ->
+ Addr = undefined, % Assumed to be on the same host
+ rpc:call(Node, mod_security, unblock_user, [User, Addr, Port, Dir]).
+
+list_auth_users(Node,Port) ->
+ Addr = undefined, % Assumed to be on the same host
+ rpc:call(Node, mod_security, list_auth_users, [Addr,Port]).
+
+list_auth_users(Node,Port,Dir) ->
+ Addr = undefined, % Assumed to be on the same host
+ rpc:call(Node, mod_security, list_auth_users, [Addr,Port,Dir]).
+
+event(What, Port, Dir, Data) ->
+ Msg = {event, What, Port, Dir, Data},
+ case global:whereis_name(mod_security_test) of
+ undefined ->
+ ok;
+ _Pid ->
+ global:send(mod_security_test, Msg)
+ end.
-block(Config) ->
- Version = ?config(http_version, Config),
- Host = ?config(host, Config),
- httpd_test_lib:verify_request(?config(type, Config), Host,
- ?config(port, Config), ?config(node, Config),
- http_request("GET /eval?httpd_example:delay(1000) ",
- Version, Host),
- [{statuscode, 200},
- {version, Version}]).
diff --git a/lib/inets/test/httpd_basic_SUITE.erl b/lib/inets/test/httpd_basic_SUITE.erl
index 2d06f3e70c..fbe65145dc 100644
--- a/lib/inets/test/httpd_basic_SUITE.erl
+++ b/lib/inets/test/httpd_basic_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2007-2012. All Rights Reserved.
+%% Copyright Ericsson AB 2007-2014. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -65,7 +65,8 @@ end_per_group(_GroupName, Config) ->
init_per_suite(Config) ->
tsp("init_per_suite -> entry with"
"~n Config: ~p", [Config]),
- ok = inets:start(),
+ inets_test_lib:stop_apps([inets]),
+ inets_test_lib:start_apps([inets]),
PrivDir = ?config(priv_dir, Config),
DataDir = ?config(data_dir, Config),
diff --git a/lib/inets/test/httpd_test_lib.erl b/lib/inets/test/httpd_test_lib.erl
index 6406eeae79..ed466fd727 100644
--- a/lib/inets/test/httpd_test_lib.erl
+++ b/lib/inets/test/httpd_test_lib.erl
@@ -92,16 +92,6 @@ verify_request(SocketType, Host, Port, Node, RequestStr, Options, TimeOut)
verify_request(SocketType, Host, Port, [], Node, RequestStr, Options, TimeOut).
verify_request(SocketType, Host, Port, TranspOpts0, Node, RequestStr, Options, TimeOut) ->
- tsp("verify_request -> entry with"
- "~n SocketType: ~p"
- "~n Host: ~p"
- "~n Port: ~p"
- "~n TranspOpts: ~p"
- "~n Node: ~p"
- "~n Options: ~p"
- "~n TimeOut: ~p",
- [SocketType, Host, Port, TranspOpts0, Node, Options, TimeOut]),
-
%% For now, until we modernize the httpd tests
TranspOpts =
case lists:member(inet6, TranspOpts0) of
@@ -113,10 +103,7 @@ verify_request(SocketType, Host, Port, TranspOpts0, Node, RequestStr, Options, T
try inets_test_lib:connect_bin(SocketType, Host, Port, TranspOpts) of
{ok, Socket} ->
- tsp("verify_request -> connected - now send message"),
SendRes = inets_test_lib:send(SocketType, Socket, RequestStr),
- tsp("verify_request -> send result: "
- "~n ~p", [SendRes]),
State = case inets_regexp:match(RequestStr, "printenv") of
nomatch ->
#state{};
@@ -127,37 +114,24 @@ verify_request(SocketType, Host, Port, TranspOpts0, Node, RequestStr, Options, T
case request(State#state{request = RequestStr,
socket = Socket}, TimeOut) of
{error, Reason} ->
- tsp("verify_request -> request failed: "
- "~n Reason: ~p", [Reason]),
{error, Reason};
NewState ->
- tsp("verify_request -> validate reply: "
- "~n NewState: ~p", [NewState]),
ValidateResult =
validate(RequestStr, NewState, Options, Node, Port),
- tsp("verify_request -> validation result: "
- "~n ~p", [ValidateResult]),
inets_test_lib:close(SocketType, Socket),
ValidateResult
end;
ConnectError ->
- tsp("verify_request -> connect error: "
- "~n ~p"
- "~n", [ConnectError]),
- tsf({connect_error, ConnectError,
- [SocketType, Host, Port, TranspOpts]})
+ ct:fail({connect_error, ConnectError,
+ [SocketType, Host, Port, TranspOpts]})
catch
T:E ->
- tsp("verify_request -> connect failed: "
- "~n E: ~p"
- "~n T: ~p"
- "~n", [E, T]),
- tsf({connect_failure,
- [{type, T},
- {error, E},
- {stacktrace, erlang:get_stacktrace()},
- {args, [SocketType, Host, Port, TranspOpts]}]})
+ ct:fail({connect_failure,
+ [{type, T},
+ {error, E},
+ {stacktrace, erlang:get_stacktrace()},
+ {args, [SocketType, Host, Port, TranspOpts]}]})
end.
request(#state{mfa = {Module, Function, Args},
@@ -166,10 +140,6 @@ 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} ->
handle_http_msg(Parsed, State);
@@ -179,22 +149,12 @@ 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]),
exit({test_failed, connection_closed});
{tcp_error, Socket, Reason} ->
- io:format("~p ~w[~w]request -> received (tcp) error"
- "~n Reason: ~p"
- "~n", [self(), ?MODULE, ?LINE, Reason]),
ct:fail({tcp_error, Reason});
{ssl, Socket, Data} ->
- print(ssl, Data, State),
case Module:Function([Data | Args]) of
{ok, Parsed} ->
handle_http_msg(Parsed, State);
@@ -204,28 +164,19 @@ request(#state{mfa = {Module, Function, Args},
request(State#state{mfa = NewMFA}, TimeOut)
end;
{ssl_closed, Socket} when Function =:= whole_body ->
- print(ssl, "closed", State),
State#state{body = hd(Args)};
{ssl_closed, Socket} ->
exit({test_failed, connection_closed});
{ssl_error, Socket, Reason} ->
ct:fail({ssl_error, Reason})
after TimeOut ->
- io:format("~p ~w[~w]request -> timeout"
- "~n", [self(), ?MODULE, ?LINE]),
+ ct:pal("~p ~w[~w]request -> timeout"
+ "~n", [self(), ?MODULE, ?LINE]),
ct: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,
@@ -285,11 +236,6 @@ validate(RequestStr, #state{status_line = {Version, StatusCode, _},
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, _} ->
@@ -311,20 +257,20 @@ check_version(Version, Options) ->
{value, {version, Version}} ->
ok;
{value, {version, Ver}} ->
- tsf({wrong_version, [{got, Version},
- {expected, Ver}]});
+ ct:fail({wrong_version, [{got, Version},
+ {expected, Ver}]});
_ ->
- case Version of
- "HTTP/1.1" ->
- ok;
+ case Version of
+ "HTTP/1.1" ->
+ ok;
_ ->
- tsf({wrong_version, [{got, Version},
- {expected, "HTTP/1.1"}]})
- end
+ ct:fail({wrong_version, [{got, Version},
+ {expected, "HTTP/1.1"}]})
+ end
end.
check_status_code(StatusCode, [], Options) ->
- tsf({wrong_status_code, [{got, StatusCode}, {expected, Options}]});
+ ct:fail({wrong_status_code, [{got, StatusCode}, {expected, Options}]});
check_status_code(StatusCode, Current = [_ | Rest], Options) ->
case lists:keysearch(statuscode, 1, Current) of
{value, {statuscode, StatusCode}} ->
@@ -332,7 +278,7 @@ check_status_code(StatusCode, Current = [_ | Rest], Options) ->
{value, {statuscode, _OtherStatus}} ->
check_status_code(StatusCode, Rest, Options);
false ->
- tsf({wrong_status_code, [{got, StatusCode}, {expected, Options}]})
+ ct:fail({wrong_status_code, [{got, StatusCode}, {expected, Options}]})
end.
do_validate(_, [], _, _) ->
@@ -345,9 +291,9 @@ do_validate(Header, [{header, HeaderField}|Rest], N, P) ->
{value, {LowerHeaderField, _Value}} ->
ok;
false ->
- tsf({missing_header_field, LowerHeaderField, Header});
+ ct:fail({missing_header_field, LowerHeaderField, Header});
_ ->
- tsf({missing_header_field, LowerHeaderField, Header})
+ ct:fail({missing_header_field, LowerHeaderField, Header})
end,
do_validate(Header, Rest, N, P);
do_validate(Header, [{header, HeaderField, Value}|Rest],N,P) ->
@@ -356,15 +302,15 @@ do_validate(Header, [{header, HeaderField, Value}|Rest],N,P) ->
{value, {LowerHeaderField, Value}} ->
ok;
false ->
- tsf({wrong_header_field_value, LowerHeaderField, Header});
+ ct:fail({wrong_header_field_value, LowerHeaderField, Header});
_ ->
- tsf({wrong_header_field_value, LowerHeaderField, Header})
+ ct:fail({wrong_header_field_value, LowerHeaderField, Header})
end,
do_validate(Header, Rest, N, P);
do_validate(Header,[{no_header, HeaderField}|Rest],N,P) ->
case lists:keysearch(HeaderField,1,Header) of
{value,_} ->
- tsf({wrong_header_field_value, HeaderField, Header});
+ ct:fail({wrong_header_field_value, HeaderField, Header});
_ ->
ok
end,
@@ -382,14 +328,14 @@ is_expect(RequestStr) ->
%% 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) ->
- tsf(content_length_error);
+ ct:fail(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;
_ ->
- tsf(content_length_error)
+ ct:fail(content_length_error)
end;
check_body(RequestStr, 200, "text/html", _, Body) ->
@@ -404,16 +350,3 @@ check_body(RequestStr, 200, "text/html", _, Body) ->
check_body(_, _, _, _,_) ->
ok.
-print(Proto, Data, #state{print = true}) ->
- ct:pal("Received ~p: ~p~n", [Proto, Data]);
-print(_, _, #state{print = false}) ->
- ok.
-
-
-tsp(F) ->
- inets_test_lib:tsp(F).
-tsp(F, A) ->
- inets_test_lib:tsp(F, A).
-
-tsf(Reason) ->
- inets_test_lib:tsf(Reason).
diff --git a/lib/inets/test/inets_sup_SUITE.erl b/lib/inets/test/inets_sup_SUITE.erl
index 12b85a816f..cf28f5a245 100644
--- a/lib/inets/test/inets_sup_SUITE.erl
+++ b/lib/inets/test/inets_sup_SUITE.erl
@@ -260,10 +260,10 @@ tftpd_worker(suite) ->
[];
tftpd_worker(Config) when is_list(Config) ->
[] = supervisor:which_children(tftp_sup),
- {ok, Pid0} = inets:start(tftpd, [{host, "localhost"},
- {port, inet_port()}]),
- {ok, _Pid1} = inets:start(tftpd, [{host, "localhost"},
- {port, inet_port()}], stand_alone),
+ {ok, Pid0} = inets:start(tftpd, [{host, inets_test_lib:hostname()},
+ {port, 0}]),
+ {ok, _Pid1} = inets:start(tftpd, [{host, inets_test_lib:hostname()},
+ {port, 0}], stand_alone),
[{_,Pid0, worker, _}] = supervisor:which_children(tftp_sup),
inets:stop(tftpd, Pid0),
@@ -397,13 +397,6 @@ httpc_subtree(Config) when is_list(Config) ->
tsp("httpc_subtree -> done"),
ok.
-inet_port() ->
- {ok, Socket} = gen_tcp:listen(0, [{reuseaddr, true}]),
- {ok, Port} = inet:port(Socket),
- gen_tcp:close(Socket),
- Port.
-
-
tsp(F) ->
tsp(F, []).
tsp(F, A) ->
diff --git a/lib/inets/test/old_httpd_SUITE.erl b/lib/inets/test/old_httpd_SUITE.erl
index de9aa4562e..3e1a1a3845 100644
--- a/lib/inets/test/old_httpd_SUITE.erl
+++ b/lib/inets/test/old_httpd_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2005-2013. All Rights Reserved.
+%% Copyright Ericsson AB 2005-2014. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -155,65 +155,103 @@ all() ->
[
{group, ip},
{group, ssl},
- {group, http_1_1_ip},
- {group, http_1_0_ip},
- {group, http_0_9_ip},
- {group, ipv6},
+ %%{group, http_1_1_ip},
+ %%{group, http_1_0_ip},
+ %%{group, http_0_9_ip},
+ %%{group, ipv6},
{group, tickets}
].
groups() ->
[
{ip, [],
- [ip_mod_alias, ip_mod_actions, ip_mod_security,
- ip_mod_auth, ip_mod_auth_api, ip_mod_auth_mnesia_api,
- ip_mod_htaccess, ip_mod_cgi, ip_mod_esi, ip_mod_get,
- ip_mod_head, ip_mod_all, ip_load_light, ip_load_medium,
- ip_load_heavy, ip_dos_hostname, ip_time_test,
- ip_restart_no_block, ip_restart_disturbing_block,
- ip_restart_non_disturbing_block,
- ip_block_disturbing_idle, ip_block_non_disturbing_idle,
- ip_block_503, ip_block_disturbing_active,
- ip_block_non_disturbing_active,
- ip_block_disturbing_active_timeout_not_released,
- ip_block_disturbing_active_timeout_released,
- ip_block_non_disturbing_active_timeout_not_released,
- ip_block_non_disturbing_active_timeout_released,
- ip_block_disturbing_blocker_dies,
- ip_block_non_disturbing_blocker_dies]},
+ [
+ %%ip_mod_alias,
+ ip_mod_actions,
+ %%ip_mod_security,
+ %% ip_mod_auth,
+ %% ip_mod_auth_api,
+ ip_mod_auth_mnesia_api,
+ %%ip_mod_htaccess,
+ %%ip_mod_cgi,
+ %%ip_mod_esi,
+ %%ip_mod_get,
+ %%ip_mod_head,
+ %%ip_mod_all,
+ %% ip_load_light,
+ %% ip_load_medium,
+ %% ip_load_heavy,
+ %%ip_dos_hostname,
+ ip_time_test
+ %% Replaced by load_config
+ %% ip_restart_no_block,
+ %% ip_restart_disturbing_block,
+ %% ip_restart_non_disturbing_block,
+ %% ip_block_disturbing_idle,
+ %% ip_block_non_disturbing_idle,
+ %% ip_block_503,
+ %% ip_block_disturbing_active,
+ %% ip_block_non_disturbing_active,
+ %% ip_block_disturbing_active_timeout_not_released,
+ %% ip_block_disturbing_active_timeout_released,
+ %% ip_block_non_disturbing_active_timeout_not_released,
+ %% ip_block_non_disturbing_active_timeout_released,
+ %% ip_block_disturbing_blocker_dies,
+ %% ip_block_non_disturbing_blocker_dies
+ ]},
{ssl, [], [{group, essl}]},
{essl, [],
- [essl_mod_alias, essl_mod_actions, essl_mod_security,
- essl_mod_auth, essl_mod_auth_api,
- essl_mod_auth_mnesia_api, essl_mod_htaccess,
- essl_mod_cgi, essl_mod_esi, essl_mod_get, essl_mod_head,
- essl_mod_all, essl_load_light, essl_load_medium,
- essl_load_heavy, essl_dos_hostname, essl_time_test,
- essl_restart_no_block, essl_restart_disturbing_block,
- essl_restart_non_disturbing_block,
- essl_block_disturbing_idle,
- essl_block_non_disturbing_idle, essl_block_503,
- essl_block_disturbing_active,
- essl_block_non_disturbing_active,
- essl_block_disturbing_active_timeout_not_released,
- essl_block_disturbing_active_timeout_released,
- essl_block_non_disturbing_active_timeout_not_released,
- essl_block_non_disturbing_active_timeout_released,
- essl_block_disturbing_blocker_dies,
- essl_block_non_disturbing_blocker_dies]},
- {http_1_1_ip, [],
- [ip_host, ip_chunked, ip_expect, ip_range, ip_if_test,
- ip_http_trace, ip_http1_1_head,
- ip_mod_cgi_chunked_encoding_test]},
- {http_1_0_ip, [],
- [ip_head_1_0, ip_get_1_0, ip_post_1_0]},
- {http_0_9_ip, [], [ip_get_0_9]},
- {ipv6, [], [ipv6_hostname_ipcomm, ipv6_address_ipcomm,
- ipv6_hostname_essl, ipv6_address_essl]},
+ [
+ %%essl_mod_alias,
+ essl_mod_actions,
+ %% essl_mod_security,
+ %% essl_mod_auth,
+ %% essl_mod_auth_api,
+ essl_mod_auth_mnesia_api,
+ %%essl_mod_htaccess,
+ %%essl_mod_cgi,
+ %%essl_mod_esi,
+ %%essl_mod_get,
+ %%essl_mod_head,
+ %% essl_mod_all,
+ %% essl_load_light,
+ %% essl_load_medium,
+ %% essl_load_heavy,
+ %%essl_dos_hostname,
+ essl_time_test
+ %% Replaced by load_config
+ %% essl_restart_no_block,
+ %% essl_restart_disturbing_block,
+ %% essl_restart_non_disturbing_block,
+ %% essl_block_disturbing_idle,
+ %% essl_block_non_disturbing_idle, essl_block_503,
+ %% essl_block_disturbing_active,
+ %% essl_block_non_disturbing_active,
+ %% essl_block_disturbing_active_timeout_not_released,
+ %% essl_block_disturbing_active_timeout_released,
+ %% essl_block_non_disturbing_active_timeout_not_released,
+ %% essl_block_non_disturbing_active_timeout_released,
+ %% essl_block_disturbing_blocker_dies,
+ %% essl_block_non_disturbing_blocker_dies
+ ]},
+ %% {http_1_1_ip, [],
+ %% [
+ %% %%ip_host, ip_chunked, ip_expect,
+ %% %%ip_range,
+ %% %%ip_if_test
+ %% %%ip_http_trace, ip_http1_1_head,
+ %% %%ip_mod_cgi_chunked_encoding_test
+ %% ]},
+ %%{http_1_0_ip, [],
+ %%[ip_head_1_0, ip_get_1_0, ip_post_1_0]},
+ %%{http_0_9_ip, [], [ip_get_0_9]},
+ %% {ipv6, [], [ipv6_hostname_ipcomm, ipv6_address_ipcomm,
+ %% ipv6_hostname_essl, ipv6_address_essl]},
{tickets, [],
- [ticket_5775, ticket_5865, ticket_5913, ticket_6003,
- ticket_7304]}].
-
+ [%%ticket_5775, ticket_5865,
+ ticket_5913%%, ticket_6003,
+ %%ticket_7304
+ ]}].
init_per_group(ipv6 = _GroupName, Config) ->
case inets_test_lib:has_ipv6_support() of
diff --git a/lib/inets/vsn.mk b/lib/inets/vsn.mk
index 6b1f149cc8..cbcf0362c9 100644
--- a/lib/inets/vsn.mk
+++ b/lib/inets/vsn.mk
@@ -18,6 +18,6 @@
# %CopyrightEnd%
APPLICATION = inets
-INETS_VSN = 5.9.8
+INETS_VSN = 5.10
PRE_VSN =
APP_VSN = "$(APPLICATION)-$(INETS_VSN)$(PRE_VSN)"
diff --git a/lib/jinterface/vsn.mk b/lib/jinterface/vsn.mk
index 1954040c3d..c50200fab6 100644
--- a/lib/jinterface/vsn.mk
+++ b/lib/jinterface/vsn.mk
@@ -1 +1 @@
-JINTERFACE_VSN = 1.5.8
+JINTERFACE_VSN = 1.5.9
diff --git a/lib/kernel/doc/src/app.xml b/lib/kernel/doc/src/app.xml
index 7c9d6eecec..8575d94048 100644
--- a/lib/kernel/doc/src/app.xml
+++ b/lib/kernel/doc/src/app.xml
@@ -61,7 +61,8 @@
{applications, Apps},
{env, Env},
{mod, Start},
- {start_phases, Phases}]}.
+ {start_phases, Phases},
+ {runtime_dependencies, RTDeps}]}.
Value Default
----- -------
@@ -77,8 +78,10 @@ Apps [App] []
Env [{Par,Val}] []
Start {Module,StartArgs} []
Phases [{Phase,PhaseArgs}] undefined
+RTDeps [ApplicationVersion] []
Module = Name = App = Par = Phase = atom()
- Val = StartArgs = PhaseArgs = term()</code>
+ Val = StartArgs = PhaseArgs = term()
+ ApplicationVersion = string()</code>
<p><c>Application</c> is the name of the application.</p>
<p>For the application controller, all keys are optional.
The respective default values are used for any omitted keys.</p>
@@ -87,6 +90,8 @@ Phases [{Phase,PhaseArgs}] undefined
<c>description</c>, <c>vsn</c>, <c>modules</c>, <c>registered</c>
and <c>applications</c>. The other keys are ignored by
<c>systools</c>.</p>
+ <warning><p>The <c>RTDeps</c> type was introduced in OTP 17.0 and
+ might be subject to changes during the OTP 17 release.</p></warning>
<taglist>
<tag><c>description</c></tag>
<item>
@@ -185,6 +190,33 @@ Phases [{Phase,PhaseArgs}] undefined
start phases must be a subset of the set of phases defined
for the primary application. Refer to <em>OTP Design Principles</em> for more information.</p>
</item>
+ <tag><marker id="runtime_dependencies"><c>runtime_dependencies</c></marker></tag>
+ <item><p>A list of application versions that the application
+ depends on. An example of such an application version is
+ <c>"kernel-3.0"</c>. Application versions specified as runtime
+ dependencies are minimum requirements. That is, a larger
+ application version than the one specified in the
+ dependency satisfies the requirement. For information on
+ how to compare application versions see
+ <seealso marker="doc/system_principles:versions">the
+ documentation of versions in the system principles
+ guide</seealso>. Note that that the application version
+ specifies a source code version. An additional indirect
+ requirement is that installed binary application of
+ the specified version has been built so that it is
+ compatible with the rest of the system.</p>
+ <p>Some dependencies might only be required in specific runtime
+ scenarios. In the case such optional dependencies exist, these are
+ specified and documented in the corresponding "App" documentation
+ of the specific application.</p>
+ <warning><p>The <c>runtime_dependencies</c> key was introduced in
+ OTP 17.0. The type of its value might be subject to changes during
+ the OTP 17 release.</p></warning>
+ <warning><p>All runtime dependencies specified in OTP applications
+ during the OTP 17 release may not be completely correct. This
+ is actively being worked on. Declared runtime dependencies in OTP
+ applications are expected to be correct in OTP 18.</p></warning>
+ </item>
</taglist>
</section>
diff --git a/lib/kernel/doc/src/application.xml b/lib/kernel/doc/src/application.xml
index 016151891c..7664fda4db 100644
--- a/lib/kernel/doc/src/application.xml
+++ b/lib/kernel/doc/src/application.xml
@@ -4,7 +4,7 @@
<erlref>
<header>
<copyright>
- <year>1996</year><year>2013</year>
+ <year>1996</year><year>2014</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -459,8 +459,7 @@ Nodes = [cp1@cave, {cp2@cave, cp3@cave}]</code>
<name>Module:start(StartType, StartArgs) -> {ok, Pid} | {ok, Pid, State} | {error, Reason}</name>
<fsummary>Start an application</fsummary>
<type>
- <v>StartType = normal | {takeover,Node} | {failover,Node}</v>
- <v>&nbsp;Node = node()</v>
+ <v>StartType = <seealso marker="#type-start_type">start_type()</seealso></v>
<v>StartArgs = term()</v>
<v>Pid = pid()</v>
<v>State = term()</v>
diff --git a/lib/kernel/doc/src/file.xml b/lib/kernel/doc/src/file.xml
index b3ec9fd33d..8dae34431b 100644
--- a/lib/kernel/doc/src/file.xml
+++ b/lib/kernel/doc/src/file.xml
@@ -642,6 +642,11 @@
<item>
<p>Symbolic links are not supported on this platform.</p>
</item>
+ <tag><c>eperm</c></tag>
+ <item>
+ <p>User does not have privileges to create symbolic links
+ (<c>SeCreateSymbolicLinkPrivilege</c> on Windows).</p>
+ </item>
</taglist>
</desc>
</func>
@@ -1630,6 +1635,11 @@
<desc>
<p>Sets the current working directory of the file server to
<c><anno>Dir</anno></c>. Returns <c>ok</c> if successful.</p>
+ <p>The functions in the <c>file</c> module usually treat binaries
+ as raw filenames, i.e. they are passed as is even when the encoding
+ of the binary does not agree with <c>file:native_name_encoding()</c>.
+ This function however expects binaries to be encoded according to the
+ value returned by <c>file:native_name_encoding()</c>.</p>
<p>Typical error reasons are:</p>
<taglist>
<tag><c>enoent</c></tag>
@@ -1654,8 +1664,8 @@
<tag><c>no_translation</c></tag>
<item>
<p><c><anno>Dir</anno></c> is a <c>binary()</c> with
- characters coded in ISO-latin-1 and the VM was started
- with the parameter <c>+fnue</c>.</p>
+ characters coded in ISO-latin-1 and the VM is operating
+ with unicode file name encoding.</p>
</item>
</taglist>
<warning>
diff --git a/lib/kernel/src/application.erl b/lib/kernel/src/application.erl
index 76a80553b0..c4bef5188a 100644
--- a/lib/kernel/src/application.erl
+++ b/lib/kernel/src/application.erl
@@ -30,6 +30,8 @@
-export([get_application/0, get_application/1, info/0]).
-export([start_type/0]).
+-export_type([start_type/0]).
+
%%%-----------------------------------------------------------------
-type start_type() :: 'normal'
@@ -58,8 +60,7 @@
%%------------------------------------------------------------------
--callback start(StartType :: normal | {takeover, node()} | {failover, node()},
- StartArgs :: term()) ->
+-callback start(StartType :: start_type(), StartArgs :: term()) ->
{'ok', pid()} | {'ok', pid(), State :: term()} | {'error', Reason :: term()}.
-callback stop(State :: term()) ->
diff --git a/lib/kernel/src/disk_log_server.erl b/lib/kernel/src/disk_log_server.erl
index 684ea5b5db..45334912eb 100644
--- a/lib/kernel/src/disk_log_server.erl
+++ b/lib/kernel/src/disk_log_server.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2013. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2014. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -199,7 +199,7 @@ do_open({open, W, #arg{name = Name}=A}=Req, From, State) ->
false when W =:= local ->
case A#arg.distributed of
{true, Nodes} ->
- Fun = fun() -> open_distr_rpc(Nodes, A, From) end,
+ Fun = open_distr_rpc_fun(Nodes, A, From),
_Pid = spawn(Fun),
%% No pending reply is expected, but don't reply yet.
{pending, State};
@@ -225,11 +225,15 @@ do_open({open, W, #arg{name = Name}=A}=Req, From, State) ->
end
end.
+-spec open_distr_rpc_fun([node()], _, _) -> % XXX: underspecified
+ fun(() -> no_return()).
+
+open_distr_rpc_fun(Nodes, A, From) ->
+ fun() -> open_distr_rpc(Nodes, A, From) end.
+
%% Spawning a process is a means to avoid deadlock when
%% disk_log_servers mutually open disk_logs.
--spec open_distr_rpc([node()], _, _) -> no_return(). % XXX: underspecified
-
open_distr_rpc(Nodes, A, From) ->
{AllReplies, BadNodes} = rpc:multicall(Nodes, ?MODULE, dist_open, [A]),
{Ok, Bad} = cr(AllReplies, [], []),
diff --git a/lib/kernel/src/file.erl b/lib/kernel/src/file.erl
index 23cf74f80f..20b703e084 100644
--- a/lib/kernel/src/file.erl
+++ b/lib/kernel/src/file.erl
@@ -199,7 +199,8 @@ get_cwd(Drive) ->
check_and_call(get_cwd, [file_name(Drive)]).
-spec set_cwd(Dir) -> ok | {error, Reason} when
- Dir :: name(),
+ Dir :: name() | EncodedBinary,
+ EncodedBinary :: binary(),
Reason :: posix() | badarg | no_translation.
set_cwd(Dirname) ->
diff --git a/lib/kernel/src/global.erl b/lib/kernel/src/global.erl
index ef878b8d0c..0a4edea452 100644
--- a/lib/kernel/src/global.erl
+++ b/lib/kernel/src/global.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2013. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2014. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -1513,14 +1513,18 @@ delete_global_name(_Name, _Pid) ->
-record(him, {node, locker, vsn, my_tag}).
start_the_locker(DoTrace) ->
- spawn_link(fun() -> init_the_locker(DoTrace) end).
-
-init_the_locker(DoTrace) ->
- process_flag(trap_exit, true), % needed?
- S0 = #multi{do_trace = DoTrace},
- S1 = update_locker_known({add, get_known()}, S0),
- loop_the_locker(S1),
- erlang:error(locker_exited).
+ spawn_link(init_the_locker_fun(DoTrace)).
+
+-spec init_the_locker_fun(boolean()) -> fun(() -> no_return()).
+
+init_the_locker_fun(DoTrace) ->
+ fun() ->
+ process_flag(trap_exit, true), % needed?
+ S0 = #multi{do_trace = DoTrace},
+ S1 = update_locker_known({add, get_known()}, S0),
+ loop_the_locker(S1),
+ erlang:error(locker_exited)
+ end.
loop_the_locker(S) ->
?trace({loop_the_locker,S}),
diff --git a/lib/kernel/src/hipe_unified_loader.erl b/lib/kernel/src/hipe_unified_loader.erl
index 976d5e35cb..e5928c7b63 100644
--- a/lib/kernel/src/hipe_unified_loader.erl
+++ b/lib/kernel/src/hipe_unified_loader.erl
@@ -194,6 +194,13 @@ load_common(Mod, Bin, Beam, OldReferencesToPatch) ->
CodeSize, CodeBinary, Refs,
0,[] % ColdSize, CRrefs
] = binary_to_term(Bin),
+ ?debug_msg("***** ErLLVM *****~nVersion: ~s~nCheckSum: ~w~nConstAlign: ~w~n" ++
+ "ConstSize: ~w~nConstMap: ~w~nLabelMap: ~w~nExportMap ~w~nRefs ~w~n",
+ [Version, CheckSum, ConstAlign, ConstSize, ConstMap, LabelMap, ExportMap,
+ Refs]),
+ %% Write HiPE binary code to a file in the current directory in order to
+ %% debug by disassembling.
+ %% file:write_file("erl.o", CodeBinary, [binary]),
%% Check that we are loading up-to-date code.
version_check(Version, Mod),
case hipe_bifs:check_crc(CheckSum) of
@@ -221,6 +228,7 @@ load_common(Mod, Bin, Beam, OldReferencesToPatch) ->
{MFAs,Addresses} = exports(ExportMap, CodeAddress),
%% Remove references to old versions of the module.
ReferencesToPatch = get_refs_from(MFAs, []),
+ %% io:format("References to patch: ~w~n", [ReferencesToPatch]),
ok = remove_refs_from(MFAs),
%% Patch all dynamic references in the code.
%% Function calls, Atoms, Constants, System calls
@@ -246,8 +254,7 @@ load_common(Mod, Bin, Beam, OldReferencesToPatch) ->
AddressesOfClosuresToPatch =
calculate_addresses(ClosurePatches, CodeAddress, Addresses),
export_funs(Addresses),
- export_funs(Mod, BeamBinary, Addresses, AddressesOfClosuresToPatch),
- ok
+ export_funs(Mod, BeamBinary, Addresses, AddressesOfClosuresToPatch)
end,
%% Redirect references to the old module to the new module's BEAM stub.
patch_to_emu_step2(OldReferencesToPatch),
diff --git a/lib/kernel/src/inet_config.erl b/lib/kernel/src/inet_config.erl
index 2461f3ff25..fdc244f959 100644
--- a/lib/kernel/src/inet_config.erl
+++ b/lib/kernel/src/inet_config.erl
@@ -197,6 +197,9 @@ do_load_resolv({win32,Type}, longnames) ->
win32_load_from_registry(Type),
inet_db:set_lookup([native]);
+do_load_resolv({ose,_}, _) ->
+ inet_db:set_lookup([file]);
+
do_load_resolv(_, _) ->
inet_db:set_lookup([native]).
diff --git a/lib/kernel/src/kernel.app.src b/lib/kernel/src/kernel.app.src
index cb8c98ab06..5658c6b6cf 100644
--- a/lib/kernel/src/kernel.app.src
+++ b/lib/kernel/src/kernel.app.src
@@ -114,6 +114,7 @@
pg2]},
{applications, []},
{env, [{error_logger, tty}]},
- {mod, {kernel, []}}
+ {mod, {kernel, []}},
+ {runtime_dependencies, ["erts-6.0", "stdlib-2.0", "sasl-2.4"]}
]
}.
diff --git a/lib/kernel/src/os.erl b/lib/kernel/src/os.erl
index 9ffa9adeab..187fd0001b 100644
--- a/lib/kernel/src/os.erl
+++ b/lib/kernel/src/os.erl
@@ -67,7 +67,7 @@ unsetenv(_) ->
%%% End of BIFs
-spec type() -> {Osfamily, Osname} when
- Osfamily :: unix | win32,
+ Osfamily :: unix | win32 | ose,
Osname :: atom().
type() ->
@@ -230,7 +230,9 @@ unix_cmd(Cmd) ->
%% and the commands are read from standard input. We set the
%% $1 parameter for easy identification of the resident shell.
%%
--define(SHELL, "/bin/sh -s unix:cmd 2>&1").
+-define(ROOT, "/").
+-define(ROOT_ANDROID, "/system").
+-define(SHELL, "bin/sh -s unix:cmd 2>&1").
-define(PORT_CREATOR_NAME, os_cmd_port_creator).
%%
@@ -280,7 +282,12 @@ start_port_srv(Request) ->
end.
start_port_srv_handle({Ref,Client}) ->
- Reply = try open_port({spawn, ?SHELL},[stream]) of
+ Path = case lists:reverse(erlang:system_info(system_architecture)) of
+ % androideabi
+ "ibaediordna" ++ _ -> filename:join([?ROOT_ANDROID, ?SHELL]);
+ _ -> filename:join([?ROOT, ?SHELL])
+ end,
+ Reply = try open_port({spawn, Path},[stream]) of
Port when is_port(Port) ->
(catch port_connect(Port, Client)),
unlink(Port),
diff --git a/lib/kernel/test/file_SUITE.erl b/lib/kernel/test/file_SUITE.erl
index 6b52493f46..f6d6cd94ab 100644
--- a/lib/kernel/test/file_SUITE.erl
+++ b/lib/kernel/test/file_SUITE.erl
@@ -428,7 +428,13 @@ make_del_dir(Config) when is_list(Config) ->
% because there are processes having that directory as current.
?line ok = ?FILE_MODULE:make_dir(NewDir),
?line {ok,CurrentDir} = file:get_cwd(),
- ?line ok = ?FILE_MODULE:set_cwd(NewDir),
+ case {os:type(), length(NewDir) >= 260 } of
+ {{win32,_}, true} ->
+ io:format("Skip set_cwd for windows path longer than 260 (MAX_PATH)\n", []),
+ io:format("\nNewDir = ~p\n", [NewDir]);
+ _ ->
+ ?line ok = ?FILE_MODULE:set_cwd(NewDir)
+ end,
try
%% Check that we get an error when trying to create...
%% a deep directory
@@ -485,32 +491,39 @@ cur_dir_0(Config) when is_list(Config) ->
atom_to_list(?MODULE)
++"_curdir"),
?line ok = ?FILE_MODULE:make_dir(NewDir),
- ?line io:format("cd to ~s",[NewDir]),
- ?line ok = ?FILE_MODULE:set_cwd(NewDir),
-
- %% Create a file in the new current directory, and check that it
- %% really is created there
- ?line UncommonName = "uncommon.fil",
- ?line {ok,Fd} = ?FILE_MODULE:open(UncommonName,read_write),
- ?line ok = ?FILE_MODULE:close(Fd),
- ?line {ok,NewDirFiles} = ?FILE_MODULE:list_dir("."),
- ?line true = lists:member(UncommonName,NewDirFiles),
-
- %% Delete the directory and return to the old current directory
- %% and check that the created file isn't there (too!)
- ?line expect({error, einval}, {error, eacces},
- ?FILE_MODULE:del_dir(NewDir)),
- ?line ?FILE_MODULE:delete(UncommonName),
- ?line {ok,[]} = ?FILE_MODULE:list_dir("."),
- ?line ok = ?FILE_MODULE:set_cwd(Dir1),
- ?line io:format("cd back to ~s",[Dir1]),
- ?line ok = ?FILE_MODULE:del_dir(NewDir),
- ?line {error, enoent} = ?FILE_MODULE:set_cwd(NewDir),
- ?line ok = ?FILE_MODULE:set_cwd(Dir1),
- ?line io:format("cd back to ~s",[Dir1]),
- ?line {ok,OldDirFiles} = ?FILE_MODULE:list_dir("."),
- ?line false = lists:member(UncommonName,OldDirFiles),
-
+ case {os:type(), length(NewDir) >= 260} of
+ {{win32,_}, true} ->
+ io:format("Skip set_cwd for windows path longer than 260 (MAX_PATH):\n"),
+ io:format("\nNewDir = ~p\n", [NewDir]);
+ _ ->
+ io:format("cd to ~s",[NewDir]),
+ ok = ?FILE_MODULE:set_cwd(NewDir),
+
+ %% Create a file in the new current directory, and check that it
+ %% really is created there
+ UncommonName = "uncommon.fil",
+ {ok,Fd} = ?FILE_MODULE:open(UncommonName,read_write),
+ ok = ?FILE_MODULE:close(Fd),
+ {ok,NewDirFiles} = ?FILE_MODULE:list_dir("."),
+ true = lists:member(UncommonName,NewDirFiles),
+
+ %% Delete the directory and return to the old current directory
+ %% and check that the created file isn't there (too!)
+ expect({error, einval}, {error, eacces},
+ ?FILE_MODULE:del_dir(NewDir)),
+ ?FILE_MODULE:delete(UncommonName),
+ {ok,[]} = ?FILE_MODULE:list_dir("."),
+ ok = ?FILE_MODULE:set_cwd(Dir1),
+ io:format("cd back to ~s",[Dir1]),
+
+ ok = ?FILE_MODULE:del_dir(NewDir),
+ {error, enoent} = ?FILE_MODULE:set_cwd(NewDir),
+ ok = ?FILE_MODULE:set_cwd(Dir1),
+ io:format("cd back to ~s",[Dir1]),
+ {ok,OldDirFiles} = ?FILE_MODULE:list_dir("."),
+ false = lists:member(UncommonName,OldDirFiles)
+ end,
+
%% Try doing some bad things
?line {error, badarg} = ?FILE_MODULE:set_cwd({foo,bar}),
?line {error, enoent} = ?FILE_MODULE:set_cwd(""),
@@ -1982,7 +1995,6 @@ names(Config) when is_list(Config) ->
?line Name1 = filename:join(RootDir, FileName),
?line Name2 = [RootDir,"/","foo1",".","fil"],
?line Name3 = [RootDir,"/",foo,$1,[[[],[],'.']],"f",il],
- ?line Name4 = list_to_atom(Name1),
?line {ok,Fd0} = ?FILE_MODULE:open(Name1,write),
?line ok = ?FILE_MODULE:close(Fd0),
@@ -1995,23 +2007,33 @@ names(Config) when is_list(Config) ->
?line ok = ?FILE_MODULE:close(Fd2),
?line {ok,Fd3} = ?FILE_MODULE:open(Name3,read),
?line ok = ?FILE_MODULE:close(Fd3),
- ?line {ok,Fd4} = ?FILE_MODULE:open(Name4,read),
- ?line ok = ?FILE_MODULE:close(Fd4),
+ case length(Name1) > 255 of
+ true ->
+ io:format("Path too long for an atom:\n\n~p\n", [Name1]);
+ false ->
+ Name4 = list_to_atom(Name1),
+ {ok,Fd4} = ?FILE_MODULE:open(Name4,read),
+ ok = ?FILE_MODULE:close(Fd4)
+ end,
%% Try some path names
?line Path1 = RootDir,
?line Path2 = [RootDir],
?line Path3 = ['',[],[RootDir,[[]]]],
- ?line Path4 = list_to_atom(Path1),
?line {ok,Fd11,_} = ?FILE_MODULE:path_open([Path1],FileName,read),
?line ok = ?FILE_MODULE:close(Fd11),
?line {ok,Fd12,_} = ?FILE_MODULE:path_open([Path2],FileName,read),
?line ok = ?FILE_MODULE:close(Fd12),
?line {ok,Fd13,_} = ?FILE_MODULE:path_open([Path3],FileName,read),
?line ok = ?FILE_MODULE:close(Fd13),
- ?line {ok,Fd14,_} = ?FILE_MODULE:path_open([Path4],FileName,read),
- ?line ok = ?FILE_MODULE:close(Fd14),
-
+ case length(Path1) > 255 of
+ true->
+ io:format("Path too long for an atom:\n\n~p\n", [Path1]);
+ false ->
+ Path4 = list_to_atom(Path1),
+ {ok,Fd14,_} = ?FILE_MODULE:path_open([Path4],FileName,read),
+ ok = ?FILE_MODULE:close(Fd14)
+ end,
?line [] = flush(),
?line test_server:timetrap_cancel(Dog),
ok.
@@ -2673,6 +2695,9 @@ symlinks(Config) when is_list(Config) ->
case ?FILE_MODULE:make_symlink(Name, Alias) of
{error, enotsup} ->
{skipped, "Links not supported on this platform"};
+ {error, eperm} ->
+ {win32,_} = os:type(),
+ {skipped, "Windows user not privileged to create symlinks"};
ok ->
?line {ok, Info1} = ?FILE_MODULE:read_file_info(Name),
?line {ok, Info1} = ?FILE_MODULE:read_file_info(Alias),
@@ -3599,7 +3624,11 @@ otp_10852(Config) when is_list(Config) ->
ok = rpc_call(Node, list_dir_all, [B]),
ok = rpc_call(Node, read_file, [B]),
ok = rpc_call(Node, make_link, [B,B]),
- ok = rpc_call(Node, make_symlink, [B,B]),
+ case rpc_call(Node, make_symlink, [B,B]) of
+ ok -> ok;
+ {error, E} when (E =:= enotsup) or (E =:= eperm) ->
+ {win32,_} = os:type()
+ end,
ok = rpc_call(Node, delete, [B]),
ok = rpc_call(Node, make_dir, [B]),
ok = rpc_call(Node, del_dir, [B]),
diff --git a/lib/kernel/test/gen_tcp_misc_SUITE.erl b/lib/kernel/test/gen_tcp_misc_SUITE.erl
index ee8bfcceb1..2df4bf7c95 100644
--- a/lib/kernel/test/gen_tcp_misc_SUITE.erl
+++ b/lib/kernel/test/gen_tcp_misc_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1998-2013. All Rights Reserved.
+%% Copyright Ericsson AB 1998-2014. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -50,6 +50,14 @@
oct_acceptor/1,
otp_7731_server/1, zombie_server/2, do_iter_max_socks/2]).
+init_per_testcase(wrapping_oct, Config) when is_list(Config) ->
+ Dog = case os:type() of
+ {ose,_} ->
+ test_server:timetrap(test_server:minutes(20));
+ _Else ->
+ test_server:timetrap(test_server:seconds(600))
+ end,
+ [{watchdog, Dog}|Config];
init_per_testcase(iter_max_socks, Config) when is_list(Config) ->
Dog = case os:type() of
{win32,_} ->
@@ -58,6 +66,17 @@ init_per_testcase(iter_max_socks, Config) when is_list(Config) ->
test_server:timetrap(test_server:seconds(240))
end,
[{watchdog, Dog}|Config];
+init_per_testcase(accept_system_limit, Config) when is_list(Config) ->
+ case os:type() of
+ {ose,_} ->
+ {skip,"Skip in OSE"};
+ _ ->
+ Dog = test_server:timetrap(test_server:seconds(240)),
+ [{watchdog,Dog}|Config]
+ end;
+init_per_testcase(wrapping_oct, Config) when is_list(Config) ->
+ Dog = test_server:timetrap(test_server:seconds(600)),
+ [{watchdog, Dog}|Config];
init_per_testcase(_Func, Config) when is_list(Config) ->
Dog = test_server:timetrap(test_server:seconds(240)),
[{watchdog, Dog}|Config].
@@ -537,7 +556,6 @@ otp_3924(Config) when is_list(Config) ->
otp_3924_1(MaxDelay).
otp_3924_1(MaxDelay) ->
- Dog = test_server:timetrap(test_server:seconds(240)),
?line {ok, Node} = start_node(otp_3924),
?line DataLen = 100*1024,
?line Data = otp_3924_data(DataLen),
@@ -548,7 +566,6 @@ otp_3924_1(MaxDelay) ->
?line ok = otp_3924(MaxDelay, Node, Data, DataLen, N)
end),
?line test_server:stop_node(Node),
- test_server:timetrap_cancel(Dog),
ok.
otp_3924(MaxDelay, Node, Data, DataLen, N) ->
@@ -1953,7 +1970,9 @@ accept_system_limit(doc) ->
accept_system_limit(Config) when is_list(Config) ->
?line {ok, LS} = gen_tcp:listen(0, []),
?line {ok, TcpPort} = inet:port(LS),
- ?line Connector = spawn_link(fun () -> connector(TcpPort) end),
+ Me = self(),
+ ?line Connector = spawn_link(fun () -> connector(TcpPort, Me) end),
+ receive {Connector, sync} -> Connector ! {self(), continue} end,
?line ok = acceptor(LS, false, []),
?line Connector ! stop,
ok.
@@ -1970,8 +1989,10 @@ acceptor(LS, GotSL, A) ->
error
end.
-connector(TcpPort) ->
+connector(TcpPort, Tester) ->
ManyPorts = open_ports([]),
+ Tester ! {self(), sync},
+ receive {Tester, continue} -> timer:sleep(100) end,
ConnF = fun (Port) ->
case catch gen_tcp:connect({127,0,0,1}, TcpPort, []) of
{ok, Sock} ->
@@ -2705,13 +2726,11 @@ wrapping_oct(doc) ->
wrapping_oct(suite) ->
[];
wrapping_oct(Config) when is_list(Config) ->
- Dog = test_server:timetrap(test_server:seconds(600)),
{ok,Sock} = gen_tcp:listen(0,[{active,false},{mode,binary}]),
{ok,Port} = inet:port(Sock),
spawn_link(?MODULE,oct_acceptor,[Sock]),
Res = oct_datapump(Port,16#1FFFFFFFF),
gen_tcp:close(Sock),
- test_server:timetrap_cancel(Dog),
ok = Res,
ok.
diff --git a/lib/kernel/test/heart_SUITE.erl b/lib/kernel/test/heart_SUITE.erl
index 320b23bea1..35d3b75b34 100644
--- a/lib/kernel/test/heart_SUITE.erl
+++ b/lib/kernel/test/heart_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2012. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2014. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -93,10 +93,10 @@ start_check(Type, Name) ->
start_check(Type, Name, []).
start_check(Type, Name, Envs) ->
Args = case ?t:os_type() of
- {win32,_} ->
- "-heart " ++ env_encode([{"HEART_COMMAND", no_reboot}|Envs]);
+ {win32,_} ->
+ "+t50000 -heart " ++ env_encode([{"HEART_COMMAND", no_reboot}|Envs]);
_ ->
- "-heart " ++ env_encode(Envs)
+ "+t50000 -heart " ++ env_encode(Envs)
end,
{ok, Node} = case Type of
loose ->
diff --git a/lib/kernel/test/prim_file_SUITE.erl b/lib/kernel/test/prim_file_SUITE.erl
index 3e6a85eadd..05bd5b3a3d 100644
--- a/lib/kernel/test/prim_file_SUITE.erl
+++ b/lib/kernel/test/prim_file_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2000-2013. All Rights Reserved.
+%% Copyright Ericsson AB 2000-2014. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -183,7 +183,6 @@ time_dist({_D1, _T1} = DT1, {_D2, _T2} = DT2) ->
read_write_file(suite) -> [];
read_write_file(doc) -> [];
read_write_file(Config) when is_list(Config) ->
- ?line Dog = test_server:timetrap(test_server:seconds(5)),
?line RootDir = ?config(priv_dir,Config),
?line Name = filename:join(RootDir,
atom_to_list(?MODULE)
@@ -232,7 +231,6 @@ read_write_file(Config) when is_list(Config) ->
?line {ok,Bin5} = ?PRIM_FILE:read_file(Name),
?line {Bin1,Bin2} = split_binary(Bin5,byte_size(Bin1)),
- ?line test_server:timetrap_cancel(Dog),
ok.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -254,7 +252,6 @@ make_del_dir_b(Config) when is_list(Config) ->
Result.
make_del_dir(Config, Handle, Suffix) ->
- ?line Dog = test_server:timetrap(test_server:seconds(5)),
?line RootDir = ?config(priv_dir,Config),
?line NewDir = filename:join(RootDir,
atom_to_list(?MODULE)
@@ -269,7 +266,13 @@ make_del_dir(Config, Handle, Suffix) ->
% because there are processes having that directory as current.
?line ok = ?PRIM_FILE_call(make_dir, Handle, [NewDir]),
?line {ok, CurrentDir} = ?PRIM_FILE_call(get_cwd, Handle, []),
- ?line ok = ?PRIM_FILE_call(set_cwd, Handle, [NewDir]),
+ case {os:type(), length(NewDir) >= 260 } of
+ {{win32,_}, true} ->
+ io:format("Skip set_cwd for windows path longer than 260 (MAX_PATH)\n", []),
+ io:format("\nNewDir = ~p\n", [NewDir]);
+ _ ->
+ ok = ?PRIM_FILE_call(set_cwd, Handle, [NewDir])
+ end,
try
%% Check that we get an error when trying to create...
%% a deep directory
@@ -302,9 +305,7 @@ make_del_dir(Config, Handle, Suffix) ->
{error, einval} -> ok %FreeBSD
end,
?line {error, enoent} = ?PRIM_FILE_call(del_dir, Handle, [""]),
- ?line {error, badarg} = ?PRIM_FILE_call(del_dir, Handle, [[3,2,1,{}]]),
-
- ?line test_server:timetrap_cancel(Dog)
+ ?line {error, badarg} = ?PRIM_FILE_call(del_dir, Handle, [[3,2,1,{}]])
after
?line ok = ?PRIM_FILE_call(set_cwd, Handle, [CurrentDir])
end,
@@ -324,7 +325,6 @@ cur_dir_0b(Config) when is_list(Config) ->
Result.
cur_dir_0(Config, Handle) ->
- ?line Dog = test_server:timetrap(test_server:seconds(5)),
%% Find out the current dir, and cd to it ;-)
?line {ok,BaseDir} = ?PRIM_FILE_call(get_cwd, Handle, []),
?line Dir1 = BaseDir ++ "", %% Check that it's a string
@@ -341,31 +341,37 @@ cur_dir_0(Config, Handle) ->
?line RootDir = ?config(priv_dir,Config),
?line NewDir = filename:join(RootDir, DirName),
?line ok = ?PRIM_FILE_call(make_dir, Handle, [NewDir]),
- ?line io:format("cd to ~s",[NewDir]),
- ?line ok = ?PRIM_FILE_call(set_cwd, Handle, [NewDir]),
-
- %% Create a file in the new current directory, and check that it
- %% really is created there
- ?line UncommonName = "uncommon.fil",
- ?line {ok,Fd} = ?PRIM_FILE:open(UncommonName, [read, write]),
- ?line ok = ?PRIM_FILE:close(Fd),
- ?line {ok,NewDirFiles} = ?PRIM_FILE_call(list_dir, Handle, ["."]),
- ?line true = lists:member(UncommonName,NewDirFiles),
-
- %% Delete the directory and return to the old current directory
- %% and check that the created file isn't there (too!)
- ?line expect({error, einval}, {error, eacces}, {error, eexist},
+ case {os:type(), length(NewDir) >= 260} of
+ {{win32,_}, true} ->
+ io:format("Skip set_cwd for windows path longer than 260 (MAX_PATH):\n"),
+ io:format("\nNewDir = ~p\n", [NewDir]);
+ _ ->
+ io:format("cd to ~s",[NewDir]),
+ ok = ?PRIM_FILE_call(set_cwd, Handle, [NewDir]),
+
+ %% Create a file in the new current directory, and check that it
+ %% really is created there
+ UncommonName = "uncommon.fil",
+ {ok,Fd} = ?PRIM_FILE:open(UncommonName, [read, write]),
+ ok = ?PRIM_FILE:close(Fd),
+ {ok,NewDirFiles} = ?PRIM_FILE_call(list_dir, Handle, ["."]),
+ true = lists:member(UncommonName,NewDirFiles),
+
+ %% Delete the directory and return to the old current directory
+ %% and check that the created file isn't there (too!)
+ expect({error, einval}, {error, eacces}, {error, eexist},
?PRIM_FILE_call(del_dir, Handle, [NewDir])),
- ?line ?PRIM_FILE_call(delete, Handle, [UncommonName]),
- ?line {ok,[]} = ?PRIM_FILE_call(list_dir, Handle, ["."]),
- ?line ok = ?PRIM_FILE_call(set_cwd, Handle, [Dir1]),
- ?line io:format("cd back to ~s",[Dir1]),
- ?line ok = ?PRIM_FILE_call(del_dir, Handle, [NewDir]),
- ?line {error, enoent} = ?PRIM_FILE_call(set_cwd, Handle, [NewDir]),
- ?line ok = ?PRIM_FILE_call(set_cwd, Handle, [Dir1]),
- ?line io:format("cd back to ~s",[Dir1]),
- ?line {ok,OldDirFiles} = ?PRIM_FILE_call(list_dir, Handle, ["."]),
- ?line false = lists:member(UncommonName,OldDirFiles),
+ ?PRIM_FILE_call(delete, Handle, [UncommonName]),
+ {ok,[]} = ?PRIM_FILE_call(list_dir, Handle, ["."]),
+ ok = ?PRIM_FILE_call(set_cwd, Handle, [Dir1]),
+ io:format("cd back to ~s",[Dir1]),
+ ok = ?PRIM_FILE_call(del_dir, Handle, [NewDir]),
+ {error, enoent} = ?PRIM_FILE_call(set_cwd, Handle, [NewDir]),
+ ok = ?PRIM_FILE_call(set_cwd, Handle, [Dir1]),
+ io:format("cd back to ~s",[Dir1]),
+ {ok,OldDirFiles} = ?PRIM_FILE_call(list_dir, Handle, ["."]),
+ false = lists:member(UncommonName,OldDirFiles)
+ end,
%% Try doing some bad things
?line {error, badarg} =
@@ -385,7 +391,6 @@ cur_dir_0(Config, Handle) ->
?line {ok, BaseDir} = ?PRIM_FILE_call(get_cwd, Handle, []),
?line false = lists:member($\\, BaseDir),
- ?line test_server:timetrap_cancel(Dog),
ok.
%% Tests ?PRIM_FILE:get_cwd/1.
@@ -404,8 +409,6 @@ cur_dir_1b(Config) when is_list(Config) ->
Result.
cur_dir_1(Config, Handle) ->
- ?line Dog = test_server:timetrap(test_server:seconds(5)),
-
?line case os:type() of
{win32, _} ->
win_cur_dir_1(Config, Handle);
@@ -413,7 +416,6 @@ cur_dir_1(Config, Handle) ->
?line {error, enotsup} =
?PRIM_FILE_call(get_cwd, Handle, ["d:"])
end,
- ?line test_server:timetrap_cancel(Dog),
ok.
win_cur_dir_1(_Config, Handle) ->
@@ -439,7 +441,6 @@ win_cur_dir_1(_Config, Handle) ->
open1(suite) -> [];
open1(doc) -> [];
open1(Config) when is_list(Config) ->
- ?line Dog = test_server:timetrap(test_server:seconds(5)),
?line RootDir = ?config(priv_dir,Config),
?line NewDir = filename:join(RootDir,
atom_to_list(?MODULE)
@@ -465,7 +466,6 @@ open1(Config) when is_list(Config) ->
?line {ok,Fd3} = ?PRIM_FILE:open(Name, [read]),
?line eof = ?PRIM_FILE:read(Fd3,Length),
?line ok = ?PRIM_FILE:close(Fd3),
- ?line test_server:timetrap_cancel(Dog),
ok.
%% Tests all open modes.
@@ -517,7 +517,6 @@ modes(Config) when is_list(Config) ->
close(suite) -> [];
close(doc) -> [];
close(Config) when is_list(Config) ->
- ?line Dog = test_server:timetrap(test_server:seconds(5)),
?line RootDir = ?config(priv_dir,Config),
?line Name = filename:join(RootDir,
atom_to_list(?MODULE)
@@ -534,13 +533,11 @@ close(Config) when is_list(Config) ->
?line Val = ?PRIM_FILE:close(Fd1),
?line io:format("Second close gave: ~p", [Val]),
- ?line test_server:timetrap_cancel(Dog),
ok.
access(suite) -> [];
access(doc) -> [];
access(Config) when is_list(Config) ->
- ?line Dog = test_server:timetrap(test_server:seconds(5)),
?line RootDir = ?config(priv_dir,Config),
?line Name = filename:join(RootDir,
atom_to_list(?MODULE)
@@ -562,7 +559,6 @@ access(Config) when is_list(Config) ->
?line {ok, Str} = ?PRIM_FILE:read(Fd3,length(Str)),
?line ok = ?PRIM_FILE:close(Fd3),
- ?line test_server:timetrap_cancel(Dog),
ok.
%% Tests ?PRIM_FILE:read/2 and ?PRIM_FILE:write/2.
@@ -570,7 +566,6 @@ access(Config) when is_list(Config) ->
read_write(suite) -> [];
read_write(doc) -> [];
read_write(Config) when is_list(Config) ->
- ?line Dog = test_server:timetrap(test_server:seconds(5)),
?line RootDir = ?config(priv_dir, Config),
?line NewDir = filename:join(RootDir,
atom_to_list(?MODULE)
@@ -582,7 +577,6 @@ read_write(Config) when is_list(Config) ->
?line {ok, Fd} = ?PRIM_FILE:open(Name, [read, write]),
?line read_write_test(Fd),
- ?line test_server:timetrap_cancel(Dog),
ok.
read_write_test(File) ->
@@ -600,7 +594,6 @@ read_write_test(File) ->
pread_write(suite) -> [];
pread_write(doc) -> [];
pread_write(Config) when is_list(Config) ->
- ?line Dog = test_server:timetrap(test_server:seconds(5)),
?line RootDir = ?config(priv_dir, Config),
?line NewDir = filename:join(RootDir,
atom_to_list(?MODULE)
@@ -612,7 +605,6 @@ pread_write(Config) when is_list(Config) ->
?line {ok, Fd} = ?PRIM_FILE:open(Name, [read, write]),
?line pread_write_test(Fd),
- ?line test_server:timetrap_cancel(Dog),
ok.
pread_write_test(File) ->
@@ -632,7 +624,6 @@ pread_write_test(File) ->
append(doc) -> "Test appending to a file.";
append(suite) -> [];
append(Config) when is_list(Config) ->
- ?line Dog = test_server:timetrap(test_server:seconds(5)),
?line RootDir = ?config(priv_dir, Config),
?line NewDir = filename:join(RootDir,
atom_to_list(?MODULE)
@@ -659,13 +650,11 @@ append(Config) when is_list(Config) ->
?line Expected = list_to_binary([First, Second, Third]),
?line {ok, Expected} = ?PRIM_FILE:read_file(Name1),
- ?line test_server:timetrap_cancel(Dog),
ok.
exclusive(suite) -> [];
exclusive(doc) -> "Test exclusive access to a file.";
exclusive(Config) when is_list(Config) ->
- ?line Dog = test_server:timetrap(test_server:seconds(5)),
?line RootDir = ?config(priv_dir,Config),
?line NewDir = filename:join(RootDir,
atom_to_list(?MODULE)
@@ -675,7 +664,6 @@ exclusive(Config) when is_list(Config) ->
?line {ok,Fd} = ?PRIM_FILE:open(Name, [write, exclusive]),
?line {error, eexist} = ?PRIM_FILE:open(Name, [write, exclusive]),
?line ok = ?PRIM_FILE:close(Fd),
- ?line test_server:timetrap_cancel(Dog),
ok.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -684,7 +672,6 @@ exclusive(Config) when is_list(Config) ->
pos1(suite) -> [];
pos1(doc) -> [];
pos1(Config) when is_list(Config) ->
- ?line Dog = test_server:timetrap(test_server:seconds(5)),
?line RootDir = ?config(priv_dir,Config),
?line Name = filename:join(RootDir,
atom_to_list(?MODULE)
@@ -741,13 +728,11 @@ pos1(Config) when is_list(Config) ->
?line {ok, 0} = ?PRIM_FILE:position(Fd2,{eof,-8}),
?line {ok, "A"} = ?PRIM_FILE:read(Fd2,1),
?line {error, einval} = ?PRIM_FILE:position(Fd2,{eof,-9}),
- ?line test_server:timetrap_cancel(Dog),
ok.
pos2(suite) -> [];
pos2(doc) -> [];
pos2(Config) when is_list(Config) ->
- ?line Dog = test_server:timetrap(test_server:seconds(5)),
?line RootDir = ?config(priv_dir,Config),
?line Name = filename:join(RootDir,
atom_to_list(?MODULE)
@@ -764,7 +749,6 @@ pos2(Config) when is_list(Config) ->
?line {ok, "D"} = ?PRIM_FILE:read(Fd2,1),
?line io:format("DONE"),
- ?line test_server:timetrap_cancel(Dog),
ok.
@@ -782,7 +766,6 @@ file_info_basic_file_b(Config) when is_list(Config) ->
Result.
file_info_basic_file(Config, Handle, Suffix) ->
- ?line Dog = test_server:timetrap(test_server:seconds(5)),
?line RootDir = ?config(priv_dir, Config),
%% Create a short file.
@@ -811,7 +794,6 @@ file_info_basic_file(Config, Handle, Suffix) ->
?line {MD, MT} = ModifyTime,
?line all_integers(tuple_to_list(MD) ++ tuple_to_list(MT)),
- ?line test_server:timetrap_cancel(Dog),
ok.
file_info_basic_directory_a(suite) -> [];
@@ -828,8 +810,6 @@ file_info_basic_directory_b(Config) when is_list(Config) ->
Result.
file_info_basic_directory(Config, Handle) ->
- ?line Dog = test_server:timetrap(test_server:seconds(5)),
-
%% Note: filename:join/1 removes any trailing slash,
%% which is essential for ?PRIM_FILE:read_file_info/1 to work on
%% platforms such as Windows95.
@@ -849,7 +829,7 @@ file_info_basic_directory(Config, Handle) ->
_ ->
?line test_directory("/", read, Handle)
end,
- ?line test_server:timetrap_cancel(Dog).
+ ok.
test_directory(Name, ExpectedAccess, Handle) ->
?line {ok, FileInfo} = ?PRIM_FILE_call(read_file_info, Handle, [Name]),
@@ -890,14 +870,12 @@ file_info_bad_b(Config) when is_list(Config) ->
Result.
file_info_bad(Config, Handle) ->
- ?line Dog = test_server:timetrap(test_server:seconds(5)),
?line RootDir = filename:join([?config(priv_dir, Config)]),
?line {error, enoent} =
?PRIM_FILE_call(
read_file_info, Handle,
[filename:join(RootDir,
atom_to_list(?MODULE)++"_nonexistent")]),
- ?line test_server:timetrap_cancel(Dog),
ok.
%% Test that the file times behave as they should.
@@ -1192,7 +1170,6 @@ get_good_directory(Config) ->
truncate(suite) -> [];
truncate(doc) -> [];
truncate(Config) when is_list(Config) ->
- ?line Dog = test_server:timetrap(test_server:seconds(5)),
?line RootDir = ?config(priv_dir,Config),
?line Name = filename:join(RootDir,
atom_to_list(?MODULE)
@@ -1218,14 +1195,12 @@ truncate(Config) when is_list(Config) ->
?line {ok, 5} = ?PRIM_FILE:position(Fd2, 5),
?line {error, _} = ?PRIM_FILE:truncate(Fd2),
- ?line test_server:timetrap_cancel(Dog),
ok.
datasync(suite) -> [];
datasync(doc) -> "Tests that ?PRIM_FILE:datasync/1 at least doesn't crash.";
datasync(Config) when is_list(Config) ->
- ?line Dog = test_server:timetrap(test_server:seconds(5)),
?line PrivDir = ?config(priv_dir, Config),
?line Sync = filename:join(PrivDir,
atom_to_list(?MODULE)
@@ -1236,14 +1211,12 @@ datasync(Config) when is_list(Config) ->
?line ok = ?PRIM_FILE:datasync(Fd),
?line ok = ?PRIM_FILE:close(Fd),
- ?line test_server:timetrap_cancel(Dog),
ok.
sync(suite) -> [];
sync(doc) -> "Tests that ?PRIM_FILE:sync/1 at least doesn't crash.";
sync(Config) when is_list(Config) ->
- ?line Dog = test_server:timetrap(test_server:seconds(5)),
?line PrivDir = ?config(priv_dir, Config),
?line Sync = filename:join(PrivDir,
atom_to_list(?MODULE)
@@ -1254,14 +1227,12 @@ sync(Config) when is_list(Config) ->
?line ok = ?PRIM_FILE:sync(Fd),
?line ok = ?PRIM_FILE:close(Fd),
- ?line test_server:timetrap_cancel(Dog),
ok.
advise(suite) -> [];
advise(doc) -> "Tests that ?PRIM_FILE:advise/4 at least doesn't crash.";
advise(Config) when is_list(Config) ->
- ?line Dog = test_server:timetrap(test_server:seconds(5)),
?line PrivDir = ?config(priv_dir, Config),
?line Advise = filename:join(PrivDir,
atom_to_list(?MODULE)
@@ -1325,7 +1296,6 @@ advise(Config) when is_list(Config) ->
?line eof = ?PRIM_FILE:read_line(Fd9),
?line ok = ?PRIM_FILE:close(Fd9),
- ?line test_server:timetrap_cancel(Dog),
ok.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -1369,7 +1339,6 @@ check_large_write(Dog, Fd, _, _, []) ->
allocate(suite) -> [];
allocate(doc) -> "Tests that ?PRIM_FILE:allocate/3 at least doesn't crash.";
allocate(Config) when is_list(Config) ->
- ?line Dog = test_server:timetrap(test_server:seconds(5)),
?line PrivDir = ?config(priv_dir, Config),
?line Allocate = filename:join(PrivDir,
atom_to_list(?MODULE)
@@ -1402,7 +1371,6 @@ allocate(Config) when is_list(Config) ->
?line ok = ?PRIM_FILE:write(Fd4, Line2),
?line ok = ?PRIM_FILE:close(Fd4),
- ?line test_server:timetrap_cancel(Dog),
ok.
allocate_and_assert(Fd, Offset, Length) ->
@@ -1450,7 +1418,6 @@ delete_b(Config) when is_list(Config) ->
Result.
delete(Config, Handle, Suffix) ->
- ?line Dog = test_server:timetrap(test_server:seconds(5)),
?line RootDir = ?config(priv_dir,Config),
?line Name = filename:join(RootDir,
atom_to_list(?MODULE)
@@ -1466,7 +1433,6 @@ delete(Config, Handle, Suffix) ->
?line {error, _} = ?PRIM_FILE:open(Name, [read]),
%% Try deleting a nonexistent file
?line {error, enoent} = ?PRIM_FILE_call(delete, Handle, [Name]),
- ?line test_server:timetrap_cancel(Dog),
ok.
rename_a(suite) ->[];
@@ -1483,7 +1449,6 @@ rename_b(Config) when is_list(Config) ->
Result.
rename(Config, Handle, Suffix) ->
- ?line Dog = test_server:timetrap(test_server:seconds(5)),
?line RootDir = ?config(priv_dir,Config),
?line FileName1 = atom_to_list(?MODULE)++"_rename"++Suffix++".fil",
?line FileName2 = atom_to_list(?MODULE)++"_rename"++Suffix++".ful",
@@ -1536,7 +1501,6 @@ rename(Config, Handle, Suffix) ->
?PRIM_FILE_call(rename, Handle, [DirName2, Name2foo]),
?line io:format("Errmsg2: ~p",[Msg2]),
- ?line test_server:timetrap_cancel(Dog),
ok.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -2029,6 +1993,9 @@ symlinks(Config, Handle, Suffix) ->
case ?PRIM_FILE_call(make_symlink, Handle, [Name, Alias]) of
{error, enotsup} ->
{skipped, "Links not supported on this platform"};
+ {error, eperm} ->
+ {win32,_} = os:type(),
+ {skipped, "Windows user not privileged to create links"};
ok ->
?line {ok, Info1} =
?PRIM_FILE_call(read_file_info, Handle, [Name]),
diff --git a/lib/megaco/aclocal.m4 b/lib/megaco/aclocal.m4
index c51c26794a..2b47f7c4bc 100644
--- a/lib/megaco/aclocal.m4
+++ b/lib/megaco/aclocal.m4
@@ -83,8 +83,10 @@ AC_ARG_VAR(erl_xcomp_ose_LM_POST_LINK, [OSE postlink tool (only used when cross
AC_ARG_VAR(erl_xcomp_ose_LM_SET_CONF, [Sets the configuration for an OSE load module (only used when cross compiling for OSE)])
AC_ARG_VAR(erl_xcomp_ose_LM_ELF_SIZE, [Prints the section size information for an OSE load module (only used when cross compiling for OSE)])
AC_ARG_VAR(erl_xcomp_ose_LM_LCF, [OSE load module linker configuration file (only used when cross compiling for OSE)])
-AC_ARG_VAR(erl_xcomp_ose_LM_CONF, [OSE load module default configuration file (only used when cross compiling for OSE)])
-AC_ARG_VAR(erl_xcomp_ose_CONFD, [OSE OSE confd source file])
+AC_ARG_VAR(erl_xcomp_ose_BEAM_LM_CONF, [BEAM OSE load module default configuration file (only used when cross compiling for OSE)])
+AC_ARG_VAR(erl_xcomp_ose_EPMD_LM_CONF, [EPMD OSE load module default configuration file (only used when cross compiling for OSE)])
+AC_ARG_VAR(erl_xcomp_ose_RUN_ERL_LM_CONF, [run_erl_lm OSE load module default configuration file (only used when cross compiling for OSE)])
+AC_ARG_VAR(erl_xcomp_ose_CONFD, [OSE confd source file])
AC_ARG_VAR(erl_xcomp_ose_CRT0_LM, [OSE crt0 lm source file])
])
diff --git a/lib/megaco/src/app/megaco.app.src b/lib/megaco/src/app/megaco.app.src
index 40265166ae..6ab85a1bbc 100644
--- a/lib/megaco/src/app/megaco.app.src
+++ b/lib/megaco/src/app/megaco.app.src
@@ -112,7 +112,10 @@
megaco_trans_sup, megaco_misc_sup, megaco_sup]},
{applications, [stdlib, kernel]},
{env, []},
- {mod, {megaco_sup, []}}
+ {mod, {megaco_sup, []}},
+ {runtime_dependencies, ["stdlib-2.0","runtime_tools-1.8.14","kernel-3.0",
+ "et-1.5","erts-6.0","debugger-4.0",
+ "asn1-3.0"]}
]}.
diff --git a/lib/megaco/vsn.mk b/lib/megaco/vsn.mk
index 01d429d0ae..373f5199bf 100644
--- a/lib/megaco/vsn.mk
+++ b/lib/megaco/vsn.mk
@@ -18,6 +18,6 @@
# %CopyrightEnd%
APPLICATION = megaco
-MEGACO_VSN = 3.17.0.3
+MEGACO_VSN = 3.17.1
PRE_VSN =
APP_VSN = "$(APPLICATION)-$(MEGACO_VSN)$(PRE_VSN)"
diff --git a/lib/mnesia/src/mnesia.app.src b/lib/mnesia/src/mnesia.app.src
index 3715488ec2..e755864792 100644
--- a/lib/mnesia/src/mnesia.app.src
+++ b/lib/mnesia/src/mnesia.app.src
@@ -47,6 +47,7 @@
mnesia_tm
]},
{applications, [kernel, stdlib]},
- {mod, {mnesia_sup, []}}]}.
+ {mod, {mnesia_sup, []}},
+ {runtime_dependencies, ["stdlib-2.0","kernel-3.0","erts-6.0"]}]}.
diff --git a/lib/mnesia/src/mnesia.hrl b/lib/mnesia/src/mnesia.hrl
index 2855792646..c8010d5466 100644
--- a/lib/mnesia/src/mnesia.hrl
+++ b/lib/mnesia/src/mnesia.hrl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2011. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2014. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -35,7 +35,7 @@
-define(ets_last(Tab), ets:last(Tab)).
-define(ets_prev(Tab, Key), ets:prev(Tab, Key)).
-define(ets_slot(Tab, Pos), ets:slot(Tab, Pos)).
--define(ets_new_table(Tab, Props), ets:new(Tab, Props)).
+-define(ets_new_table(Tab, Props), _ = ets:new(Tab, Props)).
-define(ets_delete_table(Tab), ets:delete(Tab)).
-define(ets_fixtable(Tab, Bool), ets:fixtable(Tab, Bool)).
diff --git a/lib/mnesia/src/mnesia_index.erl b/lib/mnesia/src/mnesia_index.erl
index 8fef611a48..87cb58dae1 100644
--- a/lib/mnesia/src/mnesia_index.erl
+++ b/lib/mnesia/src/mnesia_index.erl
@@ -52,7 +52,11 @@
val(Var) ->
case ?catch_val(Var) of
- {'EXIT', _ReASoN_} -> mnesia_lib:other_val(Var, _ReASoN_);
+ {'EXIT', _ReASoN_} ->
+ case mnesia_lib:other_val(Var) of
+ error -> mnesia_lib:pr_other(Var, _ReASoN_);
+ Val -> Val
+ end;
_VaLuE_ -> _VaLuE_
end.
diff --git a/lib/mnesia/src/mnesia_lib.erl b/lib/mnesia/src/mnesia_lib.erl
index 109e924971..a32c69c59e 100644
--- a/lib/mnesia/src/mnesia_lib.erl
+++ b/lib/mnesia/src/mnesia_lib.erl
@@ -115,6 +115,8 @@
mkcore/1,
not_active_here/1,
other_val/2,
+ other_val/1,
+ pr_other/2,
overload_read/0,
overload_read/1,
overload_set/2,
@@ -389,16 +391,19 @@ unset(Var) ->
?ets_delete(mnesia_gvar, Var).
other_val(Var, Other) ->
+ case other_val(Var) of
+ error -> pr_other(Var, Other);
+ Val -> Val
+ end.
+
+other_val(Var) ->
case Var of
{_, where_to_read} -> nowhere;
{_, where_to_write} -> [];
{_, active_replicas} -> [];
- _ ->
- pr_other(Var, Other)
+ _ -> error
end.
--spec pr_other(_,_) -> no_return().
-
pr_other(Var, Other) ->
Why =
case is_running() of
diff --git a/lib/mnesia/src/mnesia_locker.erl b/lib/mnesia/src/mnesia_locker.erl
index 32cea903c9..81b435c6dc 100644
--- a/lib/mnesia/src/mnesia_locker.erl
+++ b/lib/mnesia/src/mnesia_locker.erl
@@ -270,7 +270,8 @@ try_sticky_lock(Tid, Op, Pid, {Tab, _} = Oid) ->
try_lock(Tid, Op, Pid, Oid);
[{_,N}] ->
Req = {Pid, {Op, Tid, Oid}},
- Pid ! {?MODULE, node(), {switch, N, Req}}
+ Pid ! {?MODULE, node(), {switch, N, Req}},
+ true
end.
try_lock(Tid, read_write, Pid, Oid) ->
diff --git a/lib/mnesia/src/mnesia_recover.erl b/lib/mnesia/src/mnesia_recover.erl
index 0548a25ebf..b6492707e2 100644
--- a/lib/mnesia/src/mnesia_recover.erl
+++ b/lib/mnesia/src/mnesia_recover.erl
@@ -178,7 +178,11 @@ log_decision(D) ->
val(Var) ->
case ?catch_val(Var) of
- {'EXIT', Reason} -> mnesia_lib:other_val(Var, Reason);
+ {'EXIT', Reason} ->
+ case mnesia_lib:other_val(Var) of
+ error -> mnesia_lib:pr_other(Var, Reason);
+ Val -> Val
+ end;
Value -> Value
end.
diff --git a/lib/mnesia/src/mnesia_snmp_hook.erl b/lib/mnesia/src/mnesia_snmp_hook.erl
index 893b39f3c0..256f83b029 100644
--- a/lib/mnesia/src/mnesia_snmp_hook.erl
+++ b/lib/mnesia/src/mnesia_snmp_hook.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2011. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2014. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -32,7 +32,11 @@
val(Var) ->
case ?catch_val(Var) of
- {'EXIT', _ReASoN_} -> mnesia_lib:other_val(Var, _ReASoN_);
+ {'EXIT', _ReASoN_} ->
+ case mnesia_lib:other_val(Var) of
+ error -> mnesia_lib:pr_other(Var, _ReASoN_);
+ Val -> Val
+ end;
_VaLuE_ -> _VaLuE_
end.
diff --git a/lib/mnesia/test/mnesia_config_test.erl b/lib/mnesia/test/mnesia_config_test.erl
index 6baf86a4a5..c495bce63f 100644
--- a/lib/mnesia/test/mnesia_config_test.erl
+++ b/lib/mnesia/test/mnesia_config_test.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2013. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2014. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -639,10 +639,10 @@ send_compressed(Config) ->
end,
?match([], mnesia_test_lib:kill_mnesia([N2])),
-
+ sys:get_status(mnesia_monitor), %% sync N1
?match([], mnesia_test_lib:kill_mnesia([N1])),
?match(ok, mnesia:start([{send_compressed, 9}])),
- ?match(ok, mnesia:wait_for_tables([t0,t1,t2], 5000)),
+ ?match(ok, mnesia:wait_for_tables([t0,t1,t2], 25000)),
?match({atomic, ok}, mnesia:transaction(Create, [t0])),
?match({atomic, ok}, mnesia:transaction(Create, [t1])),
@@ -1158,6 +1158,7 @@ dynamic_basic(Config) when is_list(Config) ->
%%% SYNC!!!
timer:sleep(1000),
+ sys:get_status(mnesia_monitor),
?match([N3,N1], sort(rpc:call(N1, mnesia, system_info, [running_db_nodes]))),
?match([N3,N1], sort(rpc:call(N3, mnesia, system_info, [running_db_nodes]))),
diff --git a/lib/mnesia/test/mnesia_evil_coverage_test.erl b/lib/mnesia/test/mnesia_evil_coverage_test.erl
index 91820238e5..2d1623b6ca 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-2013. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2014. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -671,13 +671,16 @@ add_copy_when_going_down(Config) ->
?acquire_nodes(2, Config ++ [{tc_timeout, timer:minutes(2)}]),
?match({atomic, ok}, mnesia:create_table(a, [{ram_copies, [Node1]}])),
%% Grab a write lock
+ Tester = self(),
WriteAndWait = fun() ->
mnesia:write({a,1,1}),
- receive continue -> ok
+ Tester ! {self(), got_lock},
+ receive continue -> ok
end
end,
- _Lock = spawn(fun() -> mnesia:transaction(WriteAndWait) end),
- Tester = self(),
+ Locker = spawn(fun() -> mnesia:transaction(WriteAndWait) end),
+ receive {Locker, got_lock} -> ok end,
+
spawn_link(fun() -> Res = rpc:call(Node2, mnesia, add_table_copy,
[a, Node2, ram_copies]),
Tester ! {test, Res}
diff --git a/lib/mnesia/vsn.mk b/lib/mnesia/vsn.mk
index 064ba43791..c596f98c81 100644
--- a/lib/mnesia/vsn.mk
+++ b/lib/mnesia/vsn.mk
@@ -1 +1 @@
-MNESIA_VSN = 4.11
+MNESIA_VSN = 4.12
diff --git a/lib/observer/src/cdv_dist_cb.erl b/lib/observer/src/cdv_dist_cb.erl
index 3860324d6f..f7e6c9aded 100644
--- a/lib/observer/src/cdv_dist_cb.erl
+++ b/lib/observer/src/cdv_dist_cb.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2013. All Rights Reserved.
+%% Copyright Ericsson AB 2013-2014. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -22,7 +22,8 @@
get_info/1,
get_detail_cols/1,
get_details/1,
- detail_pages/0]).
+ detail_pages/0,
+ format/1]).
-include_lib("wx/include/wx.hrl").
-include("crashdump_viewer.hrl").
@@ -75,6 +76,11 @@ init_gen_page(Parent, Info) ->
Fields = info_fields(),
cdv_info_wx:start_link(Parent,{Fields,Info,[]}).
+format({creations,Creations}) ->
+ string:join([integer_to_list(C) || C <- Creations],",");
+format(D) ->
+ D.
+
%%%-----------------------------------------------------------------
%%% Internal
info_fields() ->
@@ -83,7 +89,7 @@ info_fields() ->
{"Type", conn_type},
{"Channel", channel},
{"Controller", {click,controller}},
- {"Creation", creation},
+ {"Creation", {{format,fun format/1},creation}},
{"Extra Info", error}]},
{scroll_boxes,
[{"Remote Links",1,{click,remote_links}},
diff --git a/lib/observer/src/crashdump_viewer.erl b/lib/observer/src/crashdump_viewer.erl
index a17efbccb0..a08d27d070 100644
--- a/lib/observer/src/crashdump_viewer.erl
+++ b/lib/observer/src/crashdump_viewer.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2003-2013. All Rights Reserved.
+%% Copyright Ericsson AB 2003-2014. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -1576,7 +1576,13 @@ get_nodeinfo(Fd,Nod) ->
"Controller" ->
get_nodeinfo(Fd,Nod#nod{controller=val(Fd)});
"Creation" ->
- get_nodeinfo(Fd,Nod#nod{creation=list_to_integer(val(Fd))});
+ %% Throwing away elements like "(refc=1)", which might be
+ %% printed from a debug compiled emulator.
+ Creations = lists:flatmap(fun(C) -> try [list_to_integer(C)]
+ catch error:badarg -> []
+ end
+ end, string:tokens(val(Fd)," ")),
+ get_nodeinfo(Fd,Nod#nod{creation={creations,Creations}});
"Remote link" ->
Procs = val(Fd), % e.g. "<0.31.0> <4322.54.0>"
{Local,Remote} = split(Procs),
@@ -2559,11 +2565,11 @@ progress_pmap(Report,File,Fun,List) ->
{L1,L2} = if length(L)>=NPerProc -> lists:split(NPerProc,L);
true -> {L,[]} % last chunk
end,
- P = spawn(
+ {P,_Ref} =
+ spawn_monitor(
fun() ->
progress_map(Collector,ReportInterval,File,Fun,L1)
end),
- erlang:monitor(process,P),
{L2,[P|Ps]}
end,
{List,[]},
diff --git a/lib/observer/src/observer.app.src b/lib/observer/src/observer.app.src
index f14f0ee849..97a54cd6f9 100644
--- a/lib/observer/src/observer.app.src
+++ b/lib/observer/src/observer.app.src
@@ -60,6 +60,9 @@
ttb_et]},
{registered, []},
{applications, [kernel, stdlib]},
- {env, []}]}.
+ {env, []},
+ {runtime_dependencies, ["wx-1.2","stdlib-2.0","runtime_tools-1.8.14",
+ "kernel-3.0","inets-5.10","et-1.5",
+ "erts-6.0"]}]}.
diff --git a/lib/observer/src/observer.erl b/lib/observer/src/observer.erl
index 098100e8ee..a30ceecc63 100644
--- a/lib/observer/src/observer.erl
+++ b/lib/observer/src/observer.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2011. All Rights Reserved.
+%% Copyright Ericsson AB 2011-2014. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -18,8 +18,11 @@
-module(observer).
--export([start/0]).
+-export([start/0, stop/0]).
start() ->
observer_wx:start().
+
+stop() ->
+ observer_wx:stop().
diff --git a/lib/observer/src/observer_lib.erl b/lib/observer/src/observer_lib.erl
index cedaf7d2b8..34c7b127ff 100644
--- a/lib/observer/src/observer_lib.erl
+++ b/lib/observer/src/observer_lib.erl
@@ -249,6 +249,8 @@ 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({{format,Fun},Value}) when is_function(Fun) ->
+ Fun(Value);
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) ->
diff --git a/lib/observer/src/observer_procinfo.erl b/lib/observer/src/observer_procinfo.erl
index 3ffa5fc77d..8e8a37fc93 100644
--- a/lib/observer/src/observer_procinfo.erl
+++ b/lib/observer/src/observer_procinfo.erl
@@ -34,6 +34,7 @@
-record(state, {parent,
frame,
+ notebook,
pid,
pages=[],
expand_table,
@@ -76,6 +77,7 @@ init([Pid, ParentFrame, Parent]) ->
{Frame, #state{parent=Parent,
pid=Pid,
frame=Frame,
+ notebook=Notebook,
pages=[ProcessPage,MessagePage,DictPage,StackPage,StatePage],
expand_table=Table
}}
@@ -158,6 +160,9 @@ handle_event(#wx{event=#wxHtmlLink{linkInfo=#wxHtmlLinkInfo{href=Info}}}, State)
handle_event(Event, _State) ->
error({unhandled_event, Event}).
+handle_info({get_debug_info, From}, State = #state{notebook=Notebook}) ->
+ From ! {procinfo_debug, Notebook},
+ {noreply, State};
handle_info(_Info, State) ->
%% io:format("~p: ~p, Handle info: ~p~n", [?MODULE, ?LINE, Info]),
{noreply, State}.
diff --git a/lib/observer/src/observer_tv_wx.erl b/lib/observer/src/observer_tv_wx.erl
index b276965f83..da4cb8e041 100644
--- a/lib/observer/src/observer_tv_wx.erl
+++ b/lib/observer/src/observer_tv_wx.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2011-2012. All Rights Reserved.
+%% Copyright Ericsson AB 2011-2014. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -132,8 +132,8 @@ handle_event(#wx{event=#wxSize{size={W,_}}}, State=#state{grid=Grid}) ->
observer_lib:set_listctrl_col_size(Grid, W),
{noreply, State};
-handle_event(#wx{obj=Grid, event=#wxList{type=command_list_item_activated,
- itemIndex=Index}},
+handle_event(#wx{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
diff --git a/lib/observer/src/observer_wx.erl b/lib/observer/src/observer_wx.erl
index ecb8e132fe..ced26f7119 100644
--- a/lib/observer/src/observer_wx.erl
+++ b/lib/observer/src/observer_wx.erl
@@ -19,7 +19,7 @@
-behaviour(wx_object).
--export([start/0]).
+-export([start/0, stop/0]).
-export([create_menus/2, get_attrib/1, get_tracer/0, set_status/1,
create_txt_dialog/4, try_rpc/4, return_to_localnode/2]).
@@ -69,6 +69,9 @@ start() ->
_Obj -> ok
end.
+stop() ->
+ wx_object:call(observer, stop).
+
create_menus(Object, Menus) when is_list(Menus) ->
wx_object:call(Object, {create_menus, Menus}).
@@ -331,6 +334,10 @@ handle_call({get_attrib, Attrib}, _From, State) ->
handle_call(get_tracer, _From, State=#state{trace_panel=TraceP}) ->
{reply, TraceP, State};
+handle_call(stop, _, State = #state{frame = Frame}) ->
+ wxFrame:destroy(Frame),
+ {stop, normal, ok, State};
+
handle_call(_Msg, _From, State) ->
{reply, ok, State}.
@@ -367,6 +374,10 @@ handle_info({open_link, Pid0}, State = #state{pro_panel=ProcViewer, frame=Frame}
end,
{noreply, State};
+handle_info({get_debug_info, From}, State = #state{notebook=Notebook, active_tab=Pid}) ->
+ From ! {observer_debug, wx:get_env(), Notebook, Pid},
+ {noreply, State};
+
handle_info({'EXIT', Pid, _Reason}, State) ->
io:format("Child (~s) crashed exiting: ~p ~p~n",
[pid2panel(Pid, State), Pid,_Reason]),
diff --git a/lib/observer/test/crashdump_viewer_SUITE.erl b/lib/observer/test/crashdump_viewer_SUITE.erl
index 7a582436b4..f6e7d18f65 100644
--- a/lib/observer/test/crashdump_viewer_SUITE.erl
+++ b/lib/observer/test/crashdump_viewer_SUITE.erl
@@ -120,27 +120,63 @@ start_stop(Config) when is_list(Config) ->
Dump = hd(?config(dumps,Config)),
timer:sleep(1000),
- ProcsBefore = length(processes()),
+ ProcsBefore = processes(),
+ NumProcsBefore = length(ProcsBefore),
ok = crashdump_viewer:start(Dump),
- true = is_pid(whereis(crashdump_viewer_server)),
- true = is_pid(whereis(cdv_wx)),
- true = is_pid(whereis(cdv_proc_cb)),
- true = is_pid(whereis(cdv_port_cb)),
- true = is_pid(whereis(cdv_ets_cb)),
- true = is_pid(whereis(cdv_timer_cb)),
- true = is_pid(whereis(cdv_fun_cb)),
- true = is_pid(whereis(cdv_atom_cb)),
- true = is_pid(whereis(cdv_dist_cb)),
- true = is_pid(whereis(cdv_mod_cb)),
+ ExpectedRegistered = [crashdump_viewer_server,
+ cdv_wx,
+ cdv_proc_cb,
+ cdv_proc_cb__holder,
+ cdv_port_cb,
+ cdv_port_cb__holder,
+ cdv_ets_cb,
+ cdv_ets_cb__holder,
+ cdv_timer_cb,
+ cdv_timer_cb__holder,
+ cdv_fun_cb,
+ cdv_fun_cb__holder,
+ cdv_atom_cb,
+ cdv_atom_cb__holder,
+ cdv_dist_cb,
+ cdv_dist_cb__holder,
+ cdv_mod_cb,
+ cdv_mod_cb__holder],
+ Regs=[begin
+ P=whereis(N),
+ {P,N,erlang:monitor(process,P)}
+ end || N <- ExpectedRegistered],
+ ct:log("CDV procs: ~n~p~n",[Regs]),
+ [true=is_pid(P) || {P,_,_} <- Regs],
timer:sleep(5000), % give some time to live
ok = crashdump_viewer:stop(),
- timer:sleep(1000), % give some time to stop
- undefined = whereis(crashdump_viewer_server),
- undefined = whereis(cdv_wx),
- ProcsAfter=length(processes()),
- ProcsAfter=ProcsBefore,
+ recv_downs(Regs),
+ timer:sleep(2000),
+ ProcsAfter = processes(),
+ NumProcsAfter = length(ProcsAfter),
+ if NumProcsAfter=/=NumProcsBefore ->
+ ct:log("Before but not after:~n~p~n",
+ [[{P,process_info(P)} || P <- ProcsBefore -- ProcsAfter]]),
+ ct:log("After but not before:~n~p~n",
+ [[{P,process_info(P)} || P <- ProcsAfter -- ProcsBefore]]),
+ ct:fail("leaking processes");
+ true ->
+ ok
+ end,
ok.
+recv_downs([]) ->
+ ok;
+recv_downs(Regs) ->
+ receive
+ {'DOWN',Ref,process,_Pid,_} ->
+ ct:log("Got 'DOWN' for process ~n~p~n",[_Pid]),
+ recv_downs(lists:keydelete(Ref,3,Regs))
+ after 30000 ->
+ ct:log("Timeout waiting for down:~n~p~n",
+ [[{Reg,process_info(P)} || {P,_,_}=Reg <- Regs]]),
+ ct:log("Message queue:~n~p~n",[process_info(self(),messages)])
+ end.
+
%% Try to load nonexisting file
non_existing(Config) when is_list(Config) ->
ExpectedReason = "non-existing-file is not an Erlang crash dump\n",
@@ -428,8 +464,10 @@ do_create_dumps(DataDir,Rel) ->
end.
-%% Create a dump which has two visible nodes, one hidden and one
+%% Create a dump which has three visible nodes, one hidden and one
%% not connected node, and with monitors and links between nodes.
+%% One of the visible nodes is stopped and started again in order to
+%% get multiple creations.
full_dist_dump(DataDir,Rel) ->
Opt = rel_opt(Rel),
Pz = "-pz \"" ++ filename:dirname(code:which(?MODULE)) ++ "\"",
@@ -450,6 +488,15 @@ full_dist_dump(DataDir,Rel) ->
get_response(P4),
get_response(P1),
+ %% start, stop and start a node in order to get multiple 'creations'
+ {ok,N5} = ?t:start_node(n5,peer,Opt ++ PzOpt),
+ P51 = rpc:call(N5,?helper_mod,remote_proc,[P1,Creator]),
+ get_response(P51),
+ ?t:stop_node(N5),
+ {ok,N5} = ?t:start_node(n5,peer,Opt ++ PzOpt),
+ P52 = rpc:call(N5,?helper_mod,remote_proc,[P1,Creator]),
+ get_response(P52),
+
{aaaaaaaa,N1} ! {hello,from,other,node}, % distribution message
?t:stop_node(N3),
@@ -458,6 +505,7 @@ full_dist_dump(DataDir,Rel) ->
?t:stop_node(N2),
?t:stop_node(N4),
+ ?t:stop_node(N5),
CD.
get_response(P) ->
diff --git a/lib/observer/test/observer_SUITE.erl b/lib/observer/test/observer_SUITE.erl
index c076c5e81e..af07165456 100644
--- a/lib/observer/test/observer_SUITE.erl
+++ b/lib/observer/test/observer_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2006-2013. All Rights Reserved.
+%% Copyright Ericsson AB 2006-2014. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -19,34 +19,35 @@
-module(observer_SUITE).
-include_lib("test_server/include/test_server.hrl").
+-include_lib("wx/include/wx.hrl").
+-include_lib("observer/src/observer_tv.hrl").
%% Test server specific exports
--export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1,
- init_per_group/2,end_per_group/2]).
--export([init_per_testcase/2, end_per_testcase/2]).
+-export([all/0, suite/0,groups/0]).
+-export([init_per_testcase/2, end_per_testcase/2,
+ init_per_group/2, end_per_group/2,
+ init_per_suite/1, end_per_suite/1
+ ]).
%% Test cases
--export([app_file/1, appup_file/1]).
+-export([app_file/1, appup_file/1,
+ basic/1, process_win/1, table_win/1
+ ]).
%% Default timetrap timeout (set in init_per_testcase)
-define(default_timeout, ?t:minutes(1)).
-init_per_testcase(_Case, Config) ->
- Dog = ?t:timetrap(?default_timeout),
- [{watchdog, Dog} | Config].
-
-end_per_testcase(_Case, Config) ->
- Dog = ?config(watchdog, Config),
- ?t:timetrap_cancel(Dog),
- ok.
-
suite() -> [{ct_hooks,[ts_install_cth]}].
-all() ->
- [app_file, appup_file].
+all() ->
+ [app_file, appup_file, {group, gui}].
-groups() ->
- [].
+groups() ->
+ [{gui, [],
+ [basic
+ %% , process_win, table_win
+ ]
+ }].
init_per_suite(Config) ->
Config.
@@ -54,12 +55,40 @@ init_per_suite(Config) ->
end_per_suite(_Config) ->
ok.
-init_per_group(_GroupName, Config) ->
- Config.
+init_per_testcase(_Case, Config) ->
+ Dog = ?t:timetrap(?default_timeout),
+ [{watchdog, Dog} | Config].
-end_per_group(_GroupName, Config) ->
- Config.
+end_per_testcase(_Case, Config) ->
+ Dog = ?config(watchdog, Config),
+ ?t:timetrap_cancel(Dog),
+ ok.
+init_per_group(gui, Config) ->
+ try
+ case os:type() of
+ {unix,darwin} ->
+ exit("Can not test on MacOSX");
+ {unix, _} ->
+ io:format("DISPLAY ~s~n", [os:getenv("DISPLAY")]),
+ case ct:get_config(xserver, none) of
+ none -> ignore;
+ Server -> os:putenv("DISPLAY", Server)
+ end;
+ _ -> ignore
+ end,
+ wx:new(),
+ wx:destroy(),
+ Config
+ catch
+ _:undef ->
+ {skipped, "No wx compiled for this platform"};
+ _:Reason ->
+ SkipReason = io_lib:format("Start wx failed: ~p", [Reason]),
+ {skipped, lists:flatten(SkipReason)}
+ end.
+end_per_group(_, _) ->
+ ok.
app_file(suite) ->
[];
@@ -72,3 +101,162 @@ app_file(Config) when is_list(Config) ->
%% Testing .appup file
appup_file(Config) when is_list(Config) ->
ok = ?t:appup_test(observer).
+
+-define(DBG(Foo), io:format("~p: ~p~n",[?LINE, catch Foo])).
+
+basic(suite) -> [];
+basic(doc) -> [""];
+basic(Config) when is_list(Config) ->
+ ok = observer:start(),
+ Notebook = setup_whitebox_testing(),
+
+ io:format("Notebook ~p~n",[Notebook]),
+ Count = wxNotebook:getPageCount(Notebook),
+ true = Count >= 6,
+ 0 = wxNotebook:getSelection(Notebook),
+ timer:sleep(500),
+ Check = fun(N, TestMore) ->
+ ok = wxNotebook:advanceSelection(Notebook),
+ TestMore andalso
+ test_page(wxNotebook:getPageText(Notebook, N),
+ wxNotebook:getCurrentPage(Notebook)),
+ timer:sleep(200)
+ end,
+ %% Just verify that we can toogle trough all pages
+ [_|_] = [Check(N, false) || N <- lists:seq(1, Count)],
+ %% Cause it to resize
+ Frame = get_top_level_parent(Notebook),
+ {W,H} = wxWindow:getSize(Frame),
+ wxWindow:setSize(Frame, W+10, H+10),
+ [_|_] = [Check(N, true) || N <- lists:seq(1, Count)],
+
+ ok = observer:stop().
+
+test_page("Load Charts" ++ _, _Window) ->
+ %% Just let it display some info and hopefully it doesn't crash
+ timer:sleep(2000),
+ ok;
+test_page("Applications" ++ _, _Window) ->
+ ok = application:start(mnesia),
+ timer:sleep(1000), %% Give it time to refresh
+ Active = get_active(),
+ FakeEv = #wx{event=#wxCommand{type=command_listbox_selected, cmdString="mnesia"}},
+ Active ! FakeEv,
+ timer:sleep(1000), %% Give it time to refresh
+ ok = application:stop(mnesia),
+ timer:sleep(1000), %% Give it time to refresh
+ ok;
+
+test_page("Processes" ++ _, _Window) ->
+ timer:sleep(500), %% Give it time to refresh
+ Active = get_active(),
+ ChangeSort = fun(N) ->
+ FakeEv = #wx{event=#wxList{type=command_list_col_click, col=N}},
+ Active ! FakeEv,
+ timer:sleep(200)
+ end,
+ [ChangeSort(N) || N <- lists:seq(1,5) ++ [0]],
+ Focus = #wx{event=#wxList{type=command_list_item_focused, itemIndex=2}},
+ Active ! Focus,
+ Activate = #wx{event=#wxList{type=command_list_item_activated}},
+ Active ! Activate,
+ timer:sleep(1000), %% Give it time to refresh
+ ok;
+
+test_page("Table" ++ _, _Window) ->
+ Tables = [ets:new(list_to_atom("Test-" ++ [C]), [public]) || C <- lists:seq($A, $Z)],
+ Active = get_active(),
+ Active ! refresh_interval,
+ ChangeSort = fun(N) ->
+ FakeEv = #wx{event=#wxList{type=command_list_col_click, col=N}},
+ Active ! FakeEv,
+ timer:sleep(200)
+ end,
+ [ChangeSort(N) || N <- lists:seq(1,5) ++ [0]],
+ timer:sleep(1000),
+ Table = lists:nth(3, Tables),
+ ets:insert(Table, [{N,100-N} || N <- lists:seq(1,100)]),
+ Focus = #wx{event=#wxList{type=command_list_item_selected, itemIndex=2}},
+ Active ! Focus,
+ Activate = #wx{event=#wxList{type=command_list_item_activated, itemIndex=2}},
+ Active ! Activate,
+
+ Info = 407, %% whitebox...
+ Active ! #wx{id=Info},
+ timer:sleep(1000),
+ ok;
+
+test_page(Title, Window) ->
+ io:format("Page ~p: ~p~n", [Title, Window]),
+ %% Just let it display some info and hopefully it doesn't crash
+ timer:sleep(1000),
+ ok.
+
+
+process_win(suite) -> [];
+process_win(doc) -> [""];
+process_win(Config) when is_list(Config) ->
+ ok = observer:start(),
+ ObserverNB = setup_whitebox_testing(),
+ Parent = get_top_level_parent(ObserverNB),
+ Frame = observer_procinfo:start(self(), Parent, self()),
+ PIPid = wx_object:get_pid(Frame),
+ PIPid ! {get_debug_info, self()},
+ Notebook = receive {procinfo_debug, NB} -> NB end,
+ Count = wxNotebook:getPageCount(Notebook),
+ Check = fun(_N) ->
+ ok = wxNotebook:advanceSelection(Notebook),
+ timer:sleep(400)
+ end,
+ [_|_] = [Check(N) || N <- lists:seq(1, Count)],
+ PIPid ! #wx{event=#wxClose{type=close_window}},
+ observer:stop(),
+ ok.
+
+table_win(suite) -> [];
+table_win(doc) -> [""];
+table_win(Config) when is_list(Config) ->
+ Tables = [ets:new(list_to_atom("Test-" ++ [C]), [public]) || C <- lists:seq($A, $Z)],
+ Table = lists:nth(3, Tables),
+ ets:insert(Table, [{N,100-N} || N <- lists:seq(1,100)]),
+ ok = observer:start(),
+ Notebook = setup_whitebox_testing(),
+ Parent = get_top_level_parent(Notebook),
+ TObj = observer_tv_table:start_link(Parent, [{node,node()}, {type,ets}, {table,#tab{name=foo, id=Table}}]),
+ %% Modal can not test edit..
+ %% TPid = wx_object:get_pid(TObj),
+ %% TPid ! #wx{event=#wxList{type=command_list_item_activated, itemIndex=12}},
+ timer:sleep(2000),
+ wx_object:get_pid(TObj) ! #wx{event=#wxClose{type=close_window}},
+ observer:stop(),
+ ok.
+
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+get_top_level_parent(Window) ->
+ Parent = wxWindow:getParent(Window),
+ case wx:is_null(Parent) of
+ true -> Window;
+ false -> get_top_level_parent(Parent)
+ end.
+
+setup_whitebox_testing() ->
+ %% So that if we die observer exists
+ link(whereis(observer)),
+ {Env, Notebook, _Active} = get_observer_debug(),
+ wx:set_env(Env),
+ Notebook.
+
+get_active() ->
+ {_, _, Active} = get_observer_debug(),
+ Active.
+
+get_observer_debug() ->
+ observer ! {get_debug_info, self()},
+ receive
+ {observer_debug, Env, Notebook, Active} ->
+ {Env, Notebook, Active}
+ end.
diff --git a/lib/observer/vsn.mk b/lib/observer/vsn.mk
index f48809a839..a6300eeb18 100644
--- a/lib/observer/vsn.mk
+++ b/lib/observer/vsn.mk
@@ -1 +1 @@
-OBSERVER_VSN = 1.3.1.2
+OBSERVER_VSN = 2.0
diff --git a/lib/odbc/aclocal.m4 b/lib/odbc/aclocal.m4
index c51c26794a..2b47f7c4bc 100644
--- a/lib/odbc/aclocal.m4
+++ b/lib/odbc/aclocal.m4
@@ -83,8 +83,10 @@ AC_ARG_VAR(erl_xcomp_ose_LM_POST_LINK, [OSE postlink tool (only used when cross
AC_ARG_VAR(erl_xcomp_ose_LM_SET_CONF, [Sets the configuration for an OSE load module (only used when cross compiling for OSE)])
AC_ARG_VAR(erl_xcomp_ose_LM_ELF_SIZE, [Prints the section size information for an OSE load module (only used when cross compiling for OSE)])
AC_ARG_VAR(erl_xcomp_ose_LM_LCF, [OSE load module linker configuration file (only used when cross compiling for OSE)])
-AC_ARG_VAR(erl_xcomp_ose_LM_CONF, [OSE load module default configuration file (only used when cross compiling for OSE)])
-AC_ARG_VAR(erl_xcomp_ose_CONFD, [OSE OSE confd source file])
+AC_ARG_VAR(erl_xcomp_ose_BEAM_LM_CONF, [BEAM OSE load module default configuration file (only used when cross compiling for OSE)])
+AC_ARG_VAR(erl_xcomp_ose_EPMD_LM_CONF, [EPMD OSE load module default configuration file (only used when cross compiling for OSE)])
+AC_ARG_VAR(erl_xcomp_ose_RUN_ERL_LM_CONF, [run_erl_lm OSE load module default configuration file (only used when cross compiling for OSE)])
+AC_ARG_VAR(erl_xcomp_ose_CONFD, [OSE confd source file])
AC_ARG_VAR(erl_xcomp_ose_CRT0_LM, [OSE crt0 lm source file])
])
diff --git a/lib/odbc/src/odbc.app.src b/lib/odbc/src/odbc.app.src
index 5229b28c08..b2c5775de2 100644
--- a/lib/odbc/src/odbc.app.src
+++ b/lib/odbc/src/odbc.app.src
@@ -11,5 +11,6 @@
]},
{applications, [kernel, stdlib]},
{env,[]},
- {mod, {odbc_app, []}}]}.
+ {mod, {odbc_app, []}},
+ {runtime_dependencies, ["stdlib-2.0","kernel-3.0","erts-6.0"]}]}.
diff --git a/lib/odbc/vsn.mk b/lib/odbc/vsn.mk
index d9e2ab26a9..1af4751248 100644
--- a/lib/odbc/vsn.mk
+++ b/lib/odbc/vsn.mk
@@ -1 +1 @@
-ODBC_VSN = 2.10.19
+ODBC_VSN = 2.10.20
diff --git a/lib/orber/src/orber.app.src b/lib/orber/src/orber.app.src
index 88df4162b6..30bd90347d 100644
--- a/lib/orber/src/orber.app.src
+++ b/lib/orber/src/orber.app.src
@@ -103,7 +103,9 @@
orber_iiop_pm, orber_env]},
{applications, [stdlib, kernel, mnesia]},
{env, []},
- {mod, {orber, []}}
+ {mod, {orber, []}},
+ {runtime_dependencies, ["stdlib-2.0","ssl-5.3.4","mnesia-4.12","kernel-3.0",
+ "inets-5.10","erts-6.0"]}
]}.
diff --git a/lib/orber/vsn.mk b/lib/orber/vsn.mk
index 7bbebc65dc..3ea64b1ff6 100644
--- a/lib/orber/vsn.mk
+++ b/lib/orber/vsn.mk
@@ -1,2 +1,2 @@
-ORBER_VSN = 3.6.26.1
+ORBER_VSN = 3.6.27
diff --git a/lib/os_mon/c_src/memsup.c b/lib/os_mon/c_src/memsup.c
index b5114d10ed..409db84aa7 100644
--- a/lib/os_mon/c_src/memsup.c
+++ b/lib/os_mon/c_src/memsup.c
@@ -324,7 +324,7 @@ get_mem_procfs(memory_ext *me){
/* arch specific functions */
-#if defined(__linux__) /* ifdef SYSINFO */
+#if defined(__linux__) && !defined(__ANDROID__)/* ifdef SYSINFO */
/* sysinfo does not include cached memory which is a problem. */
static int
get_extended_mem_sysinfo(memory_ext *me) {
@@ -395,8 +395,12 @@ get_extended_mem_sgi(memory_ext *me) {
static void
get_extended_mem(memory_ext *me) {
+/* android */
+#if defined(__ANDROID__)
+ if (get_mem_procfs(me)) return;
+
/* linux */
-#if defined(__linux__)
+#elif defined(__linux__)
if (get_mem_procfs(me)) return;
if (get_extended_mem_sysinfo(me)) return;
diff --git a/lib/os_mon/src/os_mon.app.src b/lib/os_mon/src/os_mon.app.src
index 15bbd2663c..cc08cebe3d 100644
--- a/lib/os_mon/src/os_mon.app.src
+++ b/lib/os_mon/src/os_mon.app.src
@@ -29,4 +29,7 @@
{start_disksup, true},
{start_memsup, true},
{start_os_sup, false}]},
- {mod, {os_mon, []}}]}.
+ {mod, {os_mon, []}},
+ {runtime_dependencies, ["stdlib-2.0","snmp-4.25.1","sasl-2.4",
+ "otp_mibs-1.0.9","mnesia-4.12","kernel-3.0",
+ "erts-6.0"]}]}.
diff --git a/lib/os_mon/test/cpu_sup_SUITE.erl b/lib/os_mon/test/cpu_sup_SUITE.erl
index e0382cb0c7..9f58e043db 100644
--- a/lib/os_mon/test/cpu_sup_SUITE.erl
+++ b/lib/os_mon/test/cpu_sup_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2002-2011. All Rights Reserved.
+%% Copyright Ericsson AB 2002-2014. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -257,8 +257,8 @@ port(Config) when is_list(Config) ->
terminate(suite) ->
[];
terminate(Config) when is_list(Config) ->
- ?line ok = application:set_env(os_mon, start_cpu_sup, false),
- ?line ok = supervisor:terminate_child(os_mon_sup, cpu_sup),
+ ok = application:set_env(os_mon, start_cpu_sup, false),
+ _ = supervisor:terminate_child(os_mon_sup, cpu_sup),
ok.
unavailable(suite) ->
diff --git a/lib/os_mon/test/disksup_SUITE.erl b/lib/os_mon/test/disksup_SUITE.erl
index 9c65d8b692..94661cfa77 100644
--- a/lib/os_mon/test/disksup_SUITE.erl
+++ b/lib/os_mon/test/disksup_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2011. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2014. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -350,15 +350,16 @@ otp_5910(doc) ->
otp_5910(Config) when is_list(Config) ->
%% Make sure disksup sets at least one alarm
- Data = disksup:get_disk_data(),
+ Data = lists:sort(disksup:get_disk_data()),
Threshold0 = disksup:get_almost_full_threshold(),
Threshold = case over_threshold(Data, Threshold0) of
- 0 ->
- [{_Id,_Kbyte,Cap}|_] = Data,
- ok = disksup:set_almost_full_threshold((Cap-1)/100),
- Cap-1;
- _N -> Threshold0
- end,
+ 0 ->
+ [{_Id,_Kbyte,Cap}|_] = Data,
+ io:format("Data ~p Threshold ~p ~n",[Data, Cap-1]),
+ ok = disksup:set_almost_full_threshold((Cap-1)/100),
+ Cap-1;
+ _N -> Threshold0
+ end,
ok = application:set_env(os_mon, disk_almost_full_threshold, Threshold/100),
disksup ! timeout, % force a disk check
Data2 = disksup:get_disk_data(),
diff --git a/lib/os_mon/vsn.mk b/lib/os_mon/vsn.mk
index e9e90729f2..74397c2bc6 100644
--- a/lib/os_mon/vsn.mk
+++ b/lib/os_mon/vsn.mk
@@ -1 +1 @@
-OS_MON_VSN = 2.2.14
+OS_MON_VSN = 2.2.15
diff --git a/lib/ose/doc/src/ose_intro.xml b/lib/ose/doc/src/ose_intro.xml
index 0dd3ec409e..b5e3ef8b33 100644
--- a/lib/ose/doc/src/ose_intro.xml
+++ b/lib/ose/doc/src/ose_intro.xml
@@ -78,7 +78,7 @@ rtose@acp3400> pm_start 0x110059</code>
seperate machine the paths have to be updated. In the example above
<c>/usr/local/lib/erlang</c> was replaced by <c>/mst/erlang/</c>. The
goal is to in future releases not have to do the special argument handling
- but for now (17.0-rc2) you have to do it.
+ but for now (OTP 17.0) you have to do it.
</p>
<note>
Because of a limitation in the way the OSE handles stdio when starting
@@ -146,7 +146,7 @@ os:type().
It is possible to set the priorities you want for the OSE processes that
thr emulator creates in the lmconf. An example of how to do it can be
found in the default lmconf file in
- $ERL_TOP/erts/emulator/sys/ose/default.lmconf.
+ $ERL_TOP/erts/emulator/sys/ose/beam.lmconf.
</p>
</section>
diff --git a/lib/ose/src/ose.app.src b/lib/ose/src/ose.app.src
index c39d3f2d05..60699c369b 100644
--- a/lib/ose/src/ose.app.src
+++ b/lib/ose/src/ose.app.src
@@ -23,4 +23,5 @@
{modules, [ose]},
{registered,[]},
{applications, [stdlib,kernel]},
- {env, []}]}.
+ {env, []},
+ {runtime_dependencies, ["stdlib-2.0","erts-6.0"]}]}.
diff --git a/lib/otp_mibs/src/otp_mibs.app.src b/lib/otp_mibs/src/otp_mibs.app.src
index b177af0709..ebc656b0b2 100644
--- a/lib/otp_mibs/src/otp_mibs.app.src
+++ b/lib/otp_mibs/src/otp_mibs.app.src
@@ -23,5 +23,7 @@
{modules, [otp_mib]},
{registered, []},
{applications, [kernel, stdlib, snmp]},
- {env,[]}]}.
+ {env,[]},
+ {runtime_dependencies, ["stdlib-2.0","snmp-4.25.1","mnesia-4.12",
+ "kernel-3.0","erts-6.0"]}]}.
diff --git a/lib/otp_mibs/vsn.mk b/lib/otp_mibs/vsn.mk
index 96d3088224..98db21c132 100644
--- a/lib/otp_mibs/vsn.mk
+++ b/lib/otp_mibs/vsn.mk
@@ -1,4 +1,4 @@
-OTP_MIBS_VSN = 1.0.8
+OTP_MIBS_VSN = 1.0.9
# Note: The branch 'otp_mibs' is defunct as of otp_mibs-1.0.4 and
# should NOT be used again.
diff --git a/lib/parsetools/src/parsetools.app.src b/lib/parsetools/src/parsetools.app.src
index af62fc4f6b..9eeb8fcc05 100644
--- a/lib/parsetools/src/parsetools.app.src
+++ b/lib/parsetools/src/parsetools.app.src
@@ -11,7 +11,8 @@
{applications, [kernel,stdlib]},
{env, [{file_util_search_methods,[{"", ""}, {"ebin", "esrc"}, {"ebin", "src"}]}
]
- }
+ },
+ {runtime_dependencies, ["stdlib-2.0","kernel-3.0","erts-6.0"]}
]
}.
diff --git a/lib/parsetools/vsn.mk b/lib/parsetools/vsn.mk
index d62962c54a..8fd7422c1c 100644
--- a/lib/parsetools/vsn.mk
+++ b/lib/parsetools/vsn.mk
@@ -1 +1 @@
-PARSETOOLS_VSN = 2.0.10
+PARSETOOLS_VSN = 2.0.11
diff --git a/lib/percept/src/percept.app.src b/lib/percept/src/percept.app.src
index cf4a9fc438..f8991ee577 100644
--- a/lib/percept/src/percept.app.src
+++ b/lib/percept/src/percept.app.src
@@ -35,7 +35,9 @@
]},
{registered, [percept_db,percept_port]},
{applications, [kernel,stdlib]},
- {env,[]}
+ {env,[]},
+ {runtime_dependencies, ["stdlib-2.0","runtime_tools-1.8.14","kernel-3.0",
+ "inets-5.10","erts-6.0"]}
]}.
diff --git a/lib/percept/vsn.mk b/lib/percept/vsn.mk
index 99729c11e2..935a9d1336 100644
--- a/lib/percept/vsn.mk
+++ b/lib/percept/vsn.mk
@@ -1 +1 @@
-PERCEPT_VSN = 0.8.8.2
+PERCEPT_VSN = 0.8.9
diff --git a/lib/public_key/src/pubkey_cert.erl b/lib/public_key/src/pubkey_cert.erl
index dc8d68c78f..ae517ca642 100644
--- a/lib/public_key/src/pubkey_cert.erl
+++ b/lib/public_key/src/pubkey_cert.erl
@@ -319,6 +319,8 @@ verify_fun(Otpcert, Result, UserState0, VerifyFun) ->
%%
%% Description: Extracts a specific extension from a list of extensions.
%%--------------------------------------------------------------------
+select_extension(_, asn1_NOVALUE) ->
+ undefined;
select_extension(_, []) ->
undefined;
select_extension(Id, [#'Extension'{extnID = Id} = Extension | _]) ->
@@ -342,8 +344,11 @@ match_name(uniformResourceIdentifier, URI, [PermittedName | Rest]) ->
incomplete ->
false;
{_, _, Host, _, _} ->
- match_name(fun is_valid_host_or_domain/2, Host,
- PermittedName, Rest)
+ PN = case split_uri(PermittedName) of
+ {_, _, PNhost, _, _} -> PNhost;
+ _X -> PermittedName
+ end,
+ match_name(fun is_valid_host_or_domain/2, Host, PN, Rest)
end;
match_name(emailAddress, Name, [PermittedName | Rest]) ->
@@ -511,10 +516,10 @@ is_dir_name2(Value, Value) -> true;
is_dir_name2({printableString, Value1}, {printableString, Value2}) ->
string:to_lower(strip_spaces(Value1)) =:=
string:to_lower(strip_spaces(Value2));
-is_dir_name2({utf8String, Value1}, String) -> %% BUGBUG FIX UTF8 conv
- is_dir_name2({printableString, binary_to_list(Value1)}, String);
-is_dir_name2(String, {utf8String, Value1}) -> %% BUGBUG FIX UTF8 conv
- is_dir_name2(String, {printableString, binary_to_list(Value1)});
+is_dir_name2({utf8String, Value1}, String) ->
+ is_dir_name2({printableString, unicode:characters_to_list(Value1)}, String);
+is_dir_name2(String, {utf8String, Value1}) ->
+ is_dir_name2(String, {printableString, unicode:characters_to_list(Value1)});
is_dir_name2(_, _) ->
false.
diff --git a/lib/public_key/src/pubkey_crl.erl b/lib/public_key/src/pubkey_crl.erl
index eaba5bfa1b..f0df4bc3f2 100644
--- a/lib/public_key/src/pubkey_crl.erl
+++ b/lib/public_key/src/pubkey_crl.erl
@@ -39,7 +39,13 @@ validate(OtpCert, OtherDPCRLs, DP, {DerCRL, CRL}, {DerDeltaCRL, DeltaCRL},
CertIssuer = TBSCert#'OTPTBSCertificate'.issuer,
TBSCRL = CRL#'CertificateList'.tbsCertList,
CRLIssuer = TBSCRL#'TBSCertList'.issuer,
- AltNames = subject_alt_names(TBSCert#'OTPTBSCertificate'.extensions),
+ AltNames = case pubkey_cert:select_extension(?'id-ce-subjectAltName',
+ TBSCert#'OTPTBSCertificate'.extensions) of
+ undefined ->
+ [];
+ Ext ->
+ Ext#'Extension'.extnValue
+ end,
revoked_status(DP, IDP, {directoryName, CRLIssuer},
[ {directoryName, CertIssuer} | AltNames], SerialNumber, Revoked,
DeltaRevoked, RevokedState1);
@@ -397,16 +403,18 @@ verify_dp_name(IDPNames, DPorIssuerNames) ->
match_one([], _) ->
false;
match_one([{Type, Name} | Names], CandidateNames) ->
- Candidates = [NameName || {NameType, NameName} <- CandidateNames, NameType == Type],
+ Candidates = [NameName || {NameType, NameName} <- CandidateNames,
+ NameType == Type],
case Candidates of
[] ->
false;
- [_|_] -> case pubkey_cert:match_name(Type, Name, Candidates) of
- true ->
- true;
- false ->
- match_one(Names, CandidateNames)
- end
+ [_|_] ->
+ case pubkey_cert:match_name(Type, Name, Candidates) of
+ true ->
+ true;
+ false ->
+ match_one(Names, CandidateNames)
+ end
end.
verify_dp_bools(TBSCert, IDP) ->
@@ -664,6 +672,8 @@ verify_extensions([#'TBSCertList_revokedCertificates_SEQOF'{crlEntryExtensions =
verify_extensions(pubkey_cert:extensions_list(Ext)) and verify_extensions(Rest);
verify_extensions([]) ->
true;
+verify_extensions(asn1_NOVALUE) ->
+ true;
verify_extensions([#'Extension'{critical = true, extnID = Id} | Rest]) ->
case lists:member(Id, [?'id-ce-authorityKeyIdentifier',
?'id-ce-issuerAltName',
@@ -689,13 +699,3 @@ authority_key_identifier(Extensions) ->
Enc = extension_value(?'id-ce-authorityKeyIdentifier',
'AuthorityKeyIdentifier', Extensions),
pubkey_cert_records:transform(Enc, decode).
-
-subject_alt_names(Extensions) ->
- Enc = extension_value(?'id-ce-subjectAltName',
- 'GeneralNames', Extensions),
- case Enc of
- undefined ->
- [];
- _ ->
- pubkey_cert_records:transform(Enc, decode)
- end.
diff --git a/lib/public_key/src/public_key.app.src b/lib/public_key/src/public_key.app.src
index 736a778a4b..88ef07c5a6 100644
--- a/lib/public_key/src/public_key.app.src
+++ b/lib/public_key/src/public_key.app.src
@@ -13,7 +13,9 @@
]},
{applications, [asn1, crypto, kernel, stdlib]},
{registered, []},
- {env, []}
+ {env, []},
+ {runtime_dependencies, ["stdlib-2.0","kernel-3.0","erts-6.0","crypto-3.3",
+ "asn1-3.0"]}
]
}.
diff --git a/lib/public_key/vsn.mk b/lib/public_key/vsn.mk
index 3473757c5f..f0450918aa 100644
--- a/lib/public_key/vsn.mk
+++ b/lib/public_key/vsn.mk
@@ -1 +1 @@
-PUBLIC_KEY_VSN = 0.21
+PUBLIC_KEY_VSN = 0.22
diff --git a/lib/reltool/src/reltool.app.src b/lib/reltool/src/reltool.app.src
index 4188f341f1..65fcf4aae5 100644
--- a/lib/reltool/src/reltool.app.src
+++ b/lib/reltool/src/reltool.app.src
@@ -34,5 +34,7 @@
]},
{registered, []},
{applications, [stdlib, kernel]},
- {env, []}
+ {env, []},
+ {runtime_dependencies, ["wx-1.2","tools-2.6.14","stdlib-2.0","sasl-2.4",
+ "kernel-3.0","erts-6.0"]}
]}.
diff --git a/lib/reltool/src/reltool.hrl b/lib/reltool/src/reltool.hrl
index f0d8b38519..56161a152a 100644
--- a/lib/reltool/src/reltool.hrl
+++ b/lib/reltool/src/reltool.hrl
@@ -164,7 +164,8 @@
applications = [] :: [app_name()],
env = [] :: [{atom(), term()}],
mod = undefined :: {mod_name(), [term()]} | undefined,
- start_phases = undefined :: [{atom(), term()}] | undefined
+ start_phases = undefined :: [{atom(), term()}] | undefined,
+ runtime_dependencies = [] :: [string()]
}).
-record(regexp, {source, compiled}).
diff --git a/lib/reltool/src/reltool_server.erl b/lib/reltool/src/reltool_server.erl
index 97785ca7f8..98eeed5c27 100644
--- a/lib/reltool/src/reltool_server.erl
+++ b/lib/reltool/src/reltool_server.erl
@@ -1125,6 +1125,9 @@ parse_app_info(File, [{Key, Val} | KeyVals], AI, Status) ->
start_phases ->
parse_app_info(File, KeyVals, AI#app_info{start_phases = Val},
Status);
+ runtime_dependencies ->
+ parse_app_info(File, KeyVals, AI#app_info{runtime_dependencies = Val},
+ Status);
_ ->
Status2 =
reltool_utils:add_warning("Unexpected item ~p in app file ~tp.",
diff --git a/lib/reltool/vsn.mk b/lib/reltool/vsn.mk
index 16ec570d22..163b77dfa0 100644
--- a/lib/reltool/vsn.mk
+++ b/lib/reltool/vsn.mk
@@ -1 +1 @@
-RELTOOL_VSN = 0.6.4.1
+RELTOOL_VSN = 0.6.5
diff --git a/lib/runtime_tools/doc/specs/.gitignore b/lib/runtime_tools/doc/specs/.gitignore
new file mode 100644
index 0000000000..322eebcb06
--- /dev/null
+++ b/lib/runtime_tools/doc/specs/.gitignore
@@ -0,0 +1 @@
+specs_*.xml
diff --git a/lib/runtime_tools/doc/src/Makefile b/lib/runtime_tools/doc/src/Makefile
index 51d93df418..07c63197e9 100644
--- a/lib/runtime_tools/doc/src/Makefile
+++ b/lib/runtime_tools/doc/src/Makefile
@@ -40,7 +40,7 @@ RELSYSDIR = $(RELEASE_PATH)/lib/$(APPLICATION)-$(VSN)
# Target Specs
# ----------------------------------------------------
XML_APPLICATION_FILES = ref_man.xml
-XML_REF3_FILES = dbg.xml dyntrace.xml erts_alloc_config.xml
+XML_REF3_FILES = dbg.xml dyntrace.xml erts_alloc_config.xml system_information.xml
XML_REF6_FILES = runtime_tools_app.xml
XML_PART_FILES = part_notes.xml part_notes_history.xml part.xml
@@ -71,12 +71,20 @@ HTML_REF_MAN_FILE = $(HTMLDIR)/index.html
TOP_PDF_FILE = $(PDFDIR)/$(APPLICATION)-$(VSN).pdf
+SPECS_FILES = $(XML_REF3_FILES:%.xml=$(SPECDIR)/specs_%.xml)
+
+TOP_SPECS_FILE = specs.xml
+
# ----------------------------------------------------
# FLAGS
# ----------------------------------------------------
XML_FLAGS +=
DVIPS_FLAGS +=
+SPECS_ESRC = ../../src
+
+SPECS_FLAGS = -I../../include -I../../../kernel/src
+
# ----------------------------------------------------
# Targets
# ----------------------------------------------------
diff --git a/lib/runtime_tools/doc/src/ref_man.xml b/lib/runtime_tools/doc/src/ref_man.xml
index 6017f3cdaa..25fa97896b 100644
--- a/lib/runtime_tools/doc/src/ref_man.xml
+++ b/lib/runtime_tools/doc/src/ref_man.xml
@@ -35,5 +35,6 @@
<xi:include href="dbg.xml"/>
<xi:include href="dyntrace.xml"/>
<xi:include href="erts_alloc_config.xml"/>
+ <xi:include href="system_information.xml"/>
</application>
diff --git a/lib/runtime_tools/doc/src/specs.xml b/lib/runtime_tools/doc/src/specs.xml
new file mode 100644
index 0000000000..d4c3c9dfe6
--- /dev/null
+++ b/lib/runtime_tools/doc/src/specs.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<specs xmlns:xi="http://www.w3.org/2001/XInclude">
+ <xi:include href="../specs/specs_system_information.xml"/>
+</specs>
diff --git a/lib/runtime_tools/doc/src/system_information.xml b/lib/runtime_tools/doc/src/system_information.xml
new file mode 100644
index 0000000000..b586334ae7
--- /dev/null
+++ b/lib/runtime_tools/doc/src/system_information.xml
@@ -0,0 +1,98 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<!DOCTYPE erlref SYSTEM "erlref.dtd">
+
+<erlref>
+ <header>
+ <copyright>
+ <year>2014</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></title>
+ <prepared></prepared>
+ <responsible></responsible>
+ <docno>1</docno>
+ <approved></approved>
+ <checked></checked>
+ <date></date>
+ <rev></rev>
+ <file>system_information.xml</file>
+ </header>
+ <module>system_information</module>
+ <modulesummary>System Information</modulesummary>
+ <description>
+ <p></p>
+ </description>
+ <funcs>
+ <func>
+ <name name="sanity_check" arity="0"/>
+ <fsummary>Perform a sanity check</fsummary>
+ <desc>
+ <p>Performs a sanity check on the system. If no issues
+ were found, <c>ok</c> is returned. If issues were
+ found, <c>{failed, <anno>Failures</anno>}</c> is
+ returned. All failures found will be part of the
+ <c><anno>Failures</anno></c> list. Currently defined
+ <c><anno>Failure</anno></c> elements in the
+ <c><anno>Failures</anno></c> list:</p>
+ <taglist>
+ <tag><c><anno>InvalidAppFile</anno></c></tag>
+ <item><p>An application has an invalid <c>.app</c> file. The
+ second element identifies the application which has the
+ invalid <c>.app</c> file.</p></item>
+ <tag><c><anno>InvalidApplicationVersion</anno></c></tag>
+ <item><p>An application has an invalid application version.
+ The second element identifies the application version that
+ is invalid.</p></item>
+ <tag><c><anno>MissingRuntimeDependencies</anno></c></tag>
+ <item><p>An application is missing
+ <seealso marker="kernel:app#runtime_dependencies">runtime
+ dependencies</seealso>. The second element identifies the
+ application (with version) that has missing dependencies.
+ The third element contains the missing dependencies.</p>
+ <p>Note that this check use application versions that
+ are loaded, or will be loaded when used. You might have
+ application versions that satisfies all dependencies
+ installed in the system, but if those are not loaded this
+ check will fail. The system will of course also fail when
+ used like this. This may happen when you have multiple
+ <seealso marker="doc/system_principles:versions">branched
+ versions</seealso> of the same application installed in the
+ system, but you do not use a
+ <seealso marker="doc/system_principles:system_principles#BOOTSCRIPT">boot
+ script</seealso> identifing the correct application version.</p>
+ </item>
+ </taglist>
+ <p>Currently the sanity check is limited to verifying
+ runtime dependencies found in the <c>.app</c> files of
+ all applications. More checks will be introduced in the
+ future. This implies that the return type <em>will</em>
+ change in the future.</p>
+ <note><p>An <c>ok</c> return value only means that
+ <c>sanity_check/0</c> did not find any issues, <em>not</em>
+ that no issues exist.</p></note>
+ </desc>
+ </func>
+ <func>
+ <name name="to_file" arity="1"/>
+ <fsummary>Write miscellaneous system information to file</fsummary>
+ <desc><p>Writes miscellaneous system information to file. This
+ information will typically be requested by the Erlang/OTP team
+ at Ericsson AB when reporting an issue.</p></desc>
+ </func>
+ </funcs>
+ </erlref>
+
diff --git a/lib/runtime_tools/src/runtime_tools.app.src b/lib/runtime_tools/src/runtime_tools.app.src
index d46cfe1f32..0a70802c08 100644
--- a/lib/runtime_tools/src/runtime_tools.app.src
+++ b/lib/runtime_tools/src/runtime_tools.app.src
@@ -25,6 +25,8 @@
{registered, [runtime_tools_sup]},
{applications, [kernel, stdlib]},
{env, []},
- {mod, {runtime_tools, []}}]}.
+ {mod, {runtime_tools, []}},
+ {runtime_dependencies, ["stdlib-2.0","mnesia-4.12","kernel-3.0",
+ "erts-6.0"]}]}.
diff --git a/lib/runtime_tools/src/system_information.erl b/lib/runtime_tools/src/system_information.erl
index 603b698d5e..f541d6e449 100644
--- a/lib/runtime_tools/src/system_information.erl
+++ b/lib/runtime_tools/src/system_information.erl
@@ -39,7 +39,8 @@
application/1, application/2,
environment/0, environment/1,
module/1, module/2,
- modules/1
+ modules/1,
+ sanity_check/0
]).
%% gen_server callbacks
@@ -85,9 +86,14 @@ report() -> [
{erts_compile_info, erlang:system_info(compile_info)},
{beam_dynamic_libraries, get_dynamic_libraries()},
{environment_erts, os_getenv_erts_specific()},
- {environment, [split_env(Env) || Env <- os:getenv()]}
+ {environment, [split_env(Env) || Env <- os:getenv()]},
+ {sanity_check, sanity_check()}
].
+-spec to_file(FileName) -> ok | {error, Reason} when
+ FileName :: file:name_all(),
+ Reason :: file:posix() | badarg | terminated | system_limit.
+
to_file(File) ->
file:write_file(File, iolist_to_binary([
io_lib:format("{system_information_version, ~p}.~n", [
@@ -130,6 +136,27 @@ module(M, Opts) when is_atom(M), is_list(Opts) ->
modules(Opt) when is_atom(Opt) ->
gen_server:call(?SERVER, {modules, Opt}).
+
+-spec sanity_check() -> ok | {failed, Failures} when
+ Application :: atom(),
+ ApplicationVersion :: string(),
+ MissingRuntimeDependencies :: {missing_runtime_dependencies,
+ ApplicationVersion,
+ [ApplicationVersion]},
+ InvalidApplicationVersion :: {invalid_application_version,
+ ApplicationVersion},
+ InvalidAppFile :: {invalid_app_file, Application},
+ Failure :: MissingRuntimeDependencies
+ | InvalidApplicationVersion
+ | InvalidAppFile,
+ Failures :: [Failure].
+
+sanity_check() ->
+ case check_runtime_dependencies() of
+ [] -> ok;
+ Issues -> {failed, Issues}
+ end.
+
%%===================================================================
%% gen_server callbacks
%%===================================================================
@@ -457,6 +484,8 @@ get_application_from_path(Path) ->
{description, proplists:get_value(description, Info, [])},
{vsn, proplists:get_value(vsn, Info, [])},
{path, Path},
+ {runtime_dependencies,
+ proplists:get_value(runtime_dependencies, Info, [])},
{modules, get_modules_from_path(Path)}
]}
end.
@@ -552,3 +581,252 @@ get_beam_name() ->
Value -> Value
end,
Beam ++ Type ++ Flavor.
+
+%% Check runtime dependencies...
+
+vsnstr2vsn(VsnStr) ->
+ list_to_tuple(lists:map(fun (Part) ->
+ list_to_integer(Part)
+ end,
+ string:tokens(VsnStr, "."))).
+
+rtdepstrs2rtdeps([]) ->
+ [];
+rtdepstrs2rtdeps([RTDep | RTDeps]) ->
+ [AppStr, VsnStr] = string:tokens(RTDep, "-"),
+ [{list_to_atom(AppStr), vsnstr2vsn(VsnStr)} | rtdepstrs2rtdeps(RTDeps)].
+
+build_app_table([], AppTab) ->
+ AppTab;
+build_app_table([App | Apps], AppTab0) ->
+ AppTab1 = try
+ %% We may have multiple application versions installed
+ %% of the same application! It is therefore important
+ %% to look up the application version that actually will
+ %% be used via code server.
+ AppFile = code:where_is_file(atom_to_list(App) ++ ".app"),
+ {ok, [{application, App, Info}]} = file:consult(AppFile),
+ VsnStr = proplists:get_value(vsn, Info),
+ Vsn = vsnstr2vsn(VsnStr),
+ RTDepStrs = proplists:get_value(runtime_dependencies,
+ Info, []),
+ RTDeps = rtdepstrs2rtdeps(RTDepStrs),
+ gb_trees:insert(App, {Vsn, RTDeps}, AppTab0)
+ catch
+ _ : _ ->
+ AppTab0
+ end,
+ build_app_table(Apps, AppTab1).
+
+meets_min_req(Vsn, Vsn) ->
+ true;
+meets_min_req({X}, VsnReq) ->
+ meets_min_req({X, 0, 0}, VsnReq);
+meets_min_req({X, Y}, VsnReq) ->
+ meets_min_req({X, Y, 0}, VsnReq);
+meets_min_req(Vsn, {X}) ->
+ meets_min_req(Vsn, {X, 0, 0});
+meets_min_req(Vsn, {X, Y}) ->
+ meets_min_req(Vsn, {X, Y, 0});
+meets_min_req({X, _Y, _Z}, {XReq, _YReq, _ZReq}) when X > XReq ->
+ true;
+meets_min_req({X, Y, _Z}, {X, YReq, _ZReq}) when Y > YReq ->
+ true;
+meets_min_req({X, Y, Z}, {X, Y, ZReq}) when Z > ZReq ->
+ true;
+meets_min_req({_X, _Y, _Z}, {_XReq, _YReq, _ZReq}) ->
+ false;
+meets_min_req(Vsn, VsnReq) ->
+ gp_meets_min_req(mk_gp_vsn_list(Vsn), mk_gp_vsn_list(VsnReq)).
+
+gp_meets_min_req([X, Y, Z | _Vs], [X, Y, Z]) ->
+ true;
+gp_meets_min_req([X, Y, Z | _Vs], [XReq, YReq, ZReq]) ->
+ meets_min_req({X, Y, Z}, {XReq, YReq, ZReq});
+gp_meets_min_req([X, Y, Z | Vs], [X, Y, Z | VReqs]) ->
+ gp_meets_min_req_tail(Vs, VReqs);
+gp_meets_min_req(_Vsn, _VReq) ->
+ %% Versions on different version branches, i.e., the minimum
+ %% required functionality is not included in Vsn.
+ false.
+
+gp_meets_min_req_tail([V | Vs], [V | VReqs]) ->
+ gp_meets_min_req_tail(Vs, VReqs);
+gp_meets_min_req_tail([], []) ->
+ true;
+gp_meets_min_req_tail([_V | _Vs], []) ->
+ true;
+gp_meets_min_req_tail([V | _Vs], [VReq]) when V > VReq ->
+ true;
+gp_meets_min_req_tail(_Vs, _VReqs) ->
+ %% Versions on different version branches, i.e., the minimum
+ %% required functionality is not included in Vsn.
+ false.
+
+mk_gp_vsn_list(Vsn) ->
+ [X, Y, Z | Tail] = tuple_to_list(Vsn),
+ [X, Y, Z | remove_trailing_zeroes(Tail)].
+
+remove_trailing_zeroes([]) ->
+ [];
+remove_trailing_zeroes([0 | Vs]) ->
+ case remove_trailing_zeroes(Vs) of
+ [] -> [];
+ NewVs -> [0 | NewVs]
+ end;
+remove_trailing_zeroes([V | Vs]) ->
+ [V | remove_trailing_zeroes(Vs)].
+
+mk_app_vsn_str({App, Vsn}) ->
+ mk_app_vsn_str(App, Vsn).
+
+mk_app_vsn_str(App, Vsn) ->
+ VsnList = tuple_to_list(Vsn),
+ lists:flatten([atom_to_list(App),
+ $-,
+ integer_to_list(hd(VsnList)),
+ lists:map(fun (Part) ->
+ [$., integer_to_list(Part)]
+ end, tl(VsnList))]).
+
+otp_17_0_vsns_orddict() ->
+ [{asn1,{3,0}},
+ {common_test,{1,8}},
+ {compiler,{5,0}},
+ {cosEvent,{2,1,15}},
+ {cosEventDomain,{1,1,14}},
+ {cosFileTransfer,{1,1,16}},
+ {cosNotification,{1,1,21}},
+ {cosProperty,{1,1,17}},
+ {cosTime,{1,1,14}},
+ {cosTransactions,{1,2,14}},
+ {crypto,{3,3}},
+ {debugger,{4,0}},
+ {dialyzer,{2,7}},
+ {diameter,{1,6}},
+ {edoc,{0,7,13}},
+ {eldap,{1,0,3}},
+ {erl_docgen,{0,3,5}},
+ {erl_interface,{3,7,16}},
+ {erts,{6,0}},
+ {et,{1,5}},
+ {eunit,{2,2,7}},
+ {gs,{1,5,16}},
+ {hipe,{3,10,3}},
+ {ic,{4,3,5}},
+ {inets,{5,10}},
+ {jinterface,{1,5,9}},
+ {kernel,{3,0}},
+ {megaco,{3,17,1}},
+ {mnesia,{4,12}},
+ {observer,{2,0}},
+ {odbc,{2,10,20}},
+ {orber,{3,6,27}},
+ {os_mon,{2,2,15}},
+ {ose,{1,0}},
+ {otp_mibs,{1,0,9}},
+ {parsetools,{2,0,11}},
+ {percept,{0,8,9}},
+ {public_key,{0,22}},
+ {reltool,{0,6,5}},
+ {runtime_tools,{1,8,14}},
+ {sasl,{2,4}},
+ {snmp,{4,25,1}},
+ {ssh,{3,0,1}},
+ {ssl,{5,3,4}},
+ {stdlib,{2,0}},
+ {syntax_tools,{1,6,14}},
+ {test_server,{3,7}},
+ {tools,{2,6,14}},
+ {typer,{0,9,6}},
+ {webtool,{0,8,10}},
+ {wx,{1,2}},
+ {xmerl,{1,3,7}}].
+
+otp_17_0_vsns_tab() ->
+ gb_trees:from_orddict(otp_17_0_vsns_orddict()).
+
+check_runtime_dependency({App, DepVsn}, AppTab) ->
+ case gb_trees:lookup(App, AppTab) of
+ none ->
+ false;
+ {value, {Vsn, _}} ->
+ meets_min_req(Vsn, DepVsn)
+ end.
+
+check_runtime_dependencies(App, AppTab, OtpMinVsnTab) ->
+ case gb_trees:lookup(App, AppTab) of
+ none ->
+ [{invalid_app_file, App}];
+ {value, {Vsn, RTDeps}} ->
+ RTD = case lists:foldl(
+ fun (RTDep, Acc) ->
+ case check_runtime_dependency(RTDep, AppTab) of
+ true ->
+ Acc;
+ false ->
+ [mk_app_vsn_str(RTDep) | Acc]
+ end
+ end,
+ [],
+ RTDeps) of
+ [] ->
+ [];
+ MissingDeps ->
+ [{missing_runtime_dependencies,
+ mk_app_vsn_str(App, Vsn),
+ MissingDeps}]
+ end,
+ case gb_trees:lookup(App, OtpMinVsnTab) of
+ none ->
+ RTD;
+ {value, MinVsn} ->
+ case meets_min_req(Vsn, MinVsn) of
+ true ->
+ RTD;
+ false ->
+ [{invalid_application_version,
+ mk_app_vsn_str(App, Vsn)} | RTD]
+ end
+ end
+ end.
+
+app_file_to_app(AF) ->
+ list_to_atom(filename:basename(AF, ".app")).
+
+get_apps() ->
+ get_apps(code:get_path(), []).
+
+get_apps([], Apps) ->
+ lists:usort(Apps);
+get_apps([Path|Paths], Apps) ->
+ case filelib:wildcard(filename:join(Path, "*.app")) of
+ [] ->
+ %% Not app or invalid app
+ get_apps(Paths, Apps);
+ [AppFile] ->
+ get_apps(Paths, [app_file_to_app(AppFile) | Apps]);
+ [_AppFile| _] = AppFiles ->
+ %% Strange with multple .app files... Lets put them
+ %% all in the list and see what we get...
+ lists:map(fun (AF) ->
+ app_file_to_app(AF)
+ end, AppFiles) ++ Apps
+ end.
+
+check_runtime_dependencies() ->
+ OtpMinVsnTab = otp_17_0_vsns_tab(),
+ Apps = get_apps(),
+ AppTab = build_app_table(Apps, gb_trees:empty()),
+ lists:foldl(fun (App, Acc) ->
+ case check_runtime_dependencies(App,
+ AppTab,
+ OtpMinVsnTab) of
+ [] -> Acc;
+ Issues -> Issues ++ Acc
+ end
+ end,
+ [],
+ Apps).
+
+%% End of runtime dependency checks
diff --git a/lib/runtime_tools/test/system_information_SUITE.erl b/lib/runtime_tools/test/system_information_SUITE.erl
index fb9455a30f..53d20060e7 100644
--- a/lib/runtime_tools/test/system_information_SUITE.erl
+++ b/lib/runtime_tools/test/system_information_SUITE.erl
@@ -33,6 +33,7 @@
api_report/1,
api_to_file/1,
api_from_file/1,
+ sanity_check/1,
%% server
api_start_stop/1,
validate_server_interface/1
@@ -84,7 +85,8 @@ all() -> [
api_to_file,
api_from_file,
api_start_stop,
- validate_server_interface
+ validate_server_interface,
+ sanity_check
].
@@ -262,6 +264,9 @@ validate_server_interface(Config) ->
ok = system_information:stop(),
ok.
+sanity_check(Config) when is_list(Config) ->
+ ok = system_information:sanity_check().
+
%% aux
@@ -288,7 +293,8 @@ validate_report(Report) ->
erts_compile_info,
beam_dynamic_libraries,
environment_erts,
- environment
+ environment,
+ sanity_check
], Report).
ensure_report_keys([], _) -> ok;
diff --git a/lib/runtime_tools/test/system_information_SUITE_data/information_test_report.dat b/lib/runtime_tools/test/system_information_SUITE_data/information_test_report.dat
index 0900eadd4a..18938372a3 100644
--- a/lib/runtime_tools/test/system_information_SUITE_data/information_test_report.dat
+++ b/lib/runtime_tools/test/system_information_SUITE_data/information_test_report.dat
@@ -9870,4 +9870,5 @@
{"MANPATH",
"/usr/local/man:/usr/share/man:/usr/X11R6/man:/opt/gnome/share/man"},
{"LESSKEY","/etc/lesskey.bin"},
- {"LC_PAPER","sv_SE.UTF-8"}]}]}.
+ {"LC_PAPER","sv_SE.UTF-8"}]},
+ {sanity_check,ok}]}.
diff --git a/lib/runtime_tools/vsn.mk b/lib/runtime_tools/vsn.mk
index c282661a61..32953dfc5a 100644
--- a/lib/runtime_tools/vsn.mk
+++ b/lib/runtime_tools/vsn.mk
@@ -1 +1 @@
-RUNTIME_TOOLS_VSN = 1.8.13
+RUNTIME_TOOLS_VSN = 1.8.14
diff --git a/lib/sasl/src/sasl.app.src b/lib/sasl/src/sasl.app.src
index 8c814cfaf5..8e95197a2a 100644
--- a/lib/sasl/src/sasl.app.src
+++ b/lib/sasl/src/sasl.app.src
@@ -44,5 +44,7 @@
{applications, [kernel, stdlib]},
{env, [{sasl_error_logger, tty},
{errlog_type, all}]},
- {mod, {sasl, []}}]}.
+ {mod, {sasl, []}},
+ {runtime_dependencies, ["tools-2.6.14","stdlib-2.0","kernel-3.0",
+ "erts-6.0"]}]}.
diff --git a/lib/sasl/src/systools_make.erl b/lib/sasl/src/systools_make.erl
index 3d370a93a5..e5da797efb 100644
--- a/lib/sasl/src/systools_make.erl
+++ b/lib/sasl/src/systools_make.erl
@@ -2233,7 +2233,7 @@ format_error({undefined_applications,Apps}) ->
io_lib:format("Undefined applications: ~p~n",[Apps]);
format_error({duplicate_modules,Dups}) ->
io_lib:format("Duplicated modules: ~n~ts",
- [map(fun({{Mod,_,App1,_,_},{Mod,_,App2,_,_}}) ->
+ [map(fun({{Mod,App1,_},{Mod,App2,_}}) ->
io_lib:format("\t~w specified in ~w and ~w~n",
[Mod,App1,App2])
end, Dups)]);
diff --git a/lib/sasl/test/systools_SUITE.erl b/lib/sasl/test/systools_SUITE.erl
index e3f6933476..1d3a71e94e 100644
--- a/lib/sasl/test/systools_SUITE.erl
+++ b/lib/sasl/test/systools_SUITE.erl
@@ -47,6 +47,7 @@
abnormal_script/1, src_tests_script/1, crazy_script/1,
included_script/1, included_override_script/1,
included_fail_script/1, included_bug_script/1, exref_script/1,
+ duplicate_modules_script/1,
otp_3065_circular_dependenies/1, included_and_used_sort_script/1]).
-export([tar_options/1, normal_tar/1, no_mod_vsn_tar/1, system_files_tar/1,
system_files_tar/2, invalid_system_files_tar/1,
@@ -84,6 +85,7 @@ groups() ->
src_tests_script, crazy_script,
included_script, included_override_script,
included_fail_script, included_bug_script, exref_script,
+ duplicate_modules_script,
otp_3065_circular_dependenies, included_and_used_sort_script]},
{tar, [],
[tar_options, normal_tar, no_mod_vsn_tar, system_files_tar,
@@ -822,6 +824,33 @@ no_hipe({ok, Value}) ->
{ok, Value}
end.
+%% duplicate_modules_script: Check that make_script rejects two
+%% applications providing the same module.
+duplicate_modules_script(Config) when is_list(Config) ->
+ {ok, OldDir} = file:get_cwd(),
+
+ {LatestDir, LatestName} = create_script(duplicate_modules,Config),
+
+ DataDir = filename:absname(?copydir),
+
+ ok = file:set_cwd(LatestDir),
+ LibDir = fname([DataDir, d_duplicate_modules, lib]),
+ P = [fname([LibDir, 'app1-1.0', ebin]),
+ fname([LibDir, 'app2-1.0', ebin])],
+
+ %% Check wrong app vsn
+ error = systools:make_script(LatestName, [{path, P}]),
+ {error,
+ systools_make,
+ {duplicate_modules, [
+ {{myapp,app1,_}, {myapp,app2,_}}
+ ]
+ }
+ } = systools:make_script(LatestName, [silent, {path, P}]),
+
+ ok = file:set_cwd(OldDir),
+ ok.
+
%% tar_options: Check illegal tar options.
tar_options(Config) when is_list(Config) ->
{'EXIT',{{badarg,[{path,["Path",12,"Another"]}]}, _}} =
@@ -2186,7 +2215,10 @@ create_script(current_all_future_sasl,Config) ->
do_create_script(current_all_future_sasl,Config,current,Apps);
create_script({unicode,RelVsn},Config) ->
Apps = core_apps(current) ++ [{ua,"1.0"}],
- do_create_script(unicode,RelVsn,Config,current,Apps).
+ do_create_script(unicode,RelVsn,Config,current,Apps);
+create_script(duplicate_modules,Config) ->
+ Apps = core_apps(current) ++ [{app1,"1.0"},{app2,"1.0"}],
+ do_create_script(duplicate_modules,Config,current,Apps).
do_create_script(Id,Config,ErtsVsn,AppVsns) ->
diff --git a/lib/sasl/test/systools_SUITE_data/d_duplicate_modules/lib/app1-1.0/ebin/app1.app b/lib/sasl/test/systools_SUITE_data/d_duplicate_modules/lib/app1-1.0/ebin/app1.app
new file mode 100644
index 0000000000..dea9257f2f
--- /dev/null
+++ b/lib/sasl/test/systools_SUITE_data/d_duplicate_modules/lib/app1-1.0/ebin/app1.app
@@ -0,0 +1,7 @@
+{application, app1,
+ [{description, "Application 1"},
+ {vsn, "1.0"},
+ {modules, [myapp]},
+ {registered, []},
+ {applications, []},
+ {env, []}]}.
diff --git a/lib/sasl/test/systools_SUITE_data/d_duplicate_modules/lib/app1-1.0/src/myapp.erl b/lib/sasl/test/systools_SUITE_data/d_duplicate_modules/lib/app1-1.0/src/myapp.erl
new file mode 100644
index 0000000000..bf2ab7c79c
--- /dev/null
+++ b/lib/sasl/test/systools_SUITE_data/d_duplicate_modules/lib/app1-1.0/src/myapp.erl
@@ -0,0 +1,2 @@
+-module(myapp).
+-vsn("1.0").
diff --git a/lib/sasl/test/systools_SUITE_data/d_duplicate_modules/lib/app2-1.0/ebin/app2.app b/lib/sasl/test/systools_SUITE_data/d_duplicate_modules/lib/app2-1.0/ebin/app2.app
new file mode 100644
index 0000000000..476750d8b2
--- /dev/null
+++ b/lib/sasl/test/systools_SUITE_data/d_duplicate_modules/lib/app2-1.0/ebin/app2.app
@@ -0,0 +1,7 @@
+{application, app2,
+ [{description, "Application 2"},
+ {vsn, "1.0"},
+ {modules, [myapp]},
+ {registered, []},
+ {applications, []},
+ {env, []}]}.
diff --git a/lib/sasl/test/systools_SUITE_data/d_duplicate_modules/lib/app2-1.0/src/myapp.erl b/lib/sasl/test/systools_SUITE_data/d_duplicate_modules/lib/app2-1.0/src/myapp.erl
new file mode 100644
index 0000000000..bf2ab7c79c
--- /dev/null
+++ b/lib/sasl/test/systools_SUITE_data/d_duplicate_modules/lib/app2-1.0/src/myapp.erl
@@ -0,0 +1,2 @@
+-module(myapp).
+-vsn("1.0").
diff --git a/lib/snmp/doc/src/snmpa_mib_data.xml b/lib/snmp/doc/src/snmpa_mib_data.xml
index c1ea0a91f9..95a33e603e 100644
--- a/lib/snmp/doc/src/snmpa_mib_data.xml
+++ b/lib/snmp/doc/src/snmpa_mib_data.xml
@@ -1,10 +1,10 @@
-<?xml version="1.0" encoding="iso-8859-1" ?>
+<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE erlref SYSTEM "erlref.dtd">
<erlref>
<header>
<copyright>
- <year>2013</year><year>2013</year>
+ <year>2013</year><year>2014</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
diff --git a/lib/snmp/doc/src/snmpa_mib_storage.xml b/lib/snmp/doc/src/snmpa_mib_storage.xml
index a857ce79e8..791fbc80fe 100644
--- a/lib/snmp/doc/src/snmpa_mib_storage.xml
+++ b/lib/snmp/doc/src/snmpa_mib_storage.xml
@@ -1,10 +1,10 @@
-<?xml version="1.0" encoding="iso-8859-1" ?>
+<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE erlref SYSTEM "erlref.dtd">
<erlref>
<header>
<copyright>
- <year>2013</year><year>2013</year>
+ <year>2013</year><year>2014</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
diff --git a/lib/snmp/src/app/snmp.app.src b/lib/snmp/src/app/snmp.app.src
index 904d17954b..cbd292e4c3 100644
--- a/lib/snmp/src/app/snmp.app.src
+++ b/lib/snmp/src/app/snmp.app.src
@@ -136,4 +136,6 @@
%% configuration and use), and in that case mnesia must also be started,
%% before snmp.
{applications, [kernel, stdlib]},
- {mod, {snmp_app, []}}]}.
+ {mod, {snmp_app, []}},
+ {runtime_dependencies, ["stdlib-2.0","runtime_tools-1.8.14","mnesia-4.12",
+ "kernel-3.0","erts-6.0","crypto-3.3"]}]}.
diff --git a/lib/snmp/test/Makefile b/lib/snmp/test/Makefile
index f22b7ea8ee..7bc9dd07d4 100644
--- a/lib/snmp/test/Makefile
+++ b/lib/snmp/test/Makefile
@@ -93,10 +93,10 @@ ifeq ($(SNMP_DEBUG),e)
SNMP_FLAGS += -Dsnmp_error
endif
ifeq ($(SNMP_DEBUG),l)
- SNMP_FLAGS += -Dsnmp_log
+ SNMP_FLAGS += -Dsnmp_error -Dsnmp_log
endif
ifeq ($(SNMP_DEBUG),d)
- SNMP_FLAGS += -Dsnmp_debug
+ SNMP_FLAGS += -Dsnmp_error -Dsnmp_log -Dsnmp_debug
endif
ifeq ($(DONT_USE_TS),true)
diff --git a/lib/snmp/test/modules.mk b/lib/snmp/test/modules.mk
index 3d658bf8e8..fd8315ec4d 100644
--- a/lib/snmp/test/modules.mk
+++ b/lib/snmp/test/modules.mk
@@ -2,7 +2,7 @@
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2004-2012. All Rights Reserved.
+# Copyright Ericsson AB 2004-2014. All Rights Reserved.
#
# The contents of this file are subject to the Erlang Public License,
# Version 1.1, (the "License"); you may not use this file except in
@@ -42,6 +42,7 @@ TEST_UTIL_MODULES = \
snmp_test_manager \
snmp_test_mgr \
snmp_test_mgr_misc \
+ snmp_test_mgr_counter_server \
sa \
klas3 \
test1 \
diff --git a/lib/snmp/test/snmp_agent_test.erl b/lib/snmp/test/snmp_agent_test.erl
index 89a6ce1253..2a9f2e842d 100644
--- a/lib/snmp/test/snmp_agent_test.erl
+++ b/lib/snmp/test/snmp_agent_test.erl
@@ -19,10 +19,6 @@
-module(snmp_agent_test).
-%% TODO
-%% * Test fault-tolerance (kill master etc)
-%%
-
-export([
all/0,
groups/0,
@@ -41,7 +37,7 @@
v1_processing/1,
big/1,
big2/1,
- loop_mib/1,
+ loop_mib_1/1,
api/1,
subagent/1,
mnesia/1,
@@ -394,8 +390,9 @@
usm_read/0,
usm_del_user/0,
usm_bad/0,
- loop_mib_1/0,
- loop_mib_2/0,
+ loop_mib_1_test/0,
+ loop_mib_2_test/0,
+ loop_mib_3_test/0,
otp_1129_i/1,
otp_1162_test/0,
otp_1131_test/0,
@@ -546,8 +543,9 @@ groups() ->
init_per_suite(Config0) when is_list(Config0) ->
- ?DBG("init_per_suite -> entry with"
- "~n Config0: ~p", [Config0]),
+ p("init_per_suite -> entry with"
+ "~n Config: ~p"
+ "~n Nodes: ~p", [Config0, erlang:nodes()]),
Config1 = snmp_test_lib:init_suite_top_dir(?MODULE, Config0),
Config2 = snmp_test_lib:fix_data_dir(Config1),
@@ -558,16 +556,32 @@ init_per_suite(Config0) when is_list(Config0) ->
Config3 = [{mib_dir, MibDir}, {std_mib_dir, StdMibDir} | Config2],
- ?DBG("init_per_suite -> end with"
- "~n Config3: ~p", [Config3]),
+ snmp_test_mgr_counter_server:start(),
+
+ p("init_per_suite -> end when"
+ "~n Config: ~p"
+ "~n Nodes: ~p", [Config3, erlang:nodes()]),
Config3.
end_per_suite(Config) when is_list(Config) ->
- ?DBG("end_per_suite -> entry with"
- "~n Config: ~p", [Config]),
+ p("end_per_suite -> entry with"
+ "~n Config: ~p"
+ "~n Nodes: ~p", [Config, erlang:nodes()]),
+
+ case snmp_test_mgr_counter_server:stop() of
+ {ok, _Counters} ->
+ p("end_per_suite -> sucessfully stopped counter server"
+ "~n Counters: ~p", [_Counters]);
+
+ {error, Reason} ->
+ p("end_per_suite -> failed stopping counter server"
+ "~n Reason: ~p", [Reason])
+ end,
+ p("end_per_suite -> end when"
+ "~n Nodes: ~p", [erlang:nodes()]),
Config.
@@ -675,10 +689,16 @@ end_per_group(_GroupName, Config) ->
%% ---- Init Per TestCase ----
init_per_testcase(Case, Config) when is_list(Config) ->
- ?DBG("init_per_testcase -> entry with"
- "~n Config: ~p", [Config]),
+ p("init_per_testcase -> entry with"
+ "~n Config: ~p"
+ "~n Nodes: ~p", [Config, erlang:nodes()]),
- init_per_testcase1(Case, Config).
+ Result = init_per_testcase1(Case, Config),
+
+ p("init_per_testcase -> done when"
+ "~n Result: ~p"
+ "~n Nodes: ~p", [Result, erlang:nodes()]),
+ Result.
init_per_testcase1(otp8395 = Case, Config) when is_list(Config) ->
?DBG("init_per_testcase1 -> entry with"
@@ -719,12 +739,18 @@ init_per_testcase1(_Case, Config) when is_list(Config) ->
%% ---- End Per TestCase ----
end_per_testcase(Case, Config) when is_list(Config) ->
- ?DBG("end_per_testcase -> entry with"
- "~n Config: ~p", [Config]),
+ p("end_per_testcase -> entry with"
+ "~n Config: ~p"
+ "~n Nodes: ~p", [Config, erlang:nodes()]),
display_log(Config),
- end_per_testcase1(Case, Config).
+ Result = end_per_testcase1(Case, Config),
+
+ p("end_per_testcase -> done with"
+ "~n Result: ~p"
+ "~n Nodes: ~p", [Result, erlang:nodes()]),
+ Result.
end_per_testcase1(otp8395, Config) when is_list(Config) ->
otp8395({fin, Config});
@@ -1173,7 +1199,7 @@ mse_simple(X) -> ?P(mse_simple), simple(X).
mse_v1_processing(X) -> ?P(mse_v1_processing), v1_processing(X).
mse_big(X) -> ?P(mse_big), big(X).
mse_big2(X) -> ?P(mse_big2), big2(X).
-mse_loop_mib(X) -> ?P(mse_loop_mib), loop_mib(X).
+mse_loop_mib(X) -> ?P(mse_loop_mib), loop_mib_1(X).
mse_api(X) -> ?P(mse_api), api(X).
mse_sa_register(X) -> ?P(mse_sa_register), sa_register(X).
mse_v1_trap(X) -> ?P(mse_v1_trap), v1_trap(X).
@@ -1194,7 +1220,7 @@ msd_simple(X) -> ?P(msd_simple), simple(X).
msd_v1_processing(X) -> ?P(msd_v1_processing), v1_processing(X).
msd_big(X) -> ?P(msd_big), big(X).
msd_big2(X) -> ?P(msd_big2), big2(X).
-msd_loop_mib(X) -> ?P(msd_loop_mib), loop_mib(X).
+msd_loop_mib(X) -> ?P(msd_loop_mib), loop_mib_1(X).
msd_api(X) -> ?P(msd_api), api(X).
msd_sa_register(X) -> ?P(msd_sa_register), sa_register(X).
msd_v1_trap(X) -> ?P(msd_v1_trap), v1_trap(X).
@@ -1215,7 +1241,7 @@ msm_simple(X) -> ?P(msm_simple), simple(X).
msm_v1_processing(X) -> ?P(msm_v1_processing), v1_processing(X).
msm_big(X) -> ?P(msm_big2), big(X).
msm_big2(X) -> ?P(msm_loop_mib), big2(X).
-msm_loop_mib(X) -> ?P(msm_loop_mib), loop_mib(X).
+msm_loop_mib(X) -> ?P(msm_loop_mib), loop_mib_1(X).
msm_api(X) -> ?P(msm_api), api(X).
msm_sa_register(X) -> ?P(msm_sa_register), sa_register(X).
msm_v1_trap(X) -> ?P(msm_v1_trap), v1_trap(X).
@@ -1618,7 +1644,7 @@ v1_cases() ->
v1_processing,
big,
big2,
- loop_mib,
+ loop_mib_1,
api,
subagent,
mnesia,
@@ -2095,9 +2121,9 @@ await_dummy_manager_started(Pid) ->
{ok,Pid,Port};
{'EXIT', Pid, Reason} ->
{error, Pid, Reason};
- O ->
+ _O ->
?LOG("dummy_manager_start -> received unknown message:"
- "~n ~p",[O]),
+ "~n ~p",[_O]),
await_dummy_manager_started(Pid)
end.
@@ -2120,16 +2146,16 @@ dummy_manager_send_trap2(Pid) ->
dummy_manager_await_trap2_ack() ->
?DBG("dummy_manager_await_trap2 -> entry",[]),
receive
- {received_trap,Trap} ->
- ?LOG("dummy_manager_await_trap2 -> received trap: ~p",[Trap]),
+ {received_trap, _Trap} ->
+ ?LOG("dummy_manager_await_trap2 -> received trap: ~p", [_Trap]),
%% Note:
%% Without this sleep the v2_inform_i testcase failes! There
%% is no relation between these two test cases as far as I
%% able to figure out...
?SLEEP(60000),
ok;
- O ->
- ?ERR("dummy_manager_await_trap2 -> unexpected message: ~p",[O]),
+ _O ->
+ ?ERR("dummy_manager_await_trap2 -> unexpected message: ~p",[_O]),
ok
after 10000 ->
?ERR("dummy_manager_await_trap2 -> timeout",[]),
@@ -2155,32 +2181,34 @@ dummy_manager_loop(P,S,MA) ->
"~n Trap: ~p",[Trap]),
snmpa:send_trap(MA, Trap, "standard trap"),
dummy_manager_loop(P,S,MA);
- {udp, _UdpId, Ip, UdpPort, Bytes} ->
+ {udp, _UdpId, _Ip, _UdpPort, Bytes} ->
?LOG("dummy_manager_loop -> received upd message"
"~n from: ~p:~p"
"~n size: ~p",
- [Ip, UdpPort, dummy_manager_message_sz(Bytes)]),
+ [_Ip, _UdpPort, dummy_manager_message_sz(Bytes)]),
R = dummy_manager_handle_message(Bytes),
- ?DBG("dummy_manager_loop -> R: ~p",[R]),
+ ?DBG("dummy_manager_loop -> R: ~p", [R]),
P ! R,
- dummy_manager_loop(P,S,MA);
+ dummy_manager_loop(P, S, MA);
stop ->
?DBG("dummy_manager_loop -> received stop request",[]),
P ! {dummy_manager_stopping, self()},
gen_udp:close(S),
exit(normal);
- O ->
+ _O ->
?LOG("dummy_manager_loop -> received unknown message:"
- "~n ~p",[O]),
- dummy_manager_loop(P,S,MA)
+ "~n ~p", [_O]),
+ dummy_manager_loop(P, S, MA)
end.
+-ifdef(snmp_log).
dummy_manager_message_sz(B) when is_binary(B) ->
size(B);
dummy_manager_message_sz(L) when is_list(L) ->
length(L);
dummy_manager_message_sz(_) ->
undefined.
+-endif.
dummy_manager_handle_message(Bytes) ->
case (catch snmp_pdus:dec_message(Bytes)) of
@@ -3398,11 +3426,11 @@ simple_standard_test() ->
db_notify_client(suite) -> [];
db_notify_client(Config) when is_list(Config) ->
?P(db_notify_client),
- {SaNode, MgrNode, MibDir} = init_case(Config),
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
?DBG("db_notify_client -> case initiated: "
"~n SaNode: ~p"
"~n MgrNode: ~p"
- "~n MibDir: ~p", [SaNode, MgrNode, MibDir]),
+ "~n MibDir: ~p", [_SaNode, _MgrNode, _MibDir]),
?DBG("db_notify_client -> maximize verbosity", []),
snmpa_local_db:verbosity(trace),
Self = self(),
@@ -4153,8 +4181,8 @@ ma_v2_inform1(MA) ->
CmdExp =
fun(ok) ->
ok;
- ({ok, Val}) ->
- ?DBG("ma_v2_inform -> [cmd2] Val: ~p", [Val]),
+ ({ok, _Val}) ->
+ ?DBG("ma_v2_inform -> [cmd2] Val: ~p", [_Val]),
ok;
({error, Id, Extra}) ->
{error, {unexpected, Id, Extra}};
@@ -4189,10 +4217,10 @@ ma_v2_inform1(MA) ->
CmdSnmpTargets =
fun(T) ->
receive
- {snmp_targets, T, [Addr]} ->
+ {snmp_targets, T, [_Addr]} ->
?DBG("ma_v2_inform1 -> "
"received expected snmp_targets "
- "~n with receiver: ~p",[Addr]),
+ "~n with receiver: ~p", [_Addr]),
ok;
{snmp_targets, T, Addrs} ->
?ERR("ma_v2_inform1 -> "
@@ -4210,16 +4238,16 @@ ma_v2_inform1(MA) ->
Cmd06 =
fun() ->
receive
- {snmp_notification, Tag03, {got_response, Addr}} ->
+ {snmp_notification, Tag03, {got_response, _Addr}} ->
?DBG("ma_v2_inform1 -> "
"received expected snmp_notification "
- "[with manager response] from: ~n ~p",[Addr]),
+ "[with manager response] from: ~n ~p", [_Addr]),
ok;
- {snmp_notification, Tag03, {no_response, Addr}} ->
+ {snmp_notification, Tag03, {no_response, _Addr}} ->
?ERR("ma_v2_inform1 -> "
"received unexpected snmp_notification "
"[without manager response] from: ~n ~p",
- [Addr]),
+ [_Addr]),
{error, no_response}
after
20000 ->
@@ -4249,16 +4277,16 @@ ma_v2_inform1(MA) ->
Cmd10 =
fun() ->
receive
- {snmp_notification, Tag07, {got_response, Addr}} ->
+ {snmp_notification, Tag07, {got_response, _Addr}} ->
?ERR("ma_v2_inform1 -> "
"received unexpected snmp_notification "
- "[with manager response] from: ~n ~p", [Addr]),
+ "[with manager response] from: ~n ~p", [_Addr]),
{error, got_response};
- {snmp_notification, Tag07, {no_response, Addr}} ->
+ {snmp_notification, Tag07, {no_response, _Addr}} ->
?DBG("ma_v2_inform1 -> "
"received expected snmp_notification "
"[without manager response] from: ~n ~p",
- [Addr]),
+ [_Addr]),
ok
after
240000 ->
@@ -4302,8 +4330,8 @@ ma_v2_inform2(MA) ->
CmdExp =
fun(ok) ->
ok;
- ({ok, Val}) ->
- ?DBG("ma_v2_inform -> [cmd2] Val: ~p", [Val]),
+ ({ok, _Val}) ->
+ ?DBG("ma_v2_inform -> [cmd2] Val: ~p", [_Val]),
ok;
({error, Id, Extra}) ->
{error, {unexpected, Id, Extra}};
@@ -4383,8 +4411,8 @@ ma_v2_inform3(MA) ->
"~n send notification: testTrapv22", [MA]),
CmdExpectInform =
- fun(No, Response) ->
- ?DBG("CmdExpectInform -> ~p: ~n~p", [No, Response]),
+ fun(_No, Response) ->
+ ?DBG("CmdExpectInform -> ~p: ~n~p", [_No, Response]),
?expect2({inform, Response},
[{[sysUpTime, 0], any},
{[snmpTrapOID, 0], ?system ++ [0,1]}])
@@ -4393,8 +4421,8 @@ ma_v2_inform3(MA) ->
CmdExp =
fun(ok) ->
ok;
- ({ok, Val}) ->
- ?DBG("CmdExp -> Val: ~p", [Val]),
+ ({ok, _Val}) ->
+ ?DBG("CmdExp -> Val: ~p", [_Val]),
ok;
({error, Id, Extra}) ->
{error, {unexpected, Id, Extra}};
@@ -4505,17 +4533,17 @@ delivery_info(Tag, Address, DeliveryResult, Extra) ->
command_handler([]) ->
ok;
-command_handler([{No, Desc, Cmd}|Rest]) ->
- ?LOG("command_handler -> command ~w: ~n ~s", [No, Desc]),
+command_handler([{_No, _Desc, Cmd}|Rest]) ->
+ ?LOG("command_handler -> command ~w: ~n ~s", [_No, _Desc]),
case (catch Cmd()) of
ok ->
- ?LOG("command_handler -> ~w: ok",[No]),
+ ?LOG("command_handler -> ~w: ok", [_No]),
command_handler(Rest);
{error, Reason} ->
- ?ERR("command_handler -> ~w error: ~n~p",[No, Reason]),
+ ?ERR("command_handler -> ~w error: ~n~p", [_No, Reason]),
?line ?FAIL(Reason);
Error ->
- ?ERR("command_handler -> ~w unexpected: ~n~p",[No, Error]),
+ ?ERR("command_handler -> ~w unexpected: ~n~p", [_No, Error]),
?line ?FAIL({unexpected_command_result, Error})
end.
@@ -5516,57 +5544,59 @@ usm_bad() ->
%% works.
%% Load all std mibs that are not loaded by default.
%%-----------------------------------------------------------------
-loop_mib(suite) -> [];
-loop_mib(Config) when is_list(Config) ->
- ?P(loop_mib),
- ?LOG("loop_mib -> initiate case",[]),
+loop_mib_1(suite) -> [];
+loop_mib_1(Config) when is_list(Config) ->
+ ?P(loop_mib_1),
+ ?LOG("loop_mib_1 -> initiate case",[]),
%% snmpa:verbosity(master_agent,debug),
%% snmpa:verbosity(mib_server,info),
- {SaNode, MgrNode, MibDir} = init_case(Config),
- ?DBG("loop_mib -> ~n"
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+ ?DBG("loop_mib_1 -> ~n"
"\tSaNode: ~p~n"
"\tMgrNode: ~p~n"
- "\tMibDir: ~p",[SaNode, MgrNode, MibDir]),
- ?DBG("loop_mib -> load mib SNMP-COMMUNITY-MIB",[]),
+ "\tMibDir: ~p", [_SaNode, _MgrNode, _MibDir]),
+ ?DBG("loop_mib_1 -> load mib SNMP-COMMUNITY-MIB",[]),
?line load_master_std("SNMP-COMMUNITY-MIB"),
- ?DBG("loop_mib -> load mib SNMP-MPD-MIB",[]),
+ ?DBG("loop_mib_1 -> load mib SNMP-MPD-MIB",[]),
?line load_master_std("SNMP-MPD-MIB"),
- ?DBG("loop_mib -> load mib SNMP-TARGET-MIB",[]),
+ ?DBG("loop_mib_1 -> load mib SNMP-TARGET-MIB",[]),
?line load_master_std("SNMP-TARGET-MIB"),
- ?DBG("loop_mib -> load mib SNMP-NOTIFICATION-MIB",[]),
+ ?DBG("loop_mib_1 -> load mib SNMP-NOTIFICATION-MIB",[]),
?line load_master_std("SNMP-NOTIFICATION-MIB"),
- ?DBG("loop_mib -> load mib SNMP-FRAMEWORK-MIB",[]),
+ ?DBG("loop_mib_1 -> load mib SNMP-FRAMEWORK-MIB",[]),
?line load_master_std("SNMP-FRAMEWORK-MIB"),
- ?DBG("loop_mib -> load mib SNMP-VIEW-BASED-ACM-MIB",[]),
+ ?DBG("loop_mib_1 -> load mib SNMP-VIEW-BASED-ACM-MIB",[]),
?line load_master_std("SNMP-VIEW-BASED-ACM-MIB"),
- ?DBG("loop_mib -> try",[]),
- try_test(loop_mib_1),
- ?DBG("loop_mib -> unload mib SNMP-COMMUNITY-MIB",[]),
+ ?DBG("loop_mib_1 -> try",[]),
+
+ try_test(loop_mib_1_test),
+
+ ?DBG("loop_mib_1 -> unload mib SNMP-COMMUNITY-MIB",[]),
?line unload_master("SNMP-COMMUNITY-MIB"),
- ?DBG("loop_mib -> unload mib SNMP-MPD-MIB",[]),
+ ?DBG("loop_mib_1 -> unload mib SNMP-MPD-MIB",[]),
?line unload_master("SNMP-MPD-MIB"),
- ?DBG("loop_mib -> unload mib SNMP-TARGET-MIB",[]),
+ ?DBG("loop_mib_1 -> unload mib SNMP-TARGET-MIB",[]),
?line unload_master("SNMP-TARGET-MIB"),
- ?DBG("loop_mib -> unload mib SNMP-NOTIFICATION-MIB",[]),
+ ?DBG("loop_mib_1 -> unload mib SNMP-NOTIFICATION-MIB",[]),
?line unload_master("SNMP-NOTIFICATION-MIB"),
- ?DBG("loop_mib -> unload mib SNMP-FRAMEWORK-MIB",[]),
+ ?DBG("loop_mib_1 -> unload mib SNMP-FRAMEWORK-MIB",[]),
?line unload_master("SNMP-FRAMEWORK-MIB"),
- ?DBG("loop_mib -> unload mib SNMP-VIEW-BASED-ACM-MIB",[]),
+ ?DBG("loop_mib_1 -> unload mib SNMP-VIEW-BASED-ACM-MIB",[]),
?line unload_master("SNMP-VIEW-BASED-ACM-MIB"),
%% snmpa:verbosity(master_agent,log),
%% snmpa:verbosity(mib_server,silence),
- ?LOG("loop_mib -> done",[]).
+ ?LOG("loop_mib_1 -> done",[]).
loop_mib_2(suite) -> [];
loop_mib_2(Config) when is_list(Config) ->
?P(loop_mib_2),
?LOG("loop_mib_2 -> initiate case",[]),
- {SaNode, MgrNode, MibDir} = init_case(Config),
- ?DBG("loop_mib_2 -> ~n"
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+ ?DBG("do_loop_mib_2 -> ~n"
"\tSaNode: ~p~n"
"\tMgrNode: ~p~n"
- "\tMibDir: ~p",[SaNode, MgrNode, MibDir]),
+ "\tMibDir: ~p", [_SaNode, _MgrNode, _MibDir]),
?DBG("loop_mib_2 -> load mibs",[]),
?line load_master_std("SNMP-COMMUNITY-MIB"),
?line load_master_std("SNMP-MPD-MIB"),
@@ -5574,7 +5604,9 @@ loop_mib_2(Config) when is_list(Config) ->
?line load_master_std("SNMP-NOTIFICATION-MIB"),
?line load_master_std("SNMP-FRAMEWORK-MIB"),
?line load_master_std("SNMP-VIEW-BASED-ACM-MIB"),
- try_test(loop_mib_2),
+
+ try_test(loop_mib_2_test),
+
?DBG("loop_mib_2 -> unload mibs",[]),
?line unload_master("SNMP-COMMUNITY-MIB"),
?line unload_master("SNMP-MPD-MIB"),
@@ -5589,18 +5621,18 @@ loop_mib_3(suite) -> [];
loop_mib_3(Config) when is_list(Config) ->
?P(loop_mib_3),
?LOG("loop_mib_3 -> initiate case",[]),
- {SaNode, MgrNode, MibDir} = init_case(Config),
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
?DBG("loop_mib_3 -> ~n"
"\tSaNode: ~p~n"
"\tMgrNode: ~p~n"
- "\tMibDir: ~p",[SaNode, MgrNode, MibDir]),
+ "\tMibDir: ~p", [_SaNode, _MgrNode, _MibDir]),
?DBG("loop_mib_3 -> load mibs",[]),
?line load_master_std("SNMP-TARGET-MIB"),
?line load_master_std("SNMP-NOTIFICATION-MIB"),
?line load_master_std("SNMP-VIEW-BASED-ACM-MIB"),
?line load_master_std("SNMP-USER-BASED-SM-MIB"),
- try_test(loop_mib_2),
+ try_test(loop_mib_3_test),
?DBG("loop_mib_3 -> unload mibs",[]),
?line unload_master("SNMP-TARGET-MIB"),
@@ -5611,17 +5643,16 @@ loop_mib_3(Config) when is_list(Config) ->
%% Req. As many mibs all possible
-loop_mib_1() ->
- ?DBG("loop_mib_1 -> entry",[]),
+loop_mib_1_test() ->
+ ?DBG("loop_mib_1_test -> entry",[]),
N = loop_it_1([1,1], 0),
io:format(user, "found ~w varibles\n", [N]),
?line N = if N < 100 -> 100;
true -> N
end.
-
loop_it_1(Oid, N) ->
- ?DBG("loop_it_1 -> entry with~n"
+ ?DBG("loop_it_1_test -> entry with~n"
"\tOid: ~p~n"
"\tN: ~p",[Oid,N]),
case get_next_req([Oid]) of
@@ -5629,13 +5660,13 @@ loop_it_1(Oid, N) ->
error_status = noError,
error_index = 0,
varbinds = [#varbind{oid = NOid,
- value = Value}]} when NOid > Oid ->
- ?DBG("loop_it_1 -> "
+ value = _Value}]} when NOid > Oid ->
+ ?DBG("loop_it_1_test -> "
"~n NOid: ~p"
- "~n Value: ~p",[NOid, Value]),
- ?line [Value2] = get_req(1, [NOid]), % must not be same
- ?DBG("loop_it_1 -> "
- "~n Value2: ~p",[Value2]),
+ "~n Value: ~p", [NOid, _Value]),
+ ?line [_Value2] = get_req(1, [NOid]), % must not be same
+ ?DBG("loop_it_1_test -> "
+ "~n Value2: ~p", [_Value2]),
loop_it_1(NOid, N+1);
#pdu{type = 'get-response',
@@ -5648,7 +5679,7 @@ loop_it_1(Oid, N) ->
error_status = noSuchName,
error_index = 1,
varbinds = [_]} ->
- ?DBG("loop_it_1 -> done: ~p",[N]),
+ ?DBG("loop_it_1_test -> done: ~p",[N]),
N;
#pdu{type = 'get-response',
@@ -5669,14 +5700,13 @@ loop_it_1(Oid, N) ->
%% Req. As many mibs all possible
-loop_mib_2() ->
- ?DBG("loop_mib_1 -> entry",[]),
+loop_mib_2_test() ->
+ ?DBG("loop_mib_2_test -> entry",[]),
N = loop_it_2([1,1], 0),
io:format(user, "found ~w varibles\n", [N]),
?line N = if N < 100 -> 100;
true -> N
end.
-
loop_it_2(Oid, N) ->
?DBG("loop_it_2 -> entry with"
@@ -5686,22 +5716,22 @@ loop_it_2(Oid, N) ->
#pdu{type = 'get-response',
error_status = noError,
error_index = 0,
- varbinds = [#varbind{oid = NOid, value = endOfMibView}]} ->
+ varbinds = [#varbind{oid = _NOid, value = endOfMibView}]} ->
?DBG("loop_it_2 -> "
- "~n NOid: ~p",[NOid]),
+ "~n NOid: ~p", [_NOid]),
N;
#pdu{type = 'get-response',
error_status = noError,
error_index = 0,
varbinds = [#varbind{oid = NOid,
- value = Value}]} when NOid > Oid ->
+ value = _Value}]} when NOid > Oid ->
?DBG("loop_it_2 -> "
"~n NOid: ~p"
- "~n Value: ~p",[NOid, Value]),
- ?line [Value2] = get_req(1, [NOid]), % must not be same
+ "~n Value: ~p", [NOid, _Value]),
+ ?line [_Value2] = get_req(1, [NOid]), % must not be same
?DBG("loop_it_2 -> "
- "~n Value2: ~p",[Value2]),
+ "~n Value2: ~p", [_Value2]),
loop_it_2(NOid, N+1);
#pdu{type = 'get-response',
@@ -5744,6 +5774,10 @@ loop_it_2(Oid, N) ->
end.
+loop_mib_3_test() ->
+ ?DBG("loop_mib_3_test -> entry",[]),
+ loop_mib_2_test().
+
%%%-----------------------------------------------------------------
%%% Testing of reported bugs and other tickets.
@@ -6611,16 +6645,16 @@ otp8395(Config) when is_list(Config) ->
AgentNode = ?config(agent_node, Config),
AgentLogDir = ?config(agent_log_dir, Config),
OutFile = join([AgentLogDir, "otp8395.txt"]),
- {ok, LogInfo} = rpc:call(AgentNode, snmpa, log_info, []),
- ?DBG("otp8395 -> LogInfo: ~p", [LogInfo]),
+ {ok, _LogInfo} = rpc:call(AgentNode, snmpa, log_info, []),
+ ?DBG("otp8395 -> LogInfo: ~p", [_LogInfo]),
%% SyncRes = rpc:call(AgentNode, snmp, log_sync, [?audit_trail_log_name]),
%% ?DBG("otp8395 -> SyncRes: ~p", [SyncRes]),
ok = agent_log_validation(AgentNode),
- LTTRes =
+ _LTTRes =
rpc:call(AgentNode, snmpa, log_to_txt, [AgentLogDir, [], OutFile]),
- ?DBG("otp8395 -> LTTRes: ~p", [LTTRes]),
+ ?DBG("otp8395 -> LTTRes: ~p", [_LTTRes]),
?SLEEP(1000),
?DBG("otp8395 -> done", []),
@@ -6941,10 +6975,10 @@ stop_stdalone_agent(Pid) when (node(Pid) =/= node()) ->
MRef = erlang:monitor(process, Pid),
rpc:call(node(Pid), ?MODULE, stop_stdalone_agent, [Pid]),
receive
- {'DOWN', MRef, process, Pid, Info} ->
+ {'DOWN', MRef, process, Pid, _Info} ->
?DBG("received expected DOWN message "
"regarding snmp agent supervisor: "
- "~n Info: ~p", [Info]),
+ "~n Info: ~p", [_Info]),
ok
after 5000 ->
?DBG("no DOWN message "
@@ -7003,9 +7037,9 @@ do_info(MaNode) ->
tree_size_bytes,
db_memory]}],
verify_info(Info, Keys),
- OldInfo = snmpa:old_info_format(Info),
- ?DBG("info_test1 -> OldInfo: ~n~p", [OldInfo]),
- verify_old_info(OldInfo),
+ %% OldInfo = snmpa:old_info_format(Info),
+ %% ?DBG("info_test1 -> OldInfo: ~n~p", [OldInfo]),
+ %% verify_old_info(OldInfo),
ok.
verify_info([], []) ->
@@ -7048,20 +7082,20 @@ verify_subinfo(Info0, [Key|Keys]) ->
verify_subinfo(Info, Keys)
end.
-verify_old_info(Info) ->
- Keys = [vsns, subagents, loaded_mibs,
- tree_size_bytes, process_memory, db_memory],
- verify_old_info(Keys, Info).
-
-verify_old_info([], _) ->
- ok;
-verify_old_info([Key|Keys], Info) ->
- case lists:keymember(Key, 1, Info) of
- true ->
- verify_old_info(Keys, Info);
- false ->
- ?FAIL({missing_old_info, Key})
- end.
+%% verify_old_info(Info) ->
+%% Keys = [vsns, subagents, loaded_mibs,
+%% tree_size_bytes, process_memory, db_memory],
+%% verify_old_info(Keys, Info).
+
+%% verify_old_info([], _) ->
+%% ok;
+%% verify_old_info([Key|Keys], Info) ->
+%% case lists:keymember(Key, 1, Info) of
+%% true ->
+%% verify_old_info(Keys, Info);
+%% false ->
+%% ?FAIL({missing_old_info, Key})
+%% end.
%% Index String - string used in index
is(S) -> [length(S) | S].
diff --git a/lib/snmp/test/snmp_agent_test_lib.erl b/lib/snmp/test/snmp_agent_test_lib.erl
index 122289c28e..d7109253f7 100644
--- a/lib/snmp/test/snmp_agent_test_lib.erl
+++ b/lib/snmp/test/snmp_agent_test_lib.erl
@@ -299,10 +299,10 @@ call(N,M,F,A) ->
"~n Loc: ~p", [Rn, Loc]),
put(test_server_loc, Loc),
exit(Rn);
- {done, Ret, Zed} ->
+ {done, Ret, _Zed} ->
?DBG("call -> done:"
"~n Ret: ~p"
- "~n Zed: ~p", [Ret, Zed]),
+ "~n Zed: ~p", [Ret, _Zed]),
case Ret of
{error, Reason} ->
exit(Reason);
@@ -338,8 +338,8 @@ run(Mod, Func, Args, Opts) ->
CtxEngineID = snmp_misc:get_option(context_engine_id, Opts, EngineID),
Community = snmp_misc:get_option(community, Opts, "all-rights"),
?DBG("run -> start crypto app",[]),
- Crypto = ?CRYPTO_START(),
- ?DBG("run -> Crypto: ~p", [Crypto]),
+ _CryptoRes = ?CRYPTO_START(),
+ ?DBG("run -> Crypto: ~p", [_CryptoRes]),
catch snmp_test_mgr:stop(), % If we had a running mgr from a failed case
StdM = join(code:priv_dir(snmp), "mibs") ++ "/",
Vsn = get(vsn),
@@ -676,9 +676,9 @@ stop_agent(Config) when is_list(Config) ->
(catch process_info(Sup)),
(catch process_info(Par))]),
- Info = agent_info(Sup),
+ _Info = agent_info(Sup),
?DBG("stop_agent -> Agent info: "
- "~n ~p", [Info]),
+ "~n ~p", [_Info]),
stop_sup(Sup, Par),
@@ -1303,10 +1303,10 @@ get_req(Id, Vars) ->
{ok, Val} ->
?DBG("get_req -> response: ~p",[Val]),
Val;
- {error, _, {ExpFmt, ExpArg}, {ActFmt, ActArg}} ->
+ {error, _, {_ExpFmt, ExpArg}, {_ActFmt, ActArg}} ->
?DBG("get_req -> error for ~p: "
- "~n " ++ ExpFmt ++
- "~n " ++ ActFmt,
+ "~n " ++ _ExpFmt ++
+ "~n " ++ _ActFmt,
[Id] ++ ExpArg ++ ActArg),
exit({unexpected_response, ExpArg, ActArg});
Error ->
@@ -1527,9 +1527,9 @@ rewrite_target_addr_conf(Dir, NewPort) ->
case file:read_file_info(TAFile) of
{ok, _} ->
ok;
- {error, R} ->
+ {error, _R} ->
?ERR("failure reading file info of "
- "target address config file: ~p",[R]),
+ "target address config file: ~p", [_R]),
ok
end,
diff --git a/lib/snmp/test/snmp_manager_test.erl b/lib/snmp/test/snmp_manager_test.erl
index 5fe18980bc..3a654a2805 100644
--- a/lib/snmp/test/snmp_manager_test.erl
+++ b/lib/snmp/test/snmp_manager_test.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2003-2013. All Rights Reserved.
+%% Copyright Ericsson AB 2003-2014. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -139,6 +139,8 @@
-define(NS_TIMEOUT, 10000).
+-define(DEFAULT_MNESIA_DEBUG, none).
+
%%----------------------------------------------------------------------
%% Records
@@ -173,7 +175,9 @@ end_per_suite(Config) when is_list(Config) ->
init_per_testcase(Case, Config) when is_list(Config) ->
- io:format(user, "~n~n*** INIT ~w:~w ***~n~n", [?MODULE,Case]),
+ io:format(user, "~n~n*** INIT ~w:~w ***~n~n", [?MODULE, Case]),
+ p(Case, "init_per_testcase begin when"
+ "~n Nodes: ~p~n~n", [erlang:nodes()]),
%% This version of the API, based on Addr and Port, has been deprecated
DeprecatedApiCases =
[
@@ -187,16 +191,25 @@ init_per_testcase(Case, Config) when is_list(Config) ->
simple_async_get_bulk1,
misc_async1
],
- case lists:member(Case, DeprecatedApiCases) of
- true ->
- %% ?SKIP(api_no_longer_supported);
- {skip, api_no_longer_supported};
- false ->
- init_per_testcase2(Case, Config)
- end.
+ Result =
+ case lists:member(Case, DeprecatedApiCases) of
+ true ->
+ %% ?SKIP(api_no_longer_supported);
+ {skip, api_no_longer_supported};
+ false ->
+ init_per_testcase2(Case, Config)
+ end,
+ p(Case, "init_per_testcase end when"
+ "~n Nodes: ~p"
+ "~n Result: ~p"
+ "~n~n", [Result, erlang:nodes()]),
+ Result.
init_per_testcase2(Case, Config) ->
- ?DBG("init_per_testcase2 -> ~p", [erlang:nodes()]),
+ ?DBG("init_per_testcase2 -> "
+ "~n Case: ~p"
+ "~n Config: ~p"
+ "~n Nodes: ~p", [Case, Config, erlang:nodes()]),
CaseTopDir = snmp_test_lib:init_testcase_top_dir(Case, Config),
@@ -314,6 +327,8 @@ init_per_testcase3(Case, Config) ->
end.
end_per_testcase(Case, Config) when is_list(Config) ->
+ p(Case, "end_per_testcase begin when"
+ "~n Nodes: ~p~n~n", [erlang:nodes()]),
?DBG("fin [~w] Nodes [1]: ~p", [Case, erlang:nodes()]),
Dog = ?config(watchdog, Config),
?WD_STOP(Dog),
@@ -322,6 +337,8 @@ end_per_testcase(Case, Config) when is_list(Config) ->
?DBG("fin [~w] Nodes [2]: ~p", [Case, erlang:nodes()]),
%% TopDir = ?config(top_dir, Conf2),
%% ?DEL_DIR(TopDir),
+ p(Case, "end_per_testcase end when"
+ "~n Nodes: ~p~n~n", [erlang:nodes()]),
Conf2.
end_per_testcase2(Case, Config) ->
@@ -428,10 +445,10 @@ groups() ->
{request_tests, [],
[
{group, get_tests},
- {group, get_next_tests},
+ {group, get_next_tests},
{group, set_tests},
- {group, bulk_tests},
- {group, misc_request_tests}
+ {group, bulk_tests},
+ {group, misc_request_tests}
]
},
{request_tests_mt, [],
@@ -5303,34 +5320,59 @@ init_manager(AutoInform, Config) ->
?line Node = start_manager_node(),
+ %% The point with this (try catch block) is to be
+ %% able to do some cleanup in case we fail to
+ %% start some of the apps. That is, if we fail to
+ %% start the apps (mnesia, crypto and snmp agent)
+ %% we stop the (agent) node!
- %% --
- %% Start and initiate crypto on manager node
- %%
-
- ?line ok = init_crypto(Node),
+ try
+ begin
- %%
- %% Write manager config
- %%
+ %% --
+ %% Start and initiate crypto on manager node
+ %%
+
+ ?line ok = init_crypto(Node),
+
+ %%
+ %% Write manager config
+ %%
+
+ ?line ok = write_manager_config(Config),
+
+ IRB = case AutoInform of
+ true ->
+ auto;
+ _ ->
+ user
+ end,
+ Conf = [{manager_node, Node}, {irb, IRB} | Config],
+ Vsns = [v1,v2,v3],
+ start_manager(Node, Vsns, Conf)
+ end
+ catch
+ T:E ->
+ StackTrace = ?STACK(),
+ p("Failure during manager start: "
+ "~n Error Type: ~p"
+ "~n Error: ~p"
+ "~n StackTrace: ~p", [T, E, StackTrace]),
+ %% And now, *try* to cleanup
+ (catch stop_node(Node)),
+ ?FAIL({failed_starting_manager, T, E, StackTrace})
+ end.
- ?line ok = write_manager_config(Config),
-
- IRB = case AutoInform of
- true ->
- auto;
- _ ->
- user
- end,
- Conf = [{manager_node, Node}, {irb, IRB} | Config],
- Vsns = [v1,v2,v3],
- start_manager(Node, Vsns, Conf).
-
fin_manager(Config) ->
Node = ?config(manager_node, Config),
- stop_manager(Node, Config),
- fin_crypto(Node),
- stop_node(Node),
+ StopMgrRes = stop_manager(Node),
+ StopCryptoRes = fin_crypto(Node),
+ StopNode = stop_node(Node),
+ p("fin_agent -> stop apps and (mgr node ~p) node results: "
+ "~n SNMP Mgr: ~p"
+ "~n Crypto: ~p"
+ "~n Node: ~p",
+ [Node, StopMgrRes, StopCryptoRes, StopNode]),
Config.
@@ -5352,52 +5394,93 @@ init_agent(Config) ->
?line Node = start_agent_node(),
+ %% The point with this (try catch block) is to be
+ %% able to do some cleanup in case we fail to
+ %% start some of the apps. That is, if we fail to
+ %% start the apps (mnesia, crypto and snmp agent)
+ %% we stop the (agent) node!
- %% --
- %% Start and initiate mnesia on agent node
- %%
-
- ?line ok = init_mnesia(Node, Dir),
-
-
- %% --
- %% Start and initiate crypto on agent node
- %%
-
- ?line ok = init_crypto(Node),
-
-
- %%
- %% Write agent config
- %%
-
- Vsns = [v1,v2],
- ?line ok = write_agent_config(Vsns, Config),
-
- Conf = [{agent_node, Node},
- {mib_dir, MibDir} | Config],
+ try
+ begin
+
+ %% --
+ %% Start and initiate mnesia on agent node
+ %%
+
+ ?line ok = init_mnesia(Node, Dir, ?config(mnesia_debug, Config)),
+
+
+ %% --
+ %% Start and initiate crypto on agent node
+ %%
+
+ ?line ok = init_crypto(Node),
+
+
+ %%
+ %% Write agent config
+ %%
+
+ Vsns = [v1,v2],
+ ?line ok = write_agent_config(Vsns, Config),
+
+ Conf = [{agent_node, Node},
+ {mib_dir, MibDir} | Config],
- %%
- %% Start the agent
- %%
-
- start_agent(Node, Vsns, Conf).
+ %%
+ %% Start the agent
+ %%
+
+ start_agent(Node, Vsns, Conf)
+ end
+ catch
+ T:E ->
+ StackTrace = ?STACK(),
+ p("Failure during agent start: "
+ "~n Error Type: ~p"
+ "~n Error: ~p"
+ "~n StackTrace: ~p", [T, E, StackTrace]),
+ %% And now, *try* to cleanup
+ (catch stop_node(Node)),
+ ?FAIL({failed_starting_agent, T, E, StackTrace})
+ end.
+
fin_agent(Config) ->
Node = ?config(agent_node, Config),
- stop_agent(Node, Config),
- fin_crypto(Node),
- fin_mnesia(Node),
- stop_node(Node),
+ StopAgentRes = stop_agent(Node),
+ StopCryptoRes = fin_crypto(Node),
+ StopMnesiaRes = fin_mnesia(Node),
+ StopNode = stop_node(Node),
+ p("fin_agent -> stop apps and (agent node ~p) node results: "
+ "~n SNMP Agent: ~p"
+ "~n Crypto: ~p"
+ "~n Mnesia: ~p"
+ "~n Node: ~p",
+ [Node, StopAgentRes, StopCryptoRes, StopMnesiaRes, StopNode]),
Config.
-init_mnesia(Node, Dir) ->
+init_mnesia(Node, Dir, MnesiaDebug)
+ when ((MnesiaDebug =/= none) andalso
+ (MnesiaDebug =/= debug) andalso (MnesiaDebug =/= trace)) ->
+ init_mnesia(Node, Dir, ?DEFAULT_MNESIA_DEBUG);
+init_mnesia(Node, Dir, MnesiaDebug) ->
?DBG("init_mnesia -> load application mnesia", []),
?line ok = load_mnesia(Node),
?DBG("init_mnesia -> application mnesia: set_env dir: ~n~p",[Dir]),
?line ok = set_mnesia_env(Node, dir, filename:join(Dir, "mnesia")),
+ %% Just in case, only set (known to be) valid values for debug
+ if
+ ((MnesiaDebug =:= debug) orelse (MnesiaDebug =:= trace)) ->
+ ?DBG("init_mnesia -> application mnesia: set_env debug: ~w",
+ [MnesiaDebug]),
+ ?line ok = set_mnesia_env(Node, debug, MnesiaDebug);
+ true ->
+ ok
+ end,
+
?DBG("init_mnesia -> create mnesia schema",[]),
?line case create_schema(Node) of
ok ->
@@ -5434,25 +5517,89 @@ fin_crypto(Node) ->
%% -- Misc application wrapper functions --
-load_app(Node, App) when (Node =:= node()) andalso is_atom(App) ->
- application:load(App);
-load_app(Node, App) when is_atom(App) ->
- rcall(Node, application, load, [App]).
-
-start_app(Node, App) when (Node =:= node()) andalso is_atom(App) ->
- application:start(App);
+load_app(Node, App) ->
+ VerifySuccess = fun(ok) ->
+ ok;
+ ({error, {already_loaded, LoadedApp}}) when (LoadedApp =:= App) ->
+ ok;
+ ({error, Reason}) ->
+ p("failed loading app ~w on ~p: "
+ "~n ~p", [App, Node, Reason]),
+ ?FAIL({failed_load, Node, App, Reason})
+ end,
+ do_load_app(Node, App, VerifySuccess).
+
+do_load_app(Node, App, VerifySuccess)
+ when (Node =:= node()) andalso is_atom(App) ->
+ %% Local app
+ exec(fun() -> application:load(App) end, VerifySuccess);
+do_load_app(Node, App, VerifySuccess) ->
+ %% Remote app
+ exec(fun() -> rcall(Node, application, load, [App]) end, VerifySuccess).
+
+
start_app(Node, App) ->
- rcall(Node, application, start, [App]).
+ VerifySuccess = fun(ok) ->
+ ok;
+ ({error, {already_started, LoadedApp}}) when (LoadedApp =:= App) ->
+ ok;
+ ({error, Reason}) ->
+ p("failed starting app ~w on ~p: "
+ "~n ~p", [App, Node, Reason]),
+ ?FAIL({failed_start, Node, App, Reason})
+ end,
+ start_app(Node, App, VerifySuccess).
+
+start_app(Node, App, VerifySuccess)
+ when (Node =:= node()) andalso is_atom(App) ->
+ exec(fun() -> application:start(App) end, VerifySuccess);
+start_app(Node, App, VerifySuccess) ->
+ exec(fun() -> rcall(Node, application, start, [App]) end, VerifySuccess).
+
+
+stop_app(Node, App) ->
+ VerifySuccess = fun(ok) ->
+ ok;
+ ({error, {not_started, LoadedApp}}) when (LoadedApp =:= App) ->
+ ok;
+ ({error, Reason}) ->
+ p("failed stopping app ~w on ~p: "
+ "~n ~p", [App, Node, Reason]),
+ ?FAIL({failed_stop, Node, App, Reason})
+ end,
+ stop_app(Node, App, VerifySuccess).
+
+stop_app(Node, App, VerifySuccess)
+ when (Node =:= node()) andalso is_atom(App) ->
+ exec(fun() -> application:stop(App) end, VerifySuccess);
+stop_app(Node, App, VerifySuccess) when is_atom(App) ->
+ exec(fun() -> rcall(Node, application, stop, [App]) end, VerifySuccess).
+
+
+set_app_env(Node, App, Key, Val) ->
+ VerifySuccess = fun(ok) ->
+ ok;
+ ({error, Reason}) ->
+ p("failed setting app ~w env on ~p"
+ "~n Key: ~p"
+ "~n Val: ~p"
+ "~n Reason: ~p"
+ "~n ~p", [App, Node, Key, Val, Reason]),
+ ?FAIL({failed_set_app_env,
+ Node, App, Key, Val, Reason})
+ end,
+ set_app_env(Node, App, Key, Val, VerifySuccess).
-stop_app(Node, App) when (Node =:= node()) andalso is_atom(App) ->
- application:stop(App);
-stop_app(Node, App) when is_atom(App) ->
- rcall(Node, application, stop, [App]).
+set_app_env(Node, App, Key, Val, VerifySuccess)
+ when (Node =:= node()) andalso is_atom(App) ->
+ exec(fun() -> application:set_env(App, Key, Val) end, VerifySuccess);
+set_app_env(Node, App, Key, Val, VerifySuccess) when is_atom(App) ->
+ exec(fun() -> rcall(Node, application, set_env, [App, Key, Val]) end,
+ VerifySuccess).
-set_app_env(Node, App, Key, Val) when (Node =:= node()) andalso is_atom(App) ->
- application:set_env(App, Key, Val);
-set_app_env(Node, App, Key, Val) when is_atom(App) ->
- rcall(Node, application, set_env, [App, Key, Val]).
+
+exec(Cmd, VerifySuccess) ->
+ VerifySuccess(Cmd()).
%% -- Misc snmp wrapper functions --
@@ -5900,9 +6047,9 @@ start_manager(Node, Vsns, Conf0, _Opts) ->
Conf0.
-stop_manager(Node, Conf) ->
- stop_snmp(Node),
- Conf.
+stop_manager(Node) ->
+ stop_snmp(Node).
+
%% -- Misc agent wrapper functions --
@@ -5951,9 +6098,8 @@ start_agent(Node, Vsns, Conf0, _Opts) ->
?line ok = start_snmp(Node),
Conf0.
-stop_agent(Node, Conf) ->
- stop_snmp(Node),
- Conf.
+stop_agent(Node) ->
+ stop_snmp(Node).
agent_load_mib(Node, Mib) ->
rcall(Node, snmpa, load_mibs, [[Mib]]).
@@ -6015,17 +6161,18 @@ stop_node(Node) ->
rpc:cast(Node, erlang, halt, []),
await_stopped(Node, 5).
-await_stopped(_, 0) ->
+await_stopped(Node, 0) ->
+ p("await_stopped -> ~p still exist: giving up", [Node]),
ok;
await_stopped(Node, N) ->
Nodes = erlang:nodes(),
case lists:member(Node, Nodes) of
true ->
- ?DBG("[~w] ~p still exist", [N, Node]),
+ p("await_stopped -> ~p still exist: ~w", [Node, N]),
?SLEEP(1000),
await_stopped(Node, N-1);
false ->
- ?DBG("[~w] ~p gone", [N, Node]),
+ p("await_stopped -> ~p gone: ~w", [Node, N]),
ok
end.
@@ -6271,7 +6418,7 @@ p(F, A) ->
p(TName, F, A) ->
io:format("*** [~w][~s] ***"
- "~n" ++ F ++ "~n", [TName, formated_timestamp()|A]).
+ "~n " ++ F ++ "~n", [TName, formated_timestamp()|A]).
formated_timestamp() ->
snmp_test_lib:formated_timestamp().
diff --git a/lib/snmp/test/snmp_test_mgr.erl b/lib/snmp/test/snmp_test_mgr.erl
index 40fcbce8f1..d4eb00ff91 100644
--- a/lib/snmp/test/snmp_test_mgr.erl
+++ b/lib/snmp/test/snmp_test_mgr.erl
@@ -657,7 +657,8 @@ make_vb(Oid) ->
#varbind{oid = Oid, variabletype = 'NULL', value = 'NULL'}.
make_request_id() ->
- random:uniform(16#FFFFFFF-1).
+ %% random:uniform(16#FFFFFFF-1).
+ snmp_test_mgr_counter_server:increment(mgr_request_id, 1, 1, 2147483647).
echo_pdu(PDU, MiniMIB) ->
io:format("~s", [snmp_misc:format_pdu(PDU, MiniMIB)]).
diff --git a/lib/snmp/test/snmp_test_mgr_counter_server.erl b/lib/snmp/test/snmp_test_mgr_counter_server.erl
new file mode 100644
index 0000000000..db31e0380b
--- /dev/null
+++ b/lib/snmp/test/snmp_test_mgr_counter_server.erl
@@ -0,0 +1,152 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2014-2014. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% 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%
+%%
+
+%%
+%% The reason for this (test) counter server is that the
+%% agent test suite is implemented in such a way that the
+%% agent is started once and then used for several test cases.
+%% Each request is given a request id which *was* generated using
+%% random! It is therefor possible, although unlikely, that a
+%% request may get a request id that has recently been used,
+%% which will cause the agent to silently reject the request.
+%% For this reason, we start this server at the start of the
+%% agent suite and stop it at the end and all request ids are
+%% generated by this server.
+%%
+
+-module(snmp_test_mgr_counter_server).
+
+-export([start/0, stop/0, increment/4]).
+
+-define(SERVER, ?MODULE).
+-define(TAB, snmp_test_mgr_counter_tab).
+
+
+%%%-------------------------------------------------------------------
+%%% API
+%%%-------------------------------------------------------------------
+
+-spec start() -> ok.
+
+start() ->
+ Parent = self(),
+ ReqIdServer = spawn(fun() -> init(Parent) end),
+ receive
+ {ReqIdServer, ok} ->
+ ok;
+ {ReqIdServer, {error, Reason}} ->
+ exit({failed_starting_counter_server, Reason})
+ after 5000 ->
+ exit(ReqIdServer, kill), % Cleanup, just in case
+ exit({failed_starting_counter_server, timeout})
+ end.
+
+-spec stop() -> {ok, Counters :: list()} | {error, Reason :: term()}.
+
+stop() ->
+ request(stop).
+
+
+-spec increment(Counter :: atom(),
+ Initial :: non_neg_integer(),
+ Increment :: pos_integer(),
+ Max :: pos_integer()) ->
+ Next :: pos_integer().
+
+increment(Counter, Initial, Increment, Max) ->
+ Request = {increment, Counter, Initial, Increment, Max},
+ case request(Request) of
+ {ok, ReqId} ->
+ ReqId;
+ {error, Reason} ->
+ exit(Reason)
+ end.
+
+
+request(Request) ->
+ Id = make_ref(),
+ Msg = {self(), Id, Request},
+ try
+ begin
+ global:send(?SERVER, Msg),
+ receive
+ {reply, Id, Reply} ->
+ {ok, Reply}
+ end
+ end
+ catch
+ T:E ->
+ {error, {T, E}}
+ end.
+
+
+%%%-------------------------------------------------------------------
+%%% Internal functions
+%%%-------------------------------------------------------------------
+
+init(Parent) ->
+ p("starting"),
+ case global:register_name(?SERVER, self()) of
+ yes ->
+ p("name registration ok"),
+ Parent ! {self(), ok};
+ no ->
+ p("name registration failed"),
+ Parent ! {self(), registration_failed},
+ exit(registration_failed)
+ end,
+ ets:new(?TAB, [set, named_table, {keypos, 1}]),
+ loop().
+
+loop() ->
+ receive
+ {From, Id, {increment, Counter, Initial, Increment, Max}} ->
+ Position = 2,
+ Threshold = Max,
+ SetValue = Initial,
+ UpdateOp = {Position, Increment, Threshold, SetValue},
+ NextVal =
+ try ets:update_counter(?TAB, Counter, UpdateOp) of
+ Next when is_integer(Next) ->
+ p("increment ~w: (next) ~w", [Counter, Next]),
+ Next
+ catch
+ error:badarg ->
+ %% Oups, first time
+ p("increment ~w: (initial) ~w", [Counter, Initial]),
+ ets:insert(?TAB, {Counter, Initial}),
+ Initial
+ end,
+ From ! {reply, Id, NextVal},
+ loop();
+
+ {From, Id, stop} ->
+ p("stop"),
+ Counters = ets:tab2list(?TAB),
+ From ! {reply, Id, Counters},
+ exit(normal)
+ end.
+
+
+p(F) ->
+ p(F, []).
+
+p(F, A) ->
+ io:format("*** [~s] COUNTER-SERVER [~w] " ++ F ++ "~n",
+ [snmp_test_lib:formated_timestamp(), self() | A]).
diff --git a/lib/snmp/vsn.mk b/lib/snmp/vsn.mk
index 533e313bdb..04c3cc9392 100644
--- a/lib/snmp/vsn.mk
+++ b/lib/snmp/vsn.mk
@@ -18,6 +18,6 @@
# %CopyrightEnd%
APPLICATION = snmp
-SNMP_VSN = 4.25.0.1
+SNMP_VSN = 4.25.1
PRE_VSN =
APP_VSN = "$(APPLICATION)-$(SNMP_VSN)$(PRE_VSN)"
diff --git a/lib/ssh/doc/src/ssh.xml b/lib/ssh/doc/src/ssh.xml
index eaf96d0230..7fbd70c87e 100644
--- a/lib/ssh/doc/src/ssh.xml
+++ b/lib/ssh/doc/src/ssh.xml
@@ -304,6 +304,23 @@
<c><![CDATA[true]]></c> if the password is valid and
<c><![CDATA[false]]></c> otherwise.</p>
</item>
+
+ <tag><c><![CDATA[{negotiation_timeout, integer()}]]></c></tag>
+ <item>
+ <p>Max time in milliseconds for the authentication negotiation. The default value is 2 minutes.
+ </p>
+ </item>
+
+ <tag><c><![CDATA[{parallel_login, boolean()}]]></c></tag>
+ <item>
+ <p>If set to false (the default value), only one login is handled a time. If set to true, an unlimited logins will be allowed simultanously. Note that this affects only the connections with authentication in progress, not the already authenticated connections.
+ </p>
+ <warning>
+ <p>Do not enable parallel_logins without protecting the server by other means like a firewall. If set to true, there is no protection against dos attacs.</p>
+ </warning>
+
+ </item>
+
<tag><c><![CDATA[{key_cb, atom()}]]></c></tag>
<item>
<p>Module implementing the behaviour <seealso marker="ssh_server_key_api">ssh_server_key_api</seealso>.
diff --git a/lib/ssh/src/ssh.app.src b/lib/ssh/src/ssh.app.src
index 74d7293be0..e0a51b3574 100644
--- a/lib/ssh/src/ssh.app.src
+++ b/lib/ssh/src/ssh.app.src
@@ -38,6 +38,8 @@
{registered, []},
{applications, [kernel, stdlib, crypto, public_key]},
{env, []},
- {mod, {ssh_app, []}}]}.
+ {mod, {ssh_app, []}},
+ {runtime_dependencies, ["stdlib-2.0","public_key-0.22","kernel-3.0",
+ "erts-6.0","crypto-3.3"]}]}.
diff --git a/lib/ssh/src/ssh.erl b/lib/ssh/src/ssh.erl
index d50d5a0cb3..de6e8cc421 100644
--- a/lib/ssh/src/ssh.erl
+++ b/lib/ssh/src/ssh.erl
@@ -1,4 +1,4 @@
-%%
+%
%% %CopyrightBegin%
%%
%% Copyright Ericsson AB 2004-2013. All Rights Reserved.
@@ -332,6 +332,12 @@ handle_option([{idle_time, _} = Opt | Rest], SocketOptions, SshOptions) ->
handle_option(Rest, SocketOptions, [handle_ssh_option(Opt) | SshOptions]);
handle_option([{rekey_limit, _} = Opt|Rest], SocketOptions, SshOptions) ->
handle_option(Rest, SocketOptions, [handle_ssh_option(Opt) | SshOptions]);
+handle_option([{negotiation_timeout, _} = Opt|Rest], SocketOptions, SshOptions) ->
+ handle_option(Rest, SocketOptions, [handle_ssh_option(Opt) | SshOptions]);
+handle_option([{parallel_login, _} = Opt|Rest], SocketOptions, SshOptions) ->
+ handle_option(Rest, SocketOptions, [handle_ssh_option(Opt) | SshOptions]);
+handle_option([parallel_login|Rest], SocketOptions, SshOptions) ->
+ handle_option(Rest, SocketOptions, [handle_ssh_option({parallel_login,true}) | SshOptions]);
handle_option([Opt | Rest], SocketOptions, SshOptions) ->
handle_option(Rest, [handle_inet_option(Opt) | SocketOptions], SshOptions).
@@ -360,6 +366,10 @@ handle_ssh_option({pref_public_key_algs, Value} = Opt) when is_list(Value), leng
end;
handle_ssh_option({connect_timeout, Value} = Opt) when is_integer(Value); Value == infinity ->
Opt;
+handle_ssh_option({negotiation_timeout, Value} = Opt) when is_integer(Value); Value == infinity ->
+ Opt;
+handle_ssh_option({parallel_login, Value} = Opt) when Value==true ; Value==false ->
+ Opt;
handle_ssh_option({user, Value} = Opt) when is_list(Value) ->
Opt;
handle_ssh_option({dsa_pass_phrase, Value} = Opt) when is_list(Value) ->
diff --git a/lib/ssh/src/ssh_acceptor.erl b/lib/ssh/src/ssh_acceptor.erl
index 91905b2eaf..e57b07cee8 100644
--- a/lib/ssh/src/ssh_acceptor.erl
+++ b/lib/ssh/src/ssh_acceptor.erl
@@ -84,11 +84,14 @@ handle_connection(_Callback, Address, Port, Options, Socket) ->
SystemSup = ssh_system_sup:system_supervisor(Address, Port),
{ok, SubSysSup} = ssh_system_sup:start_subsystem(SystemSup, Options),
ConnectionSup = ssh_subsystem_sup:connection_supervisor(SubSysSup),
+ Timeout = proplists:get_value(negotiation_timeout,
+ proplists:get_value(ssh_opts, Options, []),
+ 2*60*1000),
ssh_connection_handler:start_connection(server, Socket,
[{supervisors, [{system_sup, SystemSup},
{subsystem_sup, SubSysSup},
{connection_sup, ConnectionSup}]}
- | Options], infinity).
+ | Options], Timeout).
handle_error(timeout) ->
ok;
diff --git a/lib/ssh/src/ssh_auth.erl b/lib/ssh/src/ssh_auth.erl
index 409a1db6d5..45fd907383 100644
--- a/lib/ssh/src/ssh_auth.erl
+++ b/lib/ssh/src/ssh_auth.erl
@@ -196,7 +196,7 @@ handle_userauth_request(#ssh_msg_userauth_request{user = User,
{authorized, User,
ssh_transport:ssh_packet(#ssh_msg_userauth_success{}, Ssh)};
false ->
- {not_authorized, {User, {passwd, Password}},
+ {not_authorized, {User, {error,"Bad user or password"}},
ssh_transport:ssh_packet(#ssh_msg_userauth_failure{
authentications = "",
partial_success = false}, Ssh)}
@@ -228,7 +228,7 @@ handle_userauth_request(#ssh_msg_userauth_request{user = User,
ssh_transport:ssh_packet(
#ssh_msg_userauth_success{}, Ssh)};
false ->
- {not_authorized, {User, {error, "Invalid signature"}},
+ {not_authorized, {User, undefined},
ssh_transport:ssh_packet(#ssh_msg_userauth_failure{
authentications="publickey,password",
partial_success = false}, Ssh)}
diff --git a/lib/ssh/src/ssh_connection_handler.erl b/lib/ssh/src/ssh_connection_handler.erl
index 070a2db5a8..322da50f21 100644
--- a/lib/ssh/src/ssh_connection_handler.erl
+++ b/lib/ssh/src/ssh_connection_handler.erl
@@ -110,8 +110,16 @@ start_connection(server = Role, Socket, Options, Timeout) ->
{ok, Pid} = ssh_connection_sup:start_child(ConnectionSup, [Role, Socket, Opts]),
{_, Callback, _} = proplists:get_value(transport, Options, {tcp, gen_tcp, tcp_closed}),
socket_control(Socket, Pid, Callback),
- Ref = erlang:monitor(process, Pid),
- handshake(Pid, Ref, Timeout)
+ case proplists:get_value(parallel_login, Opts, false) of
+ true ->
+ spawn(fun() ->
+ Ref = erlang:monitor(process, Pid),
+ handshake(Pid, Ref, Timeout)
+ end);
+ false ->
+ Ref = erlang:monitor(process, Pid),
+ handshake(Pid, Ref, Timeout)
+ end
catch
exit:{noproc, _} ->
{error, ssh_not_started};
@@ -206,7 +214,7 @@ global_request(ConnectionHandler, Type, false = Reply, Data) ->
send_all_state_event(ConnectionHandler, {global_request, self(), Type, Reply, Data}).
%%--------------------------------------------------------------------
--spec send(pid(), channel_id(), integer(), iolist(), timeout()) ->
+-spec send(pid(), channel_id(), integer(), iodata(), timeout()) ->
ok | {error, timeout} | {error, closed}.
%%--------------------------------------------------------------------
send(ConnectionHandler, ChannelId, Type, Data, Timeout) ->
diff --git a/lib/ssh/test/ssh_unicode_SUITE.erl b/lib/ssh/test/ssh_unicode_SUITE.erl
index a896a425b9..cc916673b3 100644
--- a/lib/ssh/test/ssh_unicode_SUITE.erl
+++ b/lib/ssh/test/ssh_unicode_SUITE.erl
@@ -1,10 +1,7 @@
-%% Next line needed to enable utf8-strings in Erlang:
-%% -*- coding: utf-8 -*-
-
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2005-2013. All Rights Reserved.
+%% Copyright Ericsson AB 2005-2014. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
diff --git a/lib/ssl/doc/src/ssl.xml b/lib/ssl/doc/src/ssl.xml
index 4bc1a9a644..ffee4bd1af 100644
--- a/lib/ssl/doc/src/ssl.xml
+++ b/lib/ssl/doc/src/ssl.xml
@@ -768,39 +768,45 @@ fun(srp, Username :: string(), UserState :: term()) ->
</func>
<func>
- <name>ssl_accept(ListenSocket) -> </name>
- <name>ssl_accept(ListenSocket, Timeout) -> ok | {error, Reason}</name>
- <fsummary>Perform server-side SSL handshake</fsummary>
+ <name>ssl_accept(Socket) -> </name>
+ <name>ssl_accept(Socket, Timeout) -> ok | {error, Reason}</name>
+ <fsummary>Perform server-side SSL/TLS handshake</fsummary>
<type>
- <v>ListenSocket = sslsocket()</v>
+ <v>Socket = sslsocket()</v>
<v>Timeout = integer()</v>
<v>Reason = term()</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> Performs the SSL/TLS server-side handshake <c>Socket</c> is a socket as returned
+ by <seealso
+ marker="#transport_accept-2">ssl:transport_accept/[1,2]</seealso>
+ </p>
</desc>
</func>
<func>
- <name>ssl_accept(ListenSocket, SslOptions) -> </name>
- <name>ssl_accept(ListenSocket, SslOptions, Timeout) -> {ok, Socket} | {error, Reason}</name>
- <fsummary>Perform server-side SSL handshake</fsummary>
+ <name>ssl_accept(Socket, SslOptions) -> </name>
+ <name>ssl_accept(Socket, SslOptions, Timeout) -> {ok, Socket} | ok | {error, Reason}</name>
+ <fsummary>Perform server-side SSL/TLS handshake</fsummary>
<type>
- <v>ListenSocket = socket()</v>
+ <v>Socket = socket() | sslsocket() </v>
<v>SslOptions = ssloptions()</v>
<v>Timeout = integer()</v>
<v>Reason = term()</v>
</type>
<desc>
- <p> Upgrades a gen_tcp, or
- equivalent, socket to an ssl socket i.e. performs the
- ssl server-side handshake.</p>
+ <p> If <c>Socket</c> is a socket() - upgrades a gen_tcp, or equivalent, socket to an ssl socket
+ i.e. performs the SSL/TLS server-side handshake and returns the ssl socket.
+ </p>
+
<warning><p>Note that the listen socket should be in {active, false} mode
before telling the client that the server is ready to upgrade
- and calling this function, otherwise the upgrade may
+ by calling this function, otherwise the upgrade may
or may not succeed depending on timing.</p></warning>
+
+ <p> If <c>Socket</c> is an sslsocket() - provides additional SSL/TLS options to those specified in <seealso
+ marker="#listen-2">ssl:listen/2 </seealso> and then performs the SSL/TLS handshake.
+ </p>
</desc>
</func>
@@ -842,33 +848,38 @@ fun(srp, Username :: string(), UserState :: term()) ->
</func>
<func>
- <name>transport_accept(Socket) -></name>
- <name>transport_accept(Socket, Timeout) ->
+ <name>transport_accept(ListenSocket) -></name>
+ <name>transport_accept(ListenSocket, 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>ListenSocket = NewSocket = sslsocket()</v>
<v>Timeout = integer()</v>
<v>Reason = reason()</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>
+ <c>ListenSocket</c> must be a socket returned from
+ <seealso
+ marker="#listen-2"> ssl:listen/2</seealso>.
+ The socket returned should be passed to
+ <seealso marker="#ssl_accept-2"> ssl:ssl_accept[2,3]</seealso>
+ to complete handshaking i.e
+ establishing the SSL/TLS 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>
+ <p>The socket returned can only be used with
+ <seealso marker="#ssl_accept-2"> ssl:ssl_accept[2,3]</seealso>
+ 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>
+ <c>ListenSocket</c> in <seealso
+ marker="#listen-2"> ssl:listen/2</seealso>.</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>
+ 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>
diff --git a/lib/ssl/src/dtls_connection.erl b/lib/ssl/src/dtls_connection.erl
index da2e076856..57f8dd86d3 100644
--- a/lib/ssl/src/dtls_connection.erl
+++ b/lib/ssl/src/dtls_connection.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2013-2013. All Rights Reserved.
+%% Copyright Ericsson AB 2013-2014. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -20,222 +20,514 @@
%% Internal application API
-%%====================================================================
+-behaviour(gen_fsm).
+
+-include("dtls_connection.hrl").
+-include("dtls_handshake.hrl").
+-include("ssl_alert.hrl").
+-include("dtls_record.hrl").
+-include("ssl_cipher.hrl").
+-include("ssl_api.hrl").
+-include("ssl_internal.hrl").
+-include("ssl_srp.hrl").
+-include_lib("public_key/include/public_key.hrl").
+
%% Internal application API
-%%====================================================================
+%% Setup
+-export([start_fsm/8]).
+
+%% State transition handling
+-export([next_record/1, next_state/4%,
+ %%next_state_connection/2
+ ]).
+
+%% Handshake handling
+-export([%%renegotiate/1,
+ send_handshake/2, send_change_cipher/2]).
+
+%% Alert and close handling
+-export([send_alert/2, handle_own_alert/4, %%handle_close_alert/3,
+ handle_normal_shutdown/3
+ %%handle_unexpected_message/3,
+ %%alert_user/5, alert_user/8
+ ]).
+
+%% Data handling
+-export([%%write_application_data/3,
+ read_application_data/2%%,
+%% passive_receive/2, next_record_if_active/1
+ ]).
+
+%% Called by tls_connection_sup
+-export([start_link/7]).
+%% gen_fsm callbacks
+-export([init/1, hello/2, certify/2, cipher/2,
+ abbreviated/2, connection/2, handle_event/3,
+ handle_sync_event/4, handle_info/3, terminate/3, code_change/4]).
-%% %%====================================================================
-%% %% State functions
-%% %%====================================================================
-
-%% -spec hello(start | #hello_request{} | #client_hello{} | #server_hello{} | term(),
-%% #state{}) -> gen_fsm_state_return().
-%% %%--------------------------------------------------------------------
-%% hello(start, #state{host = Host, port = Port, role = client,
-%% ssl_options = SslOpts,
-%% session = #session{own_certificate = Cert} = Session0,
-%% session_cache = Cache, session_cache_cb = CacheCb,
-%% connection_states = ConnectionStates0,
-%% renegotiation = {Renegotiation, _},
-%% client_cookie = Cookie} = State0) ->
-%% Hello = dtls_handshake:client_hello(Host, Port, Cookie, ConnectionStates0, SslOpts,
-%% Cache, CacheCb, Renegotiation, Cert),
-
-%% Version = Hello#client_hello.client_version,
-%% State1 = State0#state{negotiated_version = Version, %% Requested version
-%% session =
-%% Session0#session{session_id = Hello#client_hello.session_id},
-%% dtls_handshake_history = ssl_handshake:init_handshake_history()},
-
-%% State2 = send_flight(Hello, waiting, State1),
-
-%% {Record, State} = next_record(State2),
-%% next_state(hello, hello, Record, State);
-
-%% hello(start, #state{role = server} = State0) ->
-%% {Record, State} = next_record(State0),
-%% next_state(hello, hello, Record, State);
-
-%% hello(#hello_request{}, #state{role = client} = State0) ->
-%% {Record, State} = next_record(State0),
-%% next_state(hello, hello, Record, State);
-
-%% hello(#server_hello{cipher_suite = CipherSuite,
-%% compression_method = Compression} = Hello,
-%% #state{session = #session{session_id = OldId},
-%% connection_states = ConnectionStates0,
-%% role = client,
-%% negotiated_version = ReqVersion,
-%% renegotiation = {Renegotiation, _},
-%% ssl_options = SslOptions} = State1) ->
-%% State0 = flight_done(State1),
-%% case ssl_handshake:hello(Hello, SslOptions, ConnectionStates0, Renegotiation) of
-%% #alert{} = Alert ->
-%% handle_own_alert(Alert, ReqVersion, hello, State0);
-%% {Version, NewId, ConnectionStates, NextProtocol} ->
-%% {KeyAlgorithm, _, _, _} =
-%% ssl_cipher:suite_definition(CipherSuite),
-
-%% PremasterSecret = make_premaster_secret(ReqVersion, KeyAlgorithm),
-
-%% NewNextProtocol = case NextProtocol of
-%% undefined ->
-%% State0#state.next_protocol;
-%% _ ->
-%% NextProtocol
-%% end,
-
-%% State = State0#state{key_algorithm = KeyAlgorithm,
-%% hashsign_algorithm = default_hashsign(Version, KeyAlgorithm),
-%% negotiated_version = Version,
-%% connection_states = ConnectionStates,
-%% premaster_secret = PremasterSecret,
-%% expecting_next_protocol_negotiation = NextProtocol =/= undefined,
-%% next_protocol = NewNextProtocol},
-
-%% case ssl_session:is_new(OldId, NewId) of
-%% true ->
-%% handle_new_session(NewId, CipherSuite, Compression,
-%% State#state{connection_states = ConnectionStates});
-%% false ->
-%% handle_resumed_session(NewId, State#state{connection_states = ConnectionStates})
-%% end
-%% end;
-
-%% hello(#hello_verify_request{cookie = Cookie},
-%% #state{host = Host, port = Port,
-%% session = #session{own_certificate = Cert},
-%% session_cache = Cache, session_cache_cb = CacheCb,
-%% ssl_options = SslOpts,
-%% connection_states = ConnectionStates0,
-%% renegotiation = {Renegotiation, _}} = State0) ->
-%% Hello = ssl_handshake:client_hello(Host, Port, Cookie, ConnectionStates0, SslOpts,
-%% Cache, CacheCb, Renegotiation, Cert),
-%% State1 = State0#state{
-%% tls_handshake_history = ssl_handshake:init_handshake_history(),
-%% client_cookie = Cookie},
-%% State2 = send_flight(Hello, waiting, State1),
-
-%% {Record, State} = next_record(State2),
-%% next_state(hello, hello, Record, State);
-
-
-%% %%--------------------------------------------------------------------
-%% -spec abbreviated(#hello_request{} | #finished{} | term(),
-%% #state{}) -> gen_fsm_state_return().
-%% %%--------------------------------------------------------------------
-
-%% abbreviated(timeout, State) ->
-%% { next_state, abbreviated, State, hibernate };
-
-%% abbreviated(Msg, State) ->
-%% handle_unexpected_message(Msg, abbreviated, State).
-
-%% %%--------------------------------------------------------------------
-%% -spec certify(#hello_request{} | #certificate{} | #server_key_exchange{} |
-%% #certificate_request{} | #server_hello_done{} | #client_key_exchange{} | term(),
-%% #state{}) -> gen_fsm_state_return().
-%% %%--------------------------------------------------------------------
-
-
-%% certify(timeout, State) ->
-%% { next_state, certify, State, hibernate };
-
-%% certify(Msg, State) ->
-%% handle_unexpected_message(Msg, certify, State).
-
-
-%% %%--------------------------------------------------------------------
-%% -spec cipher(#hello_request{} | #certificate_verify{} | #finished{} | term(),
-%% #state{}) -> gen_fsm_state_return().
-%% %%--------------------------------------------------------------------
-
-%% cipher(timeout, State) ->
-%% { next_state, cipher, State, hibernate };
-
-%% cipher(Msg, State) ->
-%% handle_unexpected_message(Msg, cipher, State).
-
-%% %%--------------------------------------------------------------------
-%% -spec connection(#hello_request{} | #client_hello{} | term(),
-%% #state{}) -> gen_fsm_state_return().
-%% %%--------------------------------------------------------------------
-
-%% connection(timeout, State) ->
-%% {next_state, connection, State, hibernate};
-
-%% connection(Msg, State) ->
-%% handle_unexpected_message(Msg, connection, State).
-
-%% %%--------------------------------------------------------------------
-%% %%% Internal functions
-%% %%--------------------------------------------------------------------
-%% handle_unexpected_message(Msg, Info, #state{negotiated_version = Version} = State) ->
-%% Alert = ?ALERT_REC(?FATAL,?UNEXPECTED_MESSAGE),
-%% handle_own_alert(Alert, Version, {Info, Msg}, State).
-
-%% send_flight(HandshakeRec, FlightState, State) ->
-%% send_flight(FlightState, buffer_flight(HandshakeRec, State)).
-
-%% send_flight(FlightState, State = #state{negotiated_version = Version,
-%% flight_buffer = Buffer}) ->
-
-%% State1 = do_send_flight(queue:to_list(Buffer), [], State),
-%% finish_send_flight(Version, FlightState, State1).
-
-%% resend_flight(State = #state{negotiated_version = Version,
-%% flight_state = FlightState,
-%% flight_buffer = Buffer})
-%% when FlightState == finished; FlightState == waiting ->
-%% State1 = do_send_flight(queue:to_list(Buffer), [], State),
-%% finish_send_flight(Version, FlightState, State1);
-
-%% resend_flight(State) ->
-%% State.
-
-%% flight_done(State) ->
-%% cancel_dtls_retransmit_timer(State#state{flight_state = done,
-%% flight_buffer = undefined}).
-
-%% do_send_flight([], BinMsgs, State = #state{transport_cb = Transport, socket = Socket}) ->
-%% Transport:send(Socket, lists:reverse(BinMsgs)),
-%% State;
-%% do_send_flight([{Epoch, MsgSeq, HandshakeRec}|T], BinMsgs0,
-%% State = #state{negotiated_version = Version,
-%% connection_states = ConnectionStates0}) ->
-%% CS0 = ssl_record:connection_state_by_epoch(ConnectionStates0, Epoch, write),
-%% {BinMsgs, CS1} = encode_handshake_rec(HandshakeRec, Version, MsgSeq, BinMsgs0, CS0),
-%% ConnectionStates1 = ssl_record:set_connection_state_by_epoch(ConnectionStates0, CS1, write),
-%% do_send_flight(T, BinMsgs, State#state{connection_states = ConnectionStates1}).
-
-%% cancel_dtls_retransmit_timer(State = #state{dtls_retransmit_timer = TimerRef}) ->
-%% cancel_timer(TimerRef),
-%% State#state{dtls_retransmit_timer = undefined}.
-
-%% rearm_dtls_retransmit_timer(State = #state{dtls_retransmit_timer = undefined}) ->
-%% TimerRef = erlang:start_timer(1000, self(), dtls_retransmit),
-%% State#state{dtls_retransmit_timer = TimerRef};
-%% rearm_dtls_retransmit_timer(State) ->
-%% State.
-
-%% finish_send_flight({254, _}, waiting, State) ->
-%% TimerRef = erlang:start_timer(1000, self(), dtls_retransmit),
-%% State#state{
-%% dtls_retransmit_timer = TimerRef,
-%% last_retransmit = timestamp(),
-%% flight_state = waiting};
-
-%% finish_send_flight(_, FlightState, State) ->
-%% State#state{flight_state = FlightState}.
-
-%% timestamp() ->
-%% {Mega, Sec, Micro} = erlang:now(),
-%% Mega * 1000000 * 1000 + Sec * 1000 + (Micro div 1000).
-
-%% encode_handshake_rec(HandshakeRec, Version, MsgSeq, BinMsgs0, CS0) ->
-%% {_, Fragments} = ssl_handshake:encode_handshake(HandshakeRec, Version, MsgSeq, 1400),
-%% lists:foldl(fun(F, {Bin, C0}) ->
-%% {B, C1} = ssl_record:encode_handshake(F, Version, C0),
-%% {[B|Bin], C1} end, {BinMsgs0, CS0}, Fragments).
+%%====================================================================
+%% Internal application API
+%%====================================================================
+start_fsm(Role, Host, Port, Socket, {#ssl_options{erl_dist = false},_} = Opts,
+ User, {CbModule, _,_, _} = CbInfo,
+ Timeout) ->
+ try
+ {ok, Pid} = dtls_connection_sup:start_child([Role, Host, Port, Socket,
+ Opts, User, CbInfo]),
+ {ok, SslSocket} = ssl_connection:socket_control(?MODULE, Socket, Pid, CbModule),
+ ok = ssl_connection:handshake(SslSocket, Timeout),
+ {ok, SslSocket}
+ 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} = dtls_connection_sup:start_child_dist([Role, Host, Port, Socket,
+ Opts, User, CbInfo]),
+ {ok, SslSocket} = ssl_connection:socket_control(?MODULE, Socket, Pid, CbModule),
+ ok = ssl_connection:handshake(SslSocket, Timeout),
+ {ok, SslSocket}
+ catch
+ error:{badmatch, {error, _} = Error} ->
+ Error
+ end.
+
+send_handshake(Handshake, #state{negotiated_version = Version,
+ tls_handshake_history = Hist0,
+ connection_states = ConnectionStates0} = State0) ->
+ {BinHandshake, ConnectionStates, Hist} =
+ encode_handshake(Handshake, Version, ConnectionStates0, Hist0),
+ send_flight(BinHandshake, State0#state{connection_states = ConnectionStates,
+ tls_handshake_history = Hist
+ }).
+
+send_alert(Alert, #state{negotiated_version = Version,
+ socket = Socket,
+ transport_cb = Transport,
+ connection_states = ConnectionStates0} = State0) ->
+ {BinMsg, ConnectionStates} =
+ ssl_alert:encode(Alert, Version, ConnectionStates0),
+ Transport:send(Socket, BinMsg),
+ State0#state{connection_states = ConnectionStates}.
+
+send_change_cipher(Msg, #state{connection_states = ConnectionStates0,
+ socket = Socket,
+ negotiated_version = Version,
+ transport_cb = Transport} = State0) ->
+ {BinChangeCipher, ConnectionStates} =
+ encode_change_cipher(Msg, Version, ConnectionStates0),
+ Transport:send(Socket, BinChangeCipher),
+ State0#state{connection_states = ConnectionStates}.
+
+%%====================================================================
+%% tls_connection_sup API
+%%====================================================================
+
+%%--------------------------------------------------------------------
+-spec start_link(atom(), host(), inet:port_number(), port(), list(), pid(), tuple()) ->
+ {ok, pid()} | ignore | {error, reason()}.
+%%
+%% Description: Creates a gen_fsm process which calls Module:init/1 to
+%% initialize. To ensure a synchronized start-up procedure, this function
+%% does not return until Module:init/1 has returned.
+%%--------------------------------------------------------------------
+start_link(Role, Host, Port, Socket, Options, User, CbInfo) ->
+ {ok, proc_lib:spawn_link(?MODULE, init, [[Role, Host, Port, Socket, Options, User, CbInfo]])}.
+
+init([Role, Host, Port, Socket, {SSLOpts0, _} = Options, User, CbInfo]) ->
+ process_flag(trap_exit, true),
+ State0 = initial_state(Role, Host, Port, Socket, Options, User, CbInfo),
+ Handshake = ssl_handshake:init_handshake_history(),
+ TimeStamp = calendar:datetime_to_gregorian_seconds({date(), time()}),
+ try ssl_config:init(SSLOpts0, Role) of
+ {ok, Ref, CertDbHandle, FileRefHandle, CacheHandle, OwnCert, Key, DHParams} ->
+ Session = State0#state.session,
+ State = State0#state{
+ tls_handshake_history = Handshake,
+ session = Session#session{own_certificate = OwnCert,
+ time_stamp = TimeStamp},
+ file_ref_db = FileRefHandle,
+ cert_db_ref = Ref,
+ cert_db = CertDbHandle,
+ session_cache = CacheHandle,
+ private_key = Key,
+ diffie_hellman_params = DHParams},
+ gen_fsm:enter_loop(?MODULE, [], hello, State, get_timeout(State))
+ catch
+ throw:Error ->
+ gen_fsm:enter_loop(?MODULE, [], error, {Error,State0}, get_timeout(State0))
+ end.
+
+%%--------------------------------------------------------------------
+%% Description:There should be one instance of this function for each
+%% possible state name. Whenever a gen_fsm receives an event sent
+%% using gen_fsm:send_event/2, the instance of this function with the
+%% same name as the current state name StateName is called to handle
+%% the event. It is also called if a timeout occurs.
+%%
+hello(start, #state{host = Host, port = Port, role = client,
+ ssl_options = SslOpts,
+ session = #session{own_certificate = Cert} = Session0,
+ session_cache = Cache, session_cache_cb = CacheCb,
+ transport_cb = Transport, socket = Socket,
+ connection_states = ConnectionStates0,
+ renegotiation = {Renegotiation, _}} = State0) ->
+ Hello = dtls_handshake:client_hello(Host, Port, ConnectionStates0, SslOpts,
+ Cache, CacheCb, Renegotiation, Cert),
+
+ Version = Hello#client_hello.client_version,
+ Handshake0 = ssl_handshake:init_handshake_history(),
+ {BinMsg, ConnectionStates, Handshake} =
+ encode_handshake(Hello, Version, ConnectionStates0, Handshake0),
+ Transport:send(Socket, BinMsg),
+ State1 = State0#state{connection_states = ConnectionStates,
+ negotiated_version = Version, %% Requested version
+ session =
+ Session0#session{session_id = Hello#client_hello.session_id},
+ tls_handshake_history = Handshake},
+ {Record, State} = next_record(State1),
+ next_state(hello, hello, Record, State);
+
+hello(Hello = #client_hello{client_version = ClientVersion,
+ extensions = #hello_extensions{hash_signs = HashSigns}},
+ State = #state{connection_states = ConnectionStates0,
+ port = Port, session = #session{own_certificate = Cert} = Session0,
+ renegotiation = {Renegotiation, _},
+ session_cache = Cache,
+ session_cache_cb = CacheCb,
+ ssl_options = SslOpts}) ->
+ HashSign = ssl_handshake:select_hashsign(HashSigns, Cert),
+ case dtls_handshake:hello(Hello, SslOpts, {Port, Session0, Cache, CacheCb,
+ ConnectionStates0, Cert}, Renegotiation) of
+ {Version, {Type, Session},
+ ConnectionStates,
+ #hello_extensions{ec_point_formats = EcPointFormats,
+ elliptic_curves = EllipticCurves} = ServerHelloExt} ->
+ ssl_connection:hello({common_client_hello, Type, ServerHelloExt, HashSign},
+ State#state{connection_states = ConnectionStates,
+ negotiated_version = Version,
+ session = Session,
+ client_ecc = {EllipticCurves, EcPointFormats}}, ?MODULE);
+ #alert{} = Alert ->
+ handle_own_alert(Alert, ClientVersion, hello, State)
+ end;
+hello(Hello,
+ #state{connection_states = ConnectionStates0,
+ negotiated_version = ReqVersion,
+ role = client,
+ renegotiation = {Renegotiation, _},
+ ssl_options = SslOptions} = State) ->
+ case dtls_handshake:hello(Hello, SslOptions, ConnectionStates0, Renegotiation) of
+ #alert{} = Alert ->
+ handle_own_alert(Alert, ReqVersion, hello, State);
+ {Version, NewId, ConnectionStates, NextProtocol} ->
+ ssl_connection:handle_session(Hello,
+ Version, NewId, ConnectionStates, NextProtocol, State)
+ end;
+
+hello(Msg, State) ->
+ ssl_connection:hello(Msg, State, ?MODULE).
+
+abbreviated(Msg, State) ->
+ ssl_connection:abbreviated(Msg, State, ?MODULE).
+
+certify(Msg, State) ->
+ ssl_connection:certify(Msg, State, ?MODULE).
+
+cipher(Msg, State) ->
+ ssl_connection:cipher(Msg, State, ?MODULE).
+
+connection(#hello_request{}, #state{host = Host, port = Port,
+ session = #session{own_certificate = Cert} = Session0,
+ session_cache = Cache, session_cache_cb = CacheCb,
+ ssl_options = SslOpts,
+ connection_states = ConnectionStates0,
+ renegotiation = {Renegotiation, _}} = State0) ->
+ Hello = dtls_handshake:client_hello(Host, Port, ConnectionStates0, SslOpts,
+ Cache, CacheCb, Renegotiation, Cert),
+ %% TODO DTLS version State1 = send_handshake(Hello, State0),
+ State1 = State0,
+ {Record, State} =
+ next_record(
+ State1#state{session = Session0#session{session_id
+ = Hello#client_hello.session_id}}),
+ 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} = State0) ->
+ Alert = ?ALERT_REC(?WARNING, ?NO_RENEGOTIATION),
+ State = send_alert(Alert, State0),
+ next_state_connection(connection, State);
+
+connection(Msg, State) ->
+ ssl_connection:connection(Msg, State, tls_connection).
+
+%%--------------------------------------------------------------------
+%% Description: Whenever a gen_fsm receives an event sent using
+%% gen_fsm:send_all_state_event/2, this function is called to handle
+%% the event. Not currently used!
+%%--------------------------------------------------------------------
+handle_event(_Event, StateName, State) ->
+ {next_state, StateName, State, get_timeout(State)}.
+
+%%--------------------------------------------------------------------
+%% Description: Whenever a gen_fsm receives an event sent using
+%% gen_fsm:sync_send_all_state_event/2,3, this function is called to handle
+%% the event.
+%%--------------------------------------------------------------------
+handle_sync_event(Event, From, StateName, State) ->
+ ssl_connection:handle_sync_event(Event, From, StateName, State).
+
+%%--------------------------------------------------------------------
+%% Description: This function is called by a gen_fsm when it receives any
+%% other message than a synchronous or asynchronous event
+%% (or a system message).
+%%--------------------------------------------------------------------
+
+%% raw data from socket, unpack records
+handle_info({Protocol, _, Data}, StateName,
+ #state{data_tag = Protocol} = State0) ->
+ %% Simplify for now to avoid dialzer warnings before implementation is compleate
+ %% case next_tls_record(Data, State0) of
+ %% {Record, State} ->
+ %% next_state(StateName, StateName, Record, State);
+ %% #alert{} = Alert ->
+ %% handle_normal_shutdown(Alert, StateName, State0),
+ %% {stop, {shutdown, own_alert}, State0}
+ %% end;
+ {Record, State} = next_tls_record(Data, State0),
+ next_state(StateName, StateName, Record, State);
+
+handle_info({CloseTag, Socket}, StateName,
+ #state{socket = Socket, close_tag = CloseTag,
+ negotiated_version = _Version} = State) ->
+ handle_normal_shutdown(?ALERT_REC(?FATAL, ?CLOSE_NOTIFY), StateName, State),
+ {stop, {shutdown, transport_closed}, State};
+
+handle_info(Msg, StateName, State) ->
+ ssl_connection:handle_info(Msg, StateName, State).
+
+%%--------------------------------------------------------------------
+%% Description:This function is called by a gen_fsm when it is about
+%% to terminate. It should be the opposite of Module:init/1 and do any
+%% necessary cleaning up. When it returns, the gen_fsm terminates with
+%% Reason. The return value is ignored.
+%%--------------------------------------------------------------------
+terminate(Reason, StateName, State) ->
+ ssl_connection:terminate(Reason, StateName, State).
+
+%%--------------------------------------------------------------------
+%% code_change(OldVsn, StateName, State, Extra) -> {ok, StateName, NewState}
+%% Description: Convert process state when code is changed
+%%--------------------------------------------------------------------
+code_change(_OldVsn, StateName, State, _Extra) ->
+ {ok, StateName, State}.
+
+%%--------------------------------------------------------------------
+%%% Internal functions
+%%--------------------------------------------------------------------
+encode_handshake(Handshake, Version, ConnectionStates0, Hist0) ->
+ Seq = sequence(ConnectionStates0),
+ {EncHandshake, FragmentedHandshake} = dtls_handshake:encode_handshake(Handshake, Version,
+ Seq),
+ Hist = ssl_handshake:update_handshake_history(Hist0, EncHandshake),
+ {Encoded, ConnectionStates} =
+ dtls_record:encode_handshake(FragmentedHandshake,
+ Version, ConnectionStates0),
+ {Encoded, ConnectionStates, Hist}.
+
+next_record(#state{%%flight = #flight{state = finished},
+ protocol_buffers =
+ #protocol_buffers{dtls_packets = [], dtls_cipher_texts = [CT | Rest]}
+ = Buffers,
+ connection_states = ConnStates0} = State) ->
+ case dtls_record:decode_cipher_text(CT, ConnStates0) of
+ {Plain, ConnStates} ->
+ {Plain, State#state{protocol_buffers =
+ Buffers#protocol_buffers{dtls_cipher_texts = Rest},
+ connection_states = ConnStates}};
+ #alert{} = Alert ->
+ {Alert, State}
+ end;
+next_record(#state{socket = Socket,
+ transport_cb = Transport} = State) -> %% when FlightState =/= finished
+ ssl_socket:setopts(Transport, Socket, [{active,once}]),
+ {no_record, State};
+
+
+next_record(State) ->
+ {no_record, State}.
+
+next_state(Current,_, #alert{} = Alert, #state{negotiated_version = Version} = State) ->
+ handle_own_alert(Alert, Version, Current, State);
+
+next_state(_,Next, no_record, State) ->
+ {next_state, Next, State, get_timeout(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(Current, Next, #ssl_tls{type = ?HANDSHAKE, fragment = Data},
+ State0 = #state{protocol_buffers =
+ #protocol_buffers{dtls_handshake_buffer = Buf0} = Buffers,
+ negotiated_version = Version}) ->
+ Handle =
+ fun({#hello_request{} = Packet, _}, {next_state, connection = SName, State}) ->
+ %% This message should not be included in handshake
+ %% message hashes. Starts new handshake (renegotiation)
+ Hs0 = ssl_handshake:init_handshake_history(),
+ ?MODULE:SName(Packet, State#state{tls_handshake_history=Hs0,
+ renegotiation = {true, peer}});
+ ({#hello_request{} = Packet, _}, {next_state, SName, State}) ->
+ %% This message should not be included in handshake
+ %% message hashes. Already in negotiation so it will be ignored!
+ ?MODULE:SName(Packet, State);
+ ({#client_hello{} = Packet, Raw}, {next_state, connection = SName, State}) ->
+ Version = Packet#client_hello.client_version,
+ Hs0 = ssl_handshake:init_handshake_history(),
+ Hs1 = ssl_handshake:update_handshake_history(Hs0, Raw),
+ ?MODULE:SName(Packet, State#state{tls_handshake_history=Hs1,
+ renegotiation = {true, peer}});
+ ({Packet, Raw}, {next_state, SName, State = #state{tls_handshake_history=Hs0}}) ->
+ Hs1 = ssl_handshake:update_handshake_history(Hs0, Raw),
+ ?MODULE:SName(Packet, State#state{tls_handshake_history=Hs1});
+ (_, StopState) -> StopState
+ end,
+ try
+ {Packets, Buf} = tls_handshake:get_tls_handshake(Version,Data,Buf0),
+ State = State0#state{protocol_buffers =
+ Buffers#protocol_buffers{dtls_packets = Packets,
+ dtls_handshake_buffer = Buf}},
+ handle_dtls_handshake(Handle, Next, State)
+ catch throw:#alert{} = Alert ->
+ handle_own_alert(Alert, Version, Current, State0)
+ end;
+
+next_state(_, StateName, #ssl_tls{type = ?APPLICATION_DATA, fragment = Data}, State0) ->
+ %% Simplify for now to avoid dialzer warnings before implementation is compleate
+ %% case read_application_data(Data, State0) of
+ %% Stop = {stop,_,_} ->
+ %% Stop;
+ %% {Record, State} ->
+ %% next_state(StateName, StateName, Record, State)
+ %% end;
+ {Record, State} = read_application_data(Data, State0),
+ next_state(StateName, StateName, Record, State);
+
+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(Current, Next, Record, State);
+next_state(Current, Next, #ssl_tls{type = _Unknown}, State0) ->
+ %% Ignore unknown type
+ {Record, State} = next_record(State0),
+ next_state(Current, Next, Record, State).
+
+handle_dtls_handshake(Handle, StateName,
+ #state{protocol_buffers =
+ #protocol_buffers{dtls_packets = [Packet]} = Buffers} = State) ->
+ FsmReturn = {next_state, StateName, State#state{protocol_buffers =
+ Buffers#protocol_buffers{dtls_packets = []}}},
+ Handle(Packet, FsmReturn);
+
+handle_dtls_handshake(Handle, StateName,
+ #state{protocol_buffers =
+ #protocol_buffers{dtls_packets = [Packet | Packets]} = Buffers} =
+ State0) ->
+ FsmReturn = {next_state, StateName, State0#state{protocol_buffers =
+ Buffers#protocol_buffers{dtls_packets =
+ Packets}}},
+ case Handle(Packet, FsmReturn) of
+ {next_state, NextStateName, State, _Timeout} ->
+ handle_dtls_handshake(Handle, NextStateName, State);
+ {stop, _,_} = Stop ->
+ Stop
+ end.
+
+
+send_flight(Fragments, #state{transport_cb = Transport, socket = Socket,
+ protocol_buffers = _PBuffers} = State) ->
+ Transport:send(Socket, Fragments),
+ %% Start retransmission
+ %% State#state{protocol_buffers =
+ %% (PBuffers#protocol_buffers){ #flight{state = waiting}}}}.
+ State.
+
+handle_own_alert(_,_,_, State) -> %% Place holder
+ {stop, {shutdown, own_alert}, State}.
+
+handle_normal_shutdown(_, _, _State) -> %% Place holder
+ ok.
+
+encode_change_cipher(#change_cipher_spec{}, Version, ConnectionStates) ->
+ dtls_record:encode_change_cipher_spec(Version, ConnectionStates).
+
+initial_state(Role, Host, Port, Socket, {SSLOptions, SocketOptions}, User,
+ {CbModule, DataTag, CloseTag, ErrorTag}) ->
+ ConnectionStates = ssl_record:init_connection_states(Role),
+
+ SessionCacheCb = case application:get_env(ssl, session_cb) of
+ {ok, Cb} when is_atom(Cb) ->
+ Cb;
+ _ ->
+ ssl_session_cache
+ end,
+
+ Monitor = erlang:monitor(process, User),
+
+ #state{socket_options = SocketOptions,
+ %% 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 = new},
+ transport_cb = CbModule,
+ data_tag = DataTag,
+ close_tag = CloseTag,
+ error_tag = ErrorTag,
+ role = Role,
+ host = Host,
+ port = Port,
+ socket = Socket,
+ connection_states = ConnectionStates,
+ protocol_buffers = #protocol_buffers{},
+ user_application = {Monitor, User},
+ user_data_buffer = <<>>,
+ session_cache_cb = SessionCacheCb,
+ renegotiation = {false, first},
+ start_or_recv_from = undefined,
+ send_queue = queue:new(),
+ protocol_cb = ?MODULE
+ }.
+read_application_data(_,State) ->
+ {#ssl_tls{fragment = <<"place holder">>}, State}.
+
+next_tls_record(_, State) ->
+ {#ssl_tls{fragment = <<"place holder">>}, State}.
+
+get_timeout(_) -> %% Place holder
+ infinity.
+
+next_state_connection(_, State) -> %% Place holder
+ {next_state, connection, State, get_timeout(State)}.
+
+sequence(_) ->
+ %%TODO real imp
+ 1.
diff --git a/lib/ssl/src/dtls_connection.hrl b/lib/ssl/src/dtls_connection.hrl
index b8dff479d5..08707dc8de 100644
--- a/lib/ssl/src/dtls_connection.hrl
+++ b/lib/ssl/src/dtls_connection.hrl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2013-2013. All Rights Reserved.
+%% Copyright Ericsson AB 2013-2014. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -28,24 +28,19 @@
-include("ssl_connection.hrl").
-record(protocol_buffers, {
- dtls_packets = [] ::[binary()], % Not yet handled decode ssl/tls packets.
- dtls_record_buffer :: binary(), % Buffer of incomplete records
- dtls_handshake_buffer :: binary(), % Buffer of incomplete handshakes
- dtls_cipher_texts :: [binary()],
- dtls_cipher_texts_next :: [binary()] % Received for Epoch not yet active
+ dtls_packets = [], %%::[binary()], % Not yet handled decode ssl/tls packets.
+ dtls_record_buffer = <<>>, %%:: binary(), % Buffer of incomplete records
+ dtls_handshake_buffer = <<>>, %%:: binary(), % Buffer of incomplete handshakes
+ dtls_cipher_texts = [], %%:: [binary()],
+ dtls_cipher_texts_next %%:: [binary()] % Received for Epoch not yet active
}).
-record(flight, {
last_retransmit,
last_read_seq,
msl_timer,
- flight_state,
- flight_buffer, % buffer of not yet ACKed TLS records
- }).
-
--record(message_sequences, {
- read = 0,
- write = 0
+ state,
+ buffer % buffer of not yet ACKed TLS records
}).
-endif. % -ifdef(dtls_connection).
diff --git a/lib/ssl/src/dtls_connection_sup.erl b/lib/ssl/src/dtls_connection_sup.erl
index 9fe545be18..0b4711cfb4 100644
--- a/lib/ssl/src/dtls_connection_sup.erl
+++ b/lib/ssl/src/dtls_connection_sup.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2007-2013. All Rights Reserved.
+%% Copyright Ericsson AB 2007-2014. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -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,8 +38,14 @@
start_link() ->
supervisor:start_link({local, ?MODULE}, ?MODULE, []).
+start_link_dist() ->
+ supervisor:start_link({local, dtls_connection_sup_dist}, ?MODULE, []).
+
start_child(Args) ->
supervisor:start_child(?MODULE, Args).
+
+start_child_dist(Args) ->
+ supervisor:start_child(dtls_connection_sup_dist, Args).
%%%=========================================================================
%%% Supervisor callback
diff --git a/lib/ssl/src/dtls_handshake.erl b/lib/ssl/src/dtls_handshake.erl
index 5db2434753..31d525b295 100644
--- a/lib/ssl/src/dtls_handshake.erl
+++ b/lib/ssl/src/dtls_handshake.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2013-2013. All Rights Reserved.
+%% Copyright Ericsson AB 2013-2014. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -20,11 +20,15 @@
-include("dtls_handshake.hrl").
-include("dtls_record.hrl").
-include("ssl_internal.hrl").
+-include("ssl_alert.hrl").
--export([client_hello/8, client_hello/9, hello/3,
+-export([client_hello/8, client_hello/9, hello/4,
get_dtls_handshake/2,
- dtls_handshake_new_flight/1, dtls_handshake_new_epoch/1,
- encode_handshake/4]).
+ %%dtls_handshake_new_flight/1, dtls_handshake_new_epoch/1,
+ encode_handshake/3]).
+
+-type dtls_handshake() :: #client_hello{} | #hello_verify_request{} |
+ ssl_handshake:ssl_handshake().
%%====================================================================
%% Internal application API
@@ -54,12 +58,12 @@ client_hello(Host, Port, Cookie, ConnectionStates,
ciphers = UserSuites
} = SslOpts,
Cache, CacheCb, Renegotiation, OwnCert) ->
- Version = dtls_record:highest_protocol_version(Versions),
+ Version = dtls_record:highest_protocol_version(Versions),
Pending = ssl_record:pending_connection_state(ConnectionStates, read),
SecParams = Pending#connection_state.security_parameters,
CipherSuites = ssl_handshake:available_suites(UserSuites, Version),
- Extensions = ssl_handshake:client_hello_extensions(Host, Version, CipherSuites,
+ Extensions = ssl_handshake:client_hello_extensions(Host, dtls_v1:corresponding_tls_version(Version), CipherSuites,
SslOpts, ConnectionStates, Renegotiation),
Id = ssl_session:client_id({Host, Port, SslOpts}, Cache, CacheCb, OwnCert),
@@ -73,163 +77,197 @@ client_hello(Host, Port, Cookie, ConnectionStates,
extensions = Extensions
}.
-hello(Address, Port,
- #ssl_tls{epoch = _Epoch, record_seq = _Seq,
- version = Version} = Record) ->
- {[{Hello, _}], _, _} =
- get_dtls_handshake(Record,
- dtls_handshake_new_flight(undefined)),
- #client_hello{client_version = {Major, Minor},
- random = Random,
- session_id = SessionId,
- cipher_suites = CipherSuites,
- compression_methods = CompressionMethods} = Hello,
- CookieData = [address_to_bin(Address, Port),
- <<?BYTE(Major), ?BYTE(Minor)>>,
- Random, SessionId, CipherSuites, CompressionMethods],
- Cookie = crypto:hmac(sha, <<"secret">>, CookieData),
-
- case Hello of
- #client_hello{cookie = Cookie} ->
- accept;
- _ ->
- %% generate HelloVerifyRequest
- HelloVerifyRequest = encode_handshake(#hello_verify_request{protocol_version = Version,
- cookie = Cookie},
- Version, 0, 1400),
- {reply, HelloVerifyRequest}
- end.
+hello(#server_hello{server_version = Version, random = Random,
+ cipher_suite = CipherSuite,
+ compression_method = Compression,
+ session_id = SessionId, extensions = HelloExt},
+ #ssl_options{versions = SupportedVersions} = SslOpt,
+ ConnectionStates0, Renegotiation) ->
+ case dtls_record:is_acceptable_version(Version, SupportedVersions) of
+ true ->
+ handle_server_hello_extensions(Version, SessionId, Random, CipherSuite,
+ Compression, HelloExt, SslOpt, ConnectionStates0, Renegotiation);
+ false ->
+ ?ALERT_REC(?FATAL, ?PROTOCOL_VERSION)
+ end;
-%%--------------------------------------------------------------------
-encode_handshake(Package, Version, MsgSeq, Mss) ->
- {MsgType, Bin} = enc_hs(Package, Version),
+hello(#client_hello{client_version = ClientVersion}, _Options, {_,_,_,_,ConnectionStates,_}, _Renegotiation) ->
+ %% Return correct typ to make dialyzer happy until we have time to make the real imp.
+ {ClientVersion, {new, #session{}}, ConnectionStates, #hello_extensions{}}.
+
+%% hello(Address, Port,
+%% #ssl_tls{epoch = _Epoch, sequence_number = _Seq,
+%% version = Version} = Record) ->
+%% case get_dtls_handshake(Record,
+%% dtls_handshake_new_flight(undefined)) of
+%% {[Hello | _], _} ->
+%% hello(Address, Port, Version, Hello);
+%% {retransmit, HandshakeState} ->
+%% {retransmit, HandshakeState}
+%% end.
+
+%% hello(Address, Port, Version, Hello) ->
+%% #client_hello{client_version = {Major, Minor},
+%% random = Random,
+%% session_id = SessionId,
+%% cipher_suites = CipherSuites,
+%% compression_methods = CompressionMethods} = Hello,
+%% CookieData = [address_to_bin(Address, Port),
+%% <<?BYTE(Major), ?BYTE(Minor)>>,
+%% Random, SessionId, CipherSuites, CompressionMethods],
+%% Cookie = crypto:hmac(sha, <<"secret">>, CookieData),
+
+%% case Hello of
+%% #client_hello{cookie = Cookie} ->
+%% accept;
+%% _ ->
+%% %% generate HelloVerifyRequest
+%% HelloVerifyRequest = enc_hs(#hello_verify_request{protocol_version = Version,
+%% cookie = Cookie},
+%% Version, 0, 1400),
+%% {reply, HelloVerifyRequest}
+%% end.
+
+%% %%--------------------------------------------------------------------
+encode_handshake(Handshake, Version, MsgSeq) ->
+ {MsgType, Bin} = enc_handshake(Handshake, Version),
Len = byte_size(Bin),
- HsHistory = [MsgType, ?uint24(Len), ?uint16(MsgSeq), ?uint24(0), ?uint24(Len), Bin],
- BinMsg = dtls_split_handshake(Mss, MsgType, Len, MsgSeq, Bin, 0, []),
- {HsHistory, BinMsg}.
+ EncHandshake = [MsgType, ?uint24(Len), ?uint16(MsgSeq), ?uint24(0), ?uint24(Len), Bin],
+ FragmentedHandshake = dtls_fragment(erlang:iolist_size(EncHandshake), MsgType, Len, MsgSeq, Bin, 0, []),
+ {EncHandshake, FragmentedHandshake}.
-%--------------------------------------------------------------------
+%%--------------------------------------------------------------------
-spec get_dtls_handshake(#ssl_tls{}, #dtls_hs_state{} | binary()) ->
- {[dtls_handshake()], #dtls_hs_state{}} | {retransmit, #dtls_hs_state{}}.
-%
-% Description: Given a DTLS state and new data from ssl_record, collects
-% and returns it as a list of handshake messages, also returns a new
-% DTLS state
-%--------------------------------------------------------------------
-% get_dtls_handshake(Record, <<>>) ->
-% get_dtls_handshake_aux(Record, dtls_hs_state_init());
+ {[dtls_handshake()], #dtls_hs_state{}} | {retransmit, #dtls_hs_state{}}.
+%%
+%% Description: Given a DTLS state and new data from ssl_record, collects
+%% and returns it as a list of handshake messages, also returns a new
+%% DTLS state
+%%--------------------------------------------------------------------
+get_dtls_handshake(Record, <<>>) ->
+ get_dtls_handshake_aux(Record, #dtls_hs_state{}); %% Init handshake state!?
get_dtls_handshake(Record, HsState) ->
get_dtls_handshake_aux(Record, HsState).
-%--------------------------------------------------------------------
--spec dtls_handshake_new_epoch(#dtls_hs_state{}) -> #dtls_hs_state{}.
-%
-% Description: Reset the DTLS decoder state for a new Epoch
-%--------------------------------------------------------------------
-% dtls_handshake_new_epoch(<<>>) ->
-% dtls_hs_state_init();
-dtls_handshake_new_epoch(HsState) ->
- HsState#dtls_hs_state{highest_record_seq = 0,
- starting_read_seq = HsState#dtls_hs_state.current_read_seq,
- fragments = gb_trees:empty(), completed = []}.
-
-%--------------------------------------------------------------------
--spec dtls_handshake_new_flight(integer() | undefined) -> #dtls_hs_state{}.
-%
-% Description: Init the DTLS decoder state for a new Flight
-dtls_handshake_new_flight(ExpectedReadReq) ->
- #dtls_hs_state{current_read_seq = ExpectedReadReq,
- highest_record_seq = 0,
- starting_read_seq = 0,
- fragments = gb_trees:empty(), completed = []}.
+%% %%--------------------------------------------------------------------
+%% -spec dtls_handshake_new_epoch(#dtls_hs_state{}) -> #dtls_hs_state{}.
+%% %%
+%% %% Description: Reset the DTLS decoder state for a new Epoch
+%% %%--------------------------------------------------------------------
+%% dtls_handshake_new_epoch(<<>>) ->
+%% dtls_hs_state_init();
+%% dtls_handshake_new_epoch(HsState) ->
+%% HsState#dtls_hs_state{highest_record_seq = 0,
+%% starting_read_seq = HsState#dtls_hs_state.current_read_seq,
+%% fragments = gb_trees:empty(), completed = []}.
+
+%% %--------------------------------------------------------------------
+%% -spec dtls_handshake_new_flight(integer() | undefined) -> #dtls_hs_state{}.
+%% %
+%% % Description: Init the DTLS decoder state for a new Flight
+%% dtls_handshake_new_flight(ExpectedReadReq) ->
+%% #dtls_hs_state{current_read_seq = ExpectedReadReq,
+%% highest_record_seq = 0,
+%% starting_read_seq = 0,
+%% fragments = gb_trees:empty(), completed = []}.
%%--------------------------------------------------------------------
%%% Internal functions
%%--------------------------------------------------------------------
+handle_server_hello_extensions(Version, SessionId, Random, CipherSuite,
+ Compression, HelloExt, SslOpt, ConnectionStates0, Renegotiation) ->
+ case ssl_handshake:handle_server_hello_extensions(dtls_record, Random, CipherSuite,
+ Compression, HelloExt, Version,
+ SslOpt, ConnectionStates0, Renegotiation) of
+ #alert{} = Alert ->
+ Alert;
+ {ConnectionStates, Protocol} ->
+ {Version, SessionId, ConnectionStates, Protocol}
+ end.
-dtls_split_handshake(Mss, MsgType, Len, MsgSeq, Bin, Offset, Acc)
+dtls_fragment(Mss, MsgType, Len, MsgSeq, Bin, Offset, Acc)
when byte_size(Bin) + 12 < Mss ->
FragmentLen = byte_size(Bin),
BinMsg = [MsgType, ?uint24(Len), ?uint16(MsgSeq), ?uint24(Offset), ?uint24(FragmentLen), Bin],
lists:reverse([BinMsg|Acc]);
-dtls_split_handshake(Mss, MsgType, Len, MsgSeq, Bin, Offset, Acc) ->
+dtls_fragment(Mss, MsgType, Len, MsgSeq, Bin, Offset, Acc) ->
FragmentLen = Mss - 12,
<<Fragment:FragmentLen/bytes, Rest/binary>> = Bin,
BinMsg = [MsgType, ?uint24(Len), ?uint16(MsgSeq), ?uint24(Offset), ?uint24(FragmentLen), Fragment],
- dtls_split_handshake(Mss, MsgType, Len, MsgSeq, Rest, Offset + FragmentLen, [BinMsg|Acc]).
+ dtls_fragment(Mss, MsgType, Len, MsgSeq, Rest, Offset + FragmentLen, [BinMsg|Acc]).
get_dtls_handshake_aux(#ssl_tls{version = Version,
- record_seq = SeqNo,
- fragment = Data}, HsState) ->
+ sequence_number = SeqNo,
+ fragment = Data}, HsState) ->
get_dtls_handshake_aux(Version, SeqNo, Data, HsState).
get_dtls_handshake_aux(Version, SeqNo,
- <<?BYTE(Type), ?UINT24(Length),
- ?UINT16(MessageSeq),
- ?UINT24(FragmentOffset), ?UINT24(FragmentLength),
- Body:FragmentLength/binary, Rest/binary>>,
- HsState0) ->
+ <<?BYTE(Type), ?UINT24(Length),
+ ?UINT16(MessageSeq),
+ ?UINT24(FragmentOffset), ?UINT24(FragmentLength),
+ Body:FragmentLength/binary, Rest/binary>>,
+ HsState0) ->
case reassemble_dtls_fragment(SeqNo, Type, Length, MessageSeq,
- FragmentOffset, FragmentLength,
- Body, HsState0) of
- {retransmit, HsState1} ->
- case Rest of
- <<>> ->
- {retransmit, HsState1};
- _ ->
- get_dtls_handshake_aux(Version, SeqNo, Rest, HsState1)
- end;
- {HsState1, HighestSeqNo, MsgBody} ->
- HsState2 = dec_dtls_fragment(Version, HighestSeqNo, Type, Length, MessageSeq, MsgBody, HsState1),
- HsState3 = process_dtls_fragments(Version, HsState2),
- get_dtls_handshake_aux(Version, SeqNo, Rest, HsState3);
- HsState2 ->
- HsState3 = process_dtls_fragments(Version, HsState2),
- get_dtls_handshake_aux(Version, SeqNo, Rest, HsState3)
- end;
+ FragmentOffset, FragmentLength,
+ Body, HsState0) of
+ {retransmit, HsState1} ->
+ case Rest of
+ <<>> ->
+ {retransmit, HsState1};
+ _ ->
+ get_dtls_handshake_aux(Version, SeqNo, Rest, HsState1)
+ end;
+ {HsState1, HighestSeqNo, MsgBody} ->
+ HsState2 = dec_dtls_fragment(Version, HighestSeqNo, Type, Length, MessageSeq, MsgBody, HsState1),
+ HsState3 = process_dtls_fragments(Version, HsState2),
+ get_dtls_handshake_aux(Version, SeqNo, Rest, HsState3);
+ HsState2 ->
+ HsState3 = process_dtls_fragments(Version, HsState2),
+ get_dtls_handshake_aux(Version, SeqNo, Rest, HsState3)
+ end;
get_dtls_handshake_aux(_Version, _SeqNo, <<>>, HsState) ->
- {lists:reverse(HsState#dtls_hs_state.completed),
- HsState#dtls_hs_state{completed = []}}.
+ {lists:reverse(HsState#dtls_hs_state.completed),
+ HsState#dtls_hs_state{completed = []}}.
dec_dtls_fragment(Version, SeqNo, Type, Length, MessageSeq, MsgBody,
- HsState = #dtls_hs_state{highest_record_seq = HighestSeqNo, completed = Acc}) ->
+ HsState = #dtls_hs_state{highest_record_seq = HighestSeqNo, completed = Acc}) ->
Raw = <<?BYTE(Type), ?UINT24(Length), ?UINT16(MessageSeq), ?UINT24(0), ?UINT24(Length), MsgBody/binary>>,
H = decode_handshake(Version, Type, MsgBody),
HsState#dtls_hs_state{completed = [{H,Raw}|Acc], highest_record_seq = erlang:max(HighestSeqNo, SeqNo)}.
process_dtls_fragments(Version,
- HsState0 = #dtls_hs_state{current_read_seq = CurrentReadSeq,
- fragments = Fragments0}) ->
+ HsState0 = #dtls_hs_state{current_read_seq = CurrentReadSeq,
+ fragments = Fragments0}) ->
case gb_trees:is_empty(Fragments0) of
- true ->
- HsState0;
- _ ->
- case gb_trees:smallest(Fragments0) of
- {CurrentReadSeq, {SeqNo, Type, Length, CurrentReadSeq, {Length, [{0, Length}], MsgBody}}} ->
- HsState1 = dtls_hs_state_process_seq(HsState0),
- HsState2 = dec_dtls_fragment(Version, SeqNo, Type, Length, CurrentReadSeq, MsgBody, HsState1),
- process_dtls_fragments(Version, HsState2);
- _ ->
- HsState0
- end
- end.
+ true ->
+ HsState0;
+ _ ->
+ case gb_trees:smallest(Fragments0) of
+ {CurrentReadSeq, {SeqNo, Type, Length, CurrentReadSeq, {Length, [{0, Length}], MsgBody}}} ->
+ HsState1 = dtls_hs_state_process_seq(HsState0),
+ HsState2 = dec_dtls_fragment(Version, SeqNo, Type, Length, CurrentReadSeq, MsgBody, HsState1),
+ process_dtls_fragments(Version, HsState2);
+ _ ->
+ HsState0
+ end
+ end.
dtls_hs_state_process_seq(HsState0 = #dtls_hs_state{current_read_seq = CurrentReadSeq,
- fragments = Fragments0}) ->
+ fragments = Fragments0}) ->
Fragments1 = gb_trees:delete_any(CurrentReadSeq, Fragments0),
HsState0#dtls_hs_state{current_read_seq = CurrentReadSeq + 1,
- fragments = Fragments1}.
+ fragments = Fragments1}.
dtls_hs_state_add_fragment(MessageSeq, Fragment, HsState0 = #dtls_hs_state{fragments = Fragments0}) ->
Fragments1 = gb_trees:enter(MessageSeq, Fragment, Fragments0),
HsState0#dtls_hs_state{fragments = Fragments1}.
reassemble_dtls_fragment(SeqNo, Type, Length, MessageSeq, 0, Length,
- Body, HsState0 = #dtls_hs_state{current_read_seq = undefined})
+ Body, HsState0 = #dtls_hs_state{current_read_seq = undefined})
when Type == ?CLIENT_HELLO;
Type == ?SERVER_HELLO;
- Type == ?HELLO_VERIFY_REQUEST ->
+ Type == ?HELLO_VERIFY_REQUEST ->
%% First message, should be client hello
%% return the current message and set the next expected Sequence
%%
@@ -245,8 +283,8 @@ reassemble_dtls_fragment(_SeqNo, _Type, Length, _MessageSeq, _, Length,
HsState;
reassemble_dtls_fragment(SeqNo, _Type, Length, MessageSeq, 0, Length,
- Body, HsState0 =
- #dtls_hs_state{starting_read_seq = StartingReadSeq})
+ Body, HsState0 =
+ #dtls_hs_state{starting_read_seq = StartingReadSeq})
when MessageSeq < StartingReadSeq ->
%% this has to be the start of a new flight, let it through
%%
@@ -257,69 +295,69 @@ reassemble_dtls_fragment(SeqNo, _Type, Length, MessageSeq, 0, Length,
{HsState, SeqNo, Body};
reassemble_dtls_fragment(_SeqNo, _Type, Length, MessageSeq, 0, Length,
- _Body, HsState =
- #dtls_hs_state{current_read_seq = CurrentReadSeq})
+ _Body, HsState =
+ #dtls_hs_state{current_read_seq = CurrentReadSeq})
when MessageSeq < CurrentReadSeq ->
{retransmit, HsState};
reassemble_dtls_fragment(_SeqNo, _Type, Length, MessageSeq, 0, Length,
- _Body, HsState = #dtls_hs_state{current_read_seq = CurrentReadSeq})
+ _Body, HsState = #dtls_hs_state{current_read_seq = CurrentReadSeq})
when MessageSeq < CurrentReadSeq ->
HsState;
reassemble_dtls_fragment(SeqNo, _Type, Length, MessageSeq, 0, Length,
- Body, HsState0 = #dtls_hs_state{current_read_seq = MessageSeq}) ->
+ Body, HsState0 = #dtls_hs_state{current_read_seq = MessageSeq}) ->
%% Message fully contained and it's the current seq
HsState1 = dtls_hs_state_process_seq(HsState0),
{HsState1, SeqNo, Body};
reassemble_dtls_fragment(SeqNo, Type, Length, MessageSeq, 0, Length,
- Body, HsState) ->
+ Body, HsState) ->
%% Message fully contained and it's the NOT the current seq -> buffer
Fragment = {SeqNo, Type, Length, MessageSeq,
- dtls_fragment_init(Length, 0, Length, Body)},
+ dtls_fragment_init(Length, 0, Length, Body)},
dtls_hs_state_add_fragment(MessageSeq, Fragment, HsState);
reassemble_dtls_fragment(_SeqNo, _Type, Length, MessageSeq, FragmentOffset, FragmentLength,
- _Body,
- HsState = #dtls_hs_state{current_read_seq = CurrentReadSeq})
+ _Body,
+ HsState = #dtls_hs_state{current_read_seq = CurrentReadSeq})
when FragmentOffset + FragmentLength == Length andalso MessageSeq == (CurrentReadSeq - 1) ->
{retransmit, HsState};
reassemble_dtls_fragment(_SeqNo, _Type, _Length, MessageSeq, _FragmentOffset, _FragmentLength,
- _Body,
- HsState = #dtls_hs_state{current_read_seq = CurrentReadSeq})
+ _Body,
+ HsState = #dtls_hs_state{current_read_seq = CurrentReadSeq})
when MessageSeq < CurrentReadSeq ->
HsState;
reassemble_dtls_fragment(SeqNo, Type, Length, MessageSeq,
- FragmentOffset, FragmentLength,
- Body,
- HsState = #dtls_hs_state{fragments = Fragments0}) ->
+ FragmentOffset, FragmentLength,
+ Body,
+ HsState = #dtls_hs_state{fragments = Fragments0}) ->
case gb_trees:lookup(MessageSeq, Fragments0) of
- {value, Fragment} ->
- dtls_fragment_reassemble(SeqNo, Type, Length, MessageSeq,
- FragmentOffset, FragmentLength,
- Body, Fragment, HsState);
- none ->
- dtls_fragment_start(SeqNo, Type, Length, MessageSeq,
- FragmentOffset, FragmentLength,
- Body, HsState)
+ {value, Fragment} ->
+ dtls_fragment_reassemble(SeqNo, Type, Length, MessageSeq,
+ FragmentOffset, FragmentLength,
+ Body, Fragment, HsState);
+ none ->
+ dtls_fragment_start(SeqNo, Type, Length, MessageSeq,
+ FragmentOffset, FragmentLength,
+ Body, HsState)
end.
dtls_fragment_start(SeqNo, Type, Length, MessageSeq,
- FragmentOffset, FragmentLength,
- Body, HsState = #dtls_hs_state{fragments = Fragments0}) ->
+ FragmentOffset, FragmentLength,
+ Body, HsState = #dtls_hs_state{fragments = Fragments0}) ->
Fragment = {SeqNo, Type, Length, MessageSeq,
- dtls_fragment_init(Length, FragmentOffset, FragmentLength, Body)},
- Fragments1 = gb_trees:insert(MessageSeq, Fragment, Fragments0),
+ dtls_fragment_init(Length, FragmentOffset, FragmentLength, Body)},
+ Fragments1 = gb_trees:insert(MessageSeq, Fragment, Fragments0),
HsState#dtls_hs_state{fragments = Fragments1}.
dtls_fragment_reassemble(SeqNo, Type, Length, MessageSeq,
FragmentOffset, FragmentLength,
- Body,
- {LastSeqNo, Type, Length, MessageSeq, FragBuffer0},
- HsState = #dtls_hs_state{fragments = Fragments0}) ->
+ Body,
+ {LastSeqNo, Type, Length, MessageSeq, FragBuffer0},
+ HsState = #dtls_hs_state{fragments = Fragments0}) ->
FragBuffer1 = dtls_fragment_add(FragBuffer0, FragmentOffset, FragmentLength, Body),
Fragment = {erlang:max(SeqNo, LastSeqNo), Type, Length, MessageSeq, FragBuffer1},
Fragments1 = gb_trees:enter(MessageSeq, Fragment, Fragments0),
@@ -328,8 +366,8 @@ dtls_fragment_reassemble(SeqNo, Type, Length, MessageSeq,
%% Type, Length or Seq mismatch, drop everything...
%% Note: the RFC is not clear on how to handle this...
dtls_fragment_reassemble(_SeqNo, _Type, _Length, MessageSeq,
- _FragmentOffset, _FragmentLength, _Body, _Fragment,
- HsState = #dtls_hs_state{fragments = Fragments0}) ->
+ _FragmentOffset, _FragmentLength, _Body, _Fragment,
+ HsState = #dtls_hs_state{fragments = Fragments0}) ->
Fragments1 = gb_trees:delete_any(MessageSeq, Fragments0),
HsState#dtls_hs_state{fragments = Fragments1}.
@@ -360,7 +398,7 @@ merge_fragment_list(Rest = [{HStart, _HEnd}|_], Frag = {_FStart, FEnd}, Acc)
lists:reverse(Acc) ++ [Frag|Rest];
merge_fragment_list([{HStart, HEnd}|Rest], _Frag = {FStart, FEnd}, Acc)
- when
+ when
FStart =< HEnd orelse FEnd >= HStart ->
Start = erlang:min(HStart, FStart),
End = erlang:max(HEnd, FEnd),
@@ -370,20 +408,20 @@ merge_fragment_list([{HStart, HEnd}|Rest], _Frag = {FStart, FEnd}, Acc)
add_fragment(List, {FragmentOffset, FragmentLength}) ->
merge_fragment_list(List, {FragmentOffset, FragmentOffset + FragmentLength}, []).
-enc_hs(#hello_verify_request{protocol_version = {Major, Minor},
- cookie = Cookie}, _Version) ->
- CookieLength = byte_size(Cookie),
+enc_handshake(#hello_verify_request{protocol_version = {Major, Minor},
+ cookie = Cookie}, _Version) ->
+ CookieLength = byte_size(Cookie),
{?HELLO_VERIFY_REQUEST, <<?BYTE(Major), ?BYTE(Minor),
- ?BYTE(CookieLength),
- Cookie/binary>>};
-
-enc_hs(#client_hello{client_version = {Major, Minor},
- random = Random,
- session_id = SessionID,
- cookie = Cookie,
- cipher_suites = CipherSuites,
- compression_methods = CompMethods,
- extensions = HelloExtensions}, Version) ->
+ ?BYTE(CookieLength),
+ Cookie/binary>>};
+
+enc_handshake(#client_hello{client_version = {Major, Minor},
+ random = Random,
+ session_id = SessionID,
+ cookie = Cookie,
+ cipher_suites = CipherSuites,
+ compression_methods = CompMethods,
+ extensions = HelloExtensions}, Version) ->
SIDLength = byte_size(SessionID),
BinCookie = enc_client_hello_cookie(Version, Cookie),
BinCompMethods = list_to_binary(CompMethods),
@@ -391,13 +429,13 @@ enc_hs(#client_hello{client_version = {Major, Minor},
BinCipherSuites = list_to_binary(CipherSuites),
CsLength = byte_size(BinCipherSuites),
ExtensionsBin = ssl_handshake:encode_hello_extensions(HelloExtensions),
-
+
{?CLIENT_HELLO, <<?BYTE(Major), ?BYTE(Minor), Random:32/binary,
- ?BYTE(SIDLength), SessionID/binary,
- BinCookie/binary,
- ?UINT16(CsLength), BinCipherSuites/binary,
- ?BYTE(CmLength), BinCompMethods/binary, ExtensionsBin/binary>>};
-enc_hs(HandshakeMsg, Version) ->
+ ?BYTE(SIDLength), SessionID/binary,
+ BinCookie/binary,
+ ?UINT16(CsLength), BinCipherSuites/binary,
+ ?BYTE(CmLength), BinCompMethods/binary, ExtensionsBin/binary>>};
+enc_handshake(HandshakeMsg, Version) ->
ssl_handshake:encode_handshake(HandshakeMsg, Version).
enc_client_hello_cookie(_, <<>>) ->
@@ -407,26 +445,26 @@ enc_client_hello_cookie(_, Cookie) ->
<<?BYTE(CookieLength), Cookie/binary>>.
decode_handshake(_Version, ?CLIENT_HELLO, <<?BYTE(Major), ?BYTE(Minor), Random:32/binary,
- ?BYTE(SID_length), Session_ID:SID_length/binary,
- ?BYTE(Cookie_length), Cookie:Cookie_length/binary,
- ?UINT16(Cs_length), CipherSuites:Cs_length/binary,
- ?BYTE(Cm_length), Comp_methods:Cm_length/binary,
- Extensions/binary>>) ->
-
+ ?BYTE(SID_length), Session_ID:SID_length/binary,
+ ?BYTE(Cookie_length), Cookie:Cookie_length/binary,
+ ?UINT16(Cs_length), CipherSuites:Cs_length/binary,
+ ?BYTE(Cm_length), Comp_methods:Cm_length/binary,
+ Extensions/binary>>) ->
+
DecodedExtensions = ssl_handshake:decode_hello_extensions(Extensions),
-
+
#client_hello{
client_version = {Major,Minor},
random = Random,
- session_id = Session_ID,
+ session_id = Session_ID,
cookie = Cookie,
cipher_suites = ssl_handshake:decode_suites('2_bytes', CipherSuites),
compression_methods = Comp_methods,
extensions = DecodedExtensions
- };
+ };
decode_handshake(_Version, ?HELLO_VERIFY_REQUEST, <<?BYTE(Major), ?BYTE(Minor),
- ?BYTE(CookieLength), Cookie:CookieLength/binary>>) ->
+ ?BYTE(CookieLength), Cookie:CookieLength/binary>>) ->
#hello_verify_request{
protocol_version = {Major,Minor},
@@ -434,7 +472,7 @@ decode_handshake(_Version, ?HELLO_VERIFY_REQUEST, <<?BYTE(Major), ?BYTE(Minor),
decode_handshake(Version, Tag, Msg) ->
ssl_handshake:decode_handshake(Version, Tag, Msg).
-address_to_bin({A,B,C,D}, Port) ->
- <<0:80,16#ffff:16,A,B,C,D,Port:16>>;
-address_to_bin({A,B,C,D,E,F,G,H}, Port) ->
- <<A:16,B:16,C:16,D:16,E:16,F:16,G:16,H:16,Port:16>>.
+%% address_to_bin({A,B,C,D}, Port) ->
+%% <<0:80,16#ffff:16,A,B,C,D,Port:16>>;
+%% address_to_bin({A,B,C,D,E,F,G,H}, Port) ->
+%% <<A:16,B:16,C:16,D:16,E:16,F:16,G:16,H:16,Port:16>>.
diff --git a/lib/ssl/src/dtls_handshake.hrl b/lib/ssl/src/dtls_handshake.hrl
index 5bdf45f627..3b57575b6d 100644
--- a/lib/ssl/src/dtls_handshake.hrl
+++ b/lib/ssl/src/dtls_handshake.hrl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2013-2013. All Rights Reserved.
+%% Copyright Ericsson AB 2013-2014. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -53,6 +53,4 @@
completed
}).
--type dtls_handshake() :: #client_hello{} | #hello_verify_request{} | ssl_handshake().
-
-endif. % -ifdef(dtls_handshake).
diff --git a/lib/ssl/src/dtls_record.erl b/lib/ssl/src/dtls_record.erl
index b0a7976864..a7bbb6bc40 100644
--- a/lib/ssl/src/dtls_record.erl
+++ b/lib/ssl/src/dtls_record.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2013-2013. All Rights Reserved.
+%% Copyright Ericsson AB 2013-2014. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -35,7 +35,7 @@
-export([decode_cipher_text/2]).
%% Encoding
--export([encode_plain_text/4]).
+-export([encode_plain_text/4, encode_handshake/3, encode_change_cipher_spec/2]).
%% Protocol version handling
-export([protocol_version/1, lowest_protocol_version/2,
@@ -46,6 +46,11 @@
-export([init_connection_state_seq/2, current_connection_state_epoch/2,
set_connection_state_by_epoch/3, connection_state_by_epoch/3]).
+-export_type([dtls_version/0, dtls_atom_version/0]).
+
+-type dtls_version() :: ssl_record:ssl_version().
+-type dtls_atom_version() :: dtlsv1 | 'dtlsv1.2'.
+
-compile(inline).
%%====================================================================
@@ -70,7 +75,7 @@ get_dtls_records_aux(<<?BYTE(?APPLICATION_DATA),?BYTE(MajVer),?BYTE(MinVer),
Acc) ->
get_dtls_records_aux(Rest, [#ssl_tls{type = ?APPLICATION_DATA,
version = {MajVer, MinVer},
- epoch = Epoch, record_seq = SequenceNumber,
+ epoch = Epoch, sequence_number = SequenceNumber,
fragment = Data} | Acc]);
get_dtls_records_aux(<<?BYTE(?HANDSHAKE),?BYTE(MajVer),?BYTE(MinVer),
?UINT16(Epoch), ?UINT48(SequenceNumber),
@@ -78,7 +83,7 @@ get_dtls_records_aux(<<?BYTE(?HANDSHAKE),?BYTE(MajVer),?BYTE(MinVer),
Data:Length/binary, Rest/binary>>, Acc) when MajVer >= 128 ->
get_dtls_records_aux(Rest, [#ssl_tls{type = ?HANDSHAKE,
version = {MajVer, MinVer},
- epoch = Epoch, record_seq = SequenceNumber,
+ epoch = Epoch, sequence_number = SequenceNumber,
fragment = Data} | Acc]);
get_dtls_records_aux(<<?BYTE(?ALERT),?BYTE(MajVer),?BYTE(MinVer),
?UINT16(Epoch), ?UINT48(SequenceNumber),
@@ -86,7 +91,7 @@ get_dtls_records_aux(<<?BYTE(?ALERT),?BYTE(MajVer),?BYTE(MinVer),
Rest/binary>>, Acc) ->
get_dtls_records_aux(Rest, [#ssl_tls{type = ?ALERT,
version = {MajVer, MinVer},
- epoch = Epoch, record_seq = SequenceNumber,
+ epoch = Epoch, sequence_number = SequenceNumber,
fragment = Data} | Acc]);
get_dtls_records_aux(<<?BYTE(?CHANGE_CIPHER_SPEC),?BYTE(MajVer),?BYTE(MinVer),
?UINT16(Epoch), ?UINT48(SequenceNumber),
@@ -94,7 +99,7 @@ get_dtls_records_aux(<<?BYTE(?CHANGE_CIPHER_SPEC),?BYTE(MajVer),?BYTE(MinVer),
Acc) ->
get_dtls_records_aux(Rest, [#ssl_tls{type = ?CHANGE_CIPHER_SPEC,
version = {MajVer, MinVer},
- epoch = Epoch, record_seq = SequenceNumber,
+ epoch = Epoch, sequence_number = SequenceNumber,
fragment = Data} | Acc]);
get_dtls_records_aux(<<0:1, _CT:7, ?BYTE(_MajVer), ?BYTE(_MinVer),
@@ -125,14 +130,15 @@ encode_plain_text(Type, Version, Data,
{Comp, CompS1} = ssl_record:compress(CompAlg, Data, CompS0),
WriteState1 = WriteState0#connection_state{compression_state = CompS1},
MacHash = calc_mac_hash(WriteState1, Type, Version, Epoch, Seq, Comp),
- {CipherFragment, WriteState} = ssl_record:cipher(Version, Comp, WriteState1, MacHash),
+ {CipherFragment, WriteState} = ssl_record:cipher(dtls_v1:corresponding_tls_version(Version),
+ Comp, WriteState1, MacHash),
CipherText = encode_tls_cipher_text(Type, Version, Epoch, Seq, CipherFragment),
{CipherText, ConnectionStates#connection_states{current_write =
WriteState#connection_state{sequence_number = Seq +1}}}.
decode_cipher_text(#ssl_tls{type = Type, version = Version,
epoch = Epoch,
- record_seq = Seq,
+ sequence_number = Seq,
fragment = CipherFragment} = CipherText,
#connection_states{current_read =
#connection_state{compression_state = CompressionS0,
@@ -141,7 +147,7 @@ decode_cipher_text(#ssl_tls{type = Type, version = Version,
CompressAlg = SecParams#security_parameters.compression_algorithm,
{PlainFragment, Mac, ReadState1} = ssl_record:decipher(dtls_v1:corresponding_tls_version(Version),
CipherFragment, ReadState0),
- MacHash = calc_mac_hash(Type, Version, Epoch, Seq, PlainFragment, ReadState1),
+ MacHash = calc_mac_hash(ReadState1, Type, Version, Epoch, Seq, PlainFragment),
case ssl_record:is_correct_mac(Mac, MacHash) of
true ->
{Plain, CompressionS1} = ssl_record:uncompress(CompressAlg,
@@ -153,10 +159,27 @@ decode_cipher_text(#ssl_tls{type = Type, version = Version,
false ->
?ALERT_REC(?FATAL, ?BAD_RECORD_MAC)
end.
+%%--------------------------------------------------------------------
+-spec encode_handshake(iolist(), dtls_version(), #connection_states{}) ->
+ {iolist(), #connection_states{}}.
+%%
+%% Description: Encodes a handshake message to send on the ssl-socket.
+%%--------------------------------------------------------------------
+encode_handshake(Frag, Version, ConnectionStates) ->
+ encode_plain_text(?HANDSHAKE, Version, Frag, ConnectionStates).
+
+%%--------------------------------------------------------------------
+-spec encode_change_cipher_spec(dtls_version(), #connection_states{}) ->
+ {iolist(), #connection_states{}}.
+%%
+%% Description: Encodes a change_cipher_spec-message to send on the ssl socket.
+%%--------------------------------------------------------------------
+encode_change_cipher_spec(Version, ConnectionStates) ->
+ encode_plain_text(?CHANGE_CIPHER_SPEC, Version, <<1:8>>, ConnectionStates).
%%--------------------------------------------------------------------
--spec protocol_version(tls_atom_version() | tls_version()) ->
- tls_version() | tls_atom_version().
+-spec protocol_version(dtls_atom_version() | dtls_version()) ->
+ dtls_version() | dtls_atom_version().
%%
%% Description: Creates a protocol version record from a version atom
%% or vice versa.
@@ -170,7 +193,7 @@ protocol_version({254, 253}) ->
protocol_version({254, 255}) ->
dtlsv1.
%%--------------------------------------------------------------------
--spec lowest_protocol_version(tls_version(), tls_version()) -> tls_version().
+-spec lowest_protocol_version(dtls_version(), dtls_version()) -> dtls_version().
%%
%% Description: Lowes protocol version of two given versions
%%--------------------------------------------------------------------
@@ -183,7 +206,7 @@ lowest_protocol_version(Version = {M,_}, {N, _}) when M > N ->
lowest_protocol_version(_,Version) ->
Version.
%%--------------------------------------------------------------------
--spec highest_protocol_version([tls_version()]) -> tls_version().
+-spec highest_protocol_version([dtls_version()]) -> dtls_version().
%%
%% Description: Highest protocol version present in a list
%%--------------------------------------------------------------------
@@ -203,7 +226,7 @@ highest_protocol_version(_, [Version | Rest]) ->
%%--------------------------------------------------------------------
--spec supported_protocol_versions() -> [tls_version()].
+-spec supported_protocol_versions() -> [dtls_version()].
%%
%% Description: Protocol versions supported
%%--------------------------------------------------------------------
@@ -234,7 +257,7 @@ supported_connection_protocol_versions([]) ->
?ALL_DATAGRAM_SUPPORTED_VERSIONS.
%%--------------------------------------------------------------------
--spec is_acceptable_version(tls_version(), Supported :: [tls_version()]) -> boolean().
+-spec is_acceptable_version(dtls_version(), Supported :: [dtls_version()]) -> boolean().
%%
%% Description: ssl version 2 is not acceptable security risks are too big.
%%
@@ -244,7 +267,7 @@ is_acceptable_version(Version, Versions) ->
%%--------------------------------------------------------------------
--spec init_connection_state_seq(tls_version(), #connection_states{}) ->
+-spec init_connection_state_seq(dtls_version(), #connection_states{}) ->
#connection_state{}.
%%
%% Description: Copy the read sequence number to the write sequence number
@@ -343,5 +366,5 @@ calc_mac_hash(#connection_state{mac_secret = MacSecret,
Length, Fragment).
mac_hash(Version, MacAlg, MacSecret, SeqNo, Type, Length, Fragment) ->
- dtls_v1:mac_hash(MacAlg, MacSecret, SeqNo, Type, Version,
+ dtls_v1:mac_hash(Version, MacAlg, MacSecret, SeqNo, Type,
Length, Fragment).
diff --git a/lib/ssl/src/dtls_record.hrl b/lib/ssl/src/dtls_record.hrl
index e935d84bdf..edb77fb2b1 100644
--- a/lib/ssl/src/dtls_record.hrl
+++ b/lib/ssl/src/dtls_record.hrl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2013-2013. All Rights Reserved.
+%% Copyright Ericsson AB 2013-2014. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -28,16 +28,15 @@
-include("ssl_record.hrl"). %% Common TLS and DTLS records and Constantes
-%% Used to handle tls_plain_text, tls_compressed and tls_cipher_text
+%% Used to handle dtls_plain_text, dtls_compressed and dtls_cipher_text
-record(ssl_tls, {
type,
version,
- record_seq, % used in plain_text
- epoch, % used in plain_text
- message_seq,
- fragment_offset,
- fragment_length,
+ epoch,
+ sequence_number,
+ offset,
+ length,
fragment
}).
diff --git a/lib/ssl/src/dtls_v1.erl b/lib/ssl/src/dtls_v1.erl
index 6e41641483..5a7ab32887 100644
--- a/lib/ssl/src/dtls_v1.erl
+++ b/lib/ssl/src/dtls_v1.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2013-2013. All Rights Reserved.
+%% Copyright Ericsson AB 2013-2014. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -22,7 +22,7 @@
-export([suites/1, mac_hash/7, ecc_curves/1, corresponding_tls_version/1]).
--spec suites(Minor:: 253|255) -> [cipher_suite()].
+-spec suites(Minor:: 253|255) -> [ssl_cipher:cipher_suite()].
suites(Minor) ->
tls_v1:suites(corresponding_minor_tls_version(Minor)).
diff --git a/lib/ssl/src/ssl.app.src b/lib/ssl/src/ssl.app.src
index 68ebc49e4a..99839f6149 100644
--- a/lib/ssl/src/ssl.app.src
+++ b/lib/ssl/src/ssl.app.src
@@ -47,6 +47,8 @@
{registered, [ssl_sup, ssl_manager]},
{applications, [crypto, public_key, kernel, stdlib]},
{env, []},
- {mod, {ssl_app, []}}]}.
+ {mod, {ssl_app, []}},
+ {runtime_dependencies, ["stdlib-2.0","public_key-0.22","kernel-3.0",
+ "erts-6.0","crypto-3.3"]}]}.
diff --git a/lib/ssl/src/ssl.erl b/lib/ssl/src/ssl.erl
index 9e098e12c4..743753bf7d 100644
--- a/lib/ssl/src/ssl.erl
+++ b/lib/ssl/src/ssl.erl
@@ -195,7 +195,8 @@ transport_accept(#sslsocket{pid = {ListenSocket,
-spec ssl_accept(#sslsocket{} | port(), timeout()| [ssl_option()
| transport_option()]) ->
ok | {ok, #sslsocket{}} | {error, reason()}.
--spec ssl_accept(port(), [ssl_option()| transport_option()], timeout()) ->
+
+-spec ssl_accept(#sslsocket{} | port(), [ssl_option()] | [ssl_option()| transport_option()], timeout()) ->
{ok, #sslsocket{}} | {error, reason()}.
%%
%% Description: Performs accept on an ssl listen socket. e.i. performs
@@ -210,6 +211,15 @@ ssl_accept(#sslsocket{} = Socket, Timeout) ->
ssl_accept(ListenSocket, SslOptions) when is_port(ListenSocket) ->
ssl_accept(ListenSocket, SslOptions, infinity).
+ssl_accept(#sslsocket{} = Socket, [], Timeout) ->
+ ssl_accept(#sslsocket{} = Socket, Timeout);
+ssl_accept(#sslsocket{} = Socket, SslOptions, Timeout) ->
+ try
+ {ok, #config{ssl = SSL}} = handle_options(SslOptions, server),
+ ssl_connection:handshake(Socket, SSL, Timeout)
+ catch
+ Error = {error, _Reason} -> Error
+ end;
ssl_accept(Socket, SslOptions, Timeout) when is_port(Socket) ->
{Transport,_,_,_} =
proplists:get_value(cb_info, SslOptions, {gen_tcp, tcp, tcp_closed, tcp_error}),
@@ -276,7 +286,7 @@ controlling_process(#sslsocket{pid = {Listen,
Transport:controlling_process(Listen, NewOwner).
%%--------------------------------------------------------------------
--spec connection_info(#sslsocket{}) -> {ok, {tls_atom_version(), erl_cipher_suite()}} |
+-spec connection_info(#sslsocket{}) -> {ok, {tls_record:tls_atom_version(), ssl_cipher:erl_cipher_suite()}} |
{error, reason()}.
%%
%% Description: Returns ssl protocol and cipher used for the connection
@@ -312,7 +322,7 @@ peercert(#sslsocket{pid = {Listen, _}}) when is_port(Listen) ->
{error, enotconn}.
%%--------------------------------------------------------------------
--spec suite_definition(cipher_suite()) -> erl_cipher_suite().
+-spec suite_definition(ssl_cipher:cipher_suite()) -> ssl_cipher:erl_cipher_suite().
%%
%% Description: Return erlang cipher suite definition.
%%--------------------------------------------------------------------
@@ -330,8 +340,8 @@ negotiated_next_protocol(#sslsocket{pid = Pid}) ->
ssl_connection:negotiated_next_protocol(Pid).
%%--------------------------------------------------------------------
--spec cipher_suites() -> [erl_cipher_suite()].
--spec cipher_suites(erlang | openssl | all) -> [erl_cipher_suite()] | [string()].
+-spec cipher_suites() -> [ssl_cipher:erl_cipher_suite()].
+-spec cipher_suites(erlang | openssl | all) -> [ssl_cipher:erl_cipher_suite()] | [string()].
%% Description: Returns all supported cipher suites.
%%--------------------------------------------------------------------
@@ -437,8 +447,8 @@ session_info(#sslsocket{pid = {Listen,_}}) when is_port(Listen) ->
{error, enotconn}.
%%---------------------------------------------------------------
--spec versions() -> [{ssl_app, string()} | {supported, [tls_atom_version()]} |
- {available, [tls_atom_version()]}].
+-spec versions() -> [{ssl_app, string()} | {supported, [tls_record:tls_atom_version()]} |
+ {available, [tls_record:tls_atom_version()]}].
%%
%% Description: Returns a list of relevant versions.
%%--------------------------------------------------------------------
@@ -558,6 +568,8 @@ handle_options(Opts0, _Role) ->
Opts = proplists:expand([{binary, [{mode, binary}]},
{list, [{mode, list}]}], Opts0),
assert_proplist(Opts),
+ RecordCb = record_cb(Opts),
+
ReuseSessionFun = fun(_, _, _, _) -> true end,
DefaultVerifyNoneFun =
@@ -600,12 +612,14 @@ handle_options(Opts0, _Role) ->
end,
CertFile = handle_option(certfile, Opts, <<>>),
-
+
+ RecordCb = record_cb(Opts),
+
Versions = case handle_option(versions, Opts, []) of
[] ->
- tls_record:supported_protocol_versions();
+ RecordCb:supported_protocol_versions();
Vsns ->
- [tls_record:protocol_version(Vsn) || Vsn <- Vsns]
+ [RecordCb:protocol_version(Vsn) || Vsn <- Vsns]
end,
SSLOptions = #ssl_options{
@@ -1035,6 +1049,13 @@ connection_cb(dtls) ->
connection_cb(Opts) ->
connection_cb(proplists:get_value(protocol, Opts, tls)).
+record_cb(tls) ->
+ tls_record;
+record_cb(dtls) ->
+ dtls_record;
+record_cb(Opts) ->
+ record_cb(proplists:get_value(protocol, Opts, tls)).
+
connection_sup(tls_connection) ->
tls_connection_sup;
connection_sup(dtls_connection) ->
diff --git a/lib/ssl/src/ssl_alert.erl b/lib/ssl/src/ssl_alert.erl
index 5c842b4d19..db1535b5ec 100644
--- a/lib/ssl/src/ssl_alert.erl
+++ b/lib/ssl/src/ssl_alert.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2007-2013. All Rights Reserved.
+%% Copyright Ericsson AB 2007-2014. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -38,7 +38,7 @@
%%====================================================================
%%--------------------------------------------------------------------
--spec encode(#alert{}, tls_version(), #connection_states{}) ->
+-spec encode(#alert{}, ssl_record:ssl_version(), #connection_states{}) ->
{iolist(), #connection_states{}}.
%%
%% Description:
@@ -124,5 +124,17 @@ description_txt(?USER_CANCELED) ->
"user canceled";
description_txt(?NO_RENEGOTIATION) ->
"no renegotiation";
+description_txt(?UNSUPPORTED_EXTENSION) ->
+ "unsupported extension";
+description_txt(?CERTIFICATE_UNOBTAINABLE) ->
+ "certificate unobtainable";
+description_txt(?UNRECOGNISED_NAME) ->
+ "unrecognised name";
+description_txt(?BAD_CERTIFICATE_STATUS_RESPONSE) ->
+ "bad certificate status response";
+description_txt(?BAD_CERTIFICATE_HASH_VALUE) ->
+ "bad certificate hash value";
description_txt(?UNKNOWN_PSK_IDENTITY) ->
- "unknown psk identity".
+ "unknown psk identity";
+description_txt(Enum) ->
+ lists:flatten(io_lib:format("unsupported/unknown alert: ~p", [Enum])).
diff --git a/lib/ssl/src/ssl_alert.hrl b/lib/ssl/src/ssl_alert.hrl
index 2a8a91aefa..2d1f323085 100644
--- a/lib/ssl/src/ssl_alert.hrl
+++ b/lib/ssl/src/ssl_alert.hrl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2007-2012. All Rights Reserved.
+%% Copyright Ericsson AB 2007-2014. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -48,7 +48,7 @@
%% unsupported_certificate(43),
%% certificate_revoked(44),
%% certificate_expired(45),
- %% certificate_unknown(46),
+%% certificate_unknown(46),
%% illegal_parameter(47),
%% unknown_ca(48),
%% access_denied(49),
@@ -60,6 +60,13 @@
%% internal_error(80),
%% user_canceled(90),
%% no_renegotiation(100),
+%% RFC 4366
+%% unsupported_extension(110),
+%% certificate_unobtainable(111),
+%% unrecognized_name(112),
+%% bad_certificate_status_response(113),
+%% bad_certificate_hash_value(114),
+%% RFC 4366
%% unknown_psk_identity(115),
%% (255)
%% } AlertDescription;
@@ -88,6 +95,11 @@
-define(INTERNAL_ERROR, 80).
-define(USER_CANCELED, 90).
-define(NO_RENEGOTIATION, 100).
+-define(UNSUPPORTED_EXTENSION, 110).
+-define(CERTIFICATE_UNOBTAINABLE, 111).
+-define(UNRECOGNISED_NAME, 112).
+-define(BAD_CERTIFICATE_STATUS_RESPONSE, 113).
+-define(BAD_CERTIFICATE_HASH_VALUE, 114).
-define(UNKNOWN_PSK_IDENTITY, 115).
-define(ALERT_REC(Level,Desc), #alert{level=Level,description=Desc,where={?FILE, ?LINE}}).
diff --git a/lib/ssl/src/ssl_api.hrl b/lib/ssl/src/ssl_api.hrl
index 607991750f..22185ff60a 100644
--- a/lib/ssl/src/ssl_api.hrl
+++ b/lib/ssl/src/ssl_api.hrl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2013-2013. All Rights Reserved.
+%% Copyright Ericsson AB 2013-2014. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -24,8 +24,6 @@
%% Visible in API
-export_type([connect_option/0, listen_option/0, ssl_option/0, transport_option/0,
- erl_cipher_suite/0, %% From ssl_cipher.hrl
- tls_atom_version/0, %% From ssl_internal.hrl
prf_random/0, sslsocket/0]).
@@ -39,23 +37,24 @@
-type listen_option() :: socket_listen_option() | ssl_option() | transport_option().
-type socket_listen_option() :: gen_tcp:listen_option().
--type ssl_option() :: {verify, verify_type()} |
- {verify_fun, {fun(), InitialUserState::term()}} |
- {fail_if_no_peer_cert, boolean()} | {depth, integer()} |
- {cert, Der::binary()} | {certfile, path()} | {key, Der::binary()} |
- {keyfile, path()} | {password, string()} | {cacerts, [Der::binary()]} |
- {cacertfile, path()} | {dh, Der::binary()} | {dhfile, path()} |
- {user_lookup_fun, {fun(), InitialUserState::term()}} |
- {psk_identity, string()} |
- {srp_identity, {string(), string()}} |
- {ciphers, ciphers()} | {ssl_imp, ssl_imp()} | {reuse_sessions, boolean()} |
- {reuse_session, fun()} | {hibernate_after, integer()|undefined} |
- {next_protocols_advertised, list(binary())} |
- {client_preferred_next_protocols, binary(), client | server, list(binary())}.
+-type ssl_option() :: {versions, ssl_record:ssl_atom_version()} |
+ {verify, verify_type()} |
+ {verify_fun, {fun(), InitialUserState::term()}} |
+ {fail_if_no_peer_cert, boolean()} | {depth, integer()} |
+ {cert, Der::binary()} | {certfile, path()} | {key, Der::binary()} |
+ {keyfile, path()} | {password, string()} | {cacerts, [Der::binary()]} |
+ {cacertfile, path()} | {dh, Der::binary()} | {dhfile, path()} |
+ {user_lookup_fun, {fun(), InitialUserState::term()}} |
+ {psk_identity, string()} |
+ {srp_identity, {string(), string()}} |
+ {ciphers, ciphers()} | {ssl_imp, ssl_imp()} | {reuse_sessions, boolean()} |
+ {reuse_session, fun()} | {hibernate_after, integer()|undefined} |
+ {next_protocols_advertised, list(binary())} |
+ {client_preferred_next_protocols, binary(), client | server, list(binary())}.
-type verify_type() :: verify_none | verify_peer.
-type path() :: string().
--type ciphers() :: [erl_cipher_suite()] |
+-type ciphers() :: [ssl_cipher:erl_cipher_suite()] |
string(). % (according to old API)
-type ssl_imp() :: new | old.
diff --git a/lib/ssl/src/ssl_cipher.erl b/lib/ssl/src/ssl_cipher.erl
index b2077c662a..78a328ace8 100644
--- a/lib/ssl/src/ssl_cipher.erl
+++ b/lib/ssl/src/ssl_cipher.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2007-2013. All Rights Reserved.
+%% Copyright Ericsson AB 2007-2014. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -38,6 +38,21 @@
openssl_suite/1, openssl_suite_name/1, filter/2, filter_suites/1,
hash_algorithm/1, sign_algorithm/1, is_acceptable_hash/2]).
+-export_type([cipher_suite/0,
+ erl_cipher_suite/0, openssl_cipher_suite/0,
+ key_algo/0]).
+
+-type cipher() :: null |rc4_128 | idea_cbc | des40_cbc | des_cbc | '3des_ede_cbc'
+ | aes_128_cbc | aes_256_cbc.
+-type hash() :: null | sha | md5 | sha224 | sha256 | sha384 | sha512.
+-type key_algo() :: null | rsa | dhe_rsa | dhe_dss | ecdhe_ecdsa| ecdh_ecdsa | ecdh_rsa| srp_rsa| srp_dss | psk | dhe_psk | rsa_psk | dh_anon | ecdh_anon | srp_anon.
+-type erl_cipher_suite() :: {key_algo(), cipher(), hash()}.
+-type int_cipher_suite() :: {key_algo(), cipher(), hash(), hash() | default_prf}.
+-type cipher_suite() :: binary().
+-type cipher_enum() :: integer().
+-type openssl_cipher_suite() :: string().
+
+
-compile(inline).
%%--------------------------------------------------------------------
@@ -51,7 +66,7 @@ security_parameters(?TLS_NULL_WITH_NULL_NULL = CipherSuite, SecParams) ->
security_parameters(undefined, CipherSuite, SecParams).
%%--------------------------------------------------------------------
--spec security_parameters(tls_version() | undefined, cipher_suite(), #security_parameters{}) ->
+-spec security_parameters(ssl_record:ssl_version() | undefined, cipher_suite(), #security_parameters{}) ->
#security_parameters{}.
%%
%% Description: Returns a security parameters record where the
@@ -72,7 +87,7 @@ security_parameters(Version, CipherSuite, SecParams) ->
hash_size = hash_size(Hash)}.
%%--------------------------------------------------------------------
--spec cipher(cipher_enum(), #cipher_state{}, binary(), iolist(), tls_version()) ->
+-spec cipher(cipher_enum(), #cipher_state{}, binary(), iodata(), ssl_record:ssl_version()) ->
{binary(), #cipher_state{}}.
%%
%% Description: Encrypts the data and the MAC using chipher described
@@ -127,7 +142,7 @@ block_cipher(Fun, BlockSz, #cipher_state{key=Key, iv=IV} = CS0,
{T, CS0#cipher_state{iv=NextIV}}.
%%--------------------------------------------------------------------
--spec decipher(cipher_enum(), integer(), #cipher_state{}, binary(), tls_version()) ->
+-spec decipher(cipher_enum(), integer(), #cipher_state{}, binary(), ssl_record:ssl_version()) ->
{binary(), binary(), #cipher_state{}} | #alert{}.
%%
%% Description: Decrypts the data and the MAC using cipher described
@@ -200,7 +215,7 @@ block_decipher(Fun, #cipher_state{key=Key, iv=IV} = CipherState0,
?ALERT_REC(?FATAL, ?BAD_RECORD_MAC)
end.
%%--------------------------------------------------------------------
--spec suites(tls_version()) -> [cipher_suite()].
+-spec suites(ssl_record:ssl_version()) -> [cipher_suite()].
%%
%% Description: Returns a list of supported cipher suites.
%%--------------------------------------------------------------------
@@ -229,7 +244,7 @@ anonymous_suites() ->
?TLS_ECDH_anon_WITH_AES_256_CBC_SHA].
%%--------------------------------------------------------------------
--spec psk_suites(tls_version() | integer()) -> [cipher_suite()].
+-spec psk_suites(ssl_record:ssl_version() | integer()) -> [cipher_suite()].
%%
%% Description: Returns a list of the PSK cipher suites, only supported
%% if explicitly set by user.
diff --git a/lib/ssl/src/ssl_cipher.hrl b/lib/ssl/src/ssl_cipher.hrl
index 62a5269def..3ce9c19aa9 100644
--- a/lib/ssl/src/ssl_cipher.hrl
+++ b/lib/ssl/src/ssl_cipher.hrl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2007-2013. All Rights Reserved.
+%% Copyright Ericsson AB 2007-2014. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -26,16 +26,6 @@
-ifndef(ssl_cipher).
-define(ssl_cipher, true).
--type cipher() :: null |rc4_128 | idea_cbc | des40_cbc | des_cbc | '3des_ede_cbc'
- | aes_128_cbc | aes_256_cbc.
--type hash() :: null | sha | md5 | sha224 | sha256 | sha384 | sha512.
--type key_algo() :: null | rsa | dhe_rsa | dhe_dss | ecdhe_ecdsa| ecdh_ecdsa | ecdh_rsa| srp_rsa| srp_dss | psk | dhe_psk | rsa_psk | dh_anon | ecdh_anon | srp_anon.
--type erl_cipher_suite() :: {key_algo(), cipher(), hash()}.
--type int_cipher_suite() :: {key_algo(), cipher(), hash(), hash() | default_prf}.
--type cipher_suite() :: binary().
--type cipher_enum() :: integer().
--type openssl_cipher_suite() :: string().
-
%%% SSL cipher protocol %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-define(CHANGE_CIPHER_SPEC_PROTO, 1). % _PROTO to not clash with
% SSL record protocol
diff --git a/lib/ssl/src/ssl_connection.erl b/lib/ssl/src/ssl_connection.erl
index e283e6079e..c2810a199f 100644
--- a/lib/ssl/src/ssl_connection.erl
+++ b/lib/ssl/src/ssl_connection.erl
@@ -36,7 +36,7 @@
-include_lib("public_key/include/public_key.hrl").
%% Setup
--export([connect/8, ssl_accept/7, handshake/2,
+-export([connect/8, ssl_accept/7, handshake/2, handshake/3,
socket_control/4]).
%% User Events
@@ -52,6 +52,7 @@
%% SSL all state functions
-export([handle_sync_event/4, handle_info/3, terminate/3]).
+
%%====================================================================
%% Internal application API
%%====================================================================
@@ -99,6 +100,20 @@ handshake(#sslsocket{pid = Pid}, Timeout) ->
Error ->
Error
end.
+
+%%--------------------------------------------------------------------
+-spec handshake(#sslsocket{}, #ssl_options{}, timeout()) -> ok | {error, reason()}.
+%%
+%% Description: Starts ssl handshake with some new options
+%%--------------------------------------------------------------------
+handshake(#sslsocket{pid = Pid}, SslOptions, Timeout) ->
+ case sync_send_all_state_event(Pid, {start, SslOptions, Timeout}) of
+ connected ->
+ ok;
+ Error ->
+ Error
+ end.
+
%--------------------------------------------------------------------
-spec socket_control(tls_connection | dtls_connection, port(), pid(), atom()) ->
{ok, #sslsocket{}} | {error, reason()}.
@@ -649,6 +664,10 @@ handle_sync_event({start, Timeout}, StartFrom, StateName, State) ->
{next_state, StateName, State#state{start_or_recv_from = StartFrom,
timer = Timer}, get_timeout(State)};
+handle_sync_event({start, Opts, Timeout}, From, StateName, #state{ssl_options = SslOpts} = State) ->
+ NewOpts = new_ssl_options(Opts, SslOpts),
+ handle_sync_event({start, Timeout}, From, StateName, State#state{ssl_options = NewOpts});
+
handle_sync_event(close, _, StateName, #state{protocol_cb = Connection} = State) ->
%% Run terminate before returning
%% so that the reuseaddr inet-option will work
@@ -1854,3 +1873,14 @@ make_premaster_secret({MajVer, MinVer}, rsa) ->
<<?BYTE(MajVer), ?BYTE(MinVer), Rand/binary>>;
make_premaster_secret(_, _) ->
undefined.
+
+%% One day this can be maps instead, but we have to be backwards compatible for now
+new_ssl_options(New, Old) ->
+ new_ssl_options(tuple_to_list(New), tuple_to_list(Old), []).
+
+new_ssl_options([], [], Acc) ->
+ list_to_tuple(lists:reverse(Acc));
+new_ssl_options([undefined | Rest0], [Head1| Rest1], Acc) ->
+ new_ssl_options(Rest0, Rest1, [Head1 | Acc]);
+new_ssl_options([Head0 | Rest0], [_| Rest1], Acc) ->
+ new_ssl_options(Rest0, Rest1, [Head0 | Acc]).
diff --git a/lib/ssl/src/ssl_connection.hrl b/lib/ssl/src/ssl_connection.hrl
index 341a4217e4..b01c6cb1b3 100644
--- a/lib/ssl/src/ssl_connection.hrl
+++ b/lib/ssl/src/ssl_connection.hrl
@@ -48,17 +48,17 @@
socket_options :: #socket_options{},
connection_states :: #connection_states{},
protocol_buffers :: term(), %% #protocol_buffers{} from tls_record.hrl or dtls_recor.hrl
- tls_handshake_history ::tls_handshake_history(),
+ tls_handshake_history :: ssl_handshake:ssl_handshake_history(),
cert_db :: reference(),
session :: #session{},
session_cache :: db_handle(),
session_cache_cb :: atom(),
- negotiated_version :: tls_version(),
+ negotiated_version :: ssl_record:ssl_version(),
client_certificate_requested = false :: boolean(),
- key_algorithm :: key_algo(),
+ key_algorithm :: ssl_cipher:key_algo(),
hashsign_algorithm = {undefined, undefined},
cert_hashsign_algorithm,
- public_key_info ::public_key_info(),
+ public_key_info ::ssl_handshake:public_key_info(),
private_key ::public_key:private_key(),
diffie_hellman_params, % PKIX: #'DHParameter'{} relevant for server side
diffie_hellman_keys, % {PublicKey, PrivateKey}
diff --git a/lib/ssl/src/ssl_handshake.erl b/lib/ssl/src/ssl_handshake.erl
index 245cd3e280..1108edcf48 100644
--- a/lib/ssl/src/ssl_handshake.erl
+++ b/lib/ssl/src/ssl_handshake.erl
@@ -31,6 +31,18 @@
-include("ssl_srp.hrl").
-include_lib("public_key/include/public_key.hrl").
+-export_type([ssl_handshake/0, ssl_handshake_history/0,
+ public_key_info/0, oid/0]).
+
+-type oid() :: tuple().
+-type public_key_params() :: #'Dss-Parms'{} | {namedCurve, oid()} | #'ECParameters'{} | term().
+-type public_key_info() :: {oid(), #'RSAPublicKey'{} | integer() | #'ECPoint'{}, public_key_params()}.
+-type ssl_handshake_history() :: {[binary()], [binary()]}.
+
+-type ssl_handshake() :: #server_hello{} | #server_hello_done{} | #certificate{} | #certificate_request{} |
+ #client_key_exchange{} | #finished{} | #certificate_verify{} |
+ #hello_request{} | #next_protocol{}.
+
%% Handshake messages
-export([hello_request/0, server_hello/4, server_hello_done/0,
certificate/4, certificate_request/4, key_exchange/3,
@@ -80,7 +92,7 @@ hello_request() ->
#hello_request{}.
%%--------------------------------------------------------------------
--spec server_hello(#session{}, tls_version(), #connection_states{},
+-spec server_hello(#session{}, ssl_record:ssl_version(), #connection_states{},
#hello_extensions{}) -> #server_hello{}.
%%
%% Description: Creates a server hello message.
@@ -164,8 +176,8 @@ next_protocol(SelectedProtocol) ->
%%--------------------------------------------------------------------
-spec client_certificate_verify(undefined | der_cert(), binary(),
- tls_version(), term(), public_key:private_key(),
- tls_handshake_history()) ->
+ ssl_record:ssl_version(), term(), public_key:private_key(),
+ ssl_handshake_history()) ->
#certificate_verify{} | ignore | #alert{}.
%%
%% Description: Creates a certificate_verify message, called by the client.
@@ -188,7 +200,7 @@ client_certificate_verify(OwnCert, MasterSecret, Version,
end.
%%--------------------------------------------------------------------
--spec certificate_request(erl_cipher_suite(), db_handle(), certdb_ref(), tls_version()) ->
+-spec certificate_request(ssl_cipher:erl_cipher_suite(), db_handle(), certdb_ref(), ssl_record:ssl_version()) ->
#certificate_request{}.
%%
%% Description: Creates a certificate_request message, called by the server.
@@ -203,7 +215,7 @@ certificate_request(CipherSuite, CertDbHandle, CertDbRef, Version) ->
certificate_authorities = Authorities
}.
%%--------------------------------------------------------------------
--spec key_exchange(client | server, tls_version(),
+-spec key_exchange(client | server, ssl_record:ssl_version(),
{premaster_secret, binary(), public_key_info()} |
{dh, binary()} |
{dh, {binary(), binary()}, #'DHParameter'{}, {HashAlgo::atom(), SignAlgo::atom()},
@@ -304,7 +316,7 @@ key_exchange(server, Version, {srp, {PublicKey, _},
ClientRandom, ServerRandom, PrivateKey).
%%--------------------------------------------------------------------
--spec finished(tls_version(), client | server, integer(), binary(), tls_handshake_history()) ->
+-spec finished(ssl_record:ssl_version(), client | server, integer(), binary(), ssl_handshake_history()) ->
#finished{}.
%%
%% Description: Creates a handshake finished message
@@ -331,8 +343,8 @@ verify_server_key(#server_key_params{params_bin = EncParams,
verify_signature(Version, Hash, HashSign, Signature, PubKeyInfo).
%%--------------------------------------------------------------------
--spec certificate_verify(binary(), public_key_info(), tls_version(), term(),
- binary(), tls_handshake_history()) -> valid | #alert{}.
+-spec certificate_verify(binary(), public_key_info(), ssl_record:ssl_version(), term(),
+ binary(), ssl_handshake_history()) -> valid | #alert{}.
%%
%% Description: Checks that the certificate_verify message is valid.
%%--------------------------------------------------------------------
@@ -346,7 +358,7 @@ certificate_verify(Signature, PublicKeyInfo, Version,
?ALERT_REC(?FATAL, ?BAD_CERTIFICATE)
end.
%%--------------------------------------------------------------------
--spec verify_signature(tls_version(), binary(), {term(), term()}, binary(),
+-spec verify_signature(ssl_record:ssl_version(), binary(), {term(), term()}, binary(),
public_key_info()) -> true | false.
%%
%% Description: Checks that a public_key signature is valid.
@@ -426,8 +438,8 @@ certify(#certificate{asn1_certificates = ASN1Certs}, CertDbHandle, CertDbRef,
end.
%%--------------------------------------------------------------------
--spec verify_connection(tls_version(), #finished{}, client | server, integer(), binary(),
- tls_handshake_history()) -> verified | #alert{}.
+-spec verify_connection(ssl_record:ssl_version(), #finished{}, client | server, integer(), binary(),
+ ssl_handshake_history()) -> verified | #alert{}.
%%
%% Description: Checks the ssl handshake finished message to verify
%% the connection.
@@ -443,7 +455,7 @@ verify_connection(Version, #finished{verify_data = Data},
end.
%%--------------------------------------------------------------------
--spec init_handshake_history() -> tls_handshake_history().
+-spec init_handshake_history() -> ssl_handshake_history().
%%
%% Description: Initialize the empty handshake history buffer.
@@ -452,8 +464,8 @@ init_handshake_history() ->
{[], []}.
%%--------------------------------------------------------------------
--spec update_handshake_history(tls_handshake_history(), Data ::term()) ->
- tls_handshake_history().
+-spec update_handshake_history(ssl_handshake:ssl_handshake_history(), Data ::term()) ->
+ ssl_handshake:ssl_handshake_history().
%%
%% Description: Update the handshake history buffer with Data.
%%--------------------------------------------------------------------
@@ -567,7 +579,7 @@ server_key_exchange_hash(md5sha, Value) ->
server_key_exchange_hash(Hash, Value) ->
crypto:hash(Hash, Value).
%%--------------------------------------------------------------------
--spec prf(tls_version(), binary(), binary(), [binary()], non_neg_integer()) ->
+-spec prf(ssl_record:ssl_version(), binary(), binary(), [binary()], non_neg_integer()) ->
{ok, binary()} | {error, undefined}.
%%
%% Description: use the TLS PRF to generate key material
@@ -611,7 +623,7 @@ select_hashsign(#hash_sign_algos{hash_sign_algos = HashSigns}, Cert) ->
HashSign
end.
%%--------------------------------------------------------------------
--spec select_cert_hashsign(#hash_sign_algos{}| undefined, oid(), tls_version() | {undefined, undefined}) ->
+-spec select_cert_hashsign(#hash_sign_algos{}| undefined, oid(), ssl_record:ssl_version() | {undefined, undefined}) ->
{atom(), atom()}.
%%
@@ -631,7 +643,7 @@ select_cert_hashsign(undefined, ?'id-dsa', _) ->
{sha, dsa}.
%%--------------------------------------------------------------------
--spec master_secret(atom(), tls_version(), #session{} | binary(), #connection_states{},
+-spec master_secret(atom(), ssl_record:ssl_version(), #session{} | binary(), #connection_states{},
client | server) -> {binary(), #connection_states{}} | #alert{}.
%%
%% Description: Sets or calculates the master secret and calculate keys,
@@ -816,7 +828,7 @@ enc_server_key_exchange(Version, Params, {HashAlgo, SignAlgo},
end.
%%--------------------------------------------------------------------
--spec decode_client_key(binary(), key_algo(), tls_version()) ->
+-spec decode_client_key(binary(), ssl_cipher:key_algo(), ssl_record:ssl_version()) ->
#encrypted_premaster_secret{}
| #client_diffie_hellman_public{}
| #client_ec_diffie_hellman_public{}
@@ -831,7 +843,7 @@ decode_client_key(ClientKey, Type, Version) ->
dec_client_key(ClientKey, key_exchange_alg(Type), Version).
%%--------------------------------------------------------------------
--spec decode_server_key(binary(), key_algo(), tls_version()) ->
+-spec decode_server_key(binary(), ssl_cipher:key_algo(), ssl_record:ssl_version()) ->
#server_key_params{}.
%%
%% Description: Decode server_key data and return appropriate type
@@ -1654,7 +1666,16 @@ dec_hello_extensions(<<?UINT16(?SIGNATURE_ALGORITHMS_EXT), ?UINT16(Len),
dec_hello_extensions(<<?UINT16(?ELLIPTIC_CURVES_EXT), ?UINT16(Len),
ExtData:Len/binary, Rest/binary>>, Acc) ->
<<?UINT16(_), EllipticCurveList/binary>> = ExtData,
- EllipticCurves = [tls_v1:enum_to_oid(X) || <<X:16>> <= EllipticCurveList],
+ %% Ignore unknown curves
+ Pick = fun(Enum) ->
+ case tls_v1:enum_to_oid(Enum) of
+ undefined ->
+ false;
+ Oid ->
+ {true, Oid}
+ end
+ end,
+ EllipticCurves = lists:filtermap(Pick, [ECC || <<ECC:16>> <= EllipticCurveList]),
dec_hello_extensions(Rest, Acc#hello_extensions{elliptic_curves =
#elliptic_curves{elliptic_curve_list =
EllipticCurves}});
diff --git a/lib/ssl/src/ssl_handshake.hrl b/lib/ssl/src/ssl_handshake.hrl
index 75160526b9..80284faef0 100644
--- a/lib/ssl/src/ssl_handshake.hrl
+++ b/lib/ssl/src/ssl_handshake.hrl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2007-2013. All Rights Reserved.
+%% Copyright Ericsson AB 2007-2014. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -352,18 +352,4 @@
hostname = undefined
}).
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% Dialyzer types
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
--type oid() :: tuple().
--type public_key_params() :: #'Dss-Parms'{} | {namedCurve, oid()} | #'ECParameters'{} | term().
--type public_key_info() :: {oid(), #'RSAPublicKey'{} | integer() | #'ECPoint'{}, public_key_params()}.
--type tls_handshake_history() :: {[binary()], [binary()]}.
-
--type ssl_handshake() :: #server_hello{} | #server_hello_done{} | #certificate{} | #certificate_request{} |
- #client_key_exchange{} | #finished{} | #certificate_verify{} |
- #hello_request{} | #next_protocol{}.
-
-
-endif. % -ifdef(ssl_handshake).
diff --git a/lib/ssl/src/ssl_internal.hrl b/lib/ssl/src/ssl_internal.hrl
index 64b89e9f95..8bf5b30a83 100644
--- a/lib/ssl/src/ssl_internal.hrl
+++ b/lib/ssl/src/ssl_internal.hrl
@@ -30,8 +30,6 @@
-type from() :: term().
-type host() :: inet:ip_address() | inet:hostname().
-type session_id() :: 0 | binary().
--type tls_version() :: {integer(), integer()}.
--type tls_atom_version() :: sslv3 | tlsv1 | 'tlsv1.1' | 'tlsv1.2'.
-type certdb_ref() :: reference().
-type db_handle() :: term().
-type der_cert() :: binary().
@@ -73,7 +71,7 @@
-record(ssl_options, {
protocol :: tls | dtls,
- versions :: ['tlsv1.2' | 'tlsv1.1' | tlsv1 | sslv3] | ['dtlsv1.2' | dtlsv1],
+ versions :: [ssl_record:ssl_version()], %% ssl_record:atom_version() in API
verify :: verify_none | verify_peer,
verify_fun, %%:: fun(CertVerifyErrors::term()) -> boolean(),
fail_if_no_peer_cert :: boolean(),
@@ -103,7 +101,6 @@
reuse_sessions :: boolean(),
renegotiate_at,
secure_renegotiate,
- debug,
%% undefined if not hibernating, or number of ms of
%% inactivity after which ssl_connection will go into
%% hibernation
diff --git a/lib/ssl/src/ssl_record.erl b/lib/ssl/src/ssl_record.erl
index 018c8befe0..b0e9943e6d 100644
--- a/lib/ssl/src/ssl_record.erl
+++ b/lib/ssl/src/ssl_record.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2013-2013. All Rights Reserved.
+%% Copyright Ericsson AB 2013-2014. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -50,6 +50,11 @@
%% Payload encryption/decryption
-export([cipher/4, decipher/3, is_correct_mac/2]).
+-export_type([ssl_version/0, ssl_atom_version/0]).
+
+-type ssl_version() :: {integer(), integer()}.
+-type ssl_atom_version() :: tls_record:tls_atom_version().
+
%%====================================================================
%% Internal application API
%%====================================================================
@@ -299,7 +304,7 @@ set_pending_cipher_state(#connection_states{pending_read = Read,
%%--------------------------------------------------------------------
--spec encode_handshake(iolist(), tls_version(), #connection_states{}) ->
+-spec encode_handshake(iolist(), ssl_version(), #connection_states{}) ->
{iolist(), #connection_states{}}.
%%
%% Description: Encodes a handshake message to send on the ssl-socket.
@@ -308,7 +313,7 @@ encode_handshake(Frag, Version, ConnectionStates) ->
encode_plain_text(?HANDSHAKE, Version, Frag, ConnectionStates).
%%--------------------------------------------------------------------
--spec encode_alert_record(#alert{}, tls_version(), #connection_states{}) ->
+-spec encode_alert_record(#alert{}, ssl_version(), #connection_states{}) ->
{iolist(), #connection_states{}}.
%%
%% Description: Encodes an alert message to send on the ssl-socket.
@@ -319,7 +324,7 @@ encode_alert_record(#alert{level = Level, description = Description},
ConnectionStates).
%%--------------------------------------------------------------------
--spec encode_change_cipher_spec(tls_version(), #connection_states{}) ->
+-spec encode_change_cipher_spec(ssl_version(), #connection_states{}) ->
{iolist(), #connection_states{}}.
%%
%% Description: Encodes a change_cipher_spec-message to send on the ssl socket.
@@ -328,7 +333,7 @@ encode_change_cipher_spec(Version, ConnectionStates) ->
encode_plain_text(?CHANGE_CIPHER_SPEC, Version, <<1:8>>, ConnectionStates).
%%--------------------------------------------------------------------
--spec encode_data(binary(), tls_version(), #connection_states{}) ->
+-spec encode_data(binary(), ssl_version(), #connection_states{}) ->
{iolist(), #connection_states{}}.
%%
%% Description: Encodes data to send on the ssl-socket.
@@ -356,7 +361,7 @@ compressions() ->
[?byte(?NULL)].
%%--------------------------------------------------------------------
--spec cipher(tls_version(), iolist(), #connection_state{}, MacHash::binary()) ->
+-spec cipher(ssl_version(), iodata(), #connection_state{}, MacHash::binary()) ->
{CipherFragment::binary(), #connection_state{}}.
%%
%% Description: Payload encryption
@@ -372,7 +377,7 @@ cipher(Version, Fragment,
ssl_cipher:cipher(BulkCipherAlgo, CipherS0, MacHash, Fragment, Version),
{CipherFragment, WriteState0#connection_state{cipher_state = CipherS1}}.
%%--------------------------------------------------------------------
--spec decipher(tls_version(), binary(), #connection_state{}) -> {binary(), binary(), #connection_state{}}.
+-spec decipher(ssl_version(), binary(), #connection_state{}) -> {binary(), binary(), #connection_state{}}.
%%
%% Description: Payload decryption
%%--------------------------------------------------------------------
diff --git a/lib/ssl/src/ssl_record.hrl b/lib/ssl/src/ssl_record.hrl
index c17fa53a62..87ed233c0a 100644
--- a/lib/ssl/src/ssl_record.hrl
+++ b/lib/ssl/src/ssl_record.hrl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2007-2013. All Rights Reserved.
+%% Copyright Ericsson AB 2007-2014. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -20,7 +20,7 @@
%%
%%----------------------------------------------------------------------
%% Purpose: Record and constant defenitions for the SSL-record protocol
-%% see RFC 2246
+% see RFC 2246
%%----------------------------------------------------------------------
-ifndef(ssl_record).
diff --git a/lib/ssl/src/ssl_v3.erl b/lib/ssl/src/ssl_v3.erl
index d477b3df81..68f7f5dee2 100644
--- a/lib/ssl/src/ssl_v3.erl
+++ b/lib/ssl/src/ssl_v3.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2007-2013. All Rights Reserved.
+%% Copyright Ericsson AB 2007-2014. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -130,7 +130,7 @@ setup_keys(MasterSecret, ServerRandom, ClientRandom, HS, KML, _EKML, IVS) ->
{ClientWriteMacSecret, ServerWriteMacSecret, ClientWriteKey,
ServerWriteKey, ClientIV, ServerIV}.
--spec suites() -> [cipher_suite()].
+-spec suites() -> [ssl_cipher:cipher_suite()].
suites() ->
[
diff --git a/lib/ssl/src/tls_handshake.erl b/lib/ssl/src/tls_handshake.erl
index 01abefca46..183cabcfcd 100644
--- a/lib/ssl/src/tls_handshake.erl
+++ b/lib/ssl/src/tls_handshake.erl
@@ -33,6 +33,8 @@
-export([client_hello/8, hello/4,
get_tls_handshake/3, encode_handshake/2, decode_handshake/3]).
+-type tls_handshake() :: #client_hello{} | ssl_handshake:ssl_handshake().
+
%%====================================================================
%% Internal application API
%%====================================================================
@@ -71,11 +73,11 @@ client_hello(Host, Port, ConnectionStates,
#connection_states{} | {inet:port_number(), #session{}, db_handle(),
atom(), #connection_states{}, binary() | undefined},
boolean()) ->
- {tls_version(), session_id(), #connection_states{}, binary() | undefined}|
- {tls_version(), {resumed | new, #session{}}, #connection_states{},
- [binary()] | undefined,
- [oid()] | undefined, [oid()] | undefined} |
- #alert{}.
+ {tls_record:tls_version(), session_id(), #connection_states{}, binary() | undefined}|
+ {tls_record:tls_version(), {resumed | new, #session{}}, #connection_states{},
+ [binary()] | undefined,
+ [ssl_handshake:oid()] | undefined, [ssl_handshake:oid()] | undefined} |
+ #alert{}.
%%
%% Description: Handles a recieved hello message
%%--------------------------------------------------------------------
@@ -122,7 +124,7 @@ hello(#client_hello{client_version = ClientVersion,
end.
%%--------------------------------------------------------------------
--spec encode_handshake(tls_handshake(), tls_version()) -> iolist().
+-spec encode_handshake(tls_handshake(), tls_record:tls_version()) -> iolist().
%%
%% Description: Encode a handshake packet
%%--------------------------------------------------------------------x
@@ -132,7 +134,7 @@ encode_handshake(Package, Version) ->
[MsgType, ?uint24(Len), Bin].
%%--------------------------------------------------------------------
--spec get_tls_handshake(tls_version(), binary(), binary() | iolist()) ->
+-spec get_tls_handshake(tls_record:tls_version(), binary(), binary() | iolist()) ->
{[tls_handshake()], binary()}.
%%
%% Description: Given buffered and new data from ssl_record, collects
diff --git a/lib/ssl/src/tls_handshake.hrl b/lib/ssl/src/tls_handshake.hrl
index dbe930cb90..1646e5b6f2 100644
--- a/lib/ssl/src/tls_handshake.hrl
+++ b/lib/ssl/src/tls_handshake.hrl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2013-2013. All Rights Reserved.
+%% Copyright Ericsson AB 2013-2014. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -37,6 +37,4 @@
extensions
}).
--type tls_handshake() :: #client_hello{} | ssl_handshake().
-
-endif. % -ifdef(tls_handshake).
diff --git a/lib/ssl/src/tls_record.erl b/lib/ssl/src/tls_record.erl
index 8c0c4f3c91..4da08e9c51 100644
--- a/lib/ssl/src/tls_record.erl
+++ b/lib/ssl/src/tls_record.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2007-2013. All Rights Reserved.
+%% Copyright Ericsson AB 2007-2014. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -44,6 +44,11 @@
highest_protocol_version/1, supported_protocol_versions/0,
is_acceptable_version/1, is_acceptable_version/2]).
+-export_type([tls_version/0, tls_atom_version/0]).
+
+-type tls_version() :: ssl_record:ssl_version().
+-type tls_atom_version() :: sslv3 | tlsv1 | 'tlsv1.1' | 'tlsv1.2'.
+
-compile(inline).
%%====================================================================
diff --git a/lib/ssl/src/tls_v1.erl b/lib/ssl/src/tls_v1.erl
index 7c7fdd64c3..067417d163 100644
--- a/lib/ssl/src/tls_v1.erl
+++ b/lib/ssl/src/tls_v1.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2007-2013. All Rights Reserved.
+%% Copyright Ericsson AB 2007-2014. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -166,7 +166,7 @@ setup_keys(Version, PrfAlgo, MasterSecret, ServerRandom, ClientRandom, HashSize,
{ClientWriteMacSecret, ServerWriteMacSecret, ClientWriteKey,
ServerWriteKey, ClientIV, ServerIV}.
--spec mac_hash(integer(), binary(), integer(), integer(), tls_version(),
+-spec mac_hash(integer(), binary(), integer(), integer(), tls_record:tls_version(),
integer(), binary()) -> binary().
mac_hash(Method, Mac_write_secret, Seq_num, Type, {Major, Minor},
@@ -181,7 +181,7 @@ mac_hash(Method, Mac_write_secret, Seq_num, Type, {Major, Minor},
Fragment]),
Mac.
--spec suites(1|2|3) -> [cipher_suite()].
+-spec suites(1|2|3) -> [ssl_cipher:cipher_suite()].
suites(Minor) when Minor == 1; Minor == 2->
case sufficent_ec_support() of
@@ -439,7 +439,9 @@ enum_to_oid(24) -> ?secp384r1;
enum_to_oid(25) -> ?secp521r1;
enum_to_oid(26) -> ?brainpoolP256r1;
enum_to_oid(27) -> ?brainpoolP384r1;
-enum_to_oid(28) -> ?brainpoolP512r1.
+enum_to_oid(28) -> ?brainpoolP512r1;
+enum_to_oid(_) ->
+ undefined.
sufficent_ec_support() ->
CryptoSupport = crypto:supports(),
diff --git a/lib/ssl/test/Makefile b/lib/ssl/test/Makefile
index 244eb5ce0a..2f8ff6f04e 100644
--- a/lib/ssl/test/Makefile
+++ b/lib/ssl/test/Makefile
@@ -39,6 +39,7 @@ MODULES = \
ssl_basic_SUITE \
ssl_cipher_SUITE \
ssl_certificate_verify_SUITE\
+ ssl_crl_SUITE\
ssl_dist_SUITE \
ssl_handshake_SUITE \
ssl_npn_hello_SUITE \
diff --git a/lib/ssl/test/make_certs.erl b/lib/ssl/test/make_certs.erl
index 4603a9f846..0947657ca7 100644
--- a/lib/ssl/test/make_certs.erl
+++ b/lib/ssl/test/make_certs.erl
@@ -18,23 +18,68 @@
%%
-module(make_certs).
+-compile([export_all]).
--export([all/2]).
+%-export([all/1, all/2, rootCA/2, intermediateCA/3, endusers/3, enduser/3, revoke/3, gencrl/2, verify/3]).
--record(dn, {commonName,
+-record(config, {commonName,
organizationalUnitName = "Erlang OTP",
organizationName = "Ericsson AB",
localityName = "Stockholm",
countryName = "SE",
- emailAddress = "[email protected]"}).
+ emailAddress = "[email protected]",
+ default_bits = 2048,
+ v2_crls = true,
+ ecc_certs = false,
+ issuing_distribution_point = false,
+ openssl_cmd = "openssl"}).
+
+
+default_config() ->
+ #config{}.
+
+make_config(Args) ->
+ make_config(Args, #config{}).
+
+make_config([], C) ->
+ C;
+make_config([{organizationalUnitName, Name}|T], C) when is_list(Name) ->
+ make_config(T, C#config{organizationalUnitName = Name});
+make_config([{organizationName, Name}|T], C) when is_list(Name) ->
+ make_config(T, C#config{organizationName = Name});
+make_config([{localityName, Name}|T], C) when is_list(Name) ->
+ make_config(T, C#config{localityName = Name});
+make_config([{countryName, Name}|T], C) when is_list(Name) ->
+ make_config(T, C#config{countryName = Name});
+make_config([{emailAddress, Name}|T], C) when is_list(Name) ->
+ make_config(T, C#config{emailAddress = Name});
+make_config([{default_bits, Bits}|T], C) when is_integer(Bits) ->
+ make_config(T, C#config{default_bits = Bits});
+make_config([{v2_crls, Bool}|T], C) when is_boolean(Bool) ->
+ make_config(T, C#config{v2_crls = Bool});
+make_config([{ecc_certs, Bool}|T], C) when is_boolean(Bool) ->
+ make_config(T, C#config{ecc_certs = Bool});
+make_config([{issuing_distribution_point, Bool}|T], C) when is_boolean(Bool) ->
+ make_config(T, C#config{issuing_distribution_point = Bool});
+make_config([{openssl_cmd, Cmd}|T], C) when is_list(Cmd) ->
+ make_config(T, C#config{openssl_cmd = Cmd}).
+
+
+all([DataDir, PrivDir]) ->
+ all(DataDir, PrivDir).
all(DataDir, PrivDir) ->
- OpenSSLCmd = "openssl",
+ all(DataDir, PrivDir, #config{}).
+
+all(DataDir, PrivDir, C) when is_list(C) ->
+ all(DataDir, PrivDir, make_config(C));
+all(DataDir, PrivDir, C = #config{}) ->
+ ok = filelib:ensure_dir(filename:join(PrivDir, "erlangCA")),
create_rnd(DataDir, PrivDir), % For all requests
- rootCA(PrivDir, OpenSSLCmd, "erlangCA"),
- intermediateCA(PrivDir, OpenSSLCmd, "otpCA", "erlangCA"),
- endusers(PrivDir, OpenSSLCmd, "otpCA", ["client", "server"]),
- collect_certs(PrivDir, ["erlangCA", "otpCA"], ["client", "server"]),
+ rootCA(PrivDir, "erlangCA", C),
+ intermediateCA(PrivDir, "otpCA", "erlangCA", C),
+ endusers(PrivDir, "otpCA", ["client", "server", "revoked"], C),
+ endusers(PrivDir, "erlangCA", ["localhost"], C),
%% Create keycert files
SDir = filename:join([PrivDir, "server"]),
SC = filename:join([SDir, "cert.pem"]),
@@ -46,7 +91,14 @@ all(DataDir, PrivDir) ->
CK = filename:join([CDir, "key.pem"]),
CKC = filename:join([CDir, "keycert.pem"]),
append_files([CK, CC], CKC),
- remove_rnd(PrivDir).
+ RDir = filename:join([PrivDir, "revoked"]),
+ RC = filename:join([RDir, "cert.pem"]),
+ RK = filename:join([RDir, "key.pem"]),
+ RKC = filename:join([RDir, "keycert.pem"]),
+ revoke(PrivDir, "otpCA", "revoked", C),
+ append_files([RK, RC], RKC),
+ remove_rnd(PrivDir),
+ {ok, C}.
append_files(FileNames, ResultFileName) ->
{ok, ResultFile} = file:open(ResultFileName, [write]),
@@ -59,111 +111,176 @@ do_append_files([F|Fs], RF) ->
ok = file:write(RF, Data),
do_append_files(Fs, RF).
-rootCA(Root, OpenSSLCmd, Name) ->
- create_ca_dir(Root, Name, ca_cnf(Name)),
- DN = #dn{commonName = Name},
- create_self_signed_cert(Root, OpenSSLCmd, Name, req_cnf(DN)),
- ok.
+rootCA(Root, Name, C) ->
+ create_ca_dir(Root, Name, ca_cnf(C#config{commonName = Name})),
+ create_self_signed_cert(Root, Name, req_cnf(C#config{commonName = Name}), C),
+ file:copy(filename:join([Root, Name, "cert.pem"]), filename:join([Root, Name, "cacerts.pem"])),
+ gencrl(Root, Name, C).
-intermediateCA(Root, OpenSSLCmd, CA, ParentCA) ->
- CA = "otpCA",
- create_ca_dir(Root, CA, ca_cnf(CA)),
+intermediateCA(Root, CA, ParentCA, C) ->
+ create_ca_dir(Root, CA, ca_cnf(C#config{commonName = CA})),
CARoot = filename:join([Root, CA]),
- DN = #dn{commonName = CA},
CnfFile = filename:join([CARoot, "req.cnf"]),
- file:write_file(CnfFile, req_cnf(DN)),
+ file:write_file(CnfFile, req_cnf(C#config{commonName = CA})),
KeyFile = filename:join([CARoot, "private", "key.pem"]),
ReqFile = filename:join([CARoot, "req.pem"]),
- create_req(Root, OpenSSLCmd, CnfFile, KeyFile, ReqFile),
+ create_req(Root, CnfFile, KeyFile, ReqFile, C),
CertFile = filename:join([CARoot, "cert.pem"]),
- sign_req(Root, OpenSSLCmd, ParentCA, "ca_cert", ReqFile, CertFile).
-
-endusers(Root, OpenSSLCmd, CA, Users) ->
- lists:foreach(fun(User) -> enduser(Root, OpenSSLCmd, CA, User) end, Users).
-
-enduser(Root, OpenSSLCmd, CA, User) ->
+ sign_req(Root, ParentCA, "ca_cert", ReqFile, CertFile, C),
+ CACertsFile = filename:join(CARoot, "cacerts.pem"),
+ file:copy(filename:join([Root, ParentCA, "cacerts.pem"]), CACertsFile),
+ %% append this CA's cert to the cacerts file
+ {ok, Bin} = file:read_file(CertFile),
+ {ok, FD} = file:open(CACertsFile, [append]),
+ file:write(FD, ["\n", Bin]),
+ file:close(FD),
+ gencrl(Root, CA, C).
+
+endusers(Root, CA, Users, C) ->
+ [enduser(Root, CA, User, C) || User <- Users].
+
+enduser(Root, CA, User, C) ->
UsrRoot = filename:join([Root, User]),
file:make_dir(UsrRoot),
CnfFile = filename:join([UsrRoot, "req.cnf"]),
- DN = #dn{commonName = User},
- file:write_file(CnfFile, req_cnf(DN)),
+ file:write_file(CnfFile, req_cnf(C#config{commonName = User})),
KeyFile = filename:join([UsrRoot, "key.pem"]),
ReqFile = filename:join([UsrRoot, "req.pem"]),
- create_req(Root, OpenSSLCmd, CnfFile, KeyFile, ReqFile),
+ create_req(Root, CnfFile, KeyFile, ReqFile, C),
+ %create_req(Root, CnfFile, KeyFile, ReqFile),
CertFileAllUsage = filename:join([UsrRoot, "cert.pem"]),
- sign_req(Root, OpenSSLCmd, CA, "user_cert", ReqFile, CertFileAllUsage),
+ sign_req(Root, CA, "user_cert", ReqFile, CertFileAllUsage, C),
CertFileDigitalSigOnly = filename:join([UsrRoot, "digital_signature_only_cert.pem"]),
- sign_req(Root, OpenSSLCmd, CA, "user_cert_digital_signature_only", ReqFile, CertFileDigitalSigOnly).
-
-collect_certs(Root, CAs, Users) ->
- Bins = lists:foldr(
- fun(CA, Acc) ->
- File = filename:join([Root, CA, "cert.pem"]),
- {ok, Bin} = file:read_file(File),
- [Bin, "\n" | Acc]
- end, [], CAs),
- lists:foreach(
- fun(User) ->
- File = filename:join([Root, User, "cacerts.pem"]),
- file:write_file(File, Bins)
- end, Users).
+ sign_req(Root, CA, "user_cert_digital_signature_only", ReqFile, CertFileDigitalSigOnly, C),
+ CACertsFile = filename:join(UsrRoot, "cacerts.pem"),
+ file:copy(filename:join([Root, CA, "cacerts.pem"]), CACertsFile),
+ ok.
+
+revoke(Root, CA, User, C) ->
+ UsrCert = filename:join([Root, User, "cert.pem"]),
+ CACnfFile = filename:join([Root, CA, "ca.cnf"]),
+ Cmd = [C#config.openssl_cmd, " ca"
+ " -revoke ", UsrCert,
+ [" -crl_reason keyCompromise" || C#config.v2_crls ],
+ " -config ", CACnfFile],
+ Env = [{"ROOTDIR", filename:absname(Root)}],
+ cmd(Cmd, Env),
+ gencrl(Root, CA, C).
+
+gencrl(Root, CA, C) ->
+ CACnfFile = filename:join([Root, CA, "ca.cnf"]),
+ CACRLFile = filename:join([Root, CA, "crl.pem"]),
+ Cmd = [C#config.openssl_cmd, " ca"
+ " -gencrl ",
+ " -crlhours 24",
+ " -out ", CACRLFile,
+ " -config ", CACnfFile],
+ Env = [{"ROOTDIR", filename:absname(Root)}],
+ cmd(Cmd, Env).
-create_self_signed_cert(Root, OpenSSLCmd, CAName, Cnf) ->
+verify(Root, CA, User, C) ->
+ CAFile = filename:join([Root, User, "cacerts.pem"]),
+ CACRLFile = filename:join([Root, CA, "crl.pem"]),
+ CertFile = filename:join([Root, User, "cert.pem"]),
+ Cmd = [C#config.openssl_cmd, " verify"
+ " -CAfile ", CAFile,
+ " -CRLfile ", CACRLFile, %% this is undocumented, but seems to work
+ " -crl_check ",
+ CertFile],
+ Env = [{"ROOTDIR", filename:absname(Root)}],
+ try cmd(Cmd, Env) catch
+ exit:{eval_cmd, _, _} ->
+ invalid
+ end.
+
+create_self_signed_cert(Root, CAName, Cnf, C = #config{ecc_certs = true}) ->
CARoot = filename:join([Root, CAName]),
CnfFile = filename:join([CARoot, "req.cnf"]),
file:write_file(CnfFile, Cnf),
KeyFile = filename:join([CARoot, "private", "key.pem"]),
CertFile = filename:join([CARoot, "cert.pem"]),
- Cmd = [OpenSSLCmd, " req"
+ Cmd = [C#config.openssl_cmd, " ecparam"
+ " -out ", KeyFile,
+ " -name secp521r1 ",
+ %" -name sect283k1 ",
+ " -genkey "],
+ Env = [{"ROOTDIR", filename:absname(Root)}],
+ cmd(Cmd, Env),
+
+ Cmd2 = [C#config.openssl_cmd, " req"
" -new"
" -x509"
" -config ", CnfFile,
- " -keyout ", KeyFile,
+ " -key ", KeyFile,
+ " -outform PEM ",
" -out ", CertFile],
- Env = [{"ROOTDIR", Root}],
- cmd(Cmd, Env),
- fix_key_file(OpenSSLCmd, KeyFile).
-
-% openssl 1.0 generates key files in pkcs8 format by default and we don't handle this format
-fix_key_file(OpenSSLCmd, KeyFile) ->
- KeyFileTmp = KeyFile ++ ".tmp",
- Cmd = [OpenSSLCmd, " rsa",
- " -in ",
- KeyFile,
- " -out ",
- KeyFileTmp],
- cmd(Cmd, []),
- ok = file:rename(KeyFileTmp, KeyFile).
+ cmd(Cmd2, Env);
+create_self_signed_cert(Root, CAName, Cnf, C) ->
+ CARoot = filename:join([Root, CAName]),
+ CnfFile = filename:join([CARoot, "req.cnf"]),
+ file:write_file(CnfFile, Cnf),
+ KeyFile = filename:join([CARoot, "private", "key.pem"]),
+ CertFile = filename:join([CARoot, "cert.pem"]),
+ Cmd = [C#config.openssl_cmd, " req"
+ " -new"
+ " -x509"
+ " -config ", CnfFile,
+ " -keyout ", KeyFile,
+ " -outform PEM",
+ " -out ", CertFile],
+ Env = [{"ROOTDIR", filename:absname(Root)}],
+ cmd(Cmd, Env).
+
create_ca_dir(Root, CAName, Cnf) ->
CARoot = filename:join([Root, CAName]),
+ ok = filelib:ensure_dir(CARoot),
file:make_dir(CARoot),
create_dirs(CARoot, ["certs", "crl", "newcerts", "private"]),
create_rnd(Root, filename:join([CAName, "private"])),
create_files(CARoot, [{"serial", "01\n"},
+ {"crlnumber", "01"},
{"index.txt", ""},
{"ca.cnf", Cnf}]).
-create_req(Root, OpenSSLCmd, CnfFile, KeyFile, ReqFile) ->
- Cmd = [OpenSSLCmd, " req"
+create_req(Root, CnfFile, KeyFile, ReqFile, C = #config{ecc_certs = true}) ->
+ Cmd = [C#config.openssl_cmd, " ecparam"
+ " -out ", KeyFile,
+ " -name secp521r1 ",
+ %" -name sect283k1 ",
+ " -genkey "],
+ Env = [{"ROOTDIR", filename:absname(Root)}],
+ cmd(Cmd, Env),
+ Cmd2 = [C#config.openssl_cmd, " req"
+ " -new ",
+ " -key ", KeyFile,
+ " -outform PEM ",
+ " -out ", ReqFile,
+ " -config ", CnfFile],
+ cmd(Cmd2, Env);
+ %fix_key_file(KeyFile).
+create_req(Root, CnfFile, KeyFile, ReqFile, C) ->
+ Cmd = [C#config.openssl_cmd, " req"
" -new"
" -config ", CnfFile,
+ " -outform PEM ",
" -keyout ", KeyFile,
" -out ", ReqFile],
- Env = [{"ROOTDIR", Root}],
- cmd(Cmd, Env),
- fix_key_file(OpenSSLCmd, KeyFile).
+ Env = [{"ROOTDIR", filename:absname(Root)}],
+ cmd(Cmd, Env).
+ %fix_key_file(KeyFile).
+
-sign_req(Root, OpenSSLCmd, CA, CertType, ReqFile, CertFile) ->
+sign_req(Root, CA, CertType, ReqFile, CertFile, C) ->
CACnfFile = filename:join([Root, CA, "ca.cnf"]),
- Cmd = [OpenSSLCmd, " ca"
+ Cmd = [C#config.openssl_cmd, " ca"
" -batch"
" -notext"
" -config ", CACnfFile,
" -extensions ", CertType,
" -in ", ReqFile,
" -out ", CertFile],
- Env = [{"ROOTDIR", Root}],
+ Env = [{"ROOTDIR", filename:absname(Root)}],
cmd(Cmd, Env).
%%
@@ -194,19 +311,19 @@ cmd(Cmd, Env) ->
FCmd = lists:flatten(Cmd),
Port = open_port({spawn, FCmd}, [stream, eof, exit_status, stderr_to_stdout,
{env, Env}]),
- eval_cmd(Port).
+ eval_cmd(Port, FCmd).
-eval_cmd(Port) ->
+eval_cmd(Port, Cmd) ->
receive
{Port, {data, _}} ->
- eval_cmd(Port);
+ eval_cmd(Port, Cmd);
{Port, eof} ->
ok
end,
receive
{Port, {exit_status, Status}} when Status /= 0 ->
%% io:fwrite("exit status: ~w~n", [Status]),
- exit({eval_cmd, Status})
+ exit({eval_cmd, Cmd, Status})
after 0 ->
ok
end.
@@ -215,7 +332,7 @@ eval_cmd(Port) ->
%% Contents of configuration files
%%
-req_cnf(DN) ->
+req_cnf(C) ->
["# Purpose: Configuration for requests (end users and CAs)."
"\n"
"ROOTDIR = $ENV::ROOTDIR\n"
@@ -224,10 +341,10 @@ req_cnf(DN) ->
"[req]\n"
"input_password = secret\n"
"output_password = secret\n"
- "default_bits = 1024\n"
+ "default_bits = ", integer_to_list(C#config.default_bits), "\n"
"RANDFILE = $ROOTDIR/RAND\n"
"encrypt_key = no\n"
- "default_md = sha1\n"
+ "default_md = md5\n"
"#string_mask = pkix\n"
"x509_extensions = ca_ext\n"
"prompt = no\n"
@@ -235,12 +352,12 @@ req_cnf(DN) ->
"\n"
"[name]\n"
- "commonName = ", DN#dn.commonName, "\n"
- "organizationalUnitName = ", DN#dn.organizationalUnitName, "\n"
- "organizationName = ", DN#dn.organizationName, "\n"
- "localityName = ", DN#dn.localityName, "\n"
- "countryName = ", DN#dn.countryName, "\n"
- "emailAddress = ", DN#dn.emailAddress, "\n"
+ "commonName = ", C#config.commonName, "\n"
+ "organizationalUnitName = ", C#config.organizationalUnitName, "\n"
+ "organizationName = ", C#config.organizationName, "\n"
+ "localityName = ", C#config.localityName, "\n"
+ "countryName = ", C#config.countryName, "\n"
+ "emailAddress = ", C#config.emailAddress, "\n"
"\n"
"[ca_ext]\n"
@@ -249,8 +366,7 @@ req_cnf(DN) ->
"subjectKeyIdentifier = hash\n"
"subjectAltName = email:copy\n"].
-
-ca_cnf(CA) ->
+ca_cnf(C) ->
["# Purpose: Configuration for CAs.\n"
"\n"
"ROOTDIR = $ENV::ROOTDIR\n"
@@ -258,21 +374,23 @@ ca_cnf(CA) ->
"\n"
"[ca]\n"
- "dir = $ROOTDIR/", CA, "\n"
+ "dir = $ROOTDIR/", C#config.commonName, "\n"
"certs = $dir/certs\n"
"crl_dir = $dir/crl\n"
"database = $dir/index.txt\n"
"new_certs_dir = $dir/newcerts\n"
"certificate = $dir/cert.pem\n"
"serial = $dir/serial\n"
- "crl = $dir/crl.pem\n"
+ "crl = $dir/crl.pem\n",
+ ["crlnumber = $dir/crlnumber\n" || C#config.v2_crls],
"private_key = $dir/private/key.pem\n"
"RANDFILE = $dir/private/RAND\n"
"\n"
- "x509_extensions = user_cert\n"
+ "x509_extensions = user_cert\n",
+ ["crl_extensions = crl_ext\n" || C#config.v2_crls],
"unique_subject = no\n"
"default_days = 3600\n"
- "default_md = sha1\n"
+ "default_md = md5\n"
"preserve = no\n"
"policy = policy_match\n"
"\n"
@@ -286,6 +404,13 @@ ca_cnf(CA) ->
"emailAddress = supplied\n"
"\n"
+ "[crl_ext]\n"
+ "authorityKeyIdentifier=keyid:always,issuer:always\n",
+ ["issuingDistributionPoint=critical, @idpsec\n" || C#config.issuing_distribution_point],
+
+ "[idpsec]\n"
+ "fullname=URI:http://localhost:8000/",C#config.commonName,"/crl.pem\n"
+
"[user_cert]\n"
"basicConstraints = CA:false\n"
"keyUsage = nonRepudiation, digitalSignature, keyEncipherment\n"
@@ -293,6 +418,12 @@ ca_cnf(CA) ->
"authorityKeyIdentifier = keyid,issuer:always\n"
"subjectAltName = email:copy\n"
"issuerAltName = issuer:copy\n"
+ "crlDistributionPoints=@crl_section\n"
+
+ "[crl_section]\n"
+ %% intentionally invalid
+ "URI.1=http://localhost/",C#config.commonName,"/crl.pem\n"
+ "URI.2=http://localhost:8000/",C#config.commonName,"/crl.pem\n"
"\n"
"[user_cert_digital_signature_only]\n"
@@ -310,4 +441,7 @@ ca_cnf(CA) ->
"subjectKeyIdentifier = hash\n"
"authorityKeyIdentifier = keyid:always,issuer:always\n"
"subjectAltName = email:copy\n"
- "issuerAltName = issuer:copy\n"].
+ "issuerAltName = issuer:copy\n"
+ "crlDistributionPoints=@crl_section\n"
+ ].
+
diff --git a/lib/ssl/test/ssl_basic_SUITE.erl b/lib/ssl/test/ssl_basic_SUITE.erl
index 64a93440c7..8e3d2e4b80 100644
--- a/lib/ssl/test/ssl_basic_SUITE.erl
+++ b/lib/ssl/test/ssl_basic_SUITE.erl
@@ -119,7 +119,8 @@ options_tests() ->
].
api_tests() ->
- [connection_info,
+ [new_options_in_accept,
+ connection_info,
peername,
peercert,
peercert_with_client_cert,
@@ -309,7 +310,11 @@ alerts(Config) when is_list(Config) ->
?ILLEGAL_PARAMETER, ?UNKNOWN_CA, ?ACCESS_DENIED, ?DECODE_ERROR,
?DECRYPT_ERROR, ?EXPORT_RESTRICTION, ?PROTOCOL_VERSION,
?INSUFFICIENT_SECURITY, ?INTERNAL_ERROR, ?USER_CANCELED,
- ?NO_RENEGOTIATION],
+ ?NO_RENEGOTIATION, ?UNSUPPORTED_EXTENSION, ?CERTIFICATE_UNOBTAINABLE,
+ ?UNRECOGNISED_NAME, ?BAD_CERTIFICATE_STATUS_RESPONSE,
+ ?BAD_CERTIFICATE_HASH_VALUE, ?UNKNOWN_PSK_IDENTITY,
+ 255 %% Unsupported/unknow alert will result in a description too
+ ],
Alerts = [?ALERT_REC(?WARNING, ?CLOSE_NOTIFY) |
[?ALERT_REC(?FATAL, Desc) || Desc <- Descriptions]],
lists:foreach(fun(Alert) ->
@@ -321,6 +326,37 @@ alerts(Config) when is_list(Config) ->
end
end, Alerts).
%%--------------------------------------------------------------------
+new_options_in_accept() ->
+ [{doc,"Test that you can set ssl options in ssl_accept/3 and not tcp upgrade"}].
+new_options_in_accept(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()},
+ {ssl_opts, [{versions, [sslv3]},
+ {ciphers,[{rsa,rc4_128,sha}]}]}, %% To be set in ssl_accept/3
+ {mfa, {?MODULE, connection_info_result, []}},
+ {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, connection_info_result, []}},
+ {options, [{versions, [sslv3]} | ClientOpts]}]),
+
+ ct:log("Testcase ~p, Client ~p Server ~p ~n",
+ [self(), Client, Server]),
+
+ ServerMsg = ClientMsg = {ok, {sslv3, {rsa, rc4_128, sha}}},
+
+ ssl_test_lib:check_result(Server, ServerMsg, Client, ClientMsg),
+
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close(Client).
+%%--------------------------------------------------------------------
+
connection_info() ->
[{doc,"Test the API function ssl:connection_info/1"}].
connection_info(Config) when is_list(Config) ->
diff --git a/lib/ssl/test/ssl_crl_SUITE.erl b/lib/ssl/test/ssl_crl_SUITE.erl
new file mode 100644
index 0000000000..4eacf3adfc
--- /dev/null
+++ b/lib/ssl/test/ssl_crl_SUITE.erl
@@ -0,0 +1,536 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2008-2013. 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_crl_SUITE).
+
+%% Note: This directive should only be used in test suites.
+-compile(export_all).
+
+-include_lib("common_test/include/ct.hrl").
+-include_lib("public_key/include/public_key.hrl").
+
+-define(TIMEOUT, 120000).
+-define(LONG_TIMEOUT, 600000).
+-define(SLEEP, 1000).
+-define(OPENSSL_RENEGOTIATE, "R\n").
+-define(OPENSSL_QUIT, "Q\n").
+-define(OPENSSL_GARBAGE, "P\n").
+-define(EXPIRE, 10).
+
+%%--------------------------------------------------------------------
+%% Common Test interface functions -----------------------------------
+%%--------------------------------------------------------------------
+
+suite() -> [{ct_hooks,[ts_install_cth]}].
+
+all() ->
+ [
+ {group, basic},
+ {group, v1_crl},
+ {group, idp_crl}
+ ].
+
+groups() ->
+ [{basic, [], basic_tests()},
+ {v1_crl, [], v1_crl_tests()},
+ {idp_crl, [], idp_crl_tests()}].
+
+basic_tests() ->
+ [crl_verify_valid, crl_verify_revoked].
+
+v1_crl_tests() ->
+ [crl_verify_valid, crl_verify_revoked].
+
+idp_crl_tests() ->
+ [crl_verify_valid, crl_verify_revoked].
+
+%%%================================================================
+%%% Suite init/end
+
+init_per_suite(Config0) ->
+ Dog = ct:timetrap(?LONG_TIMEOUT *2),
+ case os:find_executable("openssl") of
+ false ->
+ {skip, "Openssl not found"};
+ _ ->
+ TLSVersion = ?config(tls_version, Config0),
+ OpenSSL_version = (catch os:cmd("openssl version")),
+ ct:log("TLS version: ~p~nOpenSSL version: ~p~n~n~p:module_info(): ~p~n~nssh:module_info(): ~p~n",
+ [TLSVersion, OpenSSL_version, ?MODULE, ?MODULE:module_info(), ssh:module_info()]),
+ case ssl_test_lib:enough_openssl_crl_support(OpenSSL_version) of
+ false ->
+ {skip, io_lib:format("Bad openssl version: ~p",[OpenSSL_version])};
+ _ ->
+ catch crypto:stop(),
+ try crypto:start() of
+ ok ->
+ ssl:start(),
+ [{watchdog, Dog}, {openssl_version,OpenSSL_version} | Config0]
+ catch _C:_E ->
+ ct:log("crypto:start() caught ~p:~p",[_C,_E]),
+ {skip, "Crypto did not start"}
+ end
+ end
+ end.
+
+end_per_suite(_Config) ->
+ ssl:stop(),
+ application:stop(crypto).
+
+%%%================================================================
+%%% Group init/end
+
+init_per_group(Group, Config) ->
+ ct:log("~p:~p~nlisteners to port 8000:~n~p~n)",[?MODULE,?LINE,os:cmd("netstat -tln|grep ':8000'")]),
+ ssl:start(),
+ inets:start(),
+ CertDir = filename:join(?config(priv_dir, Config), Group),
+ DataDir = ?config(data_dir, Config),
+ ServerRoot = make_dir_path([?config(priv_dir,Config), Group, tmp]),
+ Result = make_certs:all(DataDir, CertDir, cert_opts(Group)),
+ ct:log("~p:~p~nmake_certs:all(~n DataDir=~p,~n CertDir=~p,~n ServerRoot=~p~n Opts=~p~n) returned ~p~n", [?MODULE,?LINE,DataDir, CertDir, ServerRoot, cert_opts(Group), Result]),
+ %% start a HTTP server to serve the CRLs
+ {ok, Httpd} = inets:start(httpd, [{server_name, "localhost"}, {port, 8000},
+ {server_root, ServerRoot},
+ {document_root, CertDir},
+ {modules, [mod_get]}
+ ]),
+ ct:log("~p:~p~nlisteners to port 8000:~n~p~n)",[?MODULE,?LINE,os:cmd("netstat -tln|grep ':8000'")]),
+ [{make_cert_result, Result}, {cert_dir, CertDir}, {httpd, Httpd} | Config].
+
+cert_opts(v1_crl) -> [{v2_crls, false}];
+cert_opts(idp_crl) -> [{issuing_distribution_point, true}];
+cert_opts(_) -> [].
+
+make_dir_path(PathComponents) ->
+ lists:foldl(fun(F,P0) -> file:make_dir(P=filename:join(P0,F)), P end,
+ "",
+ PathComponents).
+
+
+end_per_group(_GroupName, Config) ->
+ case ?config(httpd, Config) of
+ undefined -> ok;
+ Pid ->
+ ct:log("Stop httpd ~p",[Pid]),
+ ok = inets:stop(httpd, Pid)
+ ,ct:log("Stopped",[])
+ end,
+ inets:stop(),
+ ct:log("~p:~p~nlisteners to port 8000:~n~p~n)",[?MODULE,?LINE,os:cmd("netstat -tln|grep ':8000'")]),
+ Config.
+
+%%%================================================================
+%%% Test cases
+
+crl_verify_valid() ->
+ [{doc,"Verify a simple valid CRL chain"}].
+crl_verify_valid(Config) when is_list(Config) ->
+ process_flag(trap_exit, true),
+ PrivDir = ?config(cert_dir, Config),
+ ServerOpts = [{keyfile, filename:join([PrivDir, "server", "key.pem"])},
+ {certfile, filename:join([PrivDir, "server", "cert.pem"])},
+ {cacertfile, filename:join([PrivDir, "server", "cacerts.pem"])}],
+
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+ Data = "From openssl to erlang",
+
+ Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {?MODULE, erlang_ssl_receive, [Data]}},
+ %{mfa, {ssl_test_lib, no_result, []}},
+ {options, ServerOpts}]),
+ ct:log("~p:~p~nreturn from ssl_test_lib:start_server:~n~p",[?MODULE,?LINE,Server]),
+ Port = ssl_test_lib:inet_port(Server),
+
+ CACerts = load_cert(filename:join([PrivDir, "erlangCA", "cacerts.pem"])),
+
+ ClientOpts = [{cacerts, CACerts},
+ {verify, verify_peer},
+ {verify_fun, {fun validate_function/3, {CACerts, []}}}],
+
+
+ ct:log("~p:~p~ncalling ssl_test_lib:start_client",[?MODULE,?LINE]),
+ Client = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {?MODULE,
+ erlang_ssl_send, [Data]}},
+ %{mfa, {ssl_test_lib, no_result, []}},
+ {options, ClientOpts}]),
+ ct:log("~p:~p~nreturn from ssl_test_lib:start_client:~n~p",[?MODULE,?LINE,Client]),
+
+ ssl_test_lib:check_result(Client, ok, Server, ok),
+
+ %% Clean close down! Server needs to be closed first !!
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close(Client),
+ process_flag(trap_exit, false).
+
+crl_verify_revoked() ->
+ [{doc,"Verify a simple valid CRL chain"}].
+crl_verify_revoked(Config) when is_list(Config) ->
+ process_flag(trap_exit, true),
+ PrivDir = ?config(cert_dir, Config),
+ ServerOpts = [{keyfile, filename:join([PrivDir, "revoked", "key.pem"])},
+ {certfile, filename:join([PrivDir, "revoked", "cert.pem"])},
+ {cacertfile, filename:join([PrivDir, "revoked", "cacerts.pem"])}],
+ ct:log("~p:~p~nserver opts ~p~n", [?MODULE,?LINE, ServerOpts]),
+
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+
+ Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ %{mfa, {?MODULE, erlang_ssl_receive, [Data]}},
+ {mfa, {ssl_test_lib, no_result, []}},
+ {options, ServerOpts}]),
+ Port = ssl_test_lib:inet_port(Server),
+
+ CACerts = load_cert(filename:join([PrivDir, "erlangCA", "cacerts.pem"])),
+ ClientOpts = [{cacerts, CACerts},
+ {verify, verify_peer},
+ {verify_fun, {fun validate_function/3, {CACerts, []}}}],
+
+ {connect_failed, _} = ssl_test_lib:start_client([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ %{mfa, {?MODULE,
+ %erlang_ssl_receive, [Data]}},
+ {mfa, {ssl_test_lib, no_result, []}},
+ {options, ClientOpts}]),
+
+ %% Clean close down! Server needs to be closed first !!
+ ssl_test_lib:close(Server),
+ process_flag(trap_exit, false).
+
+%%%================================================================
+%%% Lib
+
+erlang_ssl_receive(Socket, Data) ->
+ ct:log("~p:~p~nConnection info: ~p~n",
+ [?MODULE,?LINE, ssl:connection_info(Socket)]),
+ receive
+ {ssl, Socket, Data} ->
+ ct:log("~p:~p~nReceived ~p~n",[?MODULE,?LINE, 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) ->
+ ct:log("~p:~p~nopenssl ~s~n",[?MODULE,?LINE, Debug]),
+ erlang_ssl_receive(Socket,Data);
+ Other ->
+ ct:fail({unexpected_message, Other})
+ after 4000 ->
+ ct:fail({did_not_get, Data})
+ end.
+
+
+erlang_ssl_send(Socket, Data) ->
+ ct:log("~p:~p~nConnection info: ~p~n",
+ [?MODULE,?LINE, ssl:connection_info(Socket)]),
+ ssl:send(Socket, Data),
+ ok.
+
+load_certs(undefined) ->
+ undefined;
+load_certs(CertDir) ->
+ case file:list_dir(CertDir) of
+ {ok, Certs} ->
+ load_certs(lists:map(fun(Cert) -> filename:join(CertDir, Cert)
+ end, Certs), []);
+ {error, _} ->
+ undefined
+ end.
+
+load_certs([], Acc) ->
+ ct:log("~p:~p~nSuccessfully loaded ~p CA certificates~n", [?MODULE,?LINE, length(Acc)]),
+ Acc;
+load_certs([Cert|Certs], Acc) ->
+ case filelib:is_dir(Cert) of
+ true ->
+ load_certs(Certs, Acc);
+ _ ->
+ %ct:log("~p:~p~nLoading certificate ~p~n", [?MODULE,?LINE, Cert]),
+ load_certs(Certs, load_cert(Cert) ++ Acc)
+ end.
+
+load_cert(Cert) ->
+ {ok, Bin} = file:read_file(Cert),
+ case filename:extension(Cert) of
+ ".der" ->
+ %% no decoding necessary
+ [Bin];
+ _ ->
+ %% assume PEM otherwise
+ Contents = public_key:pem_decode(Bin),
+ [DER || {Type, DER, Cipher} <- Contents, Type == 'Certificate', Cipher == 'not_encrypted']
+ end.
+
+%% @doc Validator function for SSL negotiation.
+%%
+validate_function(Cert, valid_peer, State) ->
+ ct:log("~p:~p~nvaliding peer ~p with ~p intermediate certs~n",
+ [?MODULE,?LINE, get_common_name(Cert),
+ length(element(2, State))]),
+ %% peer certificate validated, now check the CRL
+ Res = (catch check_crl(Cert, State)),
+ ct:log("~p:~p~nCRL validate result for ~p: ~p~n",
+ [?MODULE,?LINE, get_common_name(Cert), Res]),
+ {Res, State};
+validate_function(Cert, valid, {TrustedCAs, IntermediateCerts}=State) ->
+ case public_key:pkix_is_self_signed(Cert) of
+ true ->
+ ct:log("~p:~p~nroot certificate~n",[?MODULE,?LINE]),
+ %% this is a root cert, no CRL
+ {valid, {TrustedCAs, [Cert|IntermediateCerts]}};
+ false ->
+ %% check is valid CA certificate, add to the list of
+ %% intermediates
+ Res = (catch check_crl(Cert, State)),
+ ct:log("~p:~p~nCRL intermediate CA validate result for ~p: ~p~n",
+ [?MODULE,?LINE, get_common_name(Cert), Res]),
+ {Res, {TrustedCAs, [Cert|IntermediateCerts]}}
+ end;
+validate_function(_Cert, _Event, State) ->
+ %ct:log("~p:~p~nignoring event ~p~n", [?MODULE,?LINE, _Event]),
+ {valid, State}.
+
+%% @doc Given a certificate, find CRL distribution points for the given
+%% certificate, fetch, and attempt to validate each CRL through
+%% issuer_function/4.
+%%
+check_crl(Cert, State) ->
+ %% pull the CRL distribution point(s) out of the certificate, if any
+ ct:log("~p:~p~ncheck_crl(~n Cert=~p,~nState=~p~n)",[?MODULE,?LINE,Cert,State]),
+ case pubkey_cert:select_extension(
+ ?'id-ce-cRLDistributionPoints',
+ pubkey_cert:extensions_list(Cert#'OTPCertificate'.tbsCertificate#'OTPTBSCertificate'.extensions)) of
+ undefined ->
+ ct:log("~p:~p~nno CRL distribution points for ~p~n",
+ [?MODULE,?LINE, get_common_name(Cert)]),
+ %% fail; we can't validate if there's no CRL
+ no_crl;
+ CRLExtension ->
+ ct:log("~p:~p~nCRLExtension=~p)",[?MODULE,?LINE,CRLExtension]),
+ CRLDistPoints = CRLExtension#'Extension'.extnValue,
+ DPointsAndCRLs = lists:foldl(fun(Point, Acc) ->
+ %% try to read the CRL over http or from a
+ %% local file
+ case fetch_point(Point) of
+ not_available ->
+ ct:log("~p:~p~nfetch_point returned~n~p~n)",[?MODULE,?LINE,not_available]),
+ Acc;
+ Res ->
+ ct:log("~p:~p~nfetch_point returned~n~p~n)",[?MODULE,?LINE,Res]),
+ [{Point, Res} | Acc]
+ end
+ end, [], CRLDistPoints),
+ public_key:pkix_crls_validate(Cert,
+ DPointsAndCRLs,
+ [{issuer_fun,
+ {fun issuer_function/4, State}}])
+ end.
+
+%% @doc Given a list of distribution points for CRLs, certificates and
+%% both trusted and intermediary certificates, attempt to build and
+%% authority chain back via build_chain to verify that it is valid.
+%%
+issuer_function(_DP, CRL, _Issuer, {TrustedCAs, IntermediateCerts}) ->
+ %% XXX the 'Issuer' we get passed here is the AuthorityKeyIdentifier,
+ %% which we are not currently smart enough to understand
+ %% Read the CA certs out of the file
+ ct:log("~p:~p~nissuer_function(~nCRL=~p,~nLast param=~p)",[?MODULE,?LINE,CRL, {TrustedCAs, IntermediateCerts}]),
+ Certs = [public_key:pkix_decode_cert(DER, otp) || DER <- TrustedCAs],
+ %% get the real issuer out of the CRL
+ Issuer = public_key:pkix_normalize_name(
+ pubkey_cert_records:transform(
+ CRL#'CertificateList'.tbsCertList#'TBSCertList'.issuer, decode)),
+ %% assume certificates are ordered from root to tip
+ case find_issuer(Issuer, IntermediateCerts ++ Certs) of
+ undefined ->
+ ct:log("~p:~p~nunable to find certificate matching CRL issuer ~p~n",
+ [?MODULE,?LINE, Issuer]),
+ error;
+ IssuerCert ->
+ ct:log("~p:~p~nIssuerCert=~p~n)",[?MODULE,?LINE,IssuerCert]),
+ case build_chain({public_key:pkix_encode('OTPCertificate',
+ IssuerCert,
+ otp),
+ IssuerCert}, IntermediateCerts, Certs, []) of
+ undefined ->
+ error;
+ {OTPCert, Path} ->
+ {ok, OTPCert, Path}
+ end
+ end.
+
+%% @doc Attempt to build authority chain back using intermediary
+%% certificates, falling back on trusted certificates if the
+%% intermediary chain of certificates does not fully extend to the
+%% root.
+%%
+%% Returns: {RootCA :: #OTPCertificate{}, Chain :: [der_encoded()]}
+%%
+build_chain({DER, Cert}, IntCerts, TrustedCerts, Acc) ->
+ %% check if this cert is self-signed, if it is, we've reached the
+ %% root of the chain
+ Issuer = public_key:pkix_normalize_name(
+ Cert#'OTPCertificate'.tbsCertificate#'OTPTBSCertificate'.issuer),
+ Subject = public_key:pkix_normalize_name(
+ Cert#'OTPCertificate'.tbsCertificate#'OTPTBSCertificate'.subject),
+ case Issuer == Subject of
+ true ->
+ case find_issuer(Issuer, TrustedCerts) of
+ undefined ->
+ ct:log("~p:~p~nself-signed certificate is NOT trusted~n",[?MODULE,?LINE]),
+ undefined;
+ TrustedCert ->
+ %% return the cert from the trusted list, to prevent
+ %% issuer spoofing
+ {TrustedCert,
+ [public_key:pkix_encode(
+ 'OTPCertificate', TrustedCert, otp)|Acc]}
+ end;
+ false ->
+ Match = lists:foldl(
+ fun(C, undefined) ->
+ S = public_key:pkix_normalize_name(C#'OTPCertificate'.tbsCertificate#'OTPTBSCertificate'.subject),
+ %% compare the subject to the current issuer
+ case Issuer == S of
+ true ->
+ %% we've found our man
+ {public_key:pkix_encode('OTPCertificate', C, otp), C};
+ false ->
+ undefined
+ end;
+ (_E, A) ->
+ %% already matched
+ A
+ end, undefined, IntCerts),
+ case Match of
+ undefined when IntCerts /= TrustedCerts ->
+ %% continue the chain by using the trusted CAs
+ ct:log("~p:~p~nRan out of intermediate certs, switching to trusted certs~n",[?MODULE,?LINE]),
+ build_chain({DER, Cert}, TrustedCerts, TrustedCerts, Acc);
+ undefined ->
+ ct:log("Can't construct chain of trust beyond ~p~n",
+ [?MODULE,?LINE, get_common_name(Cert)]),
+ %% can't find the current cert's issuer
+ undefined;
+ Match ->
+ build_chain(Match, IntCerts, TrustedCerts, [DER|Acc])
+ end
+ end.
+
+%% @doc Given a certificate and a list of trusted or intermediary
+%% certificates, attempt to find a match in the list or bail with
+%% undefined.
+find_issuer(Issuer, Certs) ->
+ lists:foldl(
+ fun(OTPCert, undefined) ->
+ %% check if this certificate matches the issuer
+ Normal = public_key:pkix_normalize_name(
+ OTPCert#'OTPCertificate'.tbsCertificate#'OTPTBSCertificate'.subject),
+ case Normal == Issuer of
+ true ->
+ OTPCert;
+ false ->
+ undefined
+ end;
+ (_E, Acc) ->
+ %% already found a match
+ Acc
+ end, undefined, Certs).
+
+%% @doc Find distribution points for a given CRL and then attempt to
+%% fetch the CRL from the first available.
+fetch_point(#'DistributionPoint'{distributionPoint={fullName, Names}}) ->
+ Decoded = [{NameType,
+ pubkey_cert_records:transform(Name, decode)}
+ || {NameType, Name} <- Names],
+ ct:log("~p:~p~ncall fetch(~nDecoded=~p~n)",[?MODULE,?LINE,Decoded]),
+ fetch(Decoded).
+
+%% @doc Given a list of locations to retrieve a CRL from, attempt to
+%% retrieve either from a file or http resource and bail as soon as
+%% it can be found.
+%%
+%% Currently, only hand a armored PEM or DER encoded file, with
+%% defaulting to DER.
+%%
+fetch([]) ->
+ not_available;
+fetch([{uniformResourceIdentifier, "http"++_=URL}|Rest]) ->
+ ct:log("~p:~p~ngetting CRL from ~p~n", [?MODULE,?LINE, URL]),
+ ct:log("~p:~p~nlisteners to port 8000:~n~p~n)",[?MODULE,?LINE,os:cmd("netstat -tln|grep ':8000'")]),
+ case httpc:request(get, {URL, []}, [], [{body_format, binary}]) of
+ {ok, {_Status, _Headers, Body}} ->
+ case Body of
+ <<"-----BEGIN", _/binary>> ->
+ ct:log("~p:~p~npublic_key:pem_decode,~nBody=~p~n)",[?MODULE,?LINE,Body]),
+ [{'CertificateList',
+ DER, _}=CertList] = public_key:pem_decode(Body),
+ ct:log("~p:~p~npublic_key:pem_entry_decode,~nCertList=~p~n)",[?MODULE,?LINE,CertList]),
+ {DER, public_key:pem_entry_decode(CertList)};
+ _ ->
+ ct:log("~p:~p~npublic_key:pem_entry_decode,~nBody=~p~n)",[?MODULE,?LINE,{'CertificateList', Body, not_encrypted}]),
+ %% assume DER encoded
+ try
+ public_key:pem_entry_decode({'CertificateList', Body, not_encrypted})
+ of
+ CertList -> {Body, CertList}
+ catch
+ _C:_E ->
+ ct:log("~p:~p~nfailed DER assumption~nRest=~p", [?MODULE,?LINE,Rest]),
+ fetch(Rest)
+ end
+ end;
+ {error, _Reason} ->
+ ct:log("~p:~p~nfailed to get CRL ~p~n", [?MODULE,?LINE, _Reason]),
+ fetch(Rest);
+ Other ->
+ ct:log("~p:~p~nreally failed to get CRL ~p~n", [?MODULE,?LINE, Other]),
+ fetch(Rest)
+ end;
+fetch([Loc|Rest]) ->
+ %% unsupported CRL location
+ ct:log("~p:~p~nunable to fetch CRL from unsupported location ~p~n",
+ [?MODULE,?LINE, Loc]),
+ fetch(Rest).
+
+%% get the common name attribute out of an OTPCertificate record
+get_common_name(OTPCert) ->
+ %% You'd think there'd be an easier way than this giant mess, but I
+ %% couldn't find one.
+ {rdnSequence, Subject} = OTPCert#'OTPCertificate'.tbsCertificate#'OTPTBSCertificate'.subject,
+ case [Attribute#'AttributeTypeAndValue'.value || [Attribute] <- Subject,
+ Attribute#'AttributeTypeAndValue'.type == ?'id-at-commonName'] of
+ [Att] ->
+ case Att of
+ {teletexString, Str} -> Str;
+ {printableString, Str} -> Str;
+ {utf8String, Bin} -> binary_to_list(Bin)
+ end;
+ _ ->
+ unknown
+ end.
+
diff --git a/lib/ssl/test/ssl_handshake_SUITE.erl b/lib/ssl/test/ssl_handshake_SUITE.erl
index 7e8e8d2611..6d020c472b 100644
--- a/lib/ssl/test/ssl_handshake_SUITE.erl
+++ b/lib/ssl/test/ssl_handshake_SUITE.erl
@@ -34,6 +34,7 @@ suite() -> [{ct_hooks,[ts_install_cth]}].
all() -> [decode_hello_handshake,
decode_single_hello_extension_correctly,
+ decode_supported_elliptic_curves_hello_extension_correctly,
decode_unknown_hello_extension_correctly,
encode_single_hello_sni_extension_correctly].
@@ -67,6 +68,17 @@ decode_single_hello_extension_correctly(_Config) ->
#renegotiation_info{renegotiated_connection = <<0>>}
= Extensions#hello_extensions.renegotiation_info.
+decode_supported_elliptic_curves_hello_extension_correctly(_Config) ->
+ % List of supported and unsupported curves (RFC4492:S5.1.1)
+ ClientEllipticCurves = [0, tls_v1:oid_to_enum(?sect233k1), 37, tls_v1:oid_to_enum(?sect193r2), 16#badc],
+ % Construct extension binary - modified version of ssl_handshake:encode_hello_extensions([#elliptic_curves{}], _)
+ EllipticCurveList = << <<X:16>> || X <- ClientEllipticCurves>>,
+ ListLen = byte_size(EllipticCurveList),
+ Len = ListLen + 2,
+ Extension = <<?UINT16(?ELLIPTIC_CURVES_EXT), ?UINT16(Len), ?UINT16(ListLen), EllipticCurveList/binary>>,
+ % after decoding we should see only valid curves
+ #hello_extensions{elliptic_curves = DecodedCurves} = ssl_handshake:decode_hello_extensions(Extension),
+ #elliptic_curves{elliptic_curve_list = [?sect233k1, ?sect193r2]} = DecodedCurves.
decode_unknown_hello_extension_correctly(_Config) ->
FourByteUnknown = <<16#CA,16#FE, ?UINT16(4), 3, 0, 1, 2>>,
diff --git a/lib/ssl/test/ssl_test_lib.erl b/lib/ssl/test/ssl_test_lib.erl
index 7ed9adfcd9..59f10d53a6 100644
--- a/lib/ssl/test/ssl_test_lib.erl
+++ b/lib/ssl/test/ssl_test_lib.erl
@@ -60,7 +60,7 @@ run_server(Opts) ->
Options = proplists:get_value(options, Opts),
Pid = proplists:get_value(from, Opts),
Transport = proplists:get_value(transport, Opts, ssl),
- ct:log("ssl:listen(~p, ~p)~n", [Port, Options]),
+ ct:log("~p:~p~nssl:listen(~p, ~p)~n", [?MODULE,?LINE, Port, Options]),
{ok, ListenSocket} = rpc:call(Node, Transport, listen, [Port, Options]),
Pid ! {listen, up},
send_selected_port(Pid, Port, ListenSocket),
@@ -78,13 +78,13 @@ do_run_server(ListenSocket, AcceptSocket, Opts) ->
Pid = proplists:get_value(from, Opts),
Transport = proplists:get_value(transport, Opts, ssl),
{Module, Function, Args} = proplists:get_value(mfa, Opts),
- ct:log("Server: apply(~p,~p,~p)~n",
- [Module, Function, [AcceptSocket | Args]]),
+ ct:log("~p:~p~nServer: apply(~p,~p,~p)~n",
+ [?MODULE,?LINE, Module, Function, [AcceptSocket | Args]]),
case rpc:call(Node, Module, Function, [AcceptSocket | Args]) of
no_result_msg ->
ok;
Msg ->
- ct:log("Server Msg: ~p ~n", [Msg]),
+ ct:log("~p:~p~nServer Msg: ~p ~n", [?MODULE,?LINE, Msg]),
Pid ! {self(), Msg}
end,
receive
@@ -93,10 +93,10 @@ do_run_server(ListenSocket, AcceptSocket, Opts) ->
{listen, MFA} ->
run_server(ListenSocket, [MFA | proplists:delete(mfa, Opts)]);
close ->
- ct:log("Server closing ~p ~n", [self()]),
+ ct:log("~p:~p~nServer closing ~p ~n", [?MODULE,?LINE, self()]),
Result = rpc:call(Node, Transport, close, [AcceptSocket], 500),
Result1 = rpc:call(Node, Transport, close, [ListenSocket], 500),
- ct:log("Result ~p : ~p ~n", [Result, Result1]);
+ ct:log("~p:~p~nResult ~p : ~p ~n", [?MODULE,?LINE, Result, Result1]);
{ssl_closed, _} ->
ok
end.
@@ -106,7 +106,8 @@ connect(#sslsocket{} = ListenSocket, Opts) ->
Node = proplists:get_value(node, Opts),
ReconnectTimes = proplists:get_value(reconnect_times, Opts, 0),
Timeout = proplists:get_value(timeout, Opts, infinity),
- AcceptSocket = connect(ListenSocket, Node, 1 + ReconnectTimes, dummy, Timeout),
+ SslOpts = proplists:get_value(ssl_opts, Opts, []),
+ AcceptSocket = connect(ListenSocket, Node, 1 + ReconnectTimes, dummy, Timeout, SslOpts),
case ReconnectTimes of
0 ->
AcceptSocket;
@@ -116,27 +117,35 @@ connect(#sslsocket{} = ListenSocket, Opts) ->
end;
connect(ListenSocket, Opts) ->
Node = proplists:get_value(node, Opts),
- ct:log("gen_tcp:accept(~p)~n", [ListenSocket]),
+ ct:log("~p:~p~ngen_tcp:accept(~p)~n", [?MODULE,?LINE, ListenSocket]),
{ok, AcceptSocket} = rpc:call(Node, gen_tcp, accept,
[ListenSocket]),
AcceptSocket.
-connect(_, _, 0, AcceptSocket, _) ->
+connect(_, _, 0, AcceptSocket, _, _) ->
AcceptSocket;
-connect(ListenSocket, Node, N, _, Timeout) ->
+
+connect(ListenSocket, Node, N, _, Timeout, []) ->
ct:log("ssl:transport_accept(~p)~n", [ListenSocket]),
{ok, AcceptSocket} = rpc:call(Node, ssl, transport_accept,
[ListenSocket]),
- ct:log("ssl:ssl_accept(~p, ~p)~n", [AcceptSocket, Timeout]),
+ ct:log("~p:~p~nssl:ssl_accept(~p, ~p)~n", [?MODULE,?LINE, AcceptSocket, Timeout]),
case rpc:call(Node, ssl, ssl_accept, [AcceptSocket, Timeout]) of
ok ->
- connect(ListenSocket, Node, N-1, AcceptSocket, Timeout);
+ connect(ListenSocket, Node, N-1, AcceptSocket, Timeout, []);
Result ->
+ ct:log("~p:~p~nssl:ssl_accept@~p ret ~p",[?MODULE,?LINE, Node,Result]),
Result
- end.
+ end;
+connect(ListenSocket, Node, _, _, Timeout, Opts) ->
+ ct:log("ssl:transport_accept(~p)~n", [ListenSocket]),
+ {ok, AcceptSocket} = rpc:call(Node, ssl, transport_accept,
+ [ListenSocket]),
+ ct:log("ssl:ssl_accept(~p,~p, ~p)~n", [AcceptSocket, Opts, Timeout]),
+ rpc:call(Node, ssl, ssl_accept, [AcceptSocket, Opts, Timeout]),
+ AcceptSocket.
-
remove_close_msg(0) ->
ok;
remove_close_msg(ReconnectTimes) ->
@@ -148,11 +157,13 @@ remove_close_msg(ReconnectTimes) ->
start_client(Args) ->
Result = spawn_link(?MODULE, run_client_init, [lists:delete(return_socket, Args)]),
receive
- { connected, Socket } ->
- case lists:member(return_socket, Args) of
- true -> { Result, Socket };
- false -> Result
- end
+ {connected, Socket} ->
+ case lists:member(return_socket, Args) of
+ true -> {Result, Socket};
+ false -> Result
+ end;
+ {connect_failed, Reason} ->
+ {connect_failed, Reason}
end.
run_client_init(Opts) ->
@@ -166,27 +177,30 @@ run_client(Opts) ->
Pid = proplists:get_value(from, Opts),
Transport = proplists:get_value(transport, Opts, ssl),
Options = proplists:get_value(options, Opts),
- ct:log("ssl:connect(~p, ~p, ~p)~n", [Host, Port, Options]),
+ ct:log("~p:~p~nssl:connect(~p, ~p, ~p)~n", [?MODULE,?LINE, Host, Port, Options]),
+ct:log("~p:~p~nnet_adm:ping(~p)=~p",[?MODULE,?LINE, Node,net_adm:ping(Node)]),
+%%ct:log("~p:~p~n~p:connect(~p, ~p, ~p)@~p~n", [?MODULE,?LINE, Transport, Host, Port, Options, Node]),
+ct:log("~p:~p~n~p:connect(~p, ~p, ...)@~p~n", [?MODULE,?LINE, Transport, Host, Port, Node]),
case rpc:call(Node, Transport, connect, [Host, Port, Options]) of
{ok, Socket} ->
- Pid ! { connected, Socket },
- ct:log("Client: connected~n", []),
+ Pid ! {connected, Socket},
+ ct:log("~p:~p~nClient: connected~n", [?MODULE,?LINE]),
%% In special cases we want to know the client port, it will
%% be indicated by sending {port, 0} in options list!
send_selected_port(Pid, proplists:get_value(port, Options), Socket),
{Module, Function, Args} = proplists:get_value(mfa, Opts),
- ct:log("Client: apply(~p,~p,~p)~n",
- [Module, Function, [Socket | Args]]),
+ ct:log("~p:~p~nClient: apply(~p,~p,~p)~n",
+ [?MODULE,?LINE, Module, Function, [Socket | Args]]),
case rpc:call(Node, Module, Function, [Socket | Args]) of
no_result_msg ->
ok;
Msg ->
- ct:log("Client Msg: ~p ~n", [Msg]),
+ ct:log("~p:~p~nClient Msg: ~p ~n", [?MODULE,?LINE, Msg]),
Pid ! {self(), Msg}
end,
receive
close ->
- ct:log("Client closing~n", []),
+ ct:log("~p:~p~nClient closing~n", [?MODULE,?LINE]),
rpc:call(Node, Transport, close, [Socket]);
{ssl_closed, Socket} ->
ok;
@@ -196,50 +210,42 @@ run_client(Opts) ->
{error, econnrefused = Reason} ->
case get(retries) of
N when N < 5 ->
+ ct:log("~p:~p~neconnrefused retries=~p sleep ~p",[?MODULE,?LINE, N,?SLEEP]),
put(retries, N+1),
ct:sleep(?SLEEP),
run_client(Opts);
_ ->
- ct:log("Client faild several times: connection failed: ~p ~n", [Reason]),
+ ct:log("~p:~p~nClient faild several times: connection failed: ~p ~n", [?MODULE,?LINE, Reason]),
Pid ! {self(), {error, Reason}}
end;
{error, Reason} ->
- ct:log("Client: connection failed: ~p ~n", [Reason]),
- Pid ! {self(), {error, Reason}}
+ ct:log("~p:~p~nClient: connection failed: ~p ~n", [?MODULE,?LINE, Reason]),
+ Pid ! {connect_failed, Reason};
+ {badrpc,BadRPC} ->
+ ct:log("~p:~p~nBad rpc: ~p",[?MODULE,?LINE, BadRPC]),
+ Pid ! {connect_failed, {badrpc,BadRPC}}
end.
close(Pid) ->
- ct:log("Close ~p ~n", [Pid]),
+ ct:log("~p:~p~nClose ~p ~n", [?MODULE,?LINE, Pid]),
Monitor = erlang:monitor(process, Pid),
Pid ! close,
receive
{'DOWN', Monitor, process, Pid, Reason} ->
erlang:demonitor(Monitor),
- ct:log("Pid: ~p down due to:~p ~n", [Pid, Reason])
+ ct:log("~p:~p~nPid: ~p down due to:~p ~n", [?MODULE,?LINE, Pid, Reason])
end.
check_result(Server, ServerMsg, Client, ClientMsg) ->
receive
- {Server, ServerMsg} ->
- receive
- {Client, ClientMsg} ->
- ok;
- Unexpected ->
- Reason = {{expected, {Client, ClientMsg}},
- {got, Unexpected}},
- ct:fail(Reason)
- end;
- {Client, ClientMsg} ->
- receive
- {Server, ServerMsg} ->
- ok;
- Unexpected ->
- Reason = {{expected, {Server, ClientMsg}},
- {got, Unexpected}},
- ct:fail(Reason)
- end;
+ {Server, ServerMsg} ->
+ check_result(Client, ClientMsg);
+
+ {Client, ClientMsg} ->
+ check_result(Server, ServerMsg);
+
{Port, {data,Debug}} when is_port(Port) ->
- io:format("openssl ~s~n",[Debug]),
+ ct:log("~p:~p~nopenssl ~s~n",[?MODULE,?LINE, Debug]),
check_result(Server, ServerMsg, Client, ClientMsg);
Unexpected ->
@@ -253,7 +259,7 @@ check_result(Pid, Msg) ->
{Pid, Msg} ->
ok;
{Port, {data,Debug}} when is_port(Port) ->
- io:format("openssl ~s~n",[Debug]),
+ ct:log("~p:~p~nopenssl ~s~n",[?MODULE,?LINE, Debug]),
check_result(Pid,Msg);
Unexpected ->
Reason = {{expected, {Pid, Msg}},
@@ -278,7 +284,7 @@ wait_for_result(Server, ServerMsg, Client, ClientMsg) ->
%% Unexpected
end;
{Port, {data,Debug}} when is_port(Port) ->
- io:format("openssl ~s~n",[Debug]),
+ ct:log("~p:~p~nopenssl ~s~n",[?MODULE,?LINE, Debug]),
wait_for_result(Server, ServerMsg, Client, ClientMsg)
%% Unexpected ->
%% Unexpected
@@ -290,7 +296,7 @@ wait_for_result(Pid, Msg) ->
{Pid, Msg} ->
ok;
{Port, {data,Debug}} when is_port(Port) ->
- io:format("openssl ~s~n",[Debug]),
+ ct:log("~p:~p~nopenssl ~s~n",[?MODULE,?LINE, Debug]),
wait_for_result(Pid,Msg)
%% Unexpected ->
%% Unexpected
@@ -515,33 +521,33 @@ run_upgrade_server(Opts) ->
SslOptions = proplists:get_value(ssl_options, Opts),
Pid = proplists:get_value(from, Opts),
- ct:log("gen_tcp:listen(~p, ~p)~n", [Port, TcpOptions]),
+ ct:log("~p:~p~ngen_tcp:listen(~p, ~p)~n", [?MODULE,?LINE, Port, TcpOptions]),
{ok, ListenSocket} = rpc:call(Node, gen_tcp, listen, [Port, TcpOptions]),
Pid ! {listen, up},
send_selected_port(Pid, Port, ListenSocket),
- ct:log("gen_tcp:accept(~p)~n", [ListenSocket]),
+ ct:log("~p:~p~ngen_tcp:accept(~p)~n", [?MODULE,?LINE, ListenSocket]),
{ok, AcceptSocket} = rpc:call(Node, gen_tcp, accept, [ListenSocket]),
try
{ok, SslAcceptSocket} = case TimeOut of
infinity ->
- ct:log("ssl:ssl_accept(~p, ~p)~n",
- [AcceptSocket, SslOptions]),
+ ct:log("~p:~p~nssl:ssl_accept(~p, ~p)~n",
+ [?MODULE,?LINE, AcceptSocket, SslOptions]),
rpc:call(Node, ssl, ssl_accept,
[AcceptSocket, SslOptions]);
_ ->
- ct:log("ssl:ssl_accept(~p, ~p, ~p)~n",
- [AcceptSocket, SslOptions, TimeOut]),
+ ct:log("~p:~p~nssl:ssl_accept(~p, ~p, ~p)~n",
+ [?MODULE,?LINE, AcceptSocket, SslOptions, TimeOut]),
rpc:call(Node, ssl, ssl_accept,
[AcceptSocket, SslOptions, TimeOut])
end,
{Module, Function, Args} = proplists:get_value(mfa, Opts),
Msg = rpc:call(Node, Module, Function, [SslAcceptSocket | Args]),
- ct:log("Upgrade Server Msg: ~p ~n", [Msg]),
+ ct:log("~p:~p~nUpgrade Server Msg: ~p ~n", [?MODULE,?LINE, Msg]),
Pid ! {self(), Msg},
receive
close ->
- ct:log("Upgrade Server closing~n", []),
+ ct:log("~p:~p~nUpgrade Server closing~n", [?MODULE,?LINE]),
rpc:call(Node, ssl, close, [SslAcceptSocket])
end
catch error:{badmatch, Error} ->
@@ -559,24 +565,24 @@ run_upgrade_client(Opts) ->
TcpOptions = proplists:get_value(tcp_options, Opts),
SslOptions = proplists:get_value(ssl_options, Opts),
- ct:log("gen_tcp:connect(~p, ~p, ~p)~n",
- [Host, Port, TcpOptions]),
+ ct:log("~p:~p~ngen_tcp:connect(~p, ~p, ~p)~n",
+ [?MODULE,?LINE, Host, Port, TcpOptions]),
{ok, Socket} = rpc:call(Node, gen_tcp, connect, [Host, Port, TcpOptions]),
send_selected_port(Pid, Port, Socket),
- ct:log("ssl:connect(~p, ~p)~n", [Socket, SslOptions]),
+ ct:log("~p:~p~nssl:connect(~p, ~p)~n", [?MODULE,?LINE, Socket, SslOptions]),
{ok, SslSocket} = rpc:call(Node, ssl, connect, [Socket, SslOptions]),
{Module, Function, Args} = proplists:get_value(mfa, Opts),
- ct:log("apply(~p, ~p, ~p)~n",
- [Module, Function, [SslSocket | Args]]),
+ ct:log("~p:~p~napply(~p, ~p, ~p)~n",
+ [?MODULE,?LINE, Module, Function, [SslSocket | Args]]),
Msg = rpc:call(Node, Module, Function, [SslSocket | Args]),
- ct:log("Upgrade Client Msg: ~p ~n", [Msg]),
+ ct:log("~p:~p~nUpgrade Client Msg: ~p ~n", [?MODULE,?LINE, Msg]),
Pid ! {self(), Msg},
receive
close ->
- ct:log("Upgrade Client closing~n", []),
+ ct:log("~p:~p~nUpgrade Client closing~n", [?MODULE,?LINE]),
rpc:call(Node, ssl, close, [SslSocket])
end.
@@ -595,21 +601,21 @@ run_upgrade_server_error(Opts) ->
SslOptions = proplists:get_value(ssl_options, Opts),
Pid = proplists:get_value(from, Opts),
- ct:log("gen_tcp:listen(~p, ~p)~n", [Port, TcpOptions]),
+ ct:log("~p:~p~ngen_tcp:listen(~p, ~p)~n", [?MODULE,?LINE, Port, TcpOptions]),
{ok, ListenSocket} = rpc:call(Node, gen_tcp, listen, [Port, TcpOptions]),
Pid ! {listen, up},
send_selected_port(Pid, Port, ListenSocket),
- ct:log("gen_tcp:accept(~p)~n", [ListenSocket]),
+ ct:log("~p:~p~ngen_tcp:accept(~p)~n", [?MODULE,?LINE, ListenSocket]),
{ok, AcceptSocket} = rpc:call(Node, gen_tcp, accept, [ListenSocket]),
Error = case TimeOut of
infinity ->
- ct:log("ssl:ssl_accept(~p, ~p)~n",
- [AcceptSocket, SslOptions]),
+ ct:log("~p:~p~nssl:ssl_accept(~p, ~p)~n",
+ [?MODULE,?LINE, AcceptSocket, SslOptions]),
rpc:call(Node, ssl, ssl_accept,
[AcceptSocket, SslOptions]);
_ ->
- ct:log("ssl:ssl_accept(~p, ~p, ~p)~n",
- [AcceptSocket, SslOptions, TimeOut]),
+ ct:log("~p:~p~nssl:ssl_accept(~p, ~p, ~p)~n",
+ [?MODULE,?LINE, AcceptSocket, SslOptions, TimeOut]),
rpc:call(Node, ssl, ssl_accept,
[AcceptSocket, SslOptions, TimeOut])
end,
@@ -628,26 +634,26 @@ run_server_error(Opts) ->
Options = proplists:get_value(options, Opts),
Pid = proplists:get_value(from, Opts),
Transport = proplists:get_value(transport, Opts, ssl),
- ct:log("ssl:listen(~p, ~p)~n", [Port, Options]),
+ ct:log("~p:~p~nssl:listen(~p, ~p)~n", [?MODULE,?LINE, Port, Options]),
case rpc:call(Node, Transport, listen, [Port, Options]) of
{ok, #sslsocket{} = ListenSocket} ->
%% To make sure error_client will
%% get {error, closed} and not {error, connection_refused}
Pid ! {listen, up},
send_selected_port(Pid, Port, ListenSocket),
- ct:log("ssl:transport_accept(~p)~n", [ListenSocket]),
+ ct:log("~p:~p~nssl:transport_accept(~p)~n", [?MODULE,?LINE, ListenSocket]),
case rpc:call(Node, Transport, transport_accept, [ListenSocket]) of
{error, _} = Error ->
Pid ! {self(), Error};
{ok, AcceptSocket} ->
- ct:log("ssl:ssl_accept(~p)~n", [AcceptSocket]),
+ ct:log("~p:~p~nssl:ssl_accept(~p)~n", [?MODULE,?LINE, AcceptSocket]),
Error = rpc:call(Node, ssl, ssl_accept, [AcceptSocket]),
Pid ! {self(), Error}
end;
{ok, ListenSocket} ->
Pid ! {listen, up},
send_selected_port(Pid, Port, ListenSocket),
- ct:log("~p:accept(~p)~n", [Transport, ListenSocket]),
+ ct:log("~p:~p~n~p:accept(~p)~n", [?MODULE,?LINE, Transport, ListenSocket]),
case rpc:call(Node, Transport, accept, [ListenSocket]) of
{error, _} = Error ->
Pid ! {self(), Error}
@@ -669,7 +675,7 @@ run_client_error(Opts) ->
Pid = proplists:get_value(from, Opts),
Transport = proplists:get_value(transport, Opts, ssl),
Options = proplists:get_value(options, Opts),
- ct:log("ssl:connect(~p, ~p, ~p)~n", [Host, Port, Options]),
+ ct:log("~p:~p~nssl:connect(~p, ~p, ~p)~n", [?MODULE,?LINE, Host, Port, Options]),
Error = rpc:call(Node, Transport, connect, [Host, Port, Options]),
Pid ! {self(), Error}.
@@ -892,7 +898,7 @@ der_to_pem(File, Entries) ->
cipher_result(Socket, Result) ->
Result = ssl:connection_info(Socket),
- ct:log("Successfull connect: ~p~n", [Result]),
+ ct:log("~p:~p~nSuccessfull connect: ~p~n", [?MODULE,?LINE, Result]),
%% Importante to send two packets here
%% to properly test "cipher state" handling
ssl:send(Socket, "Hello\n"),
@@ -1061,10 +1067,13 @@ check_sane_openssl_version(Version) ->
true
end.
+enough_openssl_crl_support("OpenSSL 0." ++ _) -> false;
+enough_openssl_crl_support(_) -> true.
+
wait_for_openssl_server() ->
receive
{Port, {data, Debug}} when is_port(Port) ->
- ct:log("openssl ~s~n",[Debug]),
+ ct:log("~p:~p~nopenssl ~s~n",[?MODULE,?LINE, Debug]),
%% openssl has started make sure
%% it will be in accept. Parsing
%% output is too error prone. (Even
diff --git a/lib/stdlib/doc/src/epp.xml b/lib/stdlib/doc/src/epp.xml
index cf33530395..452341f7d2 100644
--- a/lib/stdlib/doc/src/epp.xml
+++ b/lib/stdlib/doc/src/epp.xml
@@ -4,7 +4,7 @@
<erlref>
<header>
<copyright>
- <year>1996</year><year>2013</year>
+ <year>1996</year><year>2014</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -46,8 +46,10 @@
valid encodings are <c>Latin-1</c> and <c>UTF-8</c> where the
case of the characters can be chosen freely. Examples:</p>
<pre>
-%% coding: utf-8
-%% For this file we have chosen encoding = Latin-1
+%% coding: utf-8</pre>
+ <pre>
+%% For this file we have chosen encoding = Latin-1</pre>
+ <pre>
%% -*- coding: latin-1 -*-</pre>
</description>
<datatypes>
@@ -64,11 +66,29 @@
</datatypes>
<funcs>
<func>
+ <name name="open" arity="1"/>
+ <fsummary>Open a file for preprocessing</fsummary>
+ <desc>
+ <p>Opens a file for preprocessing.</p>
+ <p>If <c>extra</c> is given in
+ <c><anno>Options</anno></c>, the return value will be
+ <c>{ok, <anno>Epp</anno>, <anno>Extra</anno>}</c> instead
+ of <c>{ok, <anno>Epp</anno>}</c>.</p>
+ </desc>
+ </func>
+ <func>
<name name="open" arity="2"/>
+ <fsummary>Open a file for preprocessing</fsummary>
+ <desc>
+ <p>Equivalent to <c>epp:open([{name, FileName}, {includes, IncludePath}])</c>.</p>
+ </desc>
+ </func>
+ <func>
<name name="open" arity="3"/>
<fsummary>Open a file for preprocessing</fsummary>
<desc>
- <p>Opens a file for preprocessing.</p>
+ <p>Equivalent to <c>epp:open([{name, FileName}, {includes, IncludePath},
+ {macros, PredefMacros}])</c>.</p>
</desc>
</func>
<func>
@@ -89,12 +109,24 @@
</desc>
</func>
<func>
- <name name="parse_file" arity="3"/>
+ <name name="parse_file" arity="2"/>
<fsummary>Preprocess and parse an Erlang source file</fsummary>
<desc>
<p>Preprocesses and parses an Erlang source file.
- Note that the tuple <c>{eof, <anno>Line</anno>}</c> returned at end-of-file is
- included as a "form".</p>
+ Note that the tuple <c>{eof, <anno>Line</anno>}</c> returned
+ at end-of-file is included as a "form".</p>
+ <p>If <c>extra</c> is given in
+ <c><anno>Options</anno></c>, the return value will be
+ <c>{ok, [<anno>Form</anno>], <anno>Extra</anno>}</c> instead
+ of <c>{ok, [<anno>Form</anno>]}</c>.</p>
+ </desc>
+ </func>
+ <func>
+ <name name="parse_file" arity="3"/>
+ <fsummary>Preprocess and parse an Erlang source file</fsummary>
+ <desc>
+ <p>Equivalent to <c>epp:parse_file(FileName, [{includes, IncludePath},
+ {macros, PredefMacros}])</c>.</p>
</desc>
</func>
<func>
@@ -111,7 +143,7 @@
<p>Returns a string representation of an encoding. The string
is recognized by <c>read_encoding/1,2</c>,
<c>read_encoding_from_binary/1,2</c>, and
- <c>set_encoding/1</c> as a valid encoding.</p>
+ <c>set_encoding/1,2</c> as a valid encoding.</p>
</desc>
</func>
<func>
@@ -157,6 +189,22 @@
</desc>
</func>
<func>
+ <name name="set_encoding" arity="2"/>
+ <fsummary>Read and set the encoding of an IO device</fsummary>
+ <desc>
+ <p>Reads the <seealso marker="#encoding">encoding</seealso> from
+ an IO device and sets the encoding of the device
+ accordingly. The position of the IO device referenced by
+ <c><anno>File</anno></c> is not affected. If no valid
+ encoding can be read from the IO device the encoding of the
+ IO device is set to the
+ <seealso marker="#encoding">encoding</seealso> given by
+ <c><anno>Default</anno></c>.</p>
+ <p>Returns the read encoding, or <c>none</c> if no valid
+ encoding was found.</p>
+ </desc>
+ </func>
+ <func>
<name name="format_error" arity="1"/>
<fsummary>Format an error descriptor</fsummary>
<desc>
diff --git a/lib/stdlib/doc/src/erl_parse.xml b/lib/stdlib/doc/src/erl_parse.xml
index 2d5aff3c6c..cf0bff48cd 100644
--- a/lib/stdlib/doc/src/erl_parse.xml
+++ b/lib/stdlib/doc/src/erl_parse.xml
@@ -4,7 +4,7 @@
<erlref>
<header>
<copyright>
- <year>1996</year><year>2013</year>
+ <year>1996</year><year>2014</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -173,6 +173,7 @@
</func>
<func>
<name name="abstract" arity="2"/>
+ <type name="encoding_func"/>
<fsummary>Convert an Erlang term into an abstract form</fsummary>
<desc>
<p>Converts the Erlang data structure <c><anno>Data</anno></c> into an
@@ -183,7 +184,12 @@
selecting which integer lists will be considered
as strings. The default is to use the encoding returned by
<seealso marker="epp#default_encoding/0">
- <c>epp:default_encoding/0</c></seealso></p>
+ <c>epp:default_encoding/0</c></seealso>.
+ The value <c>none</c> means that no integer lists will be
+ considered as strings. The <c>encoding_func()</c> will be
+ called with one integer of a list at a time, and if it
+ returns <c>true</c> for every integer the list will be
+ considered a string.</p>
</desc>
</func>
</funcs>
diff --git a/lib/stdlib/doc/src/sys.xml b/lib/stdlib/doc/src/sys.xml
index ab8b380f49..a46fa1289f 100644
--- a/lib/stdlib/doc/src/sys.xml
+++ b/lib/stdlib/doc/src/sys.xml
@@ -246,6 +246,22 @@
<c>{Module, Id, HandlerState}</c>, where <c>Module</c> is the event handler's module name,
<c>Id</c> is the handler's ID (which is the value <c>false</c> if it was registered without
an ID), and <c>HandlerState</c> is the handler's state.</p>
+ <p>If the callback module exports a <c>system_get_state/1</c> function, it will be called in the
+ target process to get its state. Its argument is the same as the <c>Misc</c> value returned by
+ <seealso marker="#get_status-1">get_status/1,2</seealso>, and the <c>system_get_state/1</c>
+ function is expected to extract the callback module's state from it. The <c>system_get_state/1</c>
+ function must return <c>{ok, State}</c> where <c>State</c> is the callback module's state.</p>
+ <p>If the callback module does not export a <c>system_get_state/1</c> function, <c>get_state/1,2</c>
+ assumes the <c>Misc</c> value is the callback module's state and returns it directly instead.</p>
+ <p>If the callback module's <c>system_get_state/1</c> function crashes or throws an exception, the
+ caller exits with error <c>{callback_failed, {Module, system_get_state}, {Class, Reason}}</c> where
+ <c>Module</c> is the name of the callback module and <c>Class</c> and <c>Reason</c> indicate
+ details of the exception.</p>
+ <p>The <c>system_get_state/1</c> function is primarily useful for user-defined
+ behaviours and modules that implement OTP <seealso marker="#special_process">special
+ processes</seealso>. The <c>gen_server</c>, <c>gen_fsm</c>, and <c>gen_event</c> OTP
+ behaviour modules export this function, and so callback modules for those behaviours
+ need not supply their own.</p>
<p>To obtain more information about a process, including its state, see
<seealso marker="#get_status-1">get_status/1</seealso> and
<seealso marker="#get_status-2">get_status/2</seealso>.</p>
@@ -289,6 +305,28 @@
function means that only the state of the particular event handler it was working on when it
failed or crashed is unchanged; it can still succeed in changing the states of other event
handlers registered in the same <c>gen_event</c> process.</p>
+ <p>If the callback module exports a <c>system_replace_state/2</c> function, it will be called in the
+ target process to replace its state using <c>StateFun</c>. Its two arguments are <c>StateFun</c>
+ and <c>Misc</c>, where <c>Misc</c> is the same as the <c>Misc</c> value returned by
+ <seealso marker="#get_status-1">get_status/1,2</seealso>. A <c>system_replace_state/2</c> function
+ is expected to return <c>{ok, NewState, NewMisc}</c> where <c>NewState</c> is the callback module's
+ new state obtained by calling <c>StateFun</c>, and <c>NewMisc</c> is a possibly new value used to
+ replace the original <c>Misc</c> (required since <c>Misc</c> often contains the callback
+ module's state within it).</p>
+ <p>If the callback module does not export a <c>system_replace_state/2</c> function,
+ <c>replace_state/2,3</c> assumes the <c>Misc</c> value is the callback module's state, passes it
+ to <c>StateFun</c> and uses the return value as both the new state and as the new value of
+ <c>Misc</c>.</p>
+ <p>If the callback module's <c>system_replace_state/2</c> function crashes or throws an exception,
+ the caller exits with error <c>{callback_failed, {Module, system_replace_state}, {Class, Reason}}</c>
+ where <c>Module</c> is the name of the callback module and <c>Class</c> and <c>Reason</c> indicate details
+ of the exception. If the callback module does not provide a <c>system_replace_state/2</c> function and
+ <c>StateFun</c> crashes or throws an exception, the caller exits with error
+ <c>{callback_failed, StateFun, {Class, Reason}}</c>.</p>
+ <p>The <c>system_replace_state/2</c> function is primarily useful for user-defined behaviours and
+ modules that implement OTP <seealso marker="#special_process">special processes</seealso>. The
+ <c>gen_server</c>, <c>gen_fsm</c>, and <c>gen_event</c> OTP behaviour modules export this function,
+ and so callback modules for those behaviours need not supply their own.</p>
</desc>
</func>
<func>
@@ -322,7 +360,7 @@
<section>
<title>Process Implementation Functions</title>
- <p>The following functions are used when implementing a
+ <p><marker id="special_process"/>The following functions are used when implementing a
special process. This is an ordinary process which does not use a
standard behaviour, but a process which understands the standard system messages.</p>
</section>
@@ -375,8 +413,9 @@
process continues the execution, or
<c><anno>Module</anno>:system_terminate(Reason, <anno>Parent</anno>, <anno>Debug</anno>, <anno>Misc</anno>)</c> if
the process should terminate. The <c><anno>Module</anno></c> must export
- <c>system_continue/3</c>, <c>system_terminate/4</c>, and
- <c>system_code_change/4</c> (see below).
+ <c>system_continue/3</c>, <c>system_terminate/4</c>,
+ <c>system_code_change/4</c>, <c>system_get_state/1</c> and
+ <c>system_replace_state/2</c> (see below).
</p>
<p>The <c><anno>Misc</anno></c> argument can be used to save internal data
in a process, for example its state. It is sent to
@@ -444,6 +483,34 @@
defined, the atom <c>undefined</c> is sent.</p>
</desc>
</func>
+ <func>
+ <name>Mod:system_get_state(Misc) -> {ok, State}</name>
+ <fsummary>Called when the process should return its current state</fsummary>
+ <type>
+ <v>Misc = term()</v>
+ <v>State = term()</v>
+ </type>
+ <desc>
+ <p>This function is called from <c>sys:handle_system_msg/6</c> when the process
+ should return a term that reflects its current state. <c>State</c> is the
+ value returned by <c>sys:get_state/2</c>.</p>
+ </desc>
+ </func>
+ <func>
+ <name>Mod:system_replace_state(StateFun, Misc) -> {ok, NState, NMisc}</name>
+ <fsummary>Called when the process should replace its current state</fsummary>
+ <type>
+ <v>StateFun = fun((State :: term()) -> NState)</v>
+ <v>Misc = term()</v>
+ <v>NState = term()</v>
+ <v>NMisc = term()</v>
+ </type>
+ <desc>
+ <p>This function is called from <c>sys:handle_system_msg/6</c> when the process
+ should replace its current state. <c>NState</c> is the value returned by
+ <c>sys:replace_state/3</c>.</p>
+ </desc>
+ </func>
</funcs>
</erlref>
diff --git a/lib/stdlib/doc/src/unicode_usage.xml b/lib/stdlib/doc/src/unicode_usage.xml
index c843ef7736..bebfbd4514 100644
--- a/lib/stdlib/doc/src/unicode_usage.xml
+++ b/lib/stdlib/doc/src/unicode_usage.xml
@@ -848,6 +848,7 @@ Eshell V5.10.1 (abort with ^G)
</section>
<section>
<title>Unicode in Environment and Parameters</title>
+ <marker id="unicode_in_environment_and_parameters"/>
<p>Environment variables and their interpretation is handled much in
the same way as file names. If Unicode file names are enabled,
environment variables as well as parameters to the Erlang VM are
diff --git a/lib/stdlib/doc/src/zip.xml b/lib/stdlib/doc/src/zip.xml
index 66c21da193..48b376743d 100644
--- a/lib/stdlib/doc/src/zip.xml
+++ b/lib/stdlib/doc/src/zip.xml
@@ -123,6 +123,18 @@
</taglist>
</desc>
</datatype>
+ <datatype>
+ <name name="filename"/>
+ <p>The name of a zip file.</p>
+ </datatype>
+ <datatype><name name="extension"/></datatype>
+ <datatype><name name="extension_spec"/></datatype>
+ <datatype>
+ <name name="create_option"/>
+ <desc>
+ <p>These options are described in <seealso marker="#zip_options">create/3</seealso>.</p>
+ </desc>
+ </datatype>
</datatypes>
<funcs>
<func>
@@ -160,6 +172,7 @@
set to <c>["gif", "jpg"]</c> and <c>uncompress</c> is set to
<c>["jpg"]</c>, only files with <c>"gif"</c> as extension will
be compressed. No other files will be compressed.</p>
+ <marker id="zip_options"></marker>
<p>The following options are available:</p>
<taglist>
<tag><c>cooked</c></tag>
diff --git a/lib/stdlib/src/dict.erl b/lib/stdlib/src/dict.erl
index 6088e1a2dd..cf8fb3114a 100644
--- a/lib/stdlib/src/dict.erl
+++ b/lib/stdlib/src/dict.erl
@@ -55,8 +55,7 @@
-define(exp_size, (?seg_size * ?expand_load)).
-define(con_size, (?seg_size * ?contract_load)).
--type segs(K, V) :: tuple()
- | {K, V}. % dummy
+-type segs(_Key, _Value) :: tuple().
%% Define a hashtable. The default values are the standard ones.
-record(dict,
diff --git a/lib/stdlib/src/epp.erl b/lib/stdlib/src/epp.erl
index 68e079b7e5..9b506b0a44 100644
--- a/lib/stdlib/src/epp.erl
+++ b/lib/stdlib/src/epp.erl
@@ -20,12 +20,12 @@
%% An Erlang code preprocessor.
--export([open/2,open/3,open/5,close/1,format_error/1]).
+-export([open/1, open/2,open/3,open/5,close/1,format_error/1]).
-export([scan_erl_form/1,parse_erl_form/1,macro_defs/1]).
--export([parse_file/1, parse_file/3]).
+-export([parse_file/1, parse_file/2, parse_file/3]).
-export([default_encoding/0, encoding_to_string/1,
read_encoding_from_binary/1, read_encoding_from_binary/2,
- set_encoding/1, read_encoding/1, read_encoding/2]).
+ set_encoding/1, set_encoding/2, read_encoding/1, read_encoding/2]).
-export([interpret_file_attribute/1]).
-export([normalize_typed_record_fields/1,restore_typed_record_fields/1]).
@@ -33,21 +33,34 @@
-export_type([source_encoding/0]).
--type macros() :: [{atom(), term()}].
+-type macros() :: [atom() | {atom(), term()}].
-type epp_handle() :: pid().
-type source_encoding() :: latin1 | utf8.
+-type ifdef() :: 'ifdef' | 'ifndef' | 'else'.
+
+-type name() :: {'atom', atom()}.
+-type argspec() :: 'none' %No arguments
+ | non_neg_integer(). %Number of arguments
+-type tokens() :: [erl_scan:token()].
+-type used() :: {name(), argspec()}.
+
+-define(DEFAULT_ENCODING, utf8).
+
%% Epp state record.
--record(epp, {file, %Current file
- location, %Current location
- delta, %Offset from Location (-file)
- name="", %Current file name
- name2="", %-"-, modified by -file
- istk=[], %Ifdef stack
- sstk=[], %State stack
- path=[], %Include-path
- macs = dict:new() :: dict:dict(),%Macros (don't care locations)
- uses = dict:new() :: dict:dict(),%Macro use structure
+-record(epp, {file :: file:io_device(), %Current file
+ location=1, %Current location
+ delta=0 :: non_neg_integer(), %Offset from Location (-file)
+ name="" :: file:name(), %Current file name
+ name2="" :: file:name(), %-"-, modified by -file
+ istk=[] :: [ifdef()], %Ifdef stack
+ sstk=[] :: [#epp{}], %State stack
+ path=[] :: [file:name()], %Include-path
+ macs = dict:new() %Macros (don't care locations)
+ :: dict:dict(name(), {argspec(), tokens()}),
+ uses = dict:new() %Macro use structure
+ :: dict:dict(name(), [{argspec(), [used()]}]),
+ default_encoding = ?DEFAULT_ENCODING :: source_encoding(),
pre_opened = false :: boolean()
}).
@@ -58,6 +71,7 @@
%%% distinction in the internal representation would simplify the code
%%% a little.
+%% open(Options)
%% open(FileName, IncludePath)
%% open(FileName, IncludePath, PreDefMacros)
%% open(FileName, IoDevice, StartLocation, IncludePath, PreDefMacros)
@@ -65,6 +79,7 @@
%% scan_erl_form(Epp)
%% parse_erl_form(Epp)
%% parse_file(Epp)
+%% parse_file(FileName, Options)
%% parse_file(FileName, IncludePath, PreDefMacros)
%% macro_defs(Epp)
@@ -87,14 +102,43 @@ open(Name, Path) ->
ErrorDescriptor :: term().
open(Name, Path, Pdm) ->
- Self = self(),
- Epp = spawn(fun() -> server(Self, Name, Path, Pdm) end),
- epp_request(Epp).
+ internal_open([{name, Name}, {includes, Path}, {macros, Pdm}], #epp{}).
open(Name, File, StartLocation, Path, Pdm) ->
- Self = self(),
- Epp = spawn(fun() -> server(Self, Name, File, StartLocation,Path,Pdm) end),
- epp_request(Epp).
+ internal_open([{name, Name}, {includes, Path}, {macros, Pdm}],
+ #epp{file=File, pre_opened=true, location=StartLocation}).
+
+-spec open(Options) ->
+ {'ok', Epp} | {'ok', Epp, Extra} | {'error', ErrorDescriptor} when
+ Options :: [{'default_encoding', DefEncoding :: source_encoding()} |
+ {'includes', IncludePath :: [DirectoryName :: file:name()]} |
+ {'macros', PredefMacros :: macros()} |
+ {'name',FileName :: file:name()} |
+ 'extra'],
+ Epp :: epp_handle(),
+ Extra :: [{'encoding', source_encoding() | 'none'}],
+ ErrorDescriptor :: term().
+
+open(Options) ->
+ internal_open(Options, #epp{}).
+
+internal_open(Options, St) ->
+ case proplists:get_value(name, Options) of
+ undefined ->
+ erlang:error(badarg);
+ Name ->
+ Self = self(),
+ Epp = spawn(fun() -> server(Self, Name, Options, St) end),
+ case epp_request(Epp) of
+ {ok, Pid, Encoding} ->
+ case proplists:get_bool(extra, Options) of
+ true -> {ok, Pid, [{encoding, Encoding}]};
+ false -> {ok, Pid}
+ end;
+ Other ->
+ Other
+ end
+ end.
-spec close(Epp) -> 'ok' when
Epp :: epp_handle().
@@ -170,9 +214,6 @@ format_error({'NYI',What}) ->
io_lib:format("not yet implemented '~s'", [What]);
format_error(E) -> file:format_error(E).
-%% parse_file(FileName, IncludePath, [PreDefMacro]) ->
-%% {ok,[Form]} | {error,OpenError}
-
-spec parse_file(FileName, IncludePath, PredefMacros) ->
{'ok', [Form]} | {error, OpenError} when
FileName :: file:name(),
@@ -184,17 +225,40 @@ format_error(E) -> file:format_error(E).
OpenError :: file:posix() | badarg | system_limit.
parse_file(Ifile, Path, Predefs) ->
- case open(Ifile, Path, Predefs) of
+ parse_file(Ifile, [{includes, Path}, {macros, Predefs}]).
+
+-spec parse_file(FileName, Options) ->
+ {'ok', [Form]} | {'ok', [Form], Extra} | {error, OpenError} when
+ FileName :: file:name(),
+ Options :: [{'includes', IncludePath :: [DirectoryName :: file:name()]} |
+ {'macros', PredefMacros :: macros()} |
+ {'default_encoding', DefEncoding :: source_encoding()} |
+ 'extra'],
+ Form :: erl_parse:abstract_form() | {'error', ErrorInfo} | {'eof',Line},
+ Line :: erl_scan:line(),
+ ErrorInfo :: erl_scan:error_info() | erl_parse:error_info(),
+ Extra :: [{'encoding', source_encoding() | 'none'}],
+ OpenError :: file:posix() | badarg | system_limit.
+
+parse_file(Ifile, Options) ->
+ case internal_open([{name, Ifile} | Options], #epp{}) of
{ok,Epp} ->
Forms = parse_file(Epp),
close(Epp),
{ok,Forms};
+ {ok,Epp,Extra} ->
+ Forms = parse_file(Epp),
+ close(Epp),
+ {ok,Forms,Extra};
{error,E} ->
{error,E}
end.
-%% parse_file(Epp) ->
-%% [Form]
+-spec parse_file(Epp) -> [Form] when
+ Epp :: epp_handle(),
+ Form :: erl_parse:abstract_form() | {'error', ErrorInfo} | {'eof',Line},
+ Line :: erl_scan:line(),
+ ErrorInfo :: erl_scan:error_info() | erl_parse:error_info().
parse_file(Epp) ->
case parse_erl_form(Epp) of
@@ -219,8 +283,6 @@ parse_file(Epp) ->
[{eof,Location}]
end.
--define(DEFAULT_ENCODING, utf8).
-
-spec default_encoding() -> source_encoding().
default_encoding() ->
@@ -258,9 +320,16 @@ read_encoding(Name, Options) ->
File :: io:device(). % pid(); raw files don't work
set_encoding(File) ->
+ set_encoding(File, ?DEFAULT_ENCODING).
+
+-spec set_encoding(File, Default) -> source_encoding() | none when
+ Default :: source_encoding(),
+ File :: io:device(). % pid(); raw files don't work
+
+set_encoding(File, Default) ->
Encoding = read_encoding_from_file(File, true),
Enc = case Encoding of
- none -> default_encoding();
+ none -> Default;
Encoding -> Encoding
end,
ok = io:setopts(File, [{encoding, Enc}]),
@@ -446,35 +515,37 @@ restore_typed_record_fields([{attribute,La,type,{{record,Record},Fields,[]}}|
restore_typed_record_fields([Form|Forms]) ->
[Form|restore_typed_record_fields(Forms)].
-%% server(StarterPid, FileName, Path, PreDefMacros)
-
-server(Pid, Name, Path, Pdm) ->
+server(Pid, Name, Options, #epp{pre_opened=PreOpened}=St) ->
process_flag(trap_exit, true),
- case file:open(Name, [read]) of
- {ok,File} ->
- Location = 1,
- init_server(Pid, Name, File, Location, Path, Pdm, false);
- {error,E} ->
- epp_reply(Pid, {error,E})
+ case PreOpened of
+ false ->
+ case file:open(Name, [read]) of
+ {ok,File} ->
+ init_server(Pid, Name, Options, St#epp{file = File});
+ {error,E} ->
+ epp_reply(Pid, {error,E})
+ end;
+ true ->
+ init_server(Pid, Name, Options, St)
end.
-%% server(StarterPid, FileName, IoDevice, Location, Path, PreDefMacros)
-server(Pid, Name, File, AtLocation, Path, Pdm) ->
- process_flag(trap_exit, true),
- init_server(Pid, Name, File, AtLocation, Path, Pdm, true).
-
-init_server(Pid, Name, File, AtLocation, Path, Pdm, Pre) ->
+init_server(Pid, Name, Options, St0) ->
+ Pdm = proplists:get_value(macros, Options, []),
Ms0 = predef_macros(Name),
case user_predef(Pdm, Ms0) of
{ok,Ms1} ->
- _ = set_encoding(File),
- epp_reply(Pid, {ok,self()}),
+ #epp{file = File, location = AtLocation} = St0,
+ DefEncoding = proplists:get_value(default_encoding, Options,
+ ?DEFAULT_ENCODING),
+ Encoding = set_encoding(File, DefEncoding),
+ epp_reply(Pid, {ok,self(),Encoding}),
%% 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=Path1, macs=Ms1,
- pre_opened = Pre},
+ Path = [filename:dirname(Name) |
+ proplists:get_value(includes, Options, [])],
+ St = St0#epp{delta=0, name=Name, name2=Name,
+ path=Path, macs=Ms1,
+ default_encoding=DefEncoding},
From = wait_request(St),
enter_file_reply(From, Name, AtLocation, AtLocation),
wait_req_scan(St);
@@ -600,9 +671,11 @@ enter_file2(NewF, Pname, From, St0, AtLocation) ->
%% 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(St0#epp.path)],
- _ = set_encoding(NewF),
+ DefEncoding = St0#epp.default_encoding,
+ _ = set_encoding(NewF, DefEncoding),
#epp{file=NewF,location=Loc,name=Pname,name2=Pname,delta=0,
- sstk=[St0|St0#epp.sstk],path=Path,macs=Ms}.
+ sstk=[St0|St0#epp.sstk],path=Path,macs=Ms,
+ default_encoding=DefEncoding}.
enter_file_reply(From, Name, Location, AtLocation) ->
Attr = loc_attr(AtLocation),
diff --git a/lib/stdlib/src/erl_compile.erl b/lib/stdlib/src/erl_compile.erl
index ed8fea5d78..caed4d41d6 100644
--- a/lib/stdlib/src/erl_compile.erl
+++ b/lib/stdlib/src/erl_compile.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2013. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2014. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -66,7 +66,7 @@ my_halt(Reason) ->
compile(List) ->
process_flag(trap_exit, true),
- Pid = spawn_link(fun() -> compiler_runner(List) end),
+ Pid = spawn_link(compiler_runner(List)),
receive
{'EXIT', Pid, {compiler_result, Result}} ->
Result;
@@ -79,14 +79,16 @@ compile(List) ->
error
end.
--spec compiler_runner([cmd_line_arg()]) -> no_return().
+-spec compiler_runner([cmd_line_arg()]) -> fun(() -> no_return()).
compiler_runner(List) ->
- %% We don't want the current directory in the code path.
- %% Remove it.
- Path = [D || D <- code:get_path(), D =/= "."],
- true = code:set_path(Path),
- exit({compiler_result, compile1(List)}).
+ fun() ->
+ %% We don't want the current directory in the code path.
+ %% Remove it.
+ Path = [D || D <- code:get_path(), D =/= "."],
+ true = code:set_path(Path),
+ exit({compiler_result, compile1(List)})
+ end.
%% Parses the first part of the option list.
diff --git a/lib/stdlib/src/erl_eval.erl b/lib/stdlib/src/erl_eval.erl
index 3a4108e297..acde3ad5d6 100644
--- a/lib/stdlib/src/erl_eval.erl
+++ b/lib/stdlib/src/erl_eval.erl
@@ -18,6 +18,9 @@
%%
-module(erl_eval).
+%% Guard is_map/1 is not yet supported in HiPE.
+-compile(no_native).
+
%% An evaluator for Erlang abstract syntax.
-export([exprs/2,exprs/3,exprs/4,expr/2,expr/3,expr/4,expr/5,
@@ -243,11 +246,18 @@ expr({record,_,_,Name,_}, _Bs, _Lf, _Ef, _RBs) ->
%% map
expr({map,_, Binding,Es}, Bs0, Lf, Ef, RBs) ->
{value, Map0, Bs1} = expr(Binding, Bs0, Lf, Ef, RBs),
- {Vs,Bs} = eval_map_fields(Es, Bs1, Lf, Ef),
- ret_expr(lists:foldl(fun
- ({map_assoc,K,V}, Mi) -> maps:put(K,V,Mi);
- ({map_exact,K,V}, Mi) -> maps:update(K,V,Mi)
- end, Map0, Vs), Bs, RBs);
+ case Map0 of
+ #{} ->
+ {Vs,Bs} = eval_map_fields(Es, Bs1, Lf, Ef),
+ Map1 = lists:foldl(fun ({map_assoc,K,V}, Mi) ->
+ maps:put(K, V, Mi);
+ ({map_exact,K,V}, Mi) ->
+ maps:update(K, V, Mi)
+ end, Map0, Vs),
+ ret_expr(Map1, Bs, RBs);
+ _ ->
+ erlang:raise(error, {badarg,Map0}, stacktrace())
+ end;
expr({map,_,Es}, Bs0, Lf, Ef, RBs) ->
{Vs,Bs} = eval_map_fields(Es, Bs0, Lf, Ef),
ret_expr(lists:foldl(fun
@@ -1113,9 +1123,10 @@ match1({tuple,_,Elts}, Tuple, Bs, BBs)
match_tuple(Elts, Tuple, 1, Bs, BBs);
match1({tuple,_,_}, _, _Bs, _BBs) ->
throw(nomatch);
-match1({map,_,Fs}, Map, Bs, BBs) ->
+match1({map,_,Fs}, #{}=Map, Bs, BBs) ->
match_map(Fs, Map, Bs, BBs);
-
+match1({map,_,_}, _, _Bs, _BBs) ->
+ throw(nomatch);
match1({bin, _, Fs}, <<_/bitstring>>=B, Bs0, BBs) ->
eval_bits:match_bits(Fs, B, Bs0, BBs,
match_fun(BBs),
diff --git a/lib/stdlib/src/erl_lint.erl b/lib/stdlib/src/erl_lint.erl
index 269e4b34cf..c4c94fbee4 100644
--- a/lib/stdlib/src/erl_lint.erl
+++ b/lib/stdlib/src/erl_lint.erl
@@ -80,13 +80,17 @@ value_option(Flag, Default, On, OnVal, Off, OffVal, Opts) ->
-type fa() :: {atom(), arity()}. % function+arity
-type ta() :: {atom(), arity()}. % type+arity
+-record(typeinfo, {attr, line}).
+
%% Usage of records, functions, and imports. The variable table, which
%% is passed on as an argument, holds the usage of variables.
-record(usage, {
calls = dict:new(), %Who calls who
imported = [], %Actually imported functions
- used_records=sets:new() :: sets:set(),%Used record definitions
- used_types = dict:new() :: dict:dict()%Used type definitions
+ used_records = sets:new() %Used record definitions
+ :: sets:set(atom()),
+ used_types = dict:new() %Used type definitions
+ :: dict:dict(ta(), line())
}).
%% Define the lint state record.
@@ -95,13 +99,17 @@ value_option(Flag, Default, On, OnVal, Off, OffVal, Opts) ->
-record(lint, {state=start :: 'start' | 'attribute' | 'function',
module=[], %Module
behaviour=[], %Behaviour
- exports=gb_sets:empty() :: gb_sets:set(),%Exports
- imports=[], %Imports
+ exports=gb_sets:empty() :: gb_sets:set(fa()),%Exports
+ imports=[] :: [fa()], %Imports, an orddict()
compile=[], %Compile flags
- records=dict:new() :: dict:dict(), %Record definitions
- locals=gb_sets:empty() :: gb_sets:set(),%All defined functions (prescanned)
- no_auto=gb_sets:empty() :: gb_sets:set() | 'all',%Functions explicitly not autoimported
- defined=gb_sets:empty() :: gb_sets:set(),%Defined fuctions
+ records=dict:new() %Record definitions
+ :: dict:dict(atom(), {line(),Fields :: term()}),
+ locals=gb_sets:empty() %All defined functions (prescanned)
+ :: gb_sets:set(fa()),
+ no_auto=gb_sets:empty() %Functions explicitly not autoimported
+ :: gb_sets:set(fa()) | 'all',
+ defined=gb_sets:empty() %Defined fuctions
+ :: gb_sets:set(fa()),
on_load=[] :: [fa()], %On-load function
on_load_line=0 :: line(), %Line for on_load
clashes=[], %Exported functions named as BIFs
@@ -116,12 +124,16 @@ value_option(Flag, Default, On, OnVal, Off, OffVal, Opts) ->
%outside any fun or lc
xqlc= false :: boolean(), %true if qlc.hrl included
new = false :: boolean(), %Has user-defined 'new/N'
- called= [] :: [{fa(),line()}], %Called functions
+ called= [] :: [{fa(),line()}], %Called functions
usage = #usage{} :: #usage{},
- specs = dict:new() :: dict:dict(), %Type specifications
- callbacks = dict:new() :: dict:dict(), %Callback types
- types = dict:new() :: dict:dict(), %Type definitions
- exp_types=gb_sets:empty():: gb_sets:set()%Exported types
+ specs = dict:new() %Type specifications
+ :: dict:dict(mfa(), line()),
+ callbacks = dict:new() %Callback types
+ :: dict:dict(mfa(), line()),
+ types = dict:new() %Type definitions
+ :: dict:dict(ta(), #typeinfo{}),
+ exp_types=gb_sets:empty() %Exported types
+ :: gb_sets:set(ta())
}).
-type lint_state() :: #lint{}.
@@ -225,6 +237,8 @@ format_error({too_many_arguments,Arity}) ->
"maximum allowed is ~w", [Arity,?MAX_ARGUMENTS]);
%% --- patterns and guards ---
format_error(illegal_pattern) -> "illegal pattern";
+format_error(illegal_map_key) ->
+ "illegal map key";
format_error({illegal_map_key_variable,K}) ->
io_lib:format("illegal use of variable ~w in map",[K]);
format_error(illegal_bin_pattern) ->
@@ -317,10 +331,14 @@ format_error({undefined_type, {TypeName, Arity}}) ->
io_lib:format("type ~w~s undefined", [TypeName, gen_type_paren(Arity)]);
format_error({unused_type, {TypeName, Arity}}) ->
io_lib:format("type ~w~s is unused", [TypeName, gen_type_paren(Arity)]);
-format_error({new_builtin_type, {TypeName, Arity}}) ->
- io_lib:format("type ~w~s is a new builtin type; "
+%% format_error({new_builtin_type, {TypeName, Arity}}) ->
+%% io_lib:format("type ~w~s is a new builtin type; "
+%% "its (re)definition is allowed only until the next release",
+%% [TypeName, gen_type_paren(Arity)]);
+format_error({new_var_arity_type, TypeName}) ->
+ io_lib:format("type ~w is a new builtin type; "
"its (re)definition is allowed only until the next release",
- [TypeName, gen_type_paren(Arity)]);
+ [TypeName]);
format_error({builtin_type, {TypeName, Arity}}) ->
io_lib:format("type ~w~s is a builtin type; it cannot be redefined",
[TypeName, gen_type_paren(Arity)]);
@@ -1168,7 +1186,7 @@ export_type(Line, ETs, #lint{usage = Usage, exp_types = ETs0} = St0) ->
add_error(Line, {bad_export_type, ETs}, St0)
end.
--spec exports(lint_state()) -> gb_sets:set().
+-spec exports(lint_state()) -> gb_sets:set(fa()).
exports(#lint{compile = Opts, defined = Defs, exports = Es}) ->
case lists:member(export_all, Opts) of
@@ -1385,19 +1403,20 @@ pattern({cons,_Line,H,T}, Vt, Old, Bvt, St0) ->
pattern({tuple,_Line,Ps}, Vt, Old, Bvt, St) ->
pattern_list(Ps, Vt, Old, Bvt, St);
pattern({map,_Line,Ps}, Vt, Old, Bvt, St) ->
- foldl(fun ({map_field_assoc,L,_,_}, {Psvt,Bvt0,St0}) ->
- {Psvt,Bvt0,add_error(L, illegal_pattern, St0)};
- ({map_field_exact,L,KP,VP}, {Psvt,Bvt0,St0}) ->
- case expr(KP, [], St0) of
- {[],_} ->
- {Pvt,Bvt1,St1} = pattern(VP, Vt, Old, Bvt, St0),
- {vtmerge_pat(Pvt, Psvt),vtmerge_pat(Bvt0, Bvt1),
- St1};
- {[Var|_],_} ->
- Error = {illegal_map_key_variable,element(1, Var)},
- {Psvt,Bvt0,add_error(L, Error, St0)}
- end
- end, {[],[],St}, Ps);
+ foldl(fun
+ ({map_field_assoc,L,_,_}, {Psvt,Bvt0,St0}) ->
+ {Psvt,Bvt0,add_error(L, illegal_pattern, St0)};
+ ({map_field_exact,L,KP,VP}, {Psvt,Bvt0,St0}) ->
+ case is_valid_map_key(KP, St0) of
+ true ->
+ {Pvt,Bvt1,St1} = pattern(VP, Vt, Old, Bvt, St0),
+ {vtmerge_pat(Pvt, Psvt),vtmerge_pat(Bvt0, Bvt1), St1};
+ false ->
+ {Psvt,Bvt0,add_error(L, illegal_map_key, St0)};
+ {false,variable,Var} ->
+ {Psvt,Bvt0,add_error(L, {illegal_map_key_variable,Var}, St0)}
+ end
+ end, {[],[],St}, Ps);
%%pattern({struct,_Line,_Tag,Ps}, Vt, Old, Bvt, St) ->
%% pattern_list(Ps, Vt, Old, Bvt, St);
pattern({record_index,Line,Name,Field}, _Vt, _Old, _Bvt, St) ->
@@ -2237,9 +2256,10 @@ check_assoc_fields([], St) ->
map_fields([{Tag,Line,K,V}|Fs], Vt, St, F) when Tag =:= map_field_assoc;
Tag =:= map_field_exact ->
St1 = case is_valid_map_key(K, St) of
- true -> St;
- {false,Var} -> add_error(Line, {illegal_map_key_variable,Var}, St)
- end,
+ true -> St;
+ false -> add_error(Line, illegal_map_key, St);
+ {false,variable,Var} -> add_error(Line, {illegal_map_key_variable,Var}, St)
+ end,
{Pvt,St2} = F([K,V], Vt, St1),
{Vts,St3} = map_fields(Fs, Vt, St2, F),
{vtupdate(Pvt, Vts),St3};
@@ -2298,11 +2318,64 @@ is_valid_call(Call) ->
_ -> true
end.
+%% is_valid_map_key(K,St) -> true | false | {false, Var::atom()}
+%% check for value expression without variables
+
is_valid_map_key(K,St) ->
case expr(K,[],St) of
- {[],_} -> true;
+ {[],_} ->
+ is_valid_map_key_value(K);
{[Var|_],_} ->
- {false,element(1,Var)}
+ {false,variable,element(1,Var)}
+ end.
+
+is_valid_map_key_value(K) ->
+ case K of
+ {char,_,_} -> true;
+ {integer,_,_} -> true;
+ {float,_,_} -> true;
+ {string,_,_} -> true;
+ {nil,_} -> true;
+ {atom,_,_} -> true;
+ {cons,_,H,T} ->
+ is_valid_map_key_value(H) andalso
+ is_valid_map_key_value(T);
+ {tuple,_,Es} ->
+ foldl(fun(E,B) ->
+ B andalso is_valid_map_key_value(E)
+ end,true,Es);
+ {map,_,Arg,Ps} ->
+ % only check for value expressions to be valid
+ % invalid map expressions are later checked in
+ % core and kernel
+ is_valid_map_key_value(Arg) andalso foldl(fun
+ ({Tag,_,Ke,Ve},B) when Tag =:= map_field_assoc;
+ Tag =:= map_field_exact ->
+ B andalso is_valid_map_key_value(Ke)
+ andalso is_valid_map_key_value(Ve)
+ end,true,Ps);
+ {map,_,Ps} ->
+ foldl(fun
+ ({Tag,_,Ke,Ve},B) when Tag =:= map_field_assoc;
+ Tag =:= map_field_exact ->
+ B andalso is_valid_map_key_value(Ke)
+ andalso is_valid_map_key_value(Ve)
+ end, true, Ps);
+ {record,_,_,Fs} ->
+ foldl(fun
+ ({record_field,_,Ke,Ve},B) ->
+ B andalso is_valid_map_key_value(Ke)
+ andalso is_valid_map_key_value(Ve)
+ end,true,Fs);
+ {bin,_,Es} ->
+ % only check for value expressions to be valid
+ % invalid binary expressions are later checked in
+ % core and kernel
+ foldl(fun
+ ({bin_element,_,E,_,_},B) ->
+ B andalso is_valid_map_key_value(E)
+ end,true,Es);
+ _ -> false
end.
%% record_def(Line, RecordName, [RecField], State) -> State.
@@ -2517,8 +2590,6 @@ find_field(_F, []) -> error.
%% Attr :: 'type' | 'opaque'
%% Checks that a type definition is valid.
--record(typeinfo, {attr, line}).
-
type_def(_Attr, _Line, {record, _RecName}, Fields, [], St0) ->
%% The record field names and such are checked in the record format.
%% We only need to check the types.
@@ -2539,23 +2610,30 @@ type_def(Attr, Line, TypeName, ProtoType, Args, St0) ->
true ->
case is_obsolete_builtin_type(TypePair) of
true -> StoreType(St0);
- false ->
- case is_newly_introduced_builtin_type(TypePair) of
- %% allow some types just for bootstrapping
- true ->
- Warn = {new_builtin_type, TypePair},
- St1 = add_warning(Line, Warn, St0),
- StoreType(St1);
- false ->
- add_error(Line, {builtin_type, TypePair}, St0)
- end
+ false -> add_error(Line, {builtin_type, TypePair}, St0)
+%% case is_newly_introduced_builtin_type(TypePair) of
+%% %% allow some types just for bootstrapping
+%% true ->
+%% Warn = {new_builtin_type, TypePair},
+%% St1 = add_warning(Line, Warn, St0),
+%% StoreType(St1);
+%% false ->
+%% add_error(Line, {builtin_type, TypePair}, St0)
+%% end
end;
false ->
case
- dict:is_key(TypePair, TypeDefs)
- orelse is_var_arity_type(TypeName)
+ dict:is_key(TypePair, TypeDefs) orelse
+ is_var_arity_type(TypeName)
of
- true -> add_error(Line, {redefine_type, TypePair}, St0);
+ true ->
+ case is_newly_introduced_var_arity_type(TypeName) of
+ true ->
+ Warn = {new_var_arity_type, TypeName},
+ add_warning(Line, Warn, St0);
+ false ->
+ add_error(Line, {redefine_type, TypePair}, St0)
+ end;
false ->
St1 = case
Attr =:= opaque andalso
@@ -2727,6 +2805,7 @@ check_record_types([], _Name, _DefFields, SeenVars, St, _SeenFields) ->
{SeenVars, St}.
is_var_arity_type(tuple) -> true;
+is_var_arity_type(map) -> true;
is_var_arity_type(product) -> true;
is_var_arity_type(union) -> true;
is_var_arity_type(record) -> true;
@@ -2759,7 +2838,6 @@ is_default_type({iodata, 0}) -> true;
is_default_type({iolist, 0}) -> true;
is_default_type({list, 0}) -> true;
is_default_type({list, 1}) -> true;
-is_default_type({map, 0}) -> true;
is_default_type({maybe_improper_list, 0}) -> true;
is_default_type({maybe_improper_list, 2}) -> true;
is_default_type({mfa, 0}) -> true;
@@ -2790,7 +2868,10 @@ is_default_type({timeout, 0}) -> true;
is_default_type({var, 1}) -> true;
is_default_type(_) -> false.
-is_newly_introduced_builtin_type({Name, _}) when is_atom(Name) -> false.
+is_newly_introduced_var_arity_type(map) -> true;
+is_newly_introduced_var_arity_type(_) -> false.
+
+%% is_newly_introduced_builtin_type({Name, _}) when is_atom(Name) -> false.
is_obsolete_builtin_type(TypePair) ->
obsolete_builtin_type(TypePair) =/= no.
diff --git a/lib/stdlib/src/erl_parse.yrl b/lib/stdlib/src/erl_parse.yrl
index 6316db7054..1dc5fc52a7 100644
--- a/lib/stdlib/src/erl_parse.yrl
+++ b/lib/stdlib/src/erl_parse.yrl
@@ -2,7 +2,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2013. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2014. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -919,59 +919,63 @@ normalise_list([]) ->
Data :: term(),
AbsTerm :: abstract_expr().
abstract(T) ->
- abstract(T, 0, epp:default_encoding()).
+ abstract(T, 0, enc_func(epp:default_encoding())).
+
+-type encoding_func() :: fun((non_neg_integer()) -> boolean()).
%%% abstract/2 takes line and encoding options
-spec abstract(Data, Options) -> AbsTerm when
Data :: term(),
Options :: Line | [Option],
Option :: {line, Line} | {encoding, Encoding},
- Encoding :: latin1 | unicode | utf8,
+ Encoding :: 'latin1' | 'unicode' | 'utf8' | 'none' | encoding_func(),
Line :: erl_scan:line(),
AbsTerm :: abstract_expr().
abstract(T, Line) when is_integer(Line) ->
- abstract(T, Line, epp:default_encoding());
+ abstract(T, Line, enc_func(epp:default_encoding()));
abstract(T, Options) when is_list(Options) ->
Line = proplists:get_value(line, Options, 0),
Encoding = proplists:get_value(encoding, Options,epp:default_encoding()),
- abstract(T, Line, Encoding).
+ EncFunc = enc_func(Encoding),
+ abstract(T, Line, EncFunc).
-define(UNICODE(C),
- is_integer(C) andalso
- (C >= 0 andalso C < 16#D800 orelse
+ (C < 16#D800 orelse
C > 16#DFFF andalso C < 16#FFFE orelse
C > 16#FFFF andalso C =< 16#10FFFF)).
+enc_func(latin1) -> fun(C) -> C < 256 end;
+enc_func(unicode) -> fun(C) -> ?UNICODE(C) end;
+enc_func(utf8) -> fun(C) -> ?UNICODE(C) end;
+enc_func(none) -> none;
+enc_func(Fun) when is_function(Fun, 1) -> Fun;
+enc_func(Term) -> erlang:error({badarg, Term}).
+
abstract(T, L, _E) when is_integer(T) -> {integer,L,T};
abstract(T, L, _E) when is_float(T) -> {float,L,T};
abstract(T, L, _E) when is_atom(T) -> {atom,L,T};
abstract([], L, _E) -> {nil,L};
abstract(B, L, _E) when is_bitstring(B) ->
{bin, L, [abstract_byte(Byte, L) || Byte <- bitstring_to_list(B)]};
-abstract([C|T], L, unicode=E) when ?UNICODE(C) ->
- abstract_unicode_string(T, [C], L, E);
-abstract([C|T], L, utf8=E) when ?UNICODE(C) ->
- abstract_unicode_string(T, [C], L, E);
-abstract([C|T], L, latin1=E) when is_integer(C), 0 =< C, C < 256 ->
- abstract_string(T, [C], L, E);
-abstract([H|T], L, E) ->
+abstract([H|T], L, none=E) ->
{cons,L,abstract(H, L, E),abstract(T, L, E)};
+abstract(List, L, E) when is_list(List) ->
+ abstract_list(List, [], L, E);
abstract(Tuple, L, E) when is_tuple(Tuple) ->
- {tuple,L,abstract_list(tuple_to_list(Tuple), L, E)}.
-
-abstract_string([C|T], String, L, E) when is_integer(C), 0 =< C, C < 256 ->
- abstract_string(T, [C|String], L, E);
-abstract_string([], String, L, _E) ->
- {string, L, lists:reverse(String)};
-abstract_string(T, String, L, E) ->
- not_string(String, abstract(T, L, E), L, E).
-
-abstract_unicode_string([C|T], String, L, E) when ?UNICODE(C) ->
- abstract_unicode_string(T, [C|String], L, E);
-abstract_unicode_string([], String, L, _E) ->
+ {tuple,L,abstract_tuple_list(tuple_to_list(Tuple), L, E)}.
+
+abstract_list([H|T], String, L, E) ->
+ case is_integer(H) andalso H >= 0 andalso E(H) of
+ true ->
+ abstract_list(T, [H|String], L, E);
+ false ->
+ AbstrList = {cons,L,abstract(H, L, E),abstract(T, L, E)},
+ not_string(String, AbstrList, L, E)
+ end;
+abstract_list([], String, L, _E) ->
{string, L, lists:reverse(String)};
-abstract_unicode_string(T, String, L, E) ->
+abstract_list(T, String, L, E) ->
not_string(String, abstract(T, L, E), L, E).
not_string([C|T], Result, L, E) ->
@@ -979,9 +983,9 @@ not_string([C|T], Result, L, E) ->
not_string([], Result, _L, _E) ->
Result.
-abstract_list([H|T], L, E) ->
- [abstract(H, L, E)|abstract_list(T, L, E)];
-abstract_list([], _L, _E) ->
+abstract_tuple_list([H|T], L, E) ->
+ [abstract(H, L, E)|abstract_tuple_list(T, L, E)];
+abstract_tuple_list([], _L, _E) ->
[].
abstract_byte(Byte, L) when is_integer(Byte) ->
diff --git a/lib/stdlib/src/erl_pp.erl b/lib/stdlib/src/erl_pp.erl
index 9dbe89da91..82bc2c1460 100644
--- a/lib/stdlib/src/erl_pp.erl
+++ b/lib/stdlib/src/erl_pp.erl
@@ -256,6 +256,10 @@ ltype({type,_Line,nonempty_list,[T]}) ->
{seq,$[,$],[$,],[ltype(T),leaf("...")]};
ltype({type,Line,nil,[]}) ->
lexpr({nil,Line}, 0, options(none));
+ltype({type,Line,map,any}) ->
+ simple_type({atom,Line,map}, []);
+ltype({type,_Line,map,Pairs}) ->
+ map_type(Pairs);
ltype({type,Line,tuple,any}) ->
simple_type({atom,Line,tuple}, []);
ltype({type,_Line,tuple,Ts}) ->
@@ -289,6 +293,15 @@ binary_type(I1, I2) ->
E2 = [[leaf("_:_*"),lexpr(I2, P, options(none))] || U],
{seq,'<<','>>',[$,],E1++E2}.
+map_type(Fs) ->
+ {first,[$#],map_pair_types(Fs)}.
+
+map_pair_types(Fs) ->
+ tuple_type(Fs, fun map_pair_type/1).
+
+map_pair_type({type,_Line,map_field_assoc,Ktype,Vtype}) ->
+ {seq,[],[]," =>",[ltype(Ktype),ltype(Vtype)]}.
+
record_type(Name, Fields) ->
{first,[record_name(Name)],field_types(Fields)}.
diff --git a/lib/stdlib/src/escript.erl b/lib/stdlib/src/escript.erl
index 35f6dff57e..6bd0eb8a22 100644
--- a/lib/stdlib/src/escript.erl
+++ b/lib/stdlib/src/escript.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2007-2013. All Rights Reserved.
+%% Copyright Ericsson AB 2007-2014. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -59,7 +59,6 @@
file:filename()
| {file:filename(), binary()}
| {file:filename(), binary(), file:file_info()}.
--type zip_create_option() :: term().
-type section() ::
shebang
| {shebang, shebang() | default | undefined}
@@ -68,8 +67,8 @@
| {emu_args, emu_args() | undefined}
| {source, file:filename() | binary()}
| {beam, file:filename() | binary()}
- | {archive, file:filename() | binary()}
- | {archive, [zip_file()], [zip_create_option()]}.
+ | {archive, zip:filename() | binary()}
+ | {archive, [zip_file()], [zip:create_option()]}.
%%-----------------------------------------------------------------------
@@ -289,6 +288,8 @@ start(EscriptOptions) ->
my_halt(127)
end.
+-spec parse_and_run(_, _, _) -> no_return().
+
parse_and_run(File, Args, Options) ->
CheckOnly = lists:member("s", Options),
{Source, Module, FormsOrBin, HasRecs, Mode} =
@@ -727,6 +728,8 @@ epp_parse_file2(Epp, S, Forms, Parsed) ->
%% Evaluate script
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+-spec debug(_, _, _) -> no_return().
+
debug(Module, AbsMod, Args) ->
case hidden_apply(debugger, debugger, start, []) of
{ok, _} ->
@@ -742,6 +745,8 @@ debug(Module, AbsMod, Args) ->
fatal("Cannot start the debugger")
end.
+-spec run(_, _) -> no_return().
+
run(Module, Args) ->
try
Module:main(Args),
@@ -751,6 +756,8 @@ run(Module, Args) ->
fatal(format_exception(Class, Reason))
end.
+-spec interpret(_, _, _, _) -> no_return().
+
interpret(Forms, HasRecs, File, Args) ->
%% Basic validation before execution
case erl_lint:module(Forms) of
diff --git a/lib/stdlib/src/gen_event.erl b/lib/stdlib/src/gen_event.erl
index 7629e88fbf..d39dd89d3a 100644
--- a/lib/stdlib/src/gen_event.erl
+++ b/lib/stdlib/src/gen_event.erl
@@ -40,6 +40,8 @@
system_continue/3,
system_terminate/4,
system_code_change/4,
+ system_get_state/1,
+ system_replace_state/2,
format_status/2]).
-export_type([handler/0, handler_args/0, add_handler_ret/0,
@@ -229,24 +231,6 @@ wake_hib(Parent, ServerName, MSL, Debug) ->
fetch_msg(Parent, ServerName, MSL, Debug, Hib) ->
receive
- {system, From, get_state} ->
- States = [{Mod,Id,State} || #handler{module=Mod, id=Id, state=State} <- MSL],
- sys:handle_system_msg(get_state, From, Parent, ?MODULE, Debug,
- {States, [ServerName, MSL, Hib]}, Hib);
- {system, From, {replace_state, StateFun}} ->
- {NMSL, NStates} =
- lists:unzip([begin
- Cur = {Mod,Id,State},
- try
- NState = {Mod,Id,NS} = StateFun(Cur),
- {HS#handler{state=NS}, NState}
- catch
- _:_ ->
- {HS, Cur}
- end
- end || #handler{module=Mod, id=Id, state=State}=HS <- MSL]),
- sys:handle_system_msg(replace_state, From, Parent, ?MODULE, Debug,
- {NStates, [ServerName, NMSL, Hib]}, Hib);
{system, From, Req} ->
sys:handle_system_msg(Req, From, Parent, ?MODULE, Debug,
[ServerName, MSL, Hib],Hib);
@@ -383,6 +367,23 @@ system_code_change([ServerName, MSL, Hib], Module, OldVsn, Extra) ->
MSL),
{ok, [ServerName, MSL1, Hib]}.
+system_get_state([_ServerName, MSL, _Hib]) ->
+ {ok, [{Mod,Id,State} || #handler{module=Mod, id=Id, state=State} <- MSL]}.
+
+system_replace_state(StateFun, [ServerName, MSL, Hib]) ->
+ {NMSL, NStates} =
+ lists:unzip([begin
+ Cur = {Mod,Id,State},
+ try
+ NState = {Mod,Id,NS} = StateFun(Cur),
+ {HS#handler{state=NS}, NState}
+ catch
+ _:_ ->
+ {HS, Cur}
+ end
+ end || #handler{module=Mod, id=Id, state=State}=HS <- MSL]),
+ {ok, NStates, [ServerName, NMSL, Hib]}.
+
%%-----------------------------------------------------------------
%% Format debug messages. Print them as the call-back module sees
%% them, not as the real erlang messages. Use trace for that.
diff --git a/lib/stdlib/src/gen_fsm.erl b/lib/stdlib/src/gen_fsm.erl
index e9654322f1..e914f7d0b2 100644
--- a/lib/stdlib/src/gen_fsm.erl
+++ b/lib/stdlib/src/gen_fsm.erl
@@ -118,6 +118,8 @@
system_continue/3,
system_terminate/4,
system_code_change/4,
+ system_get_state/1,
+ system_replace_state/2,
format_status/2]).
-import(error_logger, [format/2]).
@@ -422,17 +424,6 @@ wake_hib(Parent, Name, StateName, StateData, Mod, Debug) ->
decode_msg(Msg,Parent, Name, StateName, StateData, Mod, Time, Debug, Hib) ->
case Msg of
- {system, From, get_state} ->
- Misc = [Name, StateName, StateData, Mod, Time],
- sys:handle_system_msg(get_state, From, Parent, ?MODULE, Debug,
- {{StateName, StateData}, Misc}, Hib);
- {system, From, {replace_state, StateFun}} ->
- State = {StateName, StateData},
- NState = {NStateName, NStateData} = try StateFun(State)
- catch _:_ -> State end,
- NMisc = [Name, NStateName, NStateData, Mod, Time],
- sys:handle_system_msg(replace_state, From, Parent, ?MODULE, Debug,
- {NState, NMisc}, Hib);
{system, From, Req} ->
sys:handle_system_msg(Req, From, Parent, ?MODULE, Debug,
[Name, StateName, StateData, Mod, Time], Hib);
@@ -467,6 +458,13 @@ system_code_change([Name, StateName, StateData, Mod, Time],
Else -> Else
end.
+system_get_state([_Name, StateName, StateData, _Mod, _Time]) ->
+ {ok, {StateName, StateData}}.
+
+system_replace_state(StateFun, [Name, StateName, StateData, Mod, Time]) ->
+ Result = {NStateName, NStateData} = StateFun({StateName, StateData}),
+ {ok, Result, [Name, NStateName, NStateData, Mod, Time]}.
+
%%-----------------------------------------------------------------
%% Format debug messages. Print them as the call-back module sees
%% them, not as the real erlang messages. Use trace for that.
diff --git a/lib/stdlib/src/gen_server.erl b/lib/stdlib/src/gen_server.erl
index 5f14e48b0a..202a931fae 100644
--- a/lib/stdlib/src/gen_server.erl
+++ b/lib/stdlib/src/gen_server.erl
@@ -98,6 +98,8 @@
-export([system_continue/3,
system_terminate/4,
system_code_change/4,
+ system_get_state/1,
+ system_replace_state/2,
format_status/2]).
%% Internal exports
@@ -372,13 +374,6 @@ wake_hib(Parent, Name, State, Mod, Debug) ->
decode_msg(Msg, Parent, Name, State, Mod, Time, Debug, Hib) ->
case Msg of
- {system, From, get_state} ->
- sys:handle_system_msg(get_state, From, Parent, ?MODULE, Debug,
- {State, [Name, State, Mod, Time]}, Hib);
- {system, From, {replace_state, StateFun}} ->
- NState = try StateFun(State) catch _:_ -> State end,
- sys:handle_system_msg(replace_state, From, Parent, ?MODULE, Debug,
- {NState, [Name, NState, Mod, Time]}, Hib);
{system, From, Req} ->
sys:handle_system_msg(Req, From, Parent, ?MODULE, Debug,
[Name, State, Mod, Time], Hib);
@@ -687,6 +682,13 @@ system_code_change([Name, State, Mod, Time], _Module, OldVsn, Extra) ->
Else -> Else
end.
+system_get_state([_Name, State, _Mod, _Time]) ->
+ {ok, State}.
+
+system_replace_state(StateFun, [Name, State, Mod, Time]) ->
+ NState = StateFun(State),
+ {ok, NState, [Name, NState, Mod, Time]}.
+
%%-----------------------------------------------------------------
%% Format debug messages. Print them as the call-back module sees
%% them, not as the real erlang messages. Use trace for that.
diff --git a/lib/stdlib/src/io.erl b/lib/stdlib/src/io.erl
index b11d41e2eb..27e2a82b41 100644
--- a/lib/stdlib/src/io.erl
+++ b/lib/stdlib/src/io.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2013. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2014. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -177,13 +177,15 @@ get_password(Io) ->
| {'expand_fun', expand_fun()}
| {'encoding', encoding()}.
--spec getopts() -> [opt_pair()].
+-spec getopts() -> [opt_pair()] | {'error', Reason} when
+ Reason :: term().
getopts() ->
getopts(default_input()).
--spec getopts(IoDevice) -> [opt_pair()] when
- IoDevice :: device().
+-spec getopts(IoDevice) -> [opt_pair()] | {'error', Reason} when
+ IoDevice :: device(),
+ Reason :: term().
getopts(Io) ->
request(Io, getopts).
diff --git a/lib/stdlib/src/io_lib_pretty.erl b/lib/stdlib/src/io_lib_pretty.erl
index 4057abd8d5..aece06afa6 100644
--- a/lib/stdlib/src/io_lib_pretty.erl
+++ b/lib/stdlib/src/io_lib_pretty.erl
@@ -25,8 +25,6 @@
-export([print/1,print/2,print/3,print/4,print/5,print/6]).
--compile(no_native).
-
%%%
%%% Exported functions
%%%
diff --git a/lib/stdlib/src/maps.erl b/lib/stdlib/src/maps.erl
index 1f94d9e69d..fd6d56fa47 100644
--- a/lib/stdlib/src/maps.erl
+++ b/lib/stdlib/src/maps.erl
@@ -43,8 +43,6 @@
values/1
]).
--compile(no_native).
-
-spec get(Key,Map) -> Value when
Key :: term(),
Map :: map(),
diff --git a/lib/stdlib/src/otp_internal.erl b/lib/stdlib/src/otp_internal.erl
index 380bc3eccc..971a2e2baa 100644
--- a/lib/stdlib/src/otp_internal.erl
+++ b/lib/stdlib/src/otp_internal.erl
@@ -250,12 +250,12 @@ obsolete_1(snmp, N, A) ->
false ->
no;
true ->
- {deprecated, "Deprecated (will be removed in R17B); use snmpa:"++atom_to_list(N)++"/"++
+ {deprecated, "Deprecated (will be removed in OTP 18); use snmpa:"++atom_to_list(N)++"/"++
integer_to_list(A)++" instead"}
end;
obsolete_1(snmpa, old_info_format, 1) ->
- {deprecated, "Deprecated; (will be removed in R17B); use \"new\" format instead"};
+ {deprecated, "Deprecated; (will be removed in OTP 18); use \"new\" format instead"};
obsolete_1(snmpm, agent_info, 3) ->
{removed, {snmpm, agent_info, 2}, "R16B"};
obsolete_1(snmpm, update_agent_info, 5) ->
@@ -366,23 +366,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"};
-obsolete_1(erlang, is_constant, 1) ->
- {removed, "Removed in R13B"};
-
-%% Added in R12B-0.
-obsolete_1(ssl, port, 1) ->
- {removed, {ssl, sockname, 1}, "R13B"};
-obsolete_1(ssl, accept, A) when A =:= 1; A =:= 2 ->
- {removed, "deprecated; use ssl:transport_accept/1,2 and ssl:ssl_accept/1,2"};
-obsolete_1(erlang, fault, 1) ->
- {removed, {erlang,error,1}, "R13B"};
-obsolete_1(erlang, fault, 2) ->
- {removed, {erlang,error,2}, "R13B"};
-
-%% Added in R12B-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) -> {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"};
@@ -524,7 +507,7 @@ obsolete_1(docb_xml_check, _, _) ->
%% 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."};
+ {deprecated,"deprecated (will be removed in OTP 18); has no effect as drivers are no longer used"};
obsolete_1(ssl, pid, 1) ->
{removed,"was removed in R16; is no longer needed"};
obsolete_1(inviso, _, _) ->
@@ -532,7 +515,7 @@ obsolete_1(inviso, _, _) ->
%% Added in R15B01.
obsolete_1(gs, _, _) ->
- {deprecated,"the gs application has been deprecated and will be removed in R17; use the wx application instead"};
+ {deprecated,"the gs application has been deprecated and will be removed in OTP 18; use the wx application instead"};
obsolete_1(ssh, sign_data, 2) ->
{deprecated,"deprecated (will be removed in R16A); use public_key:pem_decode/1, public_key:pem_entry_decode/1 "
"and public_key:sign/3 instead"};
diff --git a/lib/stdlib/src/sets.erl b/lib/stdlib/src/sets.erl
index be4b600f25..167a676281 100644
--- a/lib/stdlib/src/sets.erl
+++ b/lib/stdlib/src/sets.erl
@@ -55,9 +55,8 @@
%%------------------------------------------------------------------------------
--type seg() :: tuple().
--type segs(E) :: tuple()
- | E. % dummy
+-type seg() :: tuple().
+-type segs(_Element) :: tuple().
%% Define a hash set. The default values are the standard ones.
-record(set,
diff --git a/lib/stdlib/src/slave.erl b/lib/stdlib/src/slave.erl
index 3e647635bc..1898dc8aba 100644
--- a/lib/stdlib/src/slave.erl
+++ b/lib/stdlib/src/slave.erl
@@ -290,7 +290,10 @@ register_unique_name(Number) ->
%% no need to use rsh.
mk_cmd(Host, Name, Args, Waiter, Prog0) ->
- Prog = quote_progname(Prog0),
+ Prog = case os:type() of
+ {ose,_} -> mk_ose_prog(Prog0);
+ _ -> quote_progname(Prog0)
+ end,
BasicCmd = lists:concat([Prog,
" -detached -noinput -master ", node(),
" ", long_or_short(), Name, "@", Host,
@@ -310,6 +313,24 @@ mk_cmd(Host, Name, Args, Waiter, Prog0) ->
end
end.
+%% On OSE we have to pass the beam arguments directory to the slave
+%% process. To find out what arguments that should be passed on we
+%% make an assumption. All arguments after the last "--" should be
+%% skipped. So given these arguments:
+%% -Muycs256 -A 1 -- -root /mst/ -progname beam.debug.smp -- -home /mst/ -- -kernel inetrc '"/mst/inetrc.conf"' -- -name test@localhost
+%% we send
+%% -Muycs256 -A 1 -- -root /mst/ -progname beam.debug.smp -- -home /mst/ -- -kernel inetrc '"/mst/inetrc.conf"' --
+%% to the slave with whatever other args that are added in mk_cmd.
+mk_ose_prog(Prog) ->
+ SkipTail = fun("--",[]) ->
+ ["--"];
+ (_,[]) ->
+ [];
+ (Arg,Args) ->
+ [Arg," "|Args]
+ end,
+ [Prog,tl(lists:foldr(SkipTail,[],erlang:system_info(emu_args)))].
+
%% This is an attempt to distinguish between spaces in the program
%% path and spaces that separate arguments. The program is quoted to
%% allow spaces in the path.
diff --git a/lib/stdlib/src/stdlib.app.src b/lib/stdlib/src/stdlib.app.src
index a64b8e13c0..d388410de0 100644
--- a/lib/stdlib/src/stdlib.app.src
+++ b/lib/stdlib/src/stdlib.app.src
@@ -102,5 +102,8 @@
{registered,[timer_server,rsh_starter,take_over_monitor,pool_master,
dets]},
{applications, [kernel]},
- {env, []}]}.
+ {env, []},
+ {runtime_dependencies, ["sasl-2.4","kernel-3.0","erts-6.0","crypto-3.3",
+ "compiler-5.0"]}
+]}.
diff --git a/lib/stdlib/src/sys.erl b/lib/stdlib/src/sys.erl
index 04f8dfb61b..e25cc25f57 100644
--- a/lib/stdlib/src/sys.erl
+++ b/lib/stdlib/src/sys.erl
@@ -102,20 +102,31 @@ get_status(Name, Timeout) -> send_system_msg(Name, get_status, Timeout).
-spec get_state(Name) -> State when
Name :: name(),
State :: term().
-get_state(Name) -> send_system_msg(Name, get_state).
+get_state(Name) ->
+ case send_system_msg(Name, get_state) of
+ {error, Reason} -> error(Reason);
+ State -> State
+ end.
-spec get_state(Name, Timeout) -> State when
Name :: name(),
Timeout :: timeout(),
State :: term().
-get_state(Name, Timeout) -> send_system_msg(Name, get_state, Timeout).
+get_state(Name, Timeout) ->
+ case send_system_msg(Name, get_state, Timeout) of
+ {error, Reason} -> error(Reason);
+ State -> State
+ end.
-spec replace_state(Name, StateFun) -> NewState when
Name :: name(),
StateFun :: fun((State :: term()) -> NewState :: term()),
NewState :: term().
replace_state(Name, StateFun) ->
- send_system_msg(Name, {replace_state, StateFun}).
+ case send_system_msg(Name, {replace_state, StateFun}) of
+ {error, Reason} -> error(Reason);
+ State -> State
+ end.
-spec replace_state(Name, StateFun, Timeout) -> NewState when
Name :: name(),
@@ -123,7 +134,10 @@ replace_state(Name, StateFun) ->
Timeout :: timeout(),
NewState :: term().
replace_state(Name, StateFun, Timeout) ->
- send_system_msg(Name, {replace_state, StateFun}, Timeout).
+ case send_system_msg(Name, {replace_state, StateFun}, Timeout) of
+ {error, Reason} -> error(Reason);
+ State -> State
+ end.
-spec change_code(Name, Module, OldVsn, Extra) -> 'ok' | {error, Reason} when
Name :: name(),
@@ -390,10 +404,11 @@ do_cmd(_, suspend, _Parent, _Mod, Debug, Misc) ->
{suspended, ok, Debug, Misc};
do_cmd(_, resume, _Parent, _Mod, Debug, Misc) ->
{running, ok, Debug, Misc};
-do_cmd(SysState, get_state, _Parent, _Mod, Debug, {State, Misc}) ->
- {SysState, State, Debug, Misc};
-do_cmd(SysState, replace_state, _Parent, _Mod, Debug, {State, Misc}) ->
- {SysState, State, Debug, Misc};
+do_cmd(SysState, get_state, _Parent, Mod, Debug, Misc) ->
+ {SysState, do_get_state(Mod, Misc), Debug, Misc};
+do_cmd(SysState, {replace_state, StateFun}, _Parent, Mod, Debug, Misc) ->
+ {Res, NMisc} = do_replace_state(StateFun, Mod, Misc),
+ {SysState, Res, Debug, NMisc};
do_cmd(SysState, get_status, Parent, Mod, Debug, Misc) ->
Res = get_status(SysState, Parent, Mod, Debug, Misc),
{SysState, Res, Debug, Misc};
@@ -407,6 +422,40 @@ do_cmd(suspended, {change_code, Module, Vsn, Extra}, _Parent,
do_cmd(SysState, Other, _Parent, _Mod, Debug, Misc) ->
{SysState, {error, {unknown_system_msg, Other}}, Debug, Misc}.
+do_get_state(Mod, Misc) ->
+ case erlang:function_exported(Mod, system_get_state, 1) of
+ true ->
+ try
+ {ok, State} = Mod:system_get_state(Misc),
+ State
+ catch
+ Cl:Exc ->
+ {error, {callback_failed,{Mod,system_get_state},{Cl,Exc}}}
+ end;
+ false ->
+ Misc
+ end.
+
+do_replace_state(StateFun, Mod, Misc) ->
+ case erlang:function_exported(Mod, system_replace_state, 2) of
+ true ->
+ try
+ {ok, State, NMisc} = Mod:system_replace_state(StateFun, Misc),
+ {State, NMisc}
+ catch
+ Cl:Exc ->
+ {{error, {callback_failed,{Mod,system_replace_state},{Cl,Exc}}}, Misc}
+ end;
+ false ->
+ try
+ NMisc = StateFun(Misc),
+ {NMisc, NMisc}
+ catch
+ Cl:Exc ->
+ {{error, {callback_failed,StateFun,{Cl,Exc}}}, Misc}
+ end
+ end.
+
get_status(SysState, Parent, Mod, Debug, Misc) ->
PDict = get(),
FmtMisc =
diff --git a/lib/stdlib/src/zip.erl b/lib/stdlib/src/zip.erl
index c40ce8e203..b768c6d0b9 100644
--- a/lib/stdlib/src/zip.erl
+++ b/lib/stdlib/src/zip.erl
@@ -203,8 +203,18 @@
zip_comment_length}).
--type zip_file() :: #zip_file{}.
+-type create_option() :: memory | cooked | verbose | {comment, string()}
+ | {cwd, file:filename()}
+ | {compress, extension_spec()}
+ | {uncompress, extension_spec()}.
+-type extension() :: string().
+-type extension_spec() :: all | [extension()] | {add, [extension()]} | {del, [extension()]}.
+-type filename() :: file:filename().
+
-type zip_comment() :: #zip_comment{}.
+-type zip_file() :: #zip_file{}.
+
+-export_type([create_option/0, filename/0]).
%% Open a zip archive with options
%%
@@ -340,13 +350,13 @@ unzip(F) -> unzip(F, []).
-spec(unzip(Archive, Options) -> RetValue when
Archive :: file:name() | binary(),
Options :: [Option],
- Option :: {file_list, FileList}
+ Option :: {file_list, FileList} | cooked
| keep_old_files | verbose | memory |
{file_filter, FileFilter} | {cwd, CWD},
FileList :: [file:name()],
FileBinList :: [{file:name(),binary()}],
FileFilter :: fun((ZipFile) -> boolean()),
- CWD :: string(),
+ CWD :: file:filename(),
ZipFile :: zip_file(),
RetValue :: {ok, FileList}
| {ok, FileBinList}
@@ -430,7 +440,7 @@ zip(F, Files) -> zip(F, Files, []).
What :: all | [Extension] | {add, [Extension]} | {del, [Extension]},
Extension :: string(),
Comment :: string(),
- CWD :: string(),
+ CWD :: file:filename(),
RetValue :: {ok, FileName :: file:name()}
| {ok, {FileName :: file:name(), binary()}}
| {error, Reason :: term()}).
@@ -712,8 +722,8 @@ table(F, O) -> list_dir(F, O).
FileList :: [FileSpec],
FileSpec :: file:name() | {file:name(), binary()}
| {file:name(), binary(), file:file_info()},
- RetValue :: {ok, FileName :: file:name()}
- | {ok, {FileName :: file:name(), binary()}}
+ RetValue :: {ok, FileName :: filename()}
+ | {ok, {FileName :: filename(), binary()}}
| {error, Reason :: term()}).
create(F, Fs) -> zip(F, Fs).
@@ -724,14 +734,9 @@ create(F, Fs) -> zip(F, Fs).
FileSpec :: file:name() | {file:name(), binary()}
| {file:name(), binary(), file:file_info()},
Options :: [Option],
- Option :: memory | cooked | verbose | {comment, Comment}
- | {cwd, CWD} | {compress, What} | {uncompress, What},
- What :: all | [Extension] | {add, [Extension]} | {del, [Extension]},
- Extension :: string(),
- Comment :: string(),
- CWD :: string(),
- RetValue :: {ok, FileName :: file:name()}
- | {ok, {FileName :: file:name(), binary()}}
+ Option :: create_option(),
+ RetValue :: {ok, FileName :: filename()}
+ | {ok, {FileName :: filename(), binary()}}
| {error, Reason :: term()}).
create(F, Fs, O) -> zip(F, Fs, O).
@@ -755,7 +760,7 @@ extract(F) -> unzip(F).
FileList :: [file:name()],
FileBinList :: [{file:name(),binary()}],
FileFilter :: fun((ZipFile) -> boolean()),
- CWD :: string(),
+ CWD :: file:filename(),
ZipFile :: zip_file(),
RetValue :: {ok, FileList}
| {ok, FileBinList}
@@ -1153,7 +1158,7 @@ zip_open(Archive) -> zip_open(Archive, []).
Archive :: file:name() | binary(),
ZipHandle :: pid(),
Options :: [Option],
- Option :: cooked | memory | {cwd, CWD :: string()},
+ Option :: cooked | memory | {cwd, CWD :: file:filename()},
Reason :: term()).
zip_open(Archive, Options) ->
diff --git a/lib/stdlib/test/Makefile b/lib/stdlib/test/Makefile
index af82f22b21..39f6ce423a 100644
--- a/lib/stdlib/test/Makefile
+++ b/lib/stdlib/test/Makefile
@@ -73,6 +73,8 @@ MODULES= \
supervisor_SUITE \
supervisor_bridge_SUITE \
sys_SUITE \
+ sys_sp1 \
+ sys_sp2 \
tar_SUITE \
timer_SUITE \
timer_simple_SUITE \
diff --git a/lib/stdlib/test/binary_module_SUITE.erl b/lib/stdlib/test/binary_module_SUITE.erl
index d5a0fe21b4..32cec0db6f 100644
--- a/lib/stdlib/test/binary_module_SUITE.erl
+++ b/lib/stdlib/test/binary_module_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2013. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2014. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -40,7 +40,7 @@
-export([init_per_testcase/2, end_per_testcase/2]).
% Default timetrap timeout (set in init_per_testcase).
% Some of these testcases are really heavy...
--define(default_timeout, ?t:minutes(20)).
+-define(default_timeout, ?t:minutes(30)).
-endif.
diff --git a/lib/stdlib/test/dets_SUITE.erl b/lib/stdlib/test/dets_SUITE.erl
index 00a5da42ad..6be37cbecf 100644
--- a/lib/stdlib/test/dets_SUITE.erl
+++ b/lib/stdlib/test/dets_SUITE.erl
@@ -3953,15 +3953,6 @@ otp_11709(Config) when is_list(Config) ->
%% Parts common to several test cases
%%
-start_node_rel(Name, Rel, How) ->
- Release = [{release, atom_to_list(Rel)}],
- Pa = filename:dirname(code:which(?MODULE)),
- test_server:start_node(Name, How,
- [{args,
- " -kernel net_setuptime 100 "
- " -pa " ++ Pa},
- {erl, Release}]).
-
crash(File, Where) ->
crash(File, Where, 10).
@@ -4352,7 +4343,7 @@ check_badarg({'EXIT', {badarg, [{M,F,Args,_} | _]}}, M, F, Args) ->
check_badarg({'EXIT', {badarg, [{M,F,A,_} | _]}}, M, F, Args) ->
true = test_server:is_native(M) andalso length(Args) =:= A.
-check_pps(P0) ->
+check_pps({Ports0,Procs0} = P0) ->
case pps() of
P0 ->
ok;
@@ -4364,22 +4355,28 @@ check_pps(P0) ->
case pps() of
P0 ->
ok;
- P1 ->
- io:format("failure, got ~p~n, expected ~p\n", [P1, P0]),
- {Ports0,Procs0} = P0,
- {Ports1,Procs1} = P1,
- show("Old ports", Ports0 -- Ports1),
- show("New ports", Ports1 -- Ports0),
- show("Old procs", Procs0 -- Procs1),
- show("New procs", Procs1 -- Procs0),
- ?t:fail()
- end
+ {Ports1,Procs1} = P1 ->
+ case {Ports1 -- Ports0, Procs1 -- Procs0} of
+ {[], []} -> ok;
+ {PortsDiff,ProcsDiff} ->
+ io:format("failure, got ~p~n, expected ~p\n", [P1, P0]),
+ show("Old port", Ports0 -- Ports1),
+ show("New port", PortsDiff),
+ show("Old proc", Procs0 -- Procs1),
+ show("New proc", ProcsDiff),
+ ?t:fail()
+ end
+ end
end.
show(_S, []) ->
ok;
-show(S, L) ->
- io:format("~s: ~p~n", [S, L]).
+show(S, [Pid|Pids]) when is_pid(Pid) ->
+ io:format("~s: ~p~n", [S, erlang:process_info(Pid)]),
+ show(S, Pids);
+show(S, [Port|Ports]) when is_port(Port)->
+ io:format("~s: ~p~n", [S, erlang:port_info(Port)]),
+ show(S, Ports).
pps() ->
dets:start(),
diff --git a/lib/stdlib/test/epp_SUITE.erl b/lib/stdlib/test/epp_SUITE.erl
index 0b4726c07a..b17e8bd186 100644
--- a/lib/stdlib/test/epp_SUITE.erl
+++ b/lib/stdlib/test/epp_SUITE.erl
@@ -26,7 +26,7 @@
pmod/1, not_circular/1, skip_header/1, otp_6277/1, otp_7702/1,
otp_8130/1, overload_mac/1, otp_8388/1, otp_8470/1, otp_8503/1,
otp_8562/1, otp_8665/1, otp_8911/1, otp_10302/1, otp_10820/1,
- otp_11728/1]).
+ otp_11728/1, encoding/1]).
-export([epp_parse_erl_form/2]).
@@ -68,7 +68,8 @@ all() ->
{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,
- otp_8665, otp_8911, otp_10302, otp_10820, otp_11728].
+ otp_8665, otp_8911, otp_10302, otp_10820, otp_11728,
+ encoding].
groups() ->
[{upcase_mac, [], [upcase_mac_1, upcase_mac_2]},
@@ -123,10 +124,22 @@ include_local(Config) when is_list(Config) ->
%%% regular epp:parse_file, the test case will time out, and then epp
%%% server will go on growing until we dump core.
epp_parse_file(File, Inc, Predef) ->
- {ok, Epp} = epp:open(File, Inc, Predef),
+ List = do_epp_parse_file(fun() ->
+ epp:open(File, Inc, Predef)
+ end),
+ List = do_epp_parse_file(fun() ->
+ Opts = [{name, File},
+ {includes, Inc},
+ {macros, Predef}],
+ epp:open(Opts)
+ end),
+ {ok, List}.
+
+do_epp_parse_file(Open) ->
+ {ok, Epp} = Open(),
List = collect_epp_forms(Epp),
epp:close(Epp),
- {ok, List}.
+ List.
collect_epp_forms(Epp) ->
Result = epp_parse_erl_form(Epp),
@@ -1413,6 +1426,63 @@ otp_11728(Config) when is_list(Config) ->
_ = file:delete(ErlFile),
ok.
+%% Check the new API for setting the default encoding.
+encoding(Config) when is_list(Config) ->
+ Dir = ?config(priv_dir, Config),
+ ErlFile = filename:join(Dir, "encoding.erl"),
+
+ %% Try a latin-1 file with no encoding given.
+ C1 = <<"-module(encoding).
+ %% ",246,"
+ ">>,
+ ok = file:write_file(ErlFile, C1),
+ {ok,[{attribute,1,file,_},
+ {attribute,1,module,encoding},
+ {error,_},
+ {error,{2,epp,cannot_parse}},
+ {eof,2}]} = epp:parse_file(ErlFile, []),
+ {ok,[{attribute,1,file,_},
+ {attribute,1,module,encoding},
+ {eof,3}]} =
+ epp:parse_file(ErlFile, [{default_encoding,latin1}]),
+ {ok,[{attribute,1,file,_},
+ {attribute,1,module,encoding},
+ {eof,3}],[{encoding,none}]} =
+ epp:parse_file(ErlFile, [{default_encoding,latin1},extra]),
+
+ %% Try a latin-1 file with encoding given in a comment.
+ C2 = <<"-module(encoding).
+ %% encoding: latin-1
+ %% ",246,"
+ ">>,
+ ok = file:write_file(ErlFile, C2),
+ {ok,[{attribute,1,file,_},
+ {attribute,1,module,encoding},
+ {eof,4}]} =
+ epp:parse_file(ErlFile, []),
+ {ok,[{attribute,1,file,_},
+ {attribute,1,module,encoding},
+ {eof,4}]} =
+ epp:parse_file(ErlFile, [{default_encoding,latin1}]),
+ {ok,[{attribute,1,file,_},
+ {attribute,1,module,encoding},
+ {eof,4}]} =
+ epp:parse_file(ErlFile, [{default_encoding,utf8}]),
+ {ok,[{attribute,1,file,_},
+ {attribute,1,module,encoding},
+ {eof,4}],[{encoding,latin1}]} =
+ epp:parse_file(ErlFile, [extra]),
+ {ok,[{attribute,1,file,_},
+ {attribute,1,module,encoding},
+ {eof,4}],[{encoding,latin1}]} =
+ epp:parse_file(ErlFile, [{default_encoding,latin1},extra]),
+ {ok,[{attribute,1,file,_},
+ {attribute,1,module,encoding},
+ {eof,4}],[{encoding,latin1}]} =
+ epp:parse_file(ErlFile, [{default_encoding,utf8},extra]),
+ ok.
+
+
check(Config, Tests) ->
eval_tests(Config, fun check_test/2, Tests).
diff --git a/lib/stdlib/test/erl_eval_SUITE.erl b/lib/stdlib/test/erl_eval_SUITE.erl
index e6512b7d71..b91d14b5b8 100644
--- a/lib/stdlib/test/erl_eval_SUITE.erl
+++ b/lib/stdlib/test/erl_eval_SUITE.erl
@@ -1451,6 +1451,8 @@ eep43(Config) when is_list(Config) ->
" {Map#{a := B},Map#{a => c},Map#{d => e}} "
"end.",
{#{a => b},#{a => c},#{a => b,d => e}}),
+ error_check("[camembert]#{}.", {badarg,[camembert]}),
+ error_check("#{} = 1.", {badmatch,1}),
ok.
%% Check the string in different contexts: as is; in fun; from compiled code.
diff --git a/lib/stdlib/test/erl_lint_SUITE.erl b/lib/stdlib/test/erl_lint_SUITE.erl
index 5d189006a1..bb14de333d 100644
--- a/lib/stdlib/test/erl_lint_SUITE.erl
+++ b/lib/stdlib/test/erl_lint_SUITE.erl
@@ -63,7 +63,7 @@
too_many_arguments/1,
basic_errors/1,bin_syntax_errors/1,
predef/1,
- maps/1
+ maps/1,maps_type/1
]).
% Default timetrap timeout (set in init_per_testcase).
@@ -91,7 +91,8 @@ all() ->
otp_11772, otp_11771, export_all,
bif_clash, behaviour_basic, behaviour_multiple,
otp_7550, otp_8051, format_warn, {group, on_load},
- too_many_arguments, basic_errors, bin_syntax_errors, predef, maps].
+ too_many_arguments, basic_errors, bin_syntax_errors, predef,
+ maps, maps_type].
groups() ->
[{unused_vars_warn, [],
@@ -1278,10 +1279,9 @@ guard(Config) when is_list(Config) ->
tuple.
">>,
[nowarn_obsolete_guard],
- {error,
+ {errors,
[{6,erl_lint,illegal_guard_expr},{18,erl_lint,illegal_guard_expr}],
- [{18,erl_lint,{removed,{erlang,is_constant,1},
- "Removed in R13B"}}]}},
+ []}},
{guard2,
<<"-record(apa,{}).
t1(A) when atom(A), atom(A) ->
@@ -1340,14 +1340,11 @@ guard(Config) when is_list(Config) ->
tuple.
">>,
[nowarn_obsolete_guard],
- {error,[{6,erl_lint,illegal_guard_expr},
- {6,erl_lint,illegal_guard_expr},
- {18,erl_lint,illegal_guard_expr},
- {18,erl_lint,illegal_guard_expr}],
- [{18,erl_lint,{removed,{erlang,is_constant,1},
- "Removed in R13B"}},
- {18,erl_lint,{removed,{erlang,is_constant,1},
- "Removed in R13B"}}]}},
+ {errors,[{6,erl_lint,illegal_guard_expr},
+ {6,erl_lint,illegal_guard_expr},
+ {18,erl_lint,illegal_guard_expr},
+ {18,erl_lint,illegal_guard_expr}],
+ []}},
{guard3,
<<"-record(apa,{}).
t2(A) when atom(A); atom(A) ->
@@ -3388,9 +3385,57 @@ maps(Config) ->
{error_in_illegal_map_construction,
<<"t() -> #{ a := X }.">>,
[],
- {errors,[{1,erl_lint,illegal_map_construction},
+ {errors,[{1,erl_lint,illegal_map_construction},
{1,erl_lint,{unbound_var,'X'}}],
- []}}],
+ []}},
+ {errors_in_map_keys,
+ <<"t(V) -> #{ a => 1,
+ #{a=>V} => 2,
+ #{ \"hi\" => wazzup, hi => ho } => yep,
+ [try a catch _:_ -> b end] => nope,
+ ok => 1.0,
+ [3+3] => nope,
+ 1.0 => yep,
+ {3.0+3} => nope,
+ {yep} => yep,
+ [case a of a -> a end] => nope
+ }.
+ ">>,
+ [],
+ {errors,[{2,erl_lint,{illegal_map_key_variable,'V'}},
+ {4,erl_lint,illegal_map_key},
+ {6,erl_lint,illegal_map_key},
+ {8,erl_lint,illegal_map_key},
+ {10,erl_lint,illegal_map_key}],[]}}],
+ [] = run(Config, Ts),
+ ok.
+
+maps_type(Config) when is_list(Config) ->
+ Ts = [
+ {maps_type1,
+ <<"
+ -type m() :: #{a => integer()}.
+ -spec t1(#{k=>term()}) -> {term(), map()}.
+
+ t1(#{k:=V}=M) -> {V,M}.
+
+ -spec t2(m()) -> integer().
+
+ t2(#{a:=V}) -> V.
+ ">>,
+ [],
+ []},
+ {maps_type2,
+ <<"
+ %% Built-in var arity map type:
+ -type map() :: tuple().
+ -type a() :: map().
+
+ -spec t(a()) -> a().
+ t(M) -> M.
+ ">>,
+ [],
+ {warnings,[{3,erl_lint,{new_var_arity_type,map}}]}}],
[] = run(Config, Ts),
ok.
diff --git a/lib/stdlib/test/erl_pp_SUITE.erl b/lib/stdlib/test/erl_pp_SUITE.erl
index 390322a5fa..babf3a49eb 100644
--- a/lib/stdlib/test/erl_pp_SUITE.erl
+++ b/lib/stdlib/test/erl_pp_SUITE.erl
@@ -993,6 +993,16 @@ maps_syntax(Config) when is_list(Config) ->
ok = pp_expr(<<"#{ a => 1, <<\"hi\">> => \"world\", 33 => 1.0 }">>),
ok = pp_expr(<<"#{ a := V1, <<\"hi\">> := V2 } = M">>),
ok = pp_expr(<<"M#{ a => V1, <<\"hi\">> := V2 }">>),
+ F = <<"-module(maps_type_syntax).\n"
+ "-compile(export_all).\n"
+ "-type t1() :: map().\n"
+ "-type t2() :: #{ atom() => integer(), atom() => float() }.\n"
+ "-spec f1(t1()) -> 'true'.\n"
+ "f1(M) when is_map(M) -> true.\n"
+ "-spec f2(t2()) -> integer().\n"
+ "f2(#{a := V1,b := V2}) -> V1 + V2.\n"
+ "\n">>,
+ ok = pp_forms(F),
ok.
diff --git a/lib/stdlib/test/erl_scan_SUITE.erl b/lib/stdlib/test/erl_scan_SUITE.erl
index 447e159cd4..35067e8116 100644
--- a/lib/stdlib/test/erl_scan_SUITE.erl
+++ b/lib/stdlib/test/erl_scan_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1998-2013. All Rights Reserved.
+%% Copyright Ericsson AB 1998-2014. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -21,7 +21,7 @@
init_per_group/2,end_per_group/2]).
-export([ error_1/1, error_2/1, iso88591/1, otp_7810/1, otp_10302/1,
- otp_10990/1, otp_10992/1]).
+ otp_10990/1, otp_10992/1, otp_11807/1]).
-import(lists, [nth/2,flatten/1]).
-import(io_lib, [print/1]).
@@ -60,7 +60,8 @@ end_per_testcase(_Case, Config) ->
suite() -> [{ct_hooks,[ts_install_cth]}].
all() ->
- [{group, error}, iso88591, otp_7810, otp_10302, otp_10990, otp_10992].
+ [{group, error}, iso88591, otp_7810, otp_10302, otp_10990, otp_10992,
+ otp_11807].
groups() ->
[{error, [], [error_1, error_2]}].
@@ -1144,6 +1145,25 @@ otp_10992(Config) when is_list(Config) ->
erl_parse:abstract([$A,42.0], [{encoding,utf8}]),
ok.
+otp_11807(doc) ->
+ "OTP-11807. Generalize erl_parse:abstract/2.";
+otp_11807(suite) ->
+ [];
+otp_11807(Config) when is_list(Config) ->
+ {cons,0,{integer,0,97},{cons,0,{integer,0,98},{nil,0}}} =
+ erl_parse:abstract("ab", [{encoding,none}]),
+ {cons,0,{integer,0,-1},{nil,0}} =
+ erl_parse:abstract([-1], [{encoding,latin1}]),
+ ASCII = fun(I) -> I >= 0 andalso I < 128 end,
+ {string,0,"xyz"} = erl_parse:abstract("xyz", [{encoding,ASCII}]),
+ {cons,0,{integer,0,228},{nil,0}} =
+ erl_parse:abstract([228], [{encoding,ASCII}]),
+ {cons,0,{integer,0,97},{atom,0,a}} =
+ erl_parse:abstract("a"++a, [{encoding,latin1}]),
+ {'EXIT', {{badarg,bad},_}} = % minor backward incompatibility
+ (catch erl_parse:abstract("string", [{encoding,bad}])),
+ ok.
+
test_string(String, Expected) ->
{ok, Expected, _End} = erl_scan:string(String),
test(String).
diff --git a/lib/stdlib/test/gen_event_SUITE.erl b/lib/stdlib/test/gen_event_SUITE.erl
index 5819ef3890..60a1ba8c60 100644
--- a/lib/stdlib/test/gen_event_SUITE.erl
+++ b/lib/stdlib/test/gen_event_SUITE.erl
@@ -974,6 +974,10 @@ get_state(Config) when is_list(Config) ->
[{dummy1_h,false,State1},{dummy1_h,id,State2}] = lists:sort(Result1),
Result2 = sys:get_state(Pid, 5000),
[{dummy1_h,false,State1},{dummy1_h,id,State2}] = lists:sort(Result2),
+ ok = sys:suspend(Pid),
+ Result3 = sys:get_state(Pid),
+ [{dummy1_h,false,State1},{dummy1_h,id,State2}] = lists:sort(Result3),
+ ok = sys:resume(Pid),
ok = gen_event:stop(Pid),
ok.
@@ -998,4 +1002,11 @@ replace_state(Config) when is_list(Config) ->
Replace3 = fun(_) -> exit(fail) end,
[{dummy1_h,false,NState2}] = sys:replace_state(Pid, Replace3),
[{dummy1_h,false,NState2}] = sys:get_state(Pid),
+ %% verify state replaced if process sys suspended
+ NState3 = "replaced again and again",
+ Replace4 = fun({dummy1_h,false,_}=S) -> setelement(3,S,NState3) end,
+ ok = sys:suspend(Pid),
+ [{dummy1_h,false,NState3}] = sys:replace_state(Pid, Replace4),
+ ok = sys:resume(Pid),
+ [{dummy1_h,false,NState3}] = sys:get_state(Pid),
ok.
diff --git a/lib/stdlib/test/gen_fsm_SUITE.erl b/lib/stdlib/test/gen_fsm_SUITE.erl
index fd15838b7d..8aeec07ae8 100644
--- a/lib/stdlib/test/gen_fsm_SUITE.erl
+++ b/lib/stdlib/test/gen_fsm_SUITE.erl
@@ -426,6 +426,14 @@ get_state(Config) when is_list(Config) ->
{idle, State} = sys:get_state(gfsm),
{idle, State} = sys:get_state(gfsm, 5000),
stop_it(Pid2),
+
+ %% check that get_state works when pid is sys suspended
+ {ok, Pid3} = gen_fsm:start(gen_fsm_SUITE, {state_data, State}, []),
+ {idle, State} = sys:get_state(Pid3),
+ ok = sys:suspend(Pid3),
+ {idle, State} = sys:get_state(Pid3, 5000),
+ ok = sys:resume(Pid3),
+ stop_it(Pid3),
ok.
replace_state(Config) when is_list(Config) ->
@@ -442,8 +450,18 @@ replace_state(Config) when is_list(Config) ->
{state0, NState2} = sys:get_state(Pid),
%% verify no change in state if replace function crashes
Replace3 = fun(_) -> error(fail) end,
- {state0, NState2} = sys:replace_state(Pid, Replace3),
+ {'EXIT',{{callback_failed,
+ {gen_fsm,system_replace_state},{error,fail}},_}} =
+ (catch sys:replace_state(Pid, Replace3)),
{state0, NState2} = sys:get_state(Pid),
+ %% verify state replaced if process sys suspended
+ ok = sys:suspend(Pid),
+ Suffix2 = " and again",
+ NState3 = NState2 ++ Suffix2,
+ Replace4 = fun({StateName, _}) -> {StateName, NState3} end,
+ {state0, NState3} = sys:replace_state(Pid, Replace4),
+ ok = sys:resume(Pid),
+ {state0, NState3} = sys:get_state(Pid, 5000),
stop_it(Pid),
ok.
diff --git a/lib/stdlib/test/gen_server_SUITE.erl b/lib/stdlib/test/gen_server_SUITE.erl
index a360a0809b..960e7f60e7 100644
--- a/lib/stdlib/test/gen_server_SUITE.erl
+++ b/lib/stdlib/test/gen_server_SUITE.erl
@@ -1049,6 +1049,9 @@ get_state(Config) when is_list(Config) ->
{ok, Pid} = gen_server:start_link(?MODULE, {state,State}, []),
State = sys:get_state(Pid),
State = sys:get_state(Pid, 5000),
+ ok = sys:suspend(Pid),
+ State = sys:get_state(Pid),
+ ok = sys:resume(Pid),
ok.
%% Verify that sys:replace_state correctly replaces gen_server state
@@ -1075,8 +1078,18 @@ replace_state(Config) when is_list(Config) ->
NState2 = sys:get_state(Pid, 5000),
%% verify no change in state if replace function crashes
Replace3 = fun(_) -> throw(fail) end,
- NState2 = sys:replace_state(Pid, Replace3),
+ {'EXIT',{{callback_failed,
+ {gen_server,system_replace_state},{throw,fail}},_}} =
+ (catch sys:replace_state(Pid, Replace3)),
NState2 = sys:get_state(Pid, 5000),
+ %% verify state replaced if process sys suspended
+ ok = sys:suspend(Pid),
+ Suffix2 = " and again",
+ NState3 = NState2 ++ Suffix2,
+ Replace4 = fun(S) -> S ++ Suffix2 end,
+ NState3 = sys:replace_state(Pid, Replace4),
+ ok = sys:resume(Pid),
+ NState3 = sys:get_state(Pid, 5000),
ok.
%% Test that the time for a huge message queue is not
diff --git a/lib/stdlib/test/shell_SUITE.erl b/lib/stdlib/test/shell_SUITE.erl
index 692dfe0faa..e016432f4d 100644
--- a/lib/stdlib/test/shell_SUITE.erl
+++ b/lib/stdlib/test/shell_SUITE.erl
@@ -54,7 +54,7 @@ config(priv_dir,_) ->
-include_lib("test_server/include/test_server.hrl").
-export([init_per_testcase/2, end_per_testcase/2]).
% Default timetrap timeout (set in init_per_testcase).
--define(default_timeout, ?t:minutes(2)).
+-define(default_timeout, ?t:minutes(10)).
init_per_testcase(_Case, Config) ->
?line Dog = ?t:timetrap(?default_timeout),
?line OrigPath = code:get_path(),
diff --git a/lib/stdlib/test/supervisor_SUITE.erl b/lib/stdlib/test/supervisor_SUITE.erl
index ac5a34c3bc..836ea7c030 100644
--- a/lib/stdlib/test/supervisor_SUITE.erl
+++ b/lib/stdlib/test/supervisor_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2013. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2014. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -60,7 +60,7 @@
simple_one_for_one_extra/1, simple_one_for_one_shutdown/1]).
%% Misc tests
--export([child_unlink/1, tree/1, count_children_memory/1,
+-export([child_unlink/1, tree/1, count_children/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,
@@ -82,7 +82,7 @@ all() ->
{group, normal_termination},
{group, shutdown_termination},
{group, abnormal_termination}, child_unlink, tree,
- count_children_memory, do_not_save_start_parameters_for_temporary_children,
+ count_children, 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_global_supervisor, hanging_restart_loop, hanging_restart_loop_simple].
@@ -129,23 +129,10 @@ init_per_group(_GroupName, Config) ->
end_per_group(_GroupName, Config) ->
Config.
-init_per_testcase(count_children_memory, Config) ->
- try erlang:memory() of
- _ ->
- erts_debug:set_internal_state(available_internal_state, true),
- Dog = ?t:timetrap(?TIMEOUT),
- [{watchdog,Dog}|Config]
- catch error:notsup ->
- {skip, "+Meamin used during test; erlang:memory/1 not available"}
- end;
init_per_testcase(_Case, Config) ->
Dog = ?t:timetrap(?TIMEOUT),
[{watchdog,Dog}|Config].
-end_per_testcase(count_children_memory, Config) ->
- catch erts_debug:set_internal_state(available_internal_state, false),
- ?t:timetrap_cancel(?config(watchdog,Config)),
- ok;
end_per_testcase(_Case, Config) ->
?t:timetrap_cancel(?config(watchdog,Config)),
ok.
@@ -1249,34 +1236,24 @@ tree(Config) when is_list(Config) ->
[0,0,0,0] = get_child_counts(NewSup2).
%%-------------------------------------------------------------------------
-%% Test that count_children does not eat memory.
-count_children_memory(Config) when is_list(Config) ->
+%% Test count_children
+count_children(Config) when is_list(Config) ->
process_flag(trap_exit, true),
Child = {child, {supervisor_1, start_child, []}, temporary, 1000,
worker, []},
{ok, SupPid} = start_link({ok, {{simple_one_for_one, 2, 3600}, [Child]}}),
[supervisor:start_child(sup_test, []) || _Ignore <- lists:seq(1,1000)],
- garbage_collect(),
- _Size1 = proc_memory(),
Children = supervisor:which_children(sup_test),
- _Size2 = proc_memory(),
ChildCount = get_child_counts(sup_test),
- _Size3 = proc_memory(),
[supervisor:start_child(sup_test, []) || _Ignore2 <- lists:seq(1,1000)],
- garbage_collect(),
- Children2 = supervisor:which_children(sup_test),
- Size4 = proc_memory(),
ChildCount2 = get_child_counts(sup_test),
- Size5 = proc_memory(),
+ Children2 = supervisor:which_children(sup_test),
- garbage_collect(),
- Children3 = supervisor:which_children(sup_test),
- Size6 = proc_memory(),
ChildCount3 = get_child_counts(sup_test),
- Size7 = proc_memory(),
+ Children3 = supervisor:which_children(sup_test),
1000 = length(Children),
[1,1000,0,1000] = ChildCount,
@@ -1285,27 +1262,9 @@ count_children_memory(Config) when is_list(Config) ->
Children3 = Children2,
ChildCount3 = ChildCount2,
- %% count_children consumes memory using an accumulator function,
- %% but the space can be reclaimed incrementally,
- %% which_children may generate garbage that will be reclaimed later.
- case (Size5 =< Size4) of
- true -> ok;
- false ->
- test_server:fail({count_children, used_more_memory,Size4,Size5})
- end,
- case Size7 =< Size6 of
- true -> ok;
- false ->
- test_server:fail({count_children, used_more_memory,Size6,Size7})
- end,
-
[terminate(SupPid, Pid, child, kill) || {undefined, Pid, worker, _Modules} <- Children3],
[1,0,0,0] = get_child_counts(sup_test).
-proc_memory() ->
- erts_debug:set_internal_state(wait, deallocations),
- erlang:memory(processes_used).
-
%%-------------------------------------------------------------------------
%% Temporary children shall not be restarted so they should not save
%% start parameters, as it potentially can take up a huge amount of
@@ -1483,7 +1442,7 @@ simple_one_for_one_scale_many_temporary_children(_Config) ->
if T1 > 0 ->
Scaling = T2 div T1,
- if Scaling > 20 ->
+ if Scaling > 50 ->
%% The scaling shoul be linear (i.e.10, really), but we
%% give some extra here to avoid failing the test
%% unecessarily.
diff --git a/lib/stdlib/test/sys_SUITE.erl b/lib/stdlib/test/sys_SUITE.erl
index c06ba545e7..f38bc87ae5 100644
--- a/lib/stdlib/test/sys_SUITE.erl
+++ b/lib/stdlib/test/sys_SUITE.erl
@@ -19,7 +19,7 @@
-module(sys_SUITE).
-export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1,
init_per_group/2,end_per_group/2,log/1,log_to_file/1,
- stats/1,trace/1,suspend/1,install/1]).
+ stats/1,trace/1,suspend/1,install/1,special_process/1]).
-export([handle_call/3,terminate/2,init/1]).
-include_lib("test_server/include/test_server.hrl").
@@ -27,14 +27,12 @@
%% Doesn't look into change_code at all
-%% Doesn't address writing your own process that understands
-%% system messages at all.
suite() -> [{ct_hooks,[ts_install_cth]}].
all() ->
- [log, log_to_file, stats, trace, suspend, install].
+ [log, log_to_file, stats, trace, suspend, install, special_process].
groups() ->
[].
@@ -157,6 +155,84 @@ install(Config) when is_list(Config) ->
?line stop(),
ok.
+special_process(suite) -> [];
+special_process(Config) when is_list(Config) ->
+ ok = spec_proc(sys_sp1),
+ ok = spec_proc(sys_sp2).
+
+spec_proc(Mod) ->
+ {ok,_} = Mod:start_link(100),
+ ok = sys:statistics(Mod,true),
+ ok = sys:trace(Mod,true),
+ 1 = Ch = Mod:alloc(),
+ Free = lists:seq(2,100),
+ Replace = case sys:get_state(Mod) of
+ {[Ch],Free} ->
+ fun({A,F}) ->
+ Free = F,
+ {A,[2,3,4]}
+ end;
+ {state,[Ch],Free} ->
+ fun({state,A,F}) ->
+ Free = F,
+ {state,A,[2,3,4]}
+ end
+ end,
+ case sys:replace_state(Mod, Replace) of
+ {[Ch],[2,3,4]} -> ok;
+ {state,[Ch],[2,3,4]} -> ok
+ end,
+ ok = Mod:free(Ch),
+ case sys:get_state(Mod) of
+ {[],[1,2,3,4]} -> ok;
+ {state,[],[1,2,3,4]} -> ok
+ end,
+ {ok,[{start_time,_},
+ {current_time,_},
+ {reductions,_},
+ {messages_in,2},
+ {messages_out,1}]} = sys:statistics(Mod,get),
+ ok = sys:statistics(Mod,false),
+ [] = sys:replace_state(Mod, fun(_) -> [] end),
+ process_flag(trap_exit,true),
+ ok = case catch sys:get_state(Mod) of
+ [] ->
+ ok;
+ {'EXIT',{{callback_failed,
+ {Mod,system_get_state},{throw,fail}},_}} ->
+ ok
+ end,
+ Mod:stop(),
+ WaitForUnregister = fun W() ->
+ case whereis(Mod) of
+ undefined -> ok;
+ _ -> timer:sleep(10), W()
+ end
+ end,
+ WaitForUnregister(),
+ {ok,_} = Mod:start_link(4),
+ ok = case catch sys:replace_state(Mod, fun(_) -> {} end) of
+ {} ->
+ ok;
+ {'EXIT',{{callback_failed,
+ {Mod,system_replace_state},{throw,fail}},_}} ->
+ ok
+ end,
+ Mod:stop(),
+ WaitForUnregister(),
+ {ok,_} = Mod:start_link(4),
+ StateFun = fun(_) -> error(fail) end,
+ ok = case catch sys:replace_state(Mod, StateFun) of
+ {} ->
+ ok;
+ {'EXIT',{{callback_failed,
+ {Mod,system_replace_state},{error,fail}},_}} ->
+ ok;
+ {'EXIT',{{callback_failed,StateFun,{error,fail}},_}} ->
+ ok
+ end,
+ Mod:stop().
+
%%%%%%%%%%%%%%%%%%%%
%% Dummy server
diff --git a/lib/stdlib/test/sys_sp1.erl b/lib/stdlib/test/sys_sp1.erl
new file mode 100644
index 0000000000..e84ffcfa12
--- /dev/null
+++ b/lib/stdlib/test/sys_sp1.erl
@@ -0,0 +1,114 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 1996-2013. 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(sys_sp1).
+-export([start_link/1, stop/0]).
+-export([alloc/0, free/1]).
+-export([init/1]).
+-export([system_continue/3, system_terminate/4,
+ write_debug/3,
+ system_get_state/1, system_replace_state/2]).
+
+%% Implements the ch4 example from the Design Principles doc. Same as
+%% sys_sp2 except this module exports system_get_state/1 and
+%% system_replace_state/2
+
+start_link(NumCh) ->
+ proc_lib:start_link(?MODULE, init, [[self(),NumCh]]).
+
+stop() ->
+ ?MODULE ! stop,
+ ok.
+
+alloc() ->
+ ?MODULE ! {self(), alloc},
+ receive
+ {?MODULE, Res} ->
+ Res
+ end.
+
+free(Ch) ->
+ ?MODULE ! {free, Ch},
+ ok.
+
+init([Parent,NumCh]) ->
+ register(?MODULE, self()),
+ Chs = channels(NumCh),
+ Deb = sys:debug_options([]),
+ proc_lib:init_ack(Parent, {ok, self()}),
+ loop(Chs, Parent, Deb).
+
+loop(Chs, Parent, Deb) ->
+ receive
+ {From, alloc} ->
+ Deb2 = sys:handle_debug(Deb, fun write_debug/3,
+ ?MODULE, {in, alloc, From}),
+ {Ch, Chs2} = alloc(Chs),
+ From ! {?MODULE, Ch},
+ Deb3 = sys:handle_debug(Deb2, fun write_debug/3,
+ ?MODULE, {out, {?MODULE, Ch}, From}),
+ loop(Chs2, Parent, Deb3);
+ {free, Ch} ->
+ Deb2 = sys:handle_debug(Deb, fun write_debug/3,
+ ?MODULE, {in, {free, Ch}}),
+ Chs2 = free(Ch, Chs),
+ loop(Chs2, Parent, Deb2);
+ {system, From, Request} ->
+ sys:handle_system_msg(Request, From, Parent,
+ ?MODULE, Deb, Chs);
+ stop ->
+ sys:handle_debug(Deb, fun write_debug/3,
+ ?MODULE, {in, stop}),
+ ok
+ end.
+
+system_continue(Parent, Deb, Chs) ->
+ loop(Chs, Parent, Deb).
+
+system_terminate(Reason, _Parent, _Deb, _Chs) ->
+ exit(Reason).
+
+system_get_state([]) ->
+ throw(fail);
+system_get_state(Chs) ->
+ {ok, Chs}.
+
+system_replace_state(_StateFun, {}) ->
+ throw(fail);
+system_replace_state(StateFun, Chs) ->
+ NChs = StateFun(Chs),
+ {ok, NChs, NChs}.
+
+write_debug(Dev, Event, Name) ->
+ io:format(Dev, "~p event = ~p~n", [Name, Event]).
+
+channels(NumCh) ->
+ {_Allocated=[], _Free=lists:seq(1,NumCh)}.
+
+alloc({_, []}) ->
+ {error, "no channels available"};
+alloc({Allocated, [H|T]}) ->
+ {H, {[H|Allocated], T}}.
+
+free(Ch, {Alloc, Free}=Channels) ->
+ case lists:member(Ch, Alloc) of
+ true ->
+ {lists:delete(Ch, Alloc), [Ch|Free]};
+ false ->
+ Channels
+ end.
diff --git a/lib/stdlib/test/sys_sp2.erl b/lib/stdlib/test/sys_sp2.erl
new file mode 100644
index 0000000000..56a5e4d071
--- /dev/null
+++ b/lib/stdlib/test/sys_sp2.erl
@@ -0,0 +1,107 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 1996-2013. 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(sys_sp2).
+-export([start_link/1, stop/0]).
+-export([alloc/0, free/1]).
+-export([init/1]).
+-export([system_continue/3, system_terminate/4,
+ write_debug/3]).
+
+%% Implements the ch4 example from the Design Principles doc. Same as
+%% sys_sp1 except this module does not export system_get_state/1 or
+%% system_replace_state/2
+
+start_link(NumCh) ->
+ proc_lib:start_link(?MODULE, init, [[self(),NumCh]]).
+
+stop() ->
+ ?MODULE ! stop,
+ ok.
+
+alloc() ->
+ ?MODULE ! {self(), alloc},
+ receive
+ {?MODULE, Res} ->
+ Res
+ end.
+
+free(Ch) ->
+ ?MODULE ! {free, Ch},
+ ok.
+
+%% can't use 2-tuple for state here as we do in sys_sp1, since the 2-tuple
+%% is not compatible with the backward compatibility handling for
+%% sys:get_state in sys.erl
+-record(state, {alloc,free}).
+
+init([Parent,NumCh]) ->
+ register(?MODULE, self()),
+ Chs = channels(NumCh),
+ Deb = sys:debug_options([]),
+ proc_lib:init_ack(Parent, {ok, self()}),
+ loop(Chs, Parent, Deb).
+
+loop(Chs, Parent, Deb) ->
+ receive
+ {From, alloc} ->
+ Deb2 = sys:handle_debug(Deb, fun write_debug/3,
+ ?MODULE, {in, alloc, From}),
+ {Ch, Chs2} = alloc(Chs),
+ From ! {?MODULE, Ch},
+ Deb3 = sys:handle_debug(Deb2, fun write_debug/3,
+ ?MODULE, {out, {?MODULE, Ch}, From}),
+ loop(Chs2, Parent, Deb3);
+ {free, Ch} ->
+ Deb2 = sys:handle_debug(Deb, fun write_debug/3,
+ ?MODULE, {in, {free, Ch}}),
+ Chs2 = free(Ch, Chs),
+ loop(Chs2, Parent, Deb2);
+ {system, From, Request} ->
+ sys:handle_system_msg(Request, From, Parent,
+ ?MODULE, Deb, Chs);
+ stop ->
+ sys:handle_debug(Deb, fun write_debug/3,
+ ?MODULE, {in, stop}),
+ ok
+ end.
+
+system_continue(Parent, Deb, Chs) ->
+ loop(Chs, Parent, Deb).
+
+system_terminate(Reason, _Parent, _Deb, _Chs) ->
+ exit(Reason).
+
+write_debug(Dev, Event, Name) ->
+ io:format(Dev, "~p event = ~p~n", [Name, Event]).
+
+channels(NumCh) ->
+ #state{alloc=[], free=lists:seq(1,NumCh)}.
+
+alloc(#state{free=[]}=Channels) ->
+ {{error, "no channels available"}, Channels};
+alloc(#state{alloc=Allocated, free=[H|T]}) ->
+ {H, #state{alloc=[H|Allocated], free=T}}.
+
+free(Ch, #state{alloc=Alloc, free=Free}=Channels) ->
+ case lists:member(Ch, Alloc) of
+ true ->
+ #state{alloc=lists:delete(Ch, Alloc), free=[Ch|Free]};
+ false ->
+ Channels
+ end.
diff --git a/lib/stdlib/test/unicode_SUITE.erl b/lib/stdlib/test/unicode_SUITE.erl
index e2d789bbe6..10b29d0d28 100644
--- a/lib/stdlib/test/unicode_SUITE.erl
+++ b/lib/stdlib/test/unicode_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2013. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2014. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -98,7 +98,7 @@ ex_binaries_errors_utf8(Config) when is_list(Config) ->
unicode:characters_to_list(Chomped),
BrokenPart = iolist_to_binary(DeepBrokenPart2)
end || X <- lists:seq(1,OKLen) ]
- end || N <- lists:seq(1,20) ],
+ end || N <- lists:seq(1,21,4) ],
ok.
ex_binaries_errors_utf16_little(Config) when is_list(Config) ->
@@ -124,7 +124,7 @@ ex_binaries_errors_utf16_little(Config) when is_list(Config) ->
unicode:characters_to_list(Chomped,{utf16,little}),
BrokenPart = iolist_to_binary(DeepBrokenPart2)
end || X <- lists:seq(1,OKLen) ]
- end || N <- lists:seq(1,15) ],
+ end || N <- lists:seq(1,16,3) ],
ok.
ex_binaries_errors_utf16_big(Config) when is_list(Config) ->
BrokenPart = << <<X:16/big>> || X <- lists:seq(16#DC00,16#DFFF) >>,
@@ -149,7 +149,7 @@ ex_binaries_errors_utf16_big(Config) when is_list(Config) ->
unicode:characters_to_list(Chomped,{utf16,big}),
BrokenPart = iolist_to_binary(DeepBrokenPart2)
end || X <- lists:seq(1,OKLen) ]
- end || N <- lists:seq(1,15) ],
+ end || N <- lists:seq(1,16,3) ],
ok.
ex_binaries_errors_utf32_big(Config) when is_list(Config) ->
@@ -175,7 +175,7 @@ ex_binaries_errors_utf32_big(Config) when is_list(Config) ->
unicode:characters_to_list(Chomped,{utf32,big}),
BrokenPart = iolist_to_binary(DeepBrokenPart2)
end || X <- lists:seq(1,OKLen) ]
- end || N <- lists:seq(1,15) ],
+ end || N <- lists:seq(1,16,3) ],
ok.
ex_binaries_errors_utf32_little(Config) when is_list(Config) ->
@@ -201,7 +201,7 @@ ex_binaries_errors_utf32_little(Config) when is_list(Config) ->
unicode:characters_to_list(Chomped,{utf32,little}),
BrokenPart = iolist_to_binary(DeepBrokenPart2)
end || X <- lists:seq(1,OKLen) ]
- end || N <- lists:seq(1,15) ],
+ end || N <- lists:seq(1,16,3) ],
ok.
diff --git a/lib/syntax_tools/src/syntax_tools.app.src b/lib/syntax_tools/src/syntax_tools.app.src
index dc0b9edd62..83dcb5fe23 100644
--- a/lib/syntax_tools/src/syntax_tools.app.src
+++ b/lib/syntax_tools/src/syntax_tools.app.src
@@ -14,4 +14,5 @@
prettypr]},
{registered,[]},
{applications, [stdlib]},
- {env, []}]}.
+ {env, []},
+ {runtime_dependencies, ["stdlib-2.0","kernel-3.0","erts-6.0"]}]}.
diff --git a/lib/syntax_tools/vsn.mk b/lib/syntax_tools/vsn.mk
index 26153a55f1..cf396ce636 100644
--- a/lib/syntax_tools/vsn.mk
+++ b/lib/syntax_tools/vsn.mk
@@ -1 +1 @@
-SYNTAX_TOOLS_VSN = 1.6.13
+SYNTAX_TOOLS_VSN = 1.6.14
diff --git a/lib/test_server/src/test_server.app.src b/lib/test_server/src/test_server.app.src
index 42e78ed279..5672baa6ef 100644
--- a/lib/test_server/src/test_server.app.src
+++ b/lib/test_server/src/test_server.app.src
@@ -31,5 +31,8 @@
test_server,
test_server_break_process]},
{applications, [kernel,stdlib]},
- {env, []}]}.
+ {env, []},
+ {runtime_dependencies, ["tools-2.6.14","stdlib-2.0","runtime_tools-1.8.14",
+ "observer-2.0","kernel-3.0","inets-5.10",
+ "erts-6.0"]}]}.
diff --git a/lib/test_server/src/test_server.erl b/lib/test_server/src/test_server.erl
index 82672521f7..9b05bddf63 100644
--- a/lib/test_server/src/test_server.erl
+++ b/lib/test_server/src/test_server.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2013. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2014. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -1208,6 +1208,10 @@ do_init_per_testcase(Mod, Args) ->
"a Config list.\n",[]},
{skip,{failed,{Mod,init_per_testcase,bad_return}}}
catch
+ throw:{Skip,Reason} when Skip =:= skip; Skip =:= skipped ->
+ {skip,Reason};
+ exit:{Skip,Reason} when Skip =:= skip; Skip =:= skipped ->
+ {skip,Reason};
throw:Other ->
set_loc(erlang:get_stacktrace()),
Line = get_loc(),
@@ -1378,6 +1382,10 @@ ts_tc(M, F, A) ->
Result = try
apply(M, F, A)
catch
+ throw:{skip, Reason} -> {skip, Reason};
+ throw:{skipped, Reason} -> {skip, Reason};
+ exit:{skip, Reason} -> {skip, Reason};
+ exit:{skipped, Reason} -> {skip, Reason};
Type:Reason ->
Stk = erlang:get_stacktrace(),
set_loc(Stk),
diff --git a/lib/test_server/src/test_server_sup.erl b/lib/test_server/src/test_server_sup.erl
index 3cfa84a52f..96e369a138 100644
--- a/lib/test_server/src/test_server_sup.erl
+++ b/lib/test_server/src/test_server_sup.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1998-2013. All Rights Reserved.
+%% Copyright Ericsson AB 1998-2014. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -469,7 +469,7 @@ check_instruction(_, {add_application, Application, Type}, _, _) ->
check_instruction(_, Instr, _, _) ->
throw({error, {low_level_or_invalid_instruction, Instr}}).
-check_module(Module, Modules) when is_atom(Module) ->
+check_module(Module, Modules) ->
case {is_atom(Module), lists:member(Module, Modules)} of
{true, true} -> ok;
{true, false} -> throw({error, {unknown_module, Module}});
diff --git a/lib/test_server/src/ts.unix.config b/lib/test_server/src/ts.unix.config
index a34857b9e5..1ba5d9033e 100644
--- a/lib/test_server/src/ts.unix.config
+++ b/lib/test_server/src/ts.unix.config
@@ -3,4 +3,4 @@
%% Always run a (VNC) X server on host
%% {xserver, "xserver.example.com:66"}.
-{unix,[{telnet,"belegost"},{username,"bofh"},{password,"root"},{keep_alive,true}]}.
+{unix,[{telnet,"belegost"},{username,"telnet-test"},{password,"tset-tenlet"},{keep_alive,true}]}.
diff --git a/lib/test_server/test/test_server_SUITE_data/test_server_parallel01_SUITE.erl b/lib/test_server/test/test_server_SUITE_data/test_server_parallel01_SUITE.erl
index f38f768f3b..9658191289 100644
--- a/lib/test_server/test/test_server_SUITE_data/test_server_parallel01_SUITE.erl
+++ b/lib/test_server/test/test_server_SUITE_data/test_server_parallel01_SUITE.erl
@@ -191,7 +191,7 @@ conf1_end(Config) ->
%% check 2s & 3s < 4s
Ms = timer:now_diff(now(),?config(t0,Config)),
test_server:comment(io_lib:format("~p",[now()])),
- if Ms > 3500000 -> exit({bad_parallel_exec,Ms});
+ if Ms > 4000000 -> exit({bad_parallel_exec,Ms});
Ms < 3000000 -> exit({bad_parallel_exec,Ms});
true -> ok
end.
@@ -204,7 +204,7 @@ conf2_end(Config) ->
%% check 3s & 2s < 4s
Ms = timer:now_diff(now(),?config(t0,Config)),
test_server:comment(io_lib:format("~p",[now()])),
- if Ms > 3500000 -> exit({bad_parallel_exec,Ms});
+ if Ms > 4000000 -> exit({bad_parallel_exec,Ms});
Ms < 3000000 -> exit({bad_parallel_exec,Ms});
true -> ok
end.
@@ -217,7 +217,7 @@ conf3_end(Config) ->
%% check 6s & 6s & (2s & 3s) & 1s = ~6s
Ms = timer:now_diff(now(),?config(t0,Config)),
test_server:comment(io_lib:format("~p",[now()])),
- if Ms > 6500000 -> exit({bad_parallel_exec,Ms});
+ if Ms > 7000000 -> exit({bad_parallel_exec,Ms});
Ms < 6000000 -> exit({bad_parallel_exec,Ms});
true -> ok
end.
@@ -230,7 +230,7 @@ conf4_end(Config) ->
%% check 2s & 3s >= 5s
Ms = timer:now_diff(now(),?config(t0,Config)),
test_server:comment(io_lib:format("~p",[now()])),
- if Ms > 5500000 -> exit({bad_parallel_exec,Ms});
+ if Ms > 6000000 -> exit({bad_parallel_exec,Ms});
Ms < 5000000 -> exit({bad_parallel_exec,Ms});
true -> ok
end.
@@ -243,7 +243,7 @@ conf5_end(Config) ->
%% check 1s & 1s & (3s & 2s) & 1s = ~6s
Ms = timer:now_diff(now(),?config(t0,Config)),
test_server:comment(io_lib:format("~p",[now()])),
- if Ms > 7000000 -> exit({bad_parallel_exec,Ms});
+ if Ms > 7500000 -> exit({bad_parallel_exec,Ms});
Ms < 6000000 -> exit({bad_parallel_exec,Ms});
true -> ok
end.
@@ -257,7 +257,7 @@ conf6_end(Config) ->
%% check 3s & 2s < 5s
Ms = timer:now_diff(now(),?config(t0,Config)),
test_server:comment(io_lib:format("~p",[now()])),
- if Ms > 3500000 -> exit({bad_parallel_exec,Ms});
+ if Ms > 4500000 -> exit({bad_parallel_exec,Ms});
Ms < 3000000 -> exit({bad_parallel_exec,Ms});
true -> ok
end.
@@ -277,7 +277,7 @@ conf7_end(Config) ->
%% check 1s & 1s & (2s & 2s) & 1s = ~3s
Ms = timer:now_diff(now(),?config(t0,Config)),
test_server:comment(io_lib:format("~p",[now()])),
- if Ms > 3500000 -> exit({bad_parallel_exec,Ms});
+ if Ms > 4000000 -> exit({bad_parallel_exec,Ms});
Ms < 3000000 -> exit({bad_parallel_exec,Ms});
true -> ok
end.
@@ -291,7 +291,7 @@ conf8_end(Config) ->
%% check 2s & 2s < 4s
Ms = timer:now_diff(now(),?config(t0,Config)),
test_server:comment(io_lib:format("~p",[now()])),
- if Ms > 2500000 -> exit({bad_parallel_exec,Ms});
+ if Ms > 3000000 -> exit({bad_parallel_exec,Ms});
Ms < 2000000 -> exit({bad_parallel_exec,Ms});
true -> ok
end.
diff --git a/lib/test_server/vsn.mk b/lib/test_server/vsn.mk
index 6871b5bd14..4eb70aa2cd 100644
--- a/lib/test_server/vsn.mk
+++ b/lib/test_server/vsn.mk
@@ -1 +1 @@
-TEST_SERVER_VSN = 3.6.4
+TEST_SERVER_VSN = 3.7
diff --git a/lib/tools/emacs/erlang.el b/lib/tools/emacs/erlang.el
index f007f780eb..ec5a1f4bc5 100644
--- a/lib/tools/emacs/erlang.el
+++ b/lib/tools/emacs/erlang.el
@@ -1420,6 +1420,10 @@ Other commands:
(if (boundp 'after-change-major-mode-hook)
(run-hooks 'after-change-major-mode-hook)))
+;;;###autoload
+(dolist (r '("\\.erl$" "\\.app\\.src$" "\\.escript"
+ "\\.hrl$" "\\.xrl$" "\\.yrl" "/ebin/.+\\.app"))
+ (add-to-list 'auto-mode-alist (cons r 'erlang-mode)))
(defun erlang-syntax-table-init ()
(if (null erlang-mode-syntax-table)
@@ -2570,9 +2574,9 @@ Value is list (stack token-start token-type in-what)."
(erlang-pop stack))
(if (and stack (memq (car (car stack)) '(icr begin fun try)))
(erlang-pop stack))))
- ((looking-at "catch.*of")
+ ((looking-at "catch\\b.*of")
t)
- ((looking-at "catch\\s *\\($\\|%\\|.*->\\)")
+ ((looking-at "catch\\b\\s *\\($\\|%\\|.*->\\)")
;; Must pop top icr layer, `catch' in try/catch
;;will push a new layer next.
(progn
@@ -2620,9 +2624,9 @@ Value is list (stack token-start token-type in-what)."
;;((looking-at "when\\s *\\($\\|%\\)")
((looking-at "when[^_a-zA-Z0-9]")
(erlang-push (list 'when token (current-column)) stack))
- ((looking-at "catch.*of")
+ ((looking-at "catch\\b.*of")
t)
- ((looking-at "catch\\s *\\($\\|%\\|.*->\\)")
+ ((looking-at "catch\\b\\s *\\($\\|%\\|.*->\\)")
(erlang-push (list 'icr token (current-column)) stack))
;;(erlang-push (list '-> token (current-column)) stack))
;;((looking-at "^of$")
@@ -2913,7 +2917,7 @@ Return nil if inside string, t if in a comment."
(if stack
(erlang-caddr (car stack))
0))
- ((looking-at "catch\\($\\|[^_a-zA-Z0-9]\\)")
+ ((looking-at "catch\\b\\($\\|[^_a-zA-Z0-9]\\)")
;; Are we in a try
(let ((start (if (eq (car stack-top) '->)
(car (cdr stack))
@@ -3124,12 +3128,12 @@ This assumes that the preceding expression is either simple
(defun erlang-at-keyword ()
"Are we looking at an Erlang keyword which will increase indentation?"
(looking-at (concat "\\(when\\|if\\|fun\\|case\\|begin\\|"
- "of\\|receive\\|after\\|catch\\|try\\)[^_a-zA-Z0-9]")))
+ "of\\|receive\\|after\\|catch\\|try\\)\\b")))
(defun erlang-at-operator ()
"Are we looking at an Erlang operator?"
(looking-at
- "\\(bnot\\|div\\|mod\\|band\\|bor\\|bxor\\|bsl\\|bsr\\)[^_a-zA-Z0-9]"))
+ "\\(bnot\\|div\\|mod\\|band\\|bor\\|bxor\\|bsl\\|bsr\\)\\b"))
(defun erlang-comment-indent ()
"Compute Erlang comment indentation.
diff --git a/lib/tools/emacs/test.erl.indented b/lib/tools/emacs/test.erl.indented
index 0dc1b47f0d..1c1086ca58 100644
--- a/lib/tools/emacs/test.erl.indented
+++ b/lib/tools/emacs/test.erl.indented
@@ -749,3 +749,14 @@ commas_first() ->
%% this used to result in a scan-sexp error
[{
}].
+
+%% this used to result in 2x the correct indentation within the function
+%% body, due to the function name being mistaken for a keyword
+catcher(N) ->
+ try generate_exception(N) of
+ Val -> {N, normal, Val}
+ catch
+ throw:X -> {N, caught, thrown, X};
+ exit:X -> {N, caught, exited, X};
+ error:X -> {N, caught, error, X}
+ end.
diff --git a/lib/tools/emacs/test.erl.orig b/lib/tools/emacs/test.erl.orig
index c7d2dc4ce5..a9d09000d2 100644
--- a/lib/tools/emacs/test.erl.orig
+++ b/lib/tools/emacs/test.erl.orig
@@ -749,3 +749,14 @@ commas_first() ->
%% this used to result in a scan-sexp error
[{
}].
+
+%% this used to result in 2x the correct indentation within the function
+%% body, due to the function name being mistaken for a keyword
+catcher(N) ->
+try generate_exception(N) of
+Val -> {N, normal, Val}
+catch
+throw:X -> {N, caught, thrown, X};
+exit:X -> {N, caught, exited, X};
+error:X -> {N, caught, error, X}
+end.
diff --git a/lib/tools/src/tools.app.src b/lib/tools/src/tools.app.src
index 553c5eb96b..ec5b6f3a82 100644
--- a/lib/tools/src/tools.app.src
+++ b/lib/tools/src/tools.app.src
@@ -39,23 +39,9 @@
{applications, [kernel, stdlib]},
{env, [{file_util_search_methods,[{"", ""}, {"ebin", "esrc"}, {"ebin", "src"}]}
]
- }
+ },
+ {runtime_dependencies, ["webtool-0.8.10","stdlib-2.0","runtime_tools-1.8.14",
+ "kernel-3.0","inets-5.10","erts-6.0",
+ "compiler-5.0"]}
]
}.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/lib/tools/test/cover_SUITE.erl b/lib/tools/test/cover_SUITE.erl
index ec61c57cec..80807b1d38 100644
--- a/lib/tools/test/cover_SUITE.erl
+++ b/lib/tools/test/cover_SUITE.erl
@@ -516,13 +516,11 @@ reconnect(Config) ->
cover:flush(N1),
rpc:call(N1,f,f1,[]),
- %% This will cause a call to f:f2() when nodes()==[] on N1
+ %% This will cause first casue the N1 node to initiate a
+ %% disconnect and then call f:f2() when nodes() =:= [] on N1.
rpc:cast(N1,f,call_f2_when_isolated,[]),
-
- %% Disconnect and check that node is removed from main cover node
- net_kernel:disconnect(N1),
timer:sleep(500), % allow some to detect disconnect and for f:f2() call
- [] = cover:which_nodes(),
+ cover_which_nodes([]),
%% Do some add one module (b) and remove one module (a)
code:purge(a),
@@ -530,7 +528,7 @@ reconnect(Config) ->
{ok,b} = cover:compile(b),
cover_compiled = code:which(b),
- [] = cover:which_nodes(),
+ cover_which_nodes([]),
check_f_calls(1,0), % only the first call - before the flush
%% Reconnect the node and check that b and f are cover compiled but not a
@@ -573,7 +571,7 @@ die_and_reconnect(Config) ->
%% Kill the node
rpc:call(N1,erlang,halt,[]),
- [] = cover:which_nodes(),
+ cover_which_nodes([]),
check_f_calls(1,0), % only the first call - before the flush
@@ -614,7 +612,7 @@ dont_reconnect_after_stop(Config) ->
%% Stop cover on the node, then terminate the node
cover:stop(N1),
rpc:call(N1,erlang,halt,[]),
- [] = cover:which_nodes(),
+ cover_which_nodes([]),
check_f_calls(1,0),
@@ -622,7 +620,7 @@ dont_reconnect_after_stop(Config) ->
{ok,N1} = ?t:start_node(NodeName,peer,
[{args," -pa " ++ DataDir},{start_cover,false}]),
timer:sleep(300),
- [] = cover:which_nodes(),
+ cover_which_nodes([]),
Beam = rpc:call(N1,code,which,[f]),
false = (Beam==cover_compiled),
@@ -667,7 +665,7 @@ stop_node_after_disconnect(Config) ->
{ok,N1} = ?t:start_node(NodeName,peer,
[{args," -pa " ++ DataDir},{start_cover,false}]),
timer:sleep(300),
- [] = cover:which_nodes(),
+ cover_which_nodes([]),
Beam = rpc:call(N1,code,which,[f]),
false = (Beam==cover_compiled),
@@ -1575,3 +1573,21 @@ is_unloaded(What) ->
check_f_calls(F1,F2) ->
{ok,[{{f,f1,0},F1},{{f,f2,0},F2}|_]} = cover:analyse(f,calls,function).
+
+cover_which_nodes(Expected) ->
+ case cover:which_nodes() of
+ Expected ->
+ ok;
+ Other ->
+ {Time,ok} = timer:tc(fun Retry() ->
+ case cover:which_nodes() of
+ Expected -> ok;
+ _ ->
+ ?t:sleep(100),
+ Retry()
+ end
+ end),
+ io:format("~p ms before cover:which_nodes() returned ~p",
+ [Time,Expected]),
+ Expected = Other
+ end.
diff --git a/lib/tools/test/cover_SUITE_data/f.erl b/lib/tools/test/cover_SUITE_data/f.erl
index ce2963014a..a29a67b388 100644
--- a/lib/tools/test/cover_SUITE_data/f.erl
+++ b/lib/tools/test/cover_SUITE_data/f.erl
@@ -10,10 +10,15 @@ f2() ->
f2_line2.
call_f2_when_isolated() ->
+ [Other] = nodes(),
+ net_kernel:disconnect(Other),
+ do_call_f2_when_isolated().
+
+do_call_f2_when_isolated() ->
case nodes() of
[] ->
f2();
_ ->
timer:sleep(100),
- call_f2_when_isolated()
+ do_call_f2_when_isolated()
end.
diff --git a/lib/tools/vsn.mk b/lib/tools/vsn.mk
index 0cead00554..2d2970de3a 100644
--- a/lib/tools/vsn.mk
+++ b/lib/tools/vsn.mk
@@ -1 +1 @@
-TOOLS_VSN = 2.6.13
+TOOLS_VSN = 2.6.14
diff --git a/lib/typer/src/typer.app.src b/lib/typer/src/typer.app.src
index 850829e1dc..974091b44c 100644
--- a/lib/typer/src/typer.app.src
+++ b/lib/typer/src/typer.app.src
@@ -6,4 +6,6 @@
{modules, [typer]},
{registered, []},
{applications, [compiler, dialyzer, hipe, kernel, stdlib]},
- {env, []}]}.
+ {env, []},
+ {runtime_dependencies, ["stdlib-2.0","kernel-3.0","hipe-3.10.3","erts-6.0",
+ "dialyzer-2.7","compiler-5.0"]}]}.
diff --git a/lib/typer/vsn.mk b/lib/typer/vsn.mk
index 5ac145d9ff..49fdda756e 100644
--- a/lib/typer/vsn.mk
+++ b/lib/typer/vsn.mk
@@ -1 +1 @@
-TYPER_VSN = 0.9.5
+TYPER_VSN = 0.9.6
diff --git a/lib/webtool/src/webtool.app.src b/lib/webtool/src/webtool.app.src
index 8c6774c533..3d8d11ea60 100644
--- a/lib/webtool/src/webtool.app.src
+++ b/lib/webtool/src/webtool.app.src
@@ -21,5 +21,7 @@
{vsn,"%VSN%"},
{modules,[webtool,webtool_sup]},
{registered,[web_tool,websup]},
- {applications,[kernel,stdlib]}]}.
+ {applications,[kernel,stdlib]},
+ {runtime_dependencies, ["stdlib-2.0","observer-2.0","kernel-3.0",
+ "inets-5.10","erts-6.0"]}]}.
diff --git a/lib/webtool/vsn.mk b/lib/webtool/vsn.mk
index d356a8954d..a79c273d9f 100644
--- a/lib/webtool/vsn.mk
+++ b/lib/webtool/vsn.mk
@@ -1 +1 @@
-WEBTOOL_VSN=0.8.9.2
+WEBTOOL_VSN=0.8.10
diff --git a/lib/wx/aclocal.m4 b/lib/wx/aclocal.m4
index c51c26794a..2b47f7c4bc 100644
--- a/lib/wx/aclocal.m4
+++ b/lib/wx/aclocal.m4
@@ -83,8 +83,10 @@ AC_ARG_VAR(erl_xcomp_ose_LM_POST_LINK, [OSE postlink tool (only used when cross
AC_ARG_VAR(erl_xcomp_ose_LM_SET_CONF, [Sets the configuration for an OSE load module (only used when cross compiling for OSE)])
AC_ARG_VAR(erl_xcomp_ose_LM_ELF_SIZE, [Prints the section size information for an OSE load module (only used when cross compiling for OSE)])
AC_ARG_VAR(erl_xcomp_ose_LM_LCF, [OSE load module linker configuration file (only used when cross compiling for OSE)])
-AC_ARG_VAR(erl_xcomp_ose_LM_CONF, [OSE load module default configuration file (only used when cross compiling for OSE)])
-AC_ARG_VAR(erl_xcomp_ose_CONFD, [OSE OSE confd source file])
+AC_ARG_VAR(erl_xcomp_ose_BEAM_LM_CONF, [BEAM OSE load module default configuration file (only used when cross compiling for OSE)])
+AC_ARG_VAR(erl_xcomp_ose_EPMD_LM_CONF, [EPMD OSE load module default configuration file (only used when cross compiling for OSE)])
+AC_ARG_VAR(erl_xcomp_ose_RUN_ERL_LM_CONF, [run_erl_lm OSE load module default configuration file (only used when cross compiling for OSE)])
+AC_ARG_VAR(erl_xcomp_ose_CONFD, [OSE confd source file])
AC_ARG_VAR(erl_xcomp_ose_CRT0_LM, [OSE crt0 lm source file])
])
diff --git a/lib/wx/api_gen/wx_doxygen.conf b/lib/wx/api_gen/wx_doxygen.conf
index 829702cbbf..a8516aa08e 100644
--- a/lib/wx/api_gen/wx_doxygen.conf
+++ b/lib/wx/api_gen/wx_doxygen.conf
@@ -57,7 +57,6 @@ GENERATE_DEPRECATEDLIST= NO
ENABLED_SECTIONS =
MAX_INITIALIZER_LINES = 30
SHOW_USED_FILES = YES
-SHOW_DIRECTORIES = YES
FILE_VERSION_FILTER =
#---------------------------------------------------------------------------
# configuration options related to warning and progress messages
@@ -110,7 +109,6 @@ HTML_FILE_EXTENSION = .html
HTML_HEADER =
HTML_FOOTER =
HTML_STYLESHEET =
-HTML_ALIGN_MEMBERS = YES
GENERATE_HTMLHELP = NO
CHM_FILE =
HHC_LOCATION =
@@ -252,6 +250,7 @@ PREDEFINED = \
wxUSE_SLIDER=1 \
wxUSE_CLIPBOARD=1 \
wxUSE_SYSTEM_OPTIONS=1 \
+ wxUSE_INTL=1 \
wxABI_VERSION=20809 \
__WXGTK24__=1 \
__WXGTK20__=1 \
diff --git a/lib/wx/api_gen/wx_extra/wxListCtrl.c_src b/lib/wx/api_gen/wx_extra/wxListCtrl.c_src
index 8fa31e512e..d6196d11a2 100644
--- a/lib/wx/api_gen/wx_extra/wxListCtrl.c_src
+++ b/lib/wx/api_gen/wx_extra/wxListCtrl.c_src
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2011-2013. All Rights Reserved.
+%% Copyright Ericsson AB 2011-2014. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -165,7 +165,7 @@ case ~s: { // wxListCtrl::SortItems taylormade
callbackInfo* cb = new callbackInfo();
cb->port = Ecmd.port;
cb->callbackID = sortCallback;
- bool Result = This->SortItems(wxEListCtrlCompare, (long)cb);
+ bool Result = This->SortItems(wxEListCtrlCompare, (wxeIntPtr)cb);
delete cb;
/* Destroy the callback, see wxEPrintout::clear_cb */
diff --git a/lib/wx/api_gen/wx_gen.erl b/lib/wx/api_gen/wx_gen.erl
index 0f28b3dd5e..a60a9a93d5 100644
--- a/lib/wx/api_gen/wx_gen.erl
+++ b/lib/wx/api_gen/wx_gen.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2013. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2014. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -743,7 +743,14 @@ parse_type2([N="wxTreeItemData"|R],Info,Opts,T) ->
parse_type2(R,Info,Opts,T#type{name="wxETreeItemData",base={term,N}});
parse_type2([N="wxClientData"|R],Info,Opts,T) ->
parse_type2(R,Info,Opts,T#type{name="wxeErlTerm",base={term,N}});
-parse_type2([N="wxChar"|R],Info,Opts,T) ->
+parse_type2([N="wxChar",{by_ref,_}|R],Info,Opts,T = #type{mod=[const]}) ->
+ case get(current_class) of
+ "wxLocale" -> %% Special since changed between 2.8 and 3.0
+ parse_type2(R,Info,Opts,T#type{name="wxeLocaleC",base=string});
+ _ ->
+ parse_type2(R,Info,Opts,T#type{name=N,base=int,single=false})
+ end;
+parse_type2([N="wxChar"|R],Info,Opts,T) ->
parse_type2(R,Info,Opts,T#type{name=N,base=int});
parse_type2(["wxUint32"|R],Info,Opts,T=#type{mod=Mod}) ->
parse_type2(R,Info,Opts,T#type{name=int,base=int,mod=[unsigned|Mod]});
@@ -1274,6 +1281,7 @@ parse_enums([File|Files], Parsed) ->
%%io:format("Parse Enums in ~s ~n", [FileName]),
case xmerl_scan:file(FileName, [{space, normalize}]) of
{error, enoent} ->
+ %% io:format("Ignore ~p~n", [FileName]),
parse_enums(Files, gb_sets:add(File,Parsed));
{Doc, _} ->
ES = "./compounddef/sectiondef/memberdef[@kind=\"enum\"]",
diff --git a/lib/wx/api_gen/wx_gen_cpp.erl b/lib/wx/api_gen/wx_gen_cpp.erl
index ea5d89be72..31ed1374c2 100644
--- a/lib/wx/api_gen/wx_gen_cpp.erl
+++ b/lib/wx/api_gen/wx_gen_cpp.erl
@@ -235,24 +235,27 @@ gen_funcs(Defs) ->
"wxFileDataObject", "wxTextDataObject", "wxBitmapDataObject"
],
- w("void WxeApp::delete_object(void *ptr, wxeRefData *refd) {~n", []),
+ w("bool WxeApp::delete_object(void *ptr, wxeRefData *refd) {~n", []),
w(" switch(refd->type) {~n", []),
- Case = fun(#class{name=Class, id=Id, abstract=IsAbs, parent=P}) when P /= "static" ->
+ Case = fun(C=#class{name=Class, id=Id, abstract=IsAbs, parent=P}) when P /= "static" ->
UglyWorkaround = lists:member(Class, UglySkipList),
+ HaveVirtual = virtual_dest(C),
case hd(reverse(wx_gen_erl:parents(Class))) of
- root when IsAbs == false, UglyWorkaround == false ->
- w(" case ~p: delete (~s *) ptr; break;~n", [Id, Class]);
root when IsAbs == false, UglyWorkaround == true ->
w(" case ~p: /* delete (~s *) ptr;"
"These objects must be deleted by owner object */ "
"break;~n", [Id, Class]);
+ root when IsAbs == false, HaveVirtual == true ->
+ w(" case ~p: delete (E~s *) ptr; return false;~n", [Id, Class]);
+ root when IsAbs == false, UglyWorkaround == false ->
+ w(" case ~p: delete (~s *) ptr; break;~n", [Id, Class]);
_ -> ok
end;
(_) -> ok
end,
[Case(Class) || Class <- Defs],
- w(" default: delete (wxObject *) ptr;~n", []),
- w("}}~n~n", []),
+ w(" default: delete (wxObject *) ptr; return false;~n", []),
+ w(" }~n return true;~n}~n~n", []),
Res.
gen_class(C=#class{name=Name,methods=Ms,options=Opts}) ->
@@ -401,6 +404,8 @@ declare_type(N,true,Def,#type{base=Base,single=true,name=Type,by_val=false,ref={
w(" ~s *~s=~s;~n", [Type,N,Def]);
declare_type(N,true,Def,#type{single=true,name="wxArtClient"}) ->
w(" wxArtClient ~s= ~s;~n", [N,Def]);
+declare_type(N,true,_Def,#type{name="wxeLocaleC", single=true,base=string}) ->
+ w(" wxString ~s= wxEmptyString;~n", [N]);
declare_type(N,true,Def,#type{single=true,base=string}) ->
w(" wxString ~s= ~s;~n", [N,Def]);
%% declare_type(N,true,_Def,#type{name="wxString"}) ->
@@ -997,6 +1002,8 @@ build_ret(Name,_,#type{base=float,single=true}) ->
w(" rt.addFloat(~s);~n",[Name]);
build_ret(Name,_,#type{base=double,single=true}) ->
w(" rt.addFloat(~s);~n",[Name]);
+build_ret(Name,_,#type{name="wxeLocaleC"}) ->
+ w(" rt.add(wxeLocaleC2String(~s));~n",[Name]);
build_ret(Name,_,#type{base=string,single=true}) ->
w(" rt.add(~s);~n",[Name]);
build_ret(Name,_,#type{name="wxArrayString", single=array}) ->
diff --git a/lib/wx/api_gen/wx_gen_erl.erl b/lib/wx/api_gen/wx_gen_erl.erl
index a4b03d3fd1..5ac781b40c 100644
--- a/lib/wx/api_gen/wx_gen_erl.erl
+++ b/lib/wx/api_gen/wx_gen_erl.erl
@@ -44,7 +44,11 @@ gen(Defs) ->
gen_unique_names(Defs),
gen_event_recs(),
gen_enums_ints(),
- [gen_class(Class) || Class <- Defs],
+ Static = gen_static([C || C=#class{parent="static"} <- Defs]),
+ Replace = fun(C=#class{name=Name}, Dfs) ->
+ lists:keyreplace(Name, #class.name, Dfs, C)
+ end,
+ [gen_class(Class) || Class <- lists:foldl(Replace, Defs, Static)],
gen_funcnames().
gen_class(Class) ->
@@ -54,9 +58,8 @@ gen_class(Class) ->
Class
end.
-gen_class1(C=#class{name=Name,parent="static",methods=Ms,options=_Opts}) ->
+gen_static(Files) ->
open_write("../src/gen/wx_misc.erl"),
- put(current_class, Name),
erl_copyright(),
w("", []),
w("%% This file is generated DO NOT EDIT~n~n", []),
@@ -67,17 +70,27 @@ gen_class1(C=#class{name=Name,parent="static",methods=Ms,options=_Opts}) ->
w("-module(wx_misc).~n", []),
w("-include(\"wxe.hrl\").~n",[]),
%% w("-compile(export_all).~n~n", []), %% XXXX remove ???
+ [gen_static_exports(C) || C <- Files],
+ Classes = [gen_static_methods(C) || C <- Files],
+ close(),
+ Classes.
+
+gen_static_exports(C=#class{parent="static",methods=Ms}) ->
Exp = fun(M) -> gen_export(C,M) end,
ExportList = lists:usort(lists:append(lists:map(Exp,reverse(Ms)))),
w("-export([~s]).~n~n", [args(fun({EF,_}) -> EF end, ",", ExportList, 60)]),
+ ok.
+gen_static_methods(C=#class{name=Name, parent="static",methods=Ms}) ->
+ put(current_class, Name),
Gen = fun(M) -> gen_method(Name,M) end,
NewMs = lists:map(Gen,reverse(Ms)),
- close(),
erase(current_class),
- C#class{methods=NewMs};
+ C#class{methods=NewMs}.
+gen_class1(C=#class{parent="static"}) ->
+ C;
gen_class1(C=#class{name=Name,parent=Parent,methods=Ms,options=Opts}) ->
case Opts of
["ignore"] -> throw(skipped);
@@ -755,7 +768,7 @@ write_spec(Args, Optional, {complex, Res}, Eol) ->
optional_type(Opts, Eol) ->
"Option :: " ++ args(fun optional_type2/1, Eol++"\t\t | ", Opts).
-optional_type2(#param{name=Name, def=Def, type=T}) ->
+optional_type2(#param{name=Name, def=_Def, type=T}) ->
"{" ++ erl_option_name(Name) ++ ", " ++ doc_arg_type2(T) ++ "}". %% %% Default: " ++ Def.
doc_link("utils", Func) ->
@@ -1357,4 +1370,3 @@ split_list(F, Keep, [M|Ms], Acc) ->
split_list(_, _, [], []) -> [];
split_list(_, _, [], Acc) -> [lists:reverse(Acc)].
-
diff --git a/lib/wx/api_gen/wxapi.conf b/lib/wx/api_gen/wxapi.conf
index 73c5af43d8..3a1dcc7ba5 100644
--- a/lib/wx/api_gen/wxapi.conf
+++ b/lib/wx/api_gen/wxapi.conf
@@ -1577,9 +1577,14 @@
'wxShutdown', {'wxShell', 1}, 'wxLaunchDefaultBrowser',
{'wxGetEmailAddress',0}, {'wxGetUserId',0}, {'wxGetHomeDir',0},
'wxNewId', 'wxRegisterId', 'wxGetCurrentId',
- 'wxGetOsDescription', 'wxIsPlatformLittleEndian', 'wxIsPlatform64Bit'
+ 'wxGetOsDescription', 'wxIsPlatformLittleEndian', 'wxIsPlatform64Bit'
]}.
+{class, gdicmn, static, [],
+ [ {'wxDisplaySize', [{"width", [out]}, {"height", [out]}]}, 'wxSetCursor'
+ ]}.
+
+
{class, wxPrintout, object, [{alias, [{wxePrintout, wxePrintout}]}],
[{'wxPrintout', [{where, taylormade}]},'~wxPrintout',
'GetDC', %% 'GetPageInfo',Callback
@@ -1885,3 +1890,15 @@
wxEVT_TASKBAR_LEFT_DCLICK,wxEVT_TASKBAR_RIGHT_DCLICK]}],[]}.
{class, wxInitDialogEvent, wxEvent, [{event,[wxEVT_INIT_DIALOG]}], []}.
+
+{class, wxLocale, root, [{skip, [{'wxLocale', 5}, {'Init', 6}]}],
+ ['wxLocale', '~wxLocale', 'Init',
+ 'AddCatalog','AddCatalogLookupPathPrefix',
+ %%'AddLanguage','FindLanguageInfo', 'GetLanguageInfo',
+ 'GetCanonicalName','GetLanguage',
+ 'GetLanguageName','GetLocale','GetName','GetString',
+ 'GetHeaderValue',
+ 'GetSysName',
+ 'GetSystemEncoding','GetSystemEncodingName',
+ 'GetSystemLanguage',
+ 'IsLoaded','IsOk']}.
diff --git a/lib/wx/c_src/gen/wxe_derived_dest.h b/lib/wx/c_src/gen/wxe_derived_dest.h
index 7e2d4524cb..42925bff3a 100644
--- a/lib/wx/c_src/gen/wxe_derived_dest.h
+++ b/lib/wx/c_src/gen/wxe_derived_dest.h
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2008-2013. All Rights Reserved.
+ * Copyright Ericsson AB 2008-2014. All Rights Reserved.
*
* The contents of this file are subject to the Erlang Public License,
* Version 1.1, (the "License"); you may not use this file except in
@@ -764,3 +764,9 @@ class EwxTaskBarIcon : public wxTaskBarIcon {
EwxTaskBarIcon() : wxTaskBarIcon() {};
};
+class EwxLocale : public wxLocale {
+ public: ~EwxLocale() {((WxeApp *)wxTheApp)->clearPtr(this);};
+ EwxLocale(int language,int flags) : wxLocale(language,flags) {};
+ EwxLocale() : wxLocale() {};
+};
+
diff --git a/lib/wx/c_src/gen/wxe_events.cpp b/lib/wx/c_src/gen/wxe_events.cpp
index 1bd17366a2..0ca059ead4 100644
--- a/lib/wx/c_src/gen/wxe_events.cpp
+++ b/lib/wx/c_src/gen/wxe_events.cpp
@@ -220,84 +220,84 @@ void initEventTable()
{wxEVT_STC_HOTSPOT_DCLICK, 203, "stc_hotspot_dclick"},
{wxEVT_STC_CALLTIP_CLICK, 203, "stc_calltip_click"},
{wxEVT_STC_AUTOCOMP_SELECTION, 203, "stc_autocomp_selection"},
- {wxEVT_COMMAND_TREE_BEGIN_DRAG, 208, "command_tree_begin_drag"},
- {wxEVT_COMMAND_TREE_BEGIN_RDRAG, 208, "command_tree_begin_rdrag"},
- {wxEVT_COMMAND_TREE_BEGIN_LABEL_EDIT, 208, "command_tree_begin_label_edit"},
- {wxEVT_COMMAND_TREE_END_LABEL_EDIT, 208, "command_tree_end_label_edit"},
- {wxEVT_COMMAND_TREE_DELETE_ITEM, 208, "command_tree_delete_item"},
- {wxEVT_COMMAND_TREE_GET_INFO, 208, "command_tree_get_info"},
- {wxEVT_COMMAND_TREE_SET_INFO, 208, "command_tree_set_info"},
- {wxEVT_COMMAND_TREE_ITEM_EXPANDED, 208, "command_tree_item_expanded"},
- {wxEVT_COMMAND_TREE_ITEM_EXPANDING, 208, "command_tree_item_expanding"},
- {wxEVT_COMMAND_TREE_ITEM_COLLAPSED, 208, "command_tree_item_collapsed"},
- {wxEVT_COMMAND_TREE_ITEM_COLLAPSING, 208, "command_tree_item_collapsing"},
- {wxEVT_COMMAND_TREE_SEL_CHANGED, 208, "command_tree_sel_changed"},
- {wxEVT_COMMAND_TREE_SEL_CHANGING, 208, "command_tree_sel_changing"},
- {wxEVT_COMMAND_TREE_KEY_DOWN, 208, "command_tree_key_down"},
- {wxEVT_COMMAND_TREE_ITEM_ACTIVATED, 208, "command_tree_item_activated"},
- {wxEVT_COMMAND_TREE_ITEM_RIGHT_CLICK, 208, "command_tree_item_right_click"},
- {wxEVT_COMMAND_TREE_ITEM_MIDDLE_CLICK, 208, "command_tree_item_middle_click"},
- {wxEVT_COMMAND_TREE_END_DRAG, 208, "command_tree_end_drag"},
- {wxEVT_COMMAND_TREE_STATE_IMAGE_CLICK, 208, "command_tree_state_image_click"},
- {wxEVT_COMMAND_TREE_ITEM_GETTOOLTIP, 208, "command_tree_item_gettooltip"},
- {wxEVT_COMMAND_TREE_ITEM_MENU, 208, "command_tree_item_menu"},
- {wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGED, 209, "command_notebook_page_changed"},
- {wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGING, 209, "command_notebook_page_changing"},
- {wxEVT_COMMAND_TEXT_COPY, 215, "command_text_copy"},
- {wxEVT_COMMAND_TEXT_CUT, 215, "command_text_cut"},
- {wxEVT_COMMAND_TEXT_PASTE, 215, "command_text_paste"},
- {wxEVT_COMMAND_SPINCTRL_UPDATED, 216, "command_spinctrl_updated"},
+ {wxEVT_COMMAND_TREE_BEGIN_DRAG, 209, "command_tree_begin_drag"},
+ {wxEVT_COMMAND_TREE_BEGIN_RDRAG, 209, "command_tree_begin_rdrag"},
+ {wxEVT_COMMAND_TREE_BEGIN_LABEL_EDIT, 209, "command_tree_begin_label_edit"},
+ {wxEVT_COMMAND_TREE_END_LABEL_EDIT, 209, "command_tree_end_label_edit"},
+ {wxEVT_COMMAND_TREE_DELETE_ITEM, 209, "command_tree_delete_item"},
+ {wxEVT_COMMAND_TREE_GET_INFO, 209, "command_tree_get_info"},
+ {wxEVT_COMMAND_TREE_SET_INFO, 209, "command_tree_set_info"},
+ {wxEVT_COMMAND_TREE_ITEM_EXPANDED, 209, "command_tree_item_expanded"},
+ {wxEVT_COMMAND_TREE_ITEM_EXPANDING, 209, "command_tree_item_expanding"},
+ {wxEVT_COMMAND_TREE_ITEM_COLLAPSED, 209, "command_tree_item_collapsed"},
+ {wxEVT_COMMAND_TREE_ITEM_COLLAPSING, 209, "command_tree_item_collapsing"},
+ {wxEVT_COMMAND_TREE_SEL_CHANGED, 209, "command_tree_sel_changed"},
+ {wxEVT_COMMAND_TREE_SEL_CHANGING, 209, "command_tree_sel_changing"},
+ {wxEVT_COMMAND_TREE_KEY_DOWN, 209, "command_tree_key_down"},
+ {wxEVT_COMMAND_TREE_ITEM_ACTIVATED, 209, "command_tree_item_activated"},
+ {wxEVT_COMMAND_TREE_ITEM_RIGHT_CLICK, 209, "command_tree_item_right_click"},
+ {wxEVT_COMMAND_TREE_ITEM_MIDDLE_CLICK, 209, "command_tree_item_middle_click"},
+ {wxEVT_COMMAND_TREE_END_DRAG, 209, "command_tree_end_drag"},
+ {wxEVT_COMMAND_TREE_STATE_IMAGE_CLICK, 209, "command_tree_state_image_click"},
+ {wxEVT_COMMAND_TREE_ITEM_GETTOOLTIP, 209, "command_tree_item_gettooltip"},
+ {wxEVT_COMMAND_TREE_ITEM_MENU, 209, "command_tree_item_menu"},
+ {wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGED, 210, "command_notebook_page_changed"},
+ {wxEVT_COMMAND_NOTEBOOK_PAGE_CHANGING, 210, "command_notebook_page_changing"},
+ {wxEVT_COMMAND_TEXT_COPY, 216, "command_text_copy"},
+ {wxEVT_COMMAND_TEXT_CUT, 216, "command_text_cut"},
+ {wxEVT_COMMAND_TEXT_PASTE, 216, "command_text_paste"},
+ {wxEVT_COMMAND_SPINCTRL_UPDATED, 217, "command_spinctrl_updated"},
{wxEVT_SCROLL_LINEUP + wxEVT_USER_FIRST, 165, "spin_up"},
{wxEVT_SCROLL_LINEDOWN + wxEVT_USER_FIRST, 165, "spin_down"},
{wxEVT_SCROLL_THUMBTRACK + wxEVT_USER_FIRST, 165, "spin"},
- {wxEVT_COMMAND_SPLITTER_SASH_POS_CHANGED, 218, "command_splitter_sash_pos_changed"},
- {wxEVT_COMMAND_SPLITTER_SASH_POS_CHANGING, 218, "command_splitter_sash_pos_changing"},
- {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, 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"},
+ {wxEVT_COMMAND_SPLITTER_SASH_POS_CHANGED, 219, "command_splitter_sash_pos_changed"},
+ {wxEVT_COMMAND_SPLITTER_SASH_POS_CHANGING, 219, "command_splitter_sash_pos_changing"},
+ {wxEVT_COMMAND_SPLITTER_DOUBLECLICKED, 219, "command_splitter_doubleclicked"},
+ {wxEVT_COMMAND_SPLITTER_UNSPLIT, 219, "command_splitter_unsplit"},
+ {wxEVT_COMMAND_HTML_LINK_CLICKED, 221, "command_html_link_clicked"},
+ {wxEVT_COMMAND_AUINOTEBOOK_PAGE_CLOSE, 224, "command_auinotebook_page_close"},
+ {wxEVT_COMMAND_AUINOTEBOOK_PAGE_CHANGED, 224, "command_auinotebook_page_changed"},
+ {wxEVT_COMMAND_AUINOTEBOOK_PAGE_CHANGING, 224, "command_auinotebook_page_changing"},
+ {wxEVT_COMMAND_AUINOTEBOOK_BUTTON, 224, "command_auinotebook_button"},
+ {wxEVT_COMMAND_AUINOTEBOOK_BEGIN_DRAG, 224, "command_auinotebook_begin_drag"},
+ {wxEVT_COMMAND_AUINOTEBOOK_END_DRAG, 224, "command_auinotebook_end_drag"},
+ {wxEVT_COMMAND_AUINOTEBOOK_DRAG_MOTION, 224, "command_auinotebook_drag_motion"},
+ {wxEVT_COMMAND_AUINOTEBOOK_ALLOW_DND, 224, "command_auinotebook_allow_dnd"},
#if wxCHECK_VERSION(2,8,5)
- {wxEVT_COMMAND_AUINOTEBOOK_TAB_MIDDLE_DOWN, 223, "command_auinotebook_tab_middle_down"},
+ {wxEVT_COMMAND_AUINOTEBOOK_TAB_MIDDLE_DOWN, 224, "command_auinotebook_tab_middle_down"},
#endif
#if wxCHECK_VERSION(2,8,5)
- {wxEVT_COMMAND_AUINOTEBOOK_TAB_MIDDLE_UP, 223, "command_auinotebook_tab_middle_up"},
+ {wxEVT_COMMAND_AUINOTEBOOK_TAB_MIDDLE_UP, 224, "command_auinotebook_tab_middle_up"},
#endif
#if wxCHECK_VERSION(2,8,5)
- {wxEVT_COMMAND_AUINOTEBOOK_TAB_RIGHT_DOWN, 223, "command_auinotebook_tab_right_down"},
+ {wxEVT_COMMAND_AUINOTEBOOK_TAB_RIGHT_DOWN, 224, "command_auinotebook_tab_right_down"},
#endif
#if wxCHECK_VERSION(2,8,5)
- {wxEVT_COMMAND_AUINOTEBOOK_TAB_RIGHT_UP, 223, "command_auinotebook_tab_right_up"},
+ {wxEVT_COMMAND_AUINOTEBOOK_TAB_RIGHT_UP, 224, "command_auinotebook_tab_right_up"},
#endif
#if wxCHECK_VERSION(2,8,5)
- {wxEVT_COMMAND_AUINOTEBOOK_PAGE_CLOSED, 223, "command_auinotebook_page_closed"},
+ {wxEVT_COMMAND_AUINOTEBOOK_PAGE_CLOSED, 224, "command_auinotebook_page_closed"},
#endif
#if wxCHECK_VERSION(2,8,5)
- {wxEVT_COMMAND_AUINOTEBOOK_DRAG_DONE, 223, "command_auinotebook_drag_done"},
+ {wxEVT_COMMAND_AUINOTEBOOK_DRAG_DONE, 224, "command_auinotebook_drag_done"},
#endif
#if wxCHECK_VERSION(2,8,5)
- {wxEVT_COMMAND_AUINOTEBOOK_BG_DCLICK, 223, "command_auinotebook_bg_dclick"},
+ {wxEVT_COMMAND_AUINOTEBOOK_BG_DCLICK, 224, "command_auinotebook_bg_dclick"},
#endif
- {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"},
- {wxEVT_TASKBAR_MOVE, 227, "taskbar_move"},
- {wxEVT_TASKBAR_LEFT_DOWN, 227, "taskbar_left_down"},
- {wxEVT_TASKBAR_LEFT_UP, 227, "taskbar_left_up"},
- {wxEVT_TASKBAR_RIGHT_DOWN, 227, "taskbar_right_down"},
- {wxEVT_TASKBAR_RIGHT_UP, 227, "taskbar_right_up"},
- {wxEVT_TASKBAR_LEFT_DCLICK, 227, "taskbar_left_dclick"},
- {wxEVT_TASKBAR_RIGHT_DCLICK, 227, "taskbar_right_dclick"},
- {wxEVT_INIT_DIALOG, 228, "init_dialog"},
+ {wxEVT_AUI_PANE_BUTTON, 225, "aui_pane_button"},
+ {wxEVT_AUI_PANE_CLOSE, 225, "aui_pane_close"},
+ {wxEVT_AUI_PANE_MAXIMIZE, 225, "aui_pane_maximize"},
+ {wxEVT_AUI_PANE_RESTORE, 225, "aui_pane_restore"},
+ {wxEVT_AUI_RENDER, 225, "aui_render"},
+ {wxEVT_AUI_FIND_MANAGER, 225, "aui_find_manager"},
+ {wxEVT_TASKBAR_MOVE, 228, "taskbar_move"},
+ {wxEVT_TASKBAR_LEFT_DOWN, 228, "taskbar_left_down"},
+ {wxEVT_TASKBAR_LEFT_UP, 228, "taskbar_left_up"},
+ {wxEVT_TASKBAR_RIGHT_DOWN, 228, "taskbar_right_down"},
+ {wxEVT_TASKBAR_RIGHT_UP, 228, "taskbar_right_up"},
+ {wxEVT_TASKBAR_LEFT_DCLICK, 228, "taskbar_left_dclick"},
+ {wxEVT_TASKBAR_RIGHT_DCLICK, 228, "taskbar_right_dclick"},
+ {wxEVT_INIT_DIALOG, 229, "init_dialog"},
{-1, 0, }
};
for(int i=0; event_types[i].ev_type != -1; i++) {
@@ -719,7 +719,7 @@ case 203: {// wxStyledTextEvent
rt.addTupleCount(22);
break;
}
-case 208: {// wxTreeEvent
+case 209: {// wxTreeEvent
wxTreeEvent * ev = (wxTreeEvent *) event;
evClass = (char*)"wxTreeEvent";
rt.addAtom((char*)"wxTree");
@@ -730,21 +730,21 @@ case 208: {// wxTreeEvent
rt.addTupleCount(5);
break;
}
-case 209: {// wxNotebookEvent
+case 210: {// wxNotebookEvent
evClass = (char*)"wxNotebookEvent";
rt.addAtom((char*)"wxNotebook");
rt.addAtom(Etype->eName);
rt.addTupleCount(2);
break;
}
-case 215: {// wxClipboardTextEvent
+case 216: {// wxClipboardTextEvent
evClass = (char*)"wxClipboardTextEvent";
rt.addAtom((char*)"wxClipboardText");
rt.addAtom(Etype->eName);
rt.addTupleCount(2);
break;
}
-case 216: {// wxSpinEvent
+case 217: {// wxSpinEvent
wxSpinEvent * ev = (wxSpinEvent *) event;
evClass = (char*)"wxSpinEvent";
rt.addAtom((char*)"wxSpin");
@@ -753,14 +753,14 @@ case 216: {// wxSpinEvent
rt.addTupleCount(3);
break;
}
-case 218: {// wxSplitterEvent
+case 219: {// wxSplitterEvent
evClass = (char*)"wxSplitterEvent";
rt.addAtom((char*)"wxSplitter");
rt.addAtom(Etype->eName);
rt.addTupleCount(2);
break;
}
-case 220: {// wxHtmlLinkEvent
+case 221: {// wxHtmlLinkEvent
wxHtmlLinkEvent * ev = (wxHtmlLinkEvent *) event;
evClass = (char*)"wxHtmlLinkEvent";
rt.addAtom((char*)"wxHtmlLink");
@@ -769,7 +769,7 @@ case 220: {// wxHtmlLinkEvent
rt.addTupleCount(3);
break;
}
-case 223: {// wxAuiNotebookEvent
+case 224: {// wxAuiNotebookEvent
wxAuiNotebookEvent * ev = (wxAuiNotebookEvent *) event;
wxAuiNotebook * GetDragSource = ev->GetDragSource();
evClass = (char*)"wxAuiNotebookEvent";
@@ -781,7 +781,7 @@ case 223: {// wxAuiNotebookEvent
rt.addTupleCount(5);
break;
}
-case 224: {// wxAuiManagerEvent
+case 225: {// wxAuiManagerEvent
wxAuiManagerEvent * ev = (wxAuiManagerEvent *) event;
wxAuiManager * GetManager = ev->GetManager();
wxAuiPaneInfo * GetPane = ev->GetPane();
@@ -798,14 +798,14 @@ case 224: {// wxAuiManagerEvent
rt.addTupleCount(8);
break;
}
-case 227: {// wxTaskBarIconEvent
+case 228: {// wxTaskBarIconEvent
evClass = (char*)"wxTaskBarIconEvent";
rt.addAtom((char*)"wxTaskBarIcon");
rt.addAtom(Etype->eName);
rt.addTupleCount(2);
break;
}
-case 228: {// wxInitDialogEvent
+case 229: {// wxInitDialogEvent
evClass = (char*)"wxInitDialogEvent";
rt.addAtom((char*)"wxInitDialog");
rt.addAtom(Etype->eName);
diff --git a/lib/wx/c_src/gen/wxe_funcs.cpp b/lib/wx/c_src/gen/wxe_funcs.cpp
index 3f5cb4c0f5..c1e9f3829a 100644
--- a/lib/wx/c_src/gen/wxe_funcs.cpp
+++ b/lib/wx/c_src/gen/wxe_funcs.cpp
@@ -15875,7 +15875,7 @@ case wxListCtrl_SortItems: { // wxListCtrl::SortItems taylormade
callbackInfo* cb = new callbackInfo();
cb->port = Ecmd.port;
cb->callbackID = sortCallback;
- bool Result = This->SortItems(wxEListCtrlCompare, (long)cb);
+ bool Result = This->SortItems(wxEListCtrlCompare, (wxeIntPtr)cb);
delete cb;
/* Destroy the callback, see wxEPrintout::clear_cb */
@@ -26730,6 +26730,20 @@ case utils_wxIsPlatform64Bit: { // utils::wxIsPlatform64Bit
rt.addBool(Result);
break;
}
+case gdicmn_wxDisplaySize: { // gdicmn::wxDisplaySize
+ int width;
+ int height;
+ ::wxDisplaySize(&width,&height);
+ rt.addInt(width);
+ rt.addInt(height);
+ rt.addTupleCount(2);
+ break;
+}
+case gdicmn_wxSetCursor: { // gdicmn::wxSetCursor
+ wxCursor *cursor = (wxCursor *) getPtr(bp,memenv); bp += 4;
+ ::wxSetCursor(*cursor);
+ break;
+}
case wxPrintout_new: { // wxPrintout::wxPrintout taylormade
int onPreparePrinting=0,onBeginPrinting=0,onEndPrinting=0,onBeginDocument=0,
@@ -30442,7 +30456,7 @@ case wxNotebookEvent_SetSelection: { // wxNotebookEvent::SetSelection
}
case wxFileDataObject_new: { // wxFileDataObject::wxFileDataObject
wxFileDataObject * Result = new wxFileDataObject();
- newPtr((void *) Result, 211, memenv);
+ newPtr((void *) Result, 212, memenv);
rt.addRef(getRef((void *)Result,memenv), "wxFileDataObject");
break;
}
@@ -30478,7 +30492,7 @@ case wxTextDataObject_new: { // wxTextDataObject::wxTextDataObject
} break;
}};
wxTextDataObject * Result = new wxTextDataObject(text);
- newPtr((void *) Result, 212, memenv);
+ newPtr((void *) Result, 213, memenv);
rt.addRef(getRef((void *)Result,memenv), "wxTextDataObject");
break;
}
@@ -30514,7 +30528,7 @@ case wxTextDataObject_destroy: { // wxTextDataObject::destroy
case wxBitmapDataObject_new_1_1: { // wxBitmapDataObject::wxBitmapDataObject
wxBitmap *bitmap = (wxBitmap *) getPtr(bp,memenv); bp += 4;
wxBitmapDataObject * Result = new wxBitmapDataObject(*bitmap);
- newPtr((void *) Result, 213, memenv);
+ newPtr((void *) Result, 214, memenv);
rt.addRef(getRef((void *)Result,memenv), "wxBitmapDataObject");
break;
}
@@ -30526,7 +30540,7 @@ bitmap = (wxBitmap *) getPtr(bp,memenv); bp += 4;
} break;
}};
wxBitmapDataObject * Result = new wxBitmapDataObject(*bitmap);
- newPtr((void *) Result, 213, memenv);
+ newPtr((void *) Result, 214, memenv);
rt.addRef(getRef((void *)Result,memenv), "wxBitmapDataObject");
break;
}
@@ -31359,7 +31373,7 @@ case wxAuiManagerEvent_CanVeto: { // wxAuiManagerEvent::CanVeto
}
case wxLogNull_new: { // wxLogNull::wxLogNull
wxLogNull * Result = new wxLogNull();
- newPtr((void *) Result, 225, memenv);
+ newPtr((void *) Result, 226, memenv);
rt.addRef(getRef((void *)Result,memenv), "wxLogNull");
break;
}
@@ -31406,6 +31420,213 @@ case wxTaskBarIcon_SetIcon: { // wxTaskBarIcon::SetIcon
rt.addBool(Result);
break;
}
+case wxLocale_new_0: { // wxLocale::wxLocale
+ wxLocale * Result = new EwxLocale();
+ newPtr((void *) Result, 230, memenv);
+ rt.addRef(getRef((void *)Result,memenv), "wxLocale");
+ break;
+}
+case wxLocale_new_2: { // wxLocale::wxLocale
+ int flags=wxLOCALE_LOAD_DEFAULT|wxLOCALE_CONV_ENCODING;
+ int * language = (int *) bp; bp += 4;
+ bp += 4; /* Align */
+ while( * (int*) bp) { switch (* (int*) bp) {
+ case 1: {bp += 4;
+ flags = (int)*(int *) bp; bp += 4;
+ } break;
+ }};
+ wxLocale * Result = new EwxLocale(*language,flags);
+ newPtr((void *) Result, 230, memenv);
+ rt.addRef(getRef((void *)Result,memenv), "wxLocale");
+ break;
+}
+case wxLocale_destruct: { // wxLocale::~wxLocale
+ wxLocale *This = (wxLocale *) getPtr(bp,memenv); bp += 4;
+ if(This) { ((WxeApp *) wxTheApp)->clearPtr((void *) This);
+ delete This;}
+ break;
+}
+case wxLocale_Init: { // wxLocale::Init
+ int language=wxLANGUAGE_DEFAULT;
+ int flags=wxLOCALE_LOAD_DEFAULT|wxLOCALE_CONV_ENCODING;
+ wxLocale *This = (wxLocale *) getPtr(bp,memenv); bp += 4;
+ bp += 4; /* Align */
+ while( * (int*) bp) { switch (* (int*) bp) {
+ case 1: {bp += 4;
+ language = (int)*(int *) bp; bp += 4;
+ } break;
+ case 2: {bp += 4;
+ flags = (int)*(int *) bp; bp += 4;
+ } break;
+ }};
+ if(!This) throw wxe_badarg(0);
+ bool Result = This->Init(language,flags);
+ rt.addBool(Result);
+ break;
+}
+case wxLocale_AddCatalog_1: { // wxLocale::AddCatalog
+ wxLocale *This = (wxLocale *) getPtr(bp,memenv); bp += 4;
+ int * szDomainLen = (int *) bp; bp += 4;
+ wxString szDomain = wxString(bp, wxConvUTF8);
+ bp += *szDomainLen+((8-((0+ *szDomainLen) & 7)) & 7);
+ if(!This) throw wxe_badarg(0);
+ bool Result = This->AddCatalog(szDomain);
+ rt.addBool(Result);
+ break;
+}
+case wxLocale_AddCatalog_3: { // wxLocale::AddCatalog
+ wxLocale *This = (wxLocale *) getPtr(bp,memenv); bp += 4;
+ int * szDomainLen = (int *) bp; bp += 4;
+ wxString szDomain = wxString(bp, wxConvUTF8);
+ bp += *szDomainLen+((8-((0+ *szDomainLen) & 7)) & 7);
+ wxLanguage msgIdLanguage = *(wxLanguage *) bp; bp += 4;;
+ int * msgIdCharsetLen = (int *) bp; bp += 4;
+ wxString msgIdCharset = wxString(bp, wxConvUTF8);
+ bp += *msgIdCharsetLen+((8-((0+ *msgIdCharsetLen) & 7)) & 7);
+ if(!This) throw wxe_badarg(0);
+ bool Result = This->AddCatalog(szDomain,msgIdLanguage,msgIdCharset);
+ rt.addBool(Result);
+ break;
+}
+case wxLocale_AddCatalogLookupPathPrefix: { // wxLocale::AddCatalogLookupPathPrefix
+ int * prefixLen = (int *) bp; bp += 4;
+ wxString prefix = wxString(bp, wxConvUTF8);
+ bp += *prefixLen+((8-((4+ *prefixLen) & 7)) & 7);
+ wxLocale::AddCatalogLookupPathPrefix(prefix);
+ break;
+}
+case wxLocale_GetCanonicalName: { // wxLocale::GetCanonicalName
+ wxLocale *This = (wxLocale *) getPtr(bp,memenv); bp += 4;
+ if(!This) throw wxe_badarg(0);
+ wxString Result = This->GetCanonicalName();
+ rt.add(Result);
+ break;
+}
+case wxLocale_GetLanguage: { // wxLocale::GetLanguage
+ wxLocale *This = (wxLocale *) getPtr(bp,memenv); bp += 4;
+ if(!This) throw wxe_badarg(0);
+ int Result = This->GetLanguage();
+ rt.addInt(Result);
+ break;
+}
+case wxLocale_GetLanguageName: { // wxLocale::GetLanguageName
+ int * lang = (int *) bp; bp += 4;
+ wxString Result = wxLocale::GetLanguageName(*lang);
+ rt.add(Result);
+ break;
+}
+case wxLocale_GetLocale: { // wxLocale::GetLocale
+ wxLocale *This = (wxLocale *) getPtr(bp,memenv); bp += 4;
+ if(!This) throw wxe_badarg(0);
+ const wxeLocaleC Result = This->GetLocale();
+ rt.add(wxeLocaleC2String(Result));
+ break;
+}
+case wxLocale_GetName: { // wxLocale::GetName
+ wxLocale *This = (wxLocale *) getPtr(bp,memenv); bp += 4;
+ if(!This) throw wxe_badarg(0);
+ const wxString * Result = &This->GetName();
+ rt.add(Result);
+ break;
+}
+case wxLocale_GetString_2: { // wxLocale::GetString
+ wxString szDomain= wxEmptyString;
+ wxLocale *This = (wxLocale *) getPtr(bp,memenv); bp += 4;
+ int * szOrigStringLen = (int *) bp; bp += 4;
+ wxString szOrigString = wxString(bp, wxConvUTF8);
+ bp += *szOrigStringLen+((8-((0+ *szOrigStringLen) & 7)) & 7);
+ while( * (int*) bp) { switch (* (int*) bp) {
+ case 1: {bp += 4;
+ int * szDomainLen = (int *) bp; bp += 4;
+ szDomain = wxString(bp, wxConvUTF8);
+ bp += *szDomainLen+((8-((0+ *szDomainLen) & 7)) & 7);
+ } break;
+ }};
+ if(!This) throw wxe_badarg(0);
+ const wxeLocaleC Result = This->GetString(szOrigString,szDomain);
+ rt.add(wxeLocaleC2String(Result));
+ break;
+}
+case wxLocale_GetString_4: { // wxLocale::GetString
+ wxString szDomain= wxEmptyString;
+ wxLocale *This = (wxLocale *) getPtr(bp,memenv); bp += 4;
+ int * szOrigStringLen = (int *) bp; bp += 4;
+ wxString szOrigString = wxString(bp, wxConvUTF8);
+ bp += *szOrigStringLen+((8-((0+ *szOrigStringLen) & 7)) & 7);
+ int * szOrigString2Len = (int *) bp; bp += 4;
+ wxString szOrigString2 = wxString(bp, wxConvUTF8);
+ bp += *szOrigString2Len+((8-((4+ *szOrigString2Len) & 7)) & 7);
+ int * n = (int *) bp; bp += 4;
+ bp += 4; /* Align */
+ while( * (int*) bp) { switch (* (int*) bp) {
+ case 1: {bp += 4;
+ int * szDomainLen = (int *) bp; bp += 4;
+ szDomain = wxString(bp, wxConvUTF8);
+ bp += *szDomainLen+((8-((0+ *szDomainLen) & 7)) & 7);
+ } break;
+ }};
+ if(!This) throw wxe_badarg(0);
+ const wxeLocaleC Result = This->GetString(szOrigString,szOrigString2,*n,szDomain);
+ rt.add(wxeLocaleC2String(Result));
+ break;
+}
+case wxLocale_GetHeaderValue: { // wxLocale::GetHeaderValue
+ wxString szDomain= wxEmptyString;
+ wxLocale *This = (wxLocale *) getPtr(bp,memenv); bp += 4;
+ int * szHeaderLen = (int *) bp; bp += 4;
+ wxString szHeader = wxString(bp, wxConvUTF8);
+ bp += *szHeaderLen+((8-((0+ *szHeaderLen) & 7)) & 7);
+ while( * (int*) bp) { switch (* (int*) bp) {
+ case 1: {bp += 4;
+ int * szDomainLen = (int *) bp; bp += 4;
+ szDomain = wxString(bp, wxConvUTF8);
+ bp += *szDomainLen+((8-((0+ *szDomainLen) & 7)) & 7);
+ } break;
+ }};
+ if(!This) throw wxe_badarg(0);
+ wxString Result = This->GetHeaderValue(szHeader,szDomain);
+ rt.add(Result);
+ break;
+}
+case wxLocale_GetSysName: { // wxLocale::GetSysName
+ wxLocale *This = (wxLocale *) getPtr(bp,memenv); bp += 4;
+ if(!This) throw wxe_badarg(0);
+ wxString Result = This->GetSysName();
+ rt.add(Result);
+ break;
+}
+case wxLocale_GetSystemEncoding: { // wxLocale::GetSystemEncoding
+ int Result = wxLocale::GetSystemEncoding();
+ rt.addInt(Result);
+ break;
+}
+case wxLocale_GetSystemEncodingName: { // wxLocale::GetSystemEncodingName
+ wxString Result = wxLocale::GetSystemEncodingName();
+ rt.add(Result);
+ break;
+}
+case wxLocale_GetSystemLanguage: { // wxLocale::GetSystemLanguage
+ int Result = wxLocale::GetSystemLanguage();
+ rt.addInt(Result);
+ break;
+}
+case wxLocale_IsLoaded: { // wxLocale::IsLoaded
+ wxLocale *This = (wxLocale *) getPtr(bp,memenv); bp += 4;
+ int * szDomainLen = (int *) bp; bp += 4;
+ wxString szDomain = wxString(bp, wxConvUTF8);
+ bp += *szDomainLen+((8-((0+ *szDomainLen) & 7)) & 7);
+ if(!This) throw wxe_badarg(0);
+ bool Result = This->IsLoaded(szDomain);
+ rt.addBool(Result);
+ break;
+}
+case wxLocale_IsOk: { // wxLocale::IsOk
+ wxLocale *This = (wxLocale *) getPtr(bp,memenv); bp += 4;
+ if(!This) throw wxe_badarg(0);
+ bool Result = This->IsOk();
+ rt.addBool(Result);
+ break;
+}
default: {
wxeReturn error = wxeReturn(WXE_DRV_PORT, Ecmd.caller, false); error.addAtom("_wxe_error_");
error.addInt((int) Ecmd.op);
@@ -31427,7 +31648,7 @@ case wxTaskBarIcon_SetIcon: { // wxTaskBarIcon::SetIcon
}} /* The End */
-void WxeApp::delete_object(void *ptr, wxeRefData *refd) {
+bool WxeApp::delete_object(void *ptr, wxeRefData *refd) {
switch(refd->type) {
case 24: delete (wxGridCellBoolRenderer *) ptr; break;
case 25: delete (wxGridCellBoolEditor *) ptr; break;
@@ -31446,10 +31667,13 @@ void WxeApp::delete_object(void *ptr, wxeRefData *refd) {
case 101: delete (wxListItemAttr *) ptr; break;
case 103: delete (wxTextAttr *) ptr; break;
case 155: delete (wxAuiPaneInfo *) ptr; break;
- case 211: /* delete (wxFileDataObject *) ptr;These objects must be deleted by owner object */ break;
- case 212: /* delete (wxTextDataObject *) ptr;These objects must be deleted by owner object */ break;
- case 213: /* delete (wxBitmapDataObject *) ptr;These objects must be deleted by owner object */ break;
- case 225: delete (wxLogNull *) ptr; break;
- default: delete (wxObject *) ptr;
-}}
+ 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 226: delete (wxLogNull *) ptr; break;
+ case 230: delete (EwxLocale *) ptr; return false;
+ default: delete (wxObject *) ptr; return false;
+ }
+ return true;
+}
diff --git a/lib/wx/c_src/gen/wxe_macros.h b/lib/wx/c_src/gen/wxe_macros.h
index a1da6500d5..2da24f5d5e 100644
--- a/lib/wx/c_src/gen/wxe_macros.h
+++ b/lib/wx/c_src/gen/wxe_macros.h
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2008-2013. All Rights Reserved.
+ * Copyright Ericsson AB 2008-2014. All Rights Reserved.
*
* The contents of this file are subject to the Erlang Public License,
* Version 1.1, (the "License"); you may not use this file except in
@@ -2756,601 +2756,624 @@
#define utils_wxGetOsDescription 2924
#define utils_wxIsPlatformLittleEndian 2925
#define utils_wxIsPlatform64Bit 2926
-#define wxPrintout_new 2927
-#define wxPrintout_destruct 2928
-#define wxPrintout_GetDC 2929
-#define wxPrintout_GetPageSizeMM 2930
-#define wxPrintout_GetPageSizePixels 2931
-#define wxPrintout_GetPaperRectPixels 2932
-#define wxPrintout_GetPPIPrinter 2933
-#define wxPrintout_GetPPIScreen 2934
-#define wxPrintout_GetTitle 2935
-#define wxPrintout_IsPreview 2936
-#define wxPrintout_FitThisSizeToPaper 2937
-#define wxPrintout_FitThisSizeToPage 2938
-#define wxPrintout_FitThisSizeToPageMargins 2939
-#define wxPrintout_MapScreenSizeToPaper 2940
-#define wxPrintout_MapScreenSizeToPage 2941
-#define wxPrintout_MapScreenSizeToPageMargins 2942
-#define wxPrintout_MapScreenSizeToDevice 2943
-#define wxPrintout_GetLogicalPaperRect 2944
-#define wxPrintout_GetLogicalPageRect 2945
-#define wxPrintout_GetLogicalPageMarginsRect 2946
-#define wxPrintout_SetLogicalOrigin 2947
-#define wxPrintout_OffsetLogicalOrigin 2948
-#define wxStyledTextCtrl_new_2 2949
-#define wxStyledTextCtrl_new_0 2950
-#define wxStyledTextCtrl_destruct 2951
-#define wxStyledTextCtrl_Create 2952
-#define wxStyledTextCtrl_AddText 2953
-#define wxStyledTextCtrl_AddStyledText 2954
-#define wxStyledTextCtrl_InsertText 2955
-#define wxStyledTextCtrl_ClearAll 2956
-#define wxStyledTextCtrl_ClearDocumentStyle 2957
-#define wxStyledTextCtrl_GetLength 2958
-#define wxStyledTextCtrl_GetCharAt 2959
-#define wxStyledTextCtrl_GetCurrentPos 2960
-#define wxStyledTextCtrl_GetAnchor 2961
-#define wxStyledTextCtrl_GetStyleAt 2962
-#define wxStyledTextCtrl_Redo 2963
-#define wxStyledTextCtrl_SetUndoCollection 2964
-#define wxStyledTextCtrl_SelectAll 2965
-#define wxStyledTextCtrl_SetSavePoint 2966
-#define wxStyledTextCtrl_GetStyledText 2967
-#define wxStyledTextCtrl_CanRedo 2968
-#define wxStyledTextCtrl_MarkerLineFromHandle 2969
-#define wxStyledTextCtrl_MarkerDeleteHandle 2970
-#define wxStyledTextCtrl_GetUndoCollection 2971
-#define wxStyledTextCtrl_GetViewWhiteSpace 2972
-#define wxStyledTextCtrl_SetViewWhiteSpace 2973
-#define wxStyledTextCtrl_PositionFromPoint 2974
-#define wxStyledTextCtrl_PositionFromPointClose 2975
-#define wxStyledTextCtrl_GotoLine 2976
-#define wxStyledTextCtrl_GotoPos 2977
-#define wxStyledTextCtrl_SetAnchor 2978
-#define wxStyledTextCtrl_GetCurLine 2979
-#define wxStyledTextCtrl_GetEndStyled 2980
-#define wxStyledTextCtrl_ConvertEOLs 2981
-#define wxStyledTextCtrl_GetEOLMode 2982
-#define wxStyledTextCtrl_SetEOLMode 2983
-#define wxStyledTextCtrl_StartStyling 2984
-#define wxStyledTextCtrl_SetStyling 2985
-#define wxStyledTextCtrl_GetBufferedDraw 2986
-#define wxStyledTextCtrl_SetBufferedDraw 2987
-#define wxStyledTextCtrl_SetTabWidth 2988
-#define wxStyledTextCtrl_GetTabWidth 2989
-#define wxStyledTextCtrl_SetCodePage 2990
-#define wxStyledTextCtrl_MarkerDefine 2991
-#define wxStyledTextCtrl_MarkerSetForeground 2992
-#define wxStyledTextCtrl_MarkerSetBackground 2993
-#define wxStyledTextCtrl_MarkerAdd 2994
-#define wxStyledTextCtrl_MarkerDelete 2995
-#define wxStyledTextCtrl_MarkerDeleteAll 2996
-#define wxStyledTextCtrl_MarkerGet 2997
-#define wxStyledTextCtrl_MarkerNext 2998
-#define wxStyledTextCtrl_MarkerPrevious 2999
-#define wxStyledTextCtrl_MarkerDefineBitmap 3000
-#define wxStyledTextCtrl_MarkerAddSet 3001
-#define wxStyledTextCtrl_MarkerSetAlpha 3002
-#define wxStyledTextCtrl_SetMarginType 3003
-#define wxStyledTextCtrl_GetMarginType 3004
-#define wxStyledTextCtrl_SetMarginWidth 3005
-#define wxStyledTextCtrl_GetMarginWidth 3006
-#define wxStyledTextCtrl_SetMarginMask 3007
-#define wxStyledTextCtrl_GetMarginMask 3008
-#define wxStyledTextCtrl_SetMarginSensitive 3009
-#define wxStyledTextCtrl_GetMarginSensitive 3010
-#define wxStyledTextCtrl_StyleClearAll 3011
-#define wxStyledTextCtrl_StyleSetForeground 3012
-#define wxStyledTextCtrl_StyleSetBackground 3013
-#define wxStyledTextCtrl_StyleSetBold 3014
-#define wxStyledTextCtrl_StyleSetItalic 3015
-#define wxStyledTextCtrl_StyleSetSize 3016
-#define wxStyledTextCtrl_StyleSetFaceName 3017
-#define wxStyledTextCtrl_StyleSetEOLFilled 3018
-#define wxStyledTextCtrl_StyleResetDefault 3019
-#define wxStyledTextCtrl_StyleSetUnderline 3020
-#define wxStyledTextCtrl_StyleSetCase 3021
-#define wxStyledTextCtrl_StyleSetHotSpot 3022
-#define wxStyledTextCtrl_SetSelForeground 3023
-#define wxStyledTextCtrl_SetSelBackground 3024
-#define wxStyledTextCtrl_GetSelAlpha 3025
-#define wxStyledTextCtrl_SetSelAlpha 3026
-#define wxStyledTextCtrl_SetCaretForeground 3027
-#define wxStyledTextCtrl_CmdKeyAssign 3028
-#define wxStyledTextCtrl_CmdKeyClear 3029
-#define wxStyledTextCtrl_CmdKeyClearAll 3030
-#define wxStyledTextCtrl_SetStyleBytes 3031
-#define wxStyledTextCtrl_StyleSetVisible 3032
-#define wxStyledTextCtrl_GetCaretPeriod 3033
-#define wxStyledTextCtrl_SetCaretPeriod 3034
-#define wxStyledTextCtrl_SetWordChars 3035
-#define wxStyledTextCtrl_BeginUndoAction 3036
-#define wxStyledTextCtrl_EndUndoAction 3037
-#define wxStyledTextCtrl_IndicatorSetStyle 3038
-#define wxStyledTextCtrl_IndicatorGetStyle 3039
-#define wxStyledTextCtrl_IndicatorSetForeground 3040
-#define wxStyledTextCtrl_IndicatorGetForeground 3041
-#define wxStyledTextCtrl_SetWhitespaceForeground 3042
-#define wxStyledTextCtrl_SetWhitespaceBackground 3043
-#define wxStyledTextCtrl_GetStyleBits 3044
-#define wxStyledTextCtrl_SetLineState 3045
-#define wxStyledTextCtrl_GetLineState 3046
-#define wxStyledTextCtrl_GetMaxLineState 3047
-#define wxStyledTextCtrl_GetCaretLineVisible 3048
-#define wxStyledTextCtrl_SetCaretLineVisible 3049
-#define wxStyledTextCtrl_GetCaretLineBackground 3050
-#define wxStyledTextCtrl_SetCaretLineBackground 3051
-#define wxStyledTextCtrl_AutoCompShow 3052
-#define wxStyledTextCtrl_AutoCompCancel 3053
-#define wxStyledTextCtrl_AutoCompActive 3054
-#define wxStyledTextCtrl_AutoCompPosStart 3055
-#define wxStyledTextCtrl_AutoCompComplete 3056
-#define wxStyledTextCtrl_AutoCompStops 3057
-#define wxStyledTextCtrl_AutoCompSetSeparator 3058
-#define wxStyledTextCtrl_AutoCompGetSeparator 3059
-#define wxStyledTextCtrl_AutoCompSelect 3060
-#define wxStyledTextCtrl_AutoCompSetCancelAtStart 3061
-#define wxStyledTextCtrl_AutoCompGetCancelAtStart 3062
-#define wxStyledTextCtrl_AutoCompSetFillUps 3063
-#define wxStyledTextCtrl_AutoCompSetChooseSingle 3064
-#define wxStyledTextCtrl_AutoCompGetChooseSingle 3065
-#define wxStyledTextCtrl_AutoCompSetIgnoreCase 3066
-#define wxStyledTextCtrl_AutoCompGetIgnoreCase 3067
-#define wxStyledTextCtrl_UserListShow 3068
-#define wxStyledTextCtrl_AutoCompSetAutoHide 3069
-#define wxStyledTextCtrl_AutoCompGetAutoHide 3070
-#define wxStyledTextCtrl_AutoCompSetDropRestOfWord 3071
-#define wxStyledTextCtrl_AutoCompGetDropRestOfWord 3072
-#define wxStyledTextCtrl_RegisterImage 3073
-#define wxStyledTextCtrl_ClearRegisteredImages 3074
-#define wxStyledTextCtrl_AutoCompGetTypeSeparator 3075
-#define wxStyledTextCtrl_AutoCompSetTypeSeparator 3076
-#define wxStyledTextCtrl_AutoCompSetMaxWidth 3077
-#define wxStyledTextCtrl_AutoCompGetMaxWidth 3078
-#define wxStyledTextCtrl_AutoCompSetMaxHeight 3079
-#define wxStyledTextCtrl_AutoCompGetMaxHeight 3080
-#define wxStyledTextCtrl_SetIndent 3081
-#define wxStyledTextCtrl_GetIndent 3082
-#define wxStyledTextCtrl_SetUseTabs 3083
-#define wxStyledTextCtrl_GetUseTabs 3084
-#define wxStyledTextCtrl_SetLineIndentation 3085
-#define wxStyledTextCtrl_GetLineIndentation 3086
-#define wxStyledTextCtrl_GetLineIndentPosition 3087
-#define wxStyledTextCtrl_GetColumn 3088
-#define wxStyledTextCtrl_SetUseHorizontalScrollBar 3089
-#define wxStyledTextCtrl_GetUseHorizontalScrollBar 3090
-#define wxStyledTextCtrl_SetIndentationGuides 3091
-#define wxStyledTextCtrl_GetIndentationGuides 3092
-#define wxStyledTextCtrl_SetHighlightGuide 3093
-#define wxStyledTextCtrl_GetHighlightGuide 3094
-#define wxStyledTextCtrl_GetLineEndPosition 3095
-#define wxStyledTextCtrl_GetCodePage 3096
-#define wxStyledTextCtrl_GetCaretForeground 3097
-#define wxStyledTextCtrl_GetReadOnly 3098
-#define wxStyledTextCtrl_SetCurrentPos 3099
-#define wxStyledTextCtrl_SetSelectionStart 3100
-#define wxStyledTextCtrl_GetSelectionStart 3101
-#define wxStyledTextCtrl_SetSelectionEnd 3102
-#define wxStyledTextCtrl_GetSelectionEnd 3103
-#define wxStyledTextCtrl_SetPrintMagnification 3104
-#define wxStyledTextCtrl_GetPrintMagnification 3105
-#define wxStyledTextCtrl_SetPrintColourMode 3106
-#define wxStyledTextCtrl_GetPrintColourMode 3107
-#define wxStyledTextCtrl_FindText 3108
-#define wxStyledTextCtrl_FormatRange 3109
-#define wxStyledTextCtrl_GetFirstVisibleLine 3110
-#define wxStyledTextCtrl_GetLine 3111
-#define wxStyledTextCtrl_GetLineCount 3112
-#define wxStyledTextCtrl_SetMarginLeft 3113
-#define wxStyledTextCtrl_GetMarginLeft 3114
-#define wxStyledTextCtrl_SetMarginRight 3115
-#define wxStyledTextCtrl_GetMarginRight 3116
-#define wxStyledTextCtrl_GetModify 3117
-#define wxStyledTextCtrl_SetSelection 3118
-#define wxStyledTextCtrl_GetSelectedText 3119
-#define wxStyledTextCtrl_GetTextRange 3120
-#define wxStyledTextCtrl_HideSelection 3121
-#define wxStyledTextCtrl_LineFromPosition 3122
-#define wxStyledTextCtrl_PositionFromLine 3123
-#define wxStyledTextCtrl_LineScroll 3124
-#define wxStyledTextCtrl_EnsureCaretVisible 3125
-#define wxStyledTextCtrl_ReplaceSelection 3126
-#define wxStyledTextCtrl_SetReadOnly 3127
-#define wxStyledTextCtrl_CanPaste 3128
-#define wxStyledTextCtrl_CanUndo 3129
-#define wxStyledTextCtrl_EmptyUndoBuffer 3130
-#define wxStyledTextCtrl_Undo 3131
-#define wxStyledTextCtrl_Cut 3132
-#define wxStyledTextCtrl_Copy 3133
-#define wxStyledTextCtrl_Paste 3134
-#define wxStyledTextCtrl_Clear 3135
-#define wxStyledTextCtrl_SetText 3136
-#define wxStyledTextCtrl_GetText 3137
-#define wxStyledTextCtrl_GetTextLength 3138
-#define wxStyledTextCtrl_GetOvertype 3139
-#define wxStyledTextCtrl_SetCaretWidth 3140
-#define wxStyledTextCtrl_GetCaretWidth 3141
-#define wxStyledTextCtrl_SetTargetStart 3142
-#define wxStyledTextCtrl_GetTargetStart 3143
-#define wxStyledTextCtrl_SetTargetEnd 3144
-#define wxStyledTextCtrl_GetTargetEnd 3145
-#define wxStyledTextCtrl_ReplaceTarget 3146
-#define wxStyledTextCtrl_SearchInTarget 3147
-#define wxStyledTextCtrl_SetSearchFlags 3148
-#define wxStyledTextCtrl_GetSearchFlags 3149
-#define wxStyledTextCtrl_CallTipShow 3150
-#define wxStyledTextCtrl_CallTipCancel 3151
-#define wxStyledTextCtrl_CallTipActive 3152
-#define wxStyledTextCtrl_CallTipPosAtStart 3153
-#define wxStyledTextCtrl_CallTipSetHighlight 3154
-#define wxStyledTextCtrl_CallTipSetBackground 3155
-#define wxStyledTextCtrl_CallTipSetForeground 3156
-#define wxStyledTextCtrl_CallTipSetForegroundHighlight 3157
-#define wxStyledTextCtrl_CallTipUseStyle 3158
-#define wxStyledTextCtrl_VisibleFromDocLine 3159
-#define wxStyledTextCtrl_DocLineFromVisible 3160
-#define wxStyledTextCtrl_WrapCount 3161
-#define wxStyledTextCtrl_SetFoldLevel 3162
-#define wxStyledTextCtrl_GetFoldLevel 3163
-#define wxStyledTextCtrl_GetLastChild 3164
-#define wxStyledTextCtrl_GetFoldParent 3165
-#define wxStyledTextCtrl_ShowLines 3166
-#define wxStyledTextCtrl_HideLines 3167
-#define wxStyledTextCtrl_GetLineVisible 3168
-#define wxStyledTextCtrl_SetFoldExpanded 3169
-#define wxStyledTextCtrl_GetFoldExpanded 3170
-#define wxStyledTextCtrl_ToggleFold 3171
-#define wxStyledTextCtrl_EnsureVisible 3172
-#define wxStyledTextCtrl_SetFoldFlags 3173
-#define wxStyledTextCtrl_EnsureVisibleEnforcePolicy 3174
-#define wxStyledTextCtrl_SetTabIndents 3175
-#define wxStyledTextCtrl_GetTabIndents 3176
-#define wxStyledTextCtrl_SetBackSpaceUnIndents 3177
-#define wxStyledTextCtrl_GetBackSpaceUnIndents 3178
-#define wxStyledTextCtrl_SetMouseDwellTime 3179
-#define wxStyledTextCtrl_GetMouseDwellTime 3180
-#define wxStyledTextCtrl_WordStartPosition 3181
-#define wxStyledTextCtrl_WordEndPosition 3182
-#define wxStyledTextCtrl_SetWrapMode 3183
-#define wxStyledTextCtrl_GetWrapMode 3184
-#define wxStyledTextCtrl_SetWrapVisualFlags 3185
-#define wxStyledTextCtrl_GetWrapVisualFlags 3186
-#define wxStyledTextCtrl_SetWrapVisualFlagsLocation 3187
-#define wxStyledTextCtrl_GetWrapVisualFlagsLocation 3188
-#define wxStyledTextCtrl_SetWrapStartIndent 3189
-#define wxStyledTextCtrl_GetWrapStartIndent 3190
-#define wxStyledTextCtrl_SetLayoutCache 3191
-#define wxStyledTextCtrl_GetLayoutCache 3192
-#define wxStyledTextCtrl_SetScrollWidth 3193
-#define wxStyledTextCtrl_GetScrollWidth 3194
-#define wxStyledTextCtrl_TextWidth 3195
-#define wxStyledTextCtrl_GetEndAtLastLine 3196
-#define wxStyledTextCtrl_TextHeight 3197
-#define wxStyledTextCtrl_SetUseVerticalScrollBar 3198
-#define wxStyledTextCtrl_GetUseVerticalScrollBar 3199
-#define wxStyledTextCtrl_AppendText 3200
-#define wxStyledTextCtrl_GetTwoPhaseDraw 3201
-#define wxStyledTextCtrl_SetTwoPhaseDraw 3202
-#define wxStyledTextCtrl_TargetFromSelection 3203
-#define wxStyledTextCtrl_LinesJoin 3204
-#define wxStyledTextCtrl_LinesSplit 3205
-#define wxStyledTextCtrl_SetFoldMarginColour 3206
-#define wxStyledTextCtrl_SetFoldMarginHiColour 3207
-#define wxStyledTextCtrl_LineDown 3208
-#define wxStyledTextCtrl_LineDownExtend 3209
-#define wxStyledTextCtrl_LineUp 3210
-#define wxStyledTextCtrl_LineUpExtend 3211
-#define wxStyledTextCtrl_CharLeft 3212
-#define wxStyledTextCtrl_CharLeftExtend 3213
-#define wxStyledTextCtrl_CharRight 3214
-#define wxStyledTextCtrl_CharRightExtend 3215
-#define wxStyledTextCtrl_WordLeft 3216
-#define wxStyledTextCtrl_WordLeftExtend 3217
-#define wxStyledTextCtrl_WordRight 3218
-#define wxStyledTextCtrl_WordRightExtend 3219
-#define wxStyledTextCtrl_Home 3220
-#define wxStyledTextCtrl_HomeExtend 3221
-#define wxStyledTextCtrl_LineEnd 3222
-#define wxStyledTextCtrl_LineEndExtend 3223
-#define wxStyledTextCtrl_DocumentStart 3224
-#define wxStyledTextCtrl_DocumentStartExtend 3225
-#define wxStyledTextCtrl_DocumentEnd 3226
-#define wxStyledTextCtrl_DocumentEndExtend 3227
-#define wxStyledTextCtrl_PageUp 3228
-#define wxStyledTextCtrl_PageUpExtend 3229
-#define wxStyledTextCtrl_PageDown 3230
-#define wxStyledTextCtrl_PageDownExtend 3231
-#define wxStyledTextCtrl_EditToggleOvertype 3232
-#define wxStyledTextCtrl_Cancel 3233
-#define wxStyledTextCtrl_DeleteBack 3234
-#define wxStyledTextCtrl_Tab 3235
-#define wxStyledTextCtrl_BackTab 3236
-#define wxStyledTextCtrl_NewLine 3237
-#define wxStyledTextCtrl_FormFeed 3238
-#define wxStyledTextCtrl_VCHome 3239
-#define wxStyledTextCtrl_VCHomeExtend 3240
-#define wxStyledTextCtrl_ZoomIn 3241
-#define wxStyledTextCtrl_ZoomOut 3242
-#define wxStyledTextCtrl_DelWordLeft 3243
-#define wxStyledTextCtrl_DelWordRight 3244
-#define wxStyledTextCtrl_LineCut 3245
-#define wxStyledTextCtrl_LineDelete 3246
-#define wxStyledTextCtrl_LineTranspose 3247
-#define wxStyledTextCtrl_LineDuplicate 3248
-#define wxStyledTextCtrl_LowerCase 3249
-#define wxStyledTextCtrl_UpperCase 3250
-#define wxStyledTextCtrl_LineScrollDown 3251
-#define wxStyledTextCtrl_LineScrollUp 3252
-#define wxStyledTextCtrl_DeleteBackNotLine 3253
-#define wxStyledTextCtrl_HomeDisplay 3254
-#define wxStyledTextCtrl_HomeDisplayExtend 3255
-#define wxStyledTextCtrl_LineEndDisplay 3256
-#define wxStyledTextCtrl_LineEndDisplayExtend 3257
-#define wxStyledTextCtrl_HomeWrapExtend 3258
-#define wxStyledTextCtrl_LineEndWrap 3259
-#define wxStyledTextCtrl_LineEndWrapExtend 3260
-#define wxStyledTextCtrl_VCHomeWrap 3261
-#define wxStyledTextCtrl_VCHomeWrapExtend 3262
-#define wxStyledTextCtrl_LineCopy 3263
-#define wxStyledTextCtrl_MoveCaretInsideView 3264
-#define wxStyledTextCtrl_LineLength 3265
-#define wxStyledTextCtrl_BraceHighlight 3266
-#define wxStyledTextCtrl_BraceBadLight 3267
-#define wxStyledTextCtrl_BraceMatch 3268
-#define wxStyledTextCtrl_GetViewEOL 3269
-#define wxStyledTextCtrl_SetViewEOL 3270
-#define wxStyledTextCtrl_SetModEventMask 3271
-#define wxStyledTextCtrl_GetEdgeColumn 3272
-#define wxStyledTextCtrl_SetEdgeColumn 3273
-#define wxStyledTextCtrl_SetEdgeMode 3274
-#define wxStyledTextCtrl_GetEdgeMode 3275
-#define wxStyledTextCtrl_GetEdgeColour 3276
-#define wxStyledTextCtrl_SetEdgeColour 3277
-#define wxStyledTextCtrl_SearchAnchor 3278
-#define wxStyledTextCtrl_SearchNext 3279
-#define wxStyledTextCtrl_SearchPrev 3280
-#define wxStyledTextCtrl_LinesOnScreen 3281
-#define wxStyledTextCtrl_UsePopUp 3282
-#define wxStyledTextCtrl_SelectionIsRectangle 3283
-#define wxStyledTextCtrl_SetZoom 3284
-#define wxStyledTextCtrl_GetZoom 3285
-#define wxStyledTextCtrl_GetModEventMask 3286
-#define wxStyledTextCtrl_SetSTCFocus 3287
-#define wxStyledTextCtrl_GetSTCFocus 3288
-#define wxStyledTextCtrl_SetStatus 3289
-#define wxStyledTextCtrl_GetStatus 3290
-#define wxStyledTextCtrl_SetMouseDownCaptures 3291
-#define wxStyledTextCtrl_GetMouseDownCaptures 3292
-#define wxStyledTextCtrl_SetSTCCursor 3293
-#define wxStyledTextCtrl_GetSTCCursor 3294
-#define wxStyledTextCtrl_SetControlCharSymbol 3295
-#define wxStyledTextCtrl_GetControlCharSymbol 3296
-#define wxStyledTextCtrl_WordPartLeft 3297
-#define wxStyledTextCtrl_WordPartLeftExtend 3298
-#define wxStyledTextCtrl_WordPartRight 3299
-#define wxStyledTextCtrl_WordPartRightExtend 3300
-#define wxStyledTextCtrl_SetVisiblePolicy 3301
-#define wxStyledTextCtrl_DelLineLeft 3302
-#define wxStyledTextCtrl_DelLineRight 3303
-#define wxStyledTextCtrl_GetXOffset 3304
-#define wxStyledTextCtrl_ChooseCaretX 3305
-#define wxStyledTextCtrl_SetXCaretPolicy 3306
-#define wxStyledTextCtrl_SetYCaretPolicy 3307
-#define wxStyledTextCtrl_GetPrintWrapMode 3308
-#define wxStyledTextCtrl_SetHotspotActiveForeground 3309
-#define wxStyledTextCtrl_SetHotspotActiveBackground 3310
-#define wxStyledTextCtrl_SetHotspotActiveUnderline 3311
-#define wxStyledTextCtrl_SetHotspotSingleLine 3312
-#define wxStyledTextCtrl_ParaDownExtend 3313
-#define wxStyledTextCtrl_ParaUp 3314
-#define wxStyledTextCtrl_ParaUpExtend 3315
-#define wxStyledTextCtrl_PositionBefore 3316
-#define wxStyledTextCtrl_PositionAfter 3317
-#define wxStyledTextCtrl_CopyRange 3318
-#define wxStyledTextCtrl_CopyText 3319
-#define wxStyledTextCtrl_SetSelectionMode 3320
-#define wxStyledTextCtrl_GetSelectionMode 3321
-#define wxStyledTextCtrl_LineDownRectExtend 3322
-#define wxStyledTextCtrl_LineUpRectExtend 3323
-#define wxStyledTextCtrl_CharLeftRectExtend 3324
-#define wxStyledTextCtrl_CharRightRectExtend 3325
-#define wxStyledTextCtrl_HomeRectExtend 3326
-#define wxStyledTextCtrl_VCHomeRectExtend 3327
-#define wxStyledTextCtrl_LineEndRectExtend 3328
-#define wxStyledTextCtrl_PageUpRectExtend 3329
-#define wxStyledTextCtrl_PageDownRectExtend 3330
-#define wxStyledTextCtrl_StutteredPageUp 3331
-#define wxStyledTextCtrl_StutteredPageUpExtend 3332
-#define wxStyledTextCtrl_StutteredPageDown 3333
-#define wxStyledTextCtrl_StutteredPageDownExtend 3334
-#define wxStyledTextCtrl_WordLeftEnd 3335
-#define wxStyledTextCtrl_WordLeftEndExtend 3336
-#define wxStyledTextCtrl_WordRightEnd 3337
-#define wxStyledTextCtrl_WordRightEndExtend 3338
-#define wxStyledTextCtrl_SetWhitespaceChars 3339
-#define wxStyledTextCtrl_SetCharsDefault 3340
-#define wxStyledTextCtrl_AutoCompGetCurrent 3341
-#define wxStyledTextCtrl_Allocate 3342
-#define wxStyledTextCtrl_FindColumn 3343
-#define wxStyledTextCtrl_GetCaretSticky 3344
-#define wxStyledTextCtrl_SetCaretSticky 3345
-#define wxStyledTextCtrl_ToggleCaretSticky 3346
-#define wxStyledTextCtrl_SetPasteConvertEndings 3347
-#define wxStyledTextCtrl_GetPasteConvertEndings 3348
-#define wxStyledTextCtrl_SelectionDuplicate 3349
-#define wxStyledTextCtrl_SetCaretLineBackAlpha 3350
-#define wxStyledTextCtrl_GetCaretLineBackAlpha 3351
-#define wxStyledTextCtrl_StartRecord 3352
-#define wxStyledTextCtrl_StopRecord 3353
-#define wxStyledTextCtrl_SetLexer 3354
-#define wxStyledTextCtrl_GetLexer 3355
-#define wxStyledTextCtrl_Colourise 3356
-#define wxStyledTextCtrl_SetProperty 3357
-#define wxStyledTextCtrl_SetKeyWords 3358
-#define wxStyledTextCtrl_SetLexerLanguage 3359
-#define wxStyledTextCtrl_GetProperty 3360
-#define wxStyledTextCtrl_GetStyleBitsNeeded 3361
-#define wxStyledTextCtrl_GetCurrentLine 3362
-#define wxStyledTextCtrl_StyleSetSpec 3363
-#define wxStyledTextCtrl_StyleSetFont 3364
-#define wxStyledTextCtrl_StyleSetFontAttr 3365
-#define wxStyledTextCtrl_StyleSetCharacterSet 3366
-#define wxStyledTextCtrl_StyleSetFontEncoding 3367
-#define wxStyledTextCtrl_CmdKeyExecute 3368
-#define wxStyledTextCtrl_SetMargins 3369
-#define wxStyledTextCtrl_GetSelection 3370
-#define wxStyledTextCtrl_PointFromPosition 3371
-#define wxStyledTextCtrl_ScrollToLine 3372
-#define wxStyledTextCtrl_ScrollToColumn 3373
-#define wxStyledTextCtrl_SetVScrollBar 3374
-#define wxStyledTextCtrl_SetHScrollBar 3375
-#define wxStyledTextCtrl_GetLastKeydownProcessed 3376
-#define wxStyledTextCtrl_SetLastKeydownProcessed 3377
-#define wxStyledTextCtrl_SaveFile 3378
-#define wxStyledTextCtrl_LoadFile 3379
-#define wxStyledTextCtrl_DoDragOver 3380
-#define wxStyledTextCtrl_DoDropText 3381
-#define wxStyledTextCtrl_GetUseAntiAliasing 3382
-#define wxStyledTextCtrl_AddTextRaw 3383
-#define wxStyledTextCtrl_InsertTextRaw 3384
-#define wxStyledTextCtrl_GetCurLineRaw 3385
-#define wxStyledTextCtrl_GetLineRaw 3386
-#define wxStyledTextCtrl_GetSelectedTextRaw 3387
-#define wxStyledTextCtrl_GetTextRangeRaw 3388
-#define wxStyledTextCtrl_SetTextRaw 3389
-#define wxStyledTextCtrl_GetTextRaw 3390
-#define wxStyledTextCtrl_AppendTextRaw 3391
-#define wxArtProvider_GetBitmap 3392
-#define wxArtProvider_GetIcon 3393
-#define wxTreeEvent_GetKeyCode 3394
-#define wxTreeEvent_GetItem 3395
-#define wxTreeEvent_GetKeyEvent 3396
-#define wxTreeEvent_GetLabel 3397
-#define wxTreeEvent_GetOldItem 3398
-#define wxTreeEvent_GetPoint 3399
-#define wxTreeEvent_IsEditCancelled 3400
-#define wxTreeEvent_SetToolTip 3401
-#define wxNotebookEvent_GetOldSelection 3402
-#define wxNotebookEvent_GetSelection 3403
-#define wxNotebookEvent_SetOldSelection 3404
-#define wxNotebookEvent_SetSelection 3405
-#define wxFileDataObject_new 3406
-#define wxFileDataObject_AddFile 3407
-#define wxFileDataObject_GetFilenames 3408
-#define wxFileDataObject_destroy 3409
-#define wxTextDataObject_new 3410
-#define wxTextDataObject_GetTextLength 3411
-#define wxTextDataObject_GetText 3412
-#define wxTextDataObject_SetText 3413
-#define wxTextDataObject_destroy 3414
-#define wxBitmapDataObject_new_1_1 3415
-#define wxBitmapDataObject_new_1_0 3416
-#define wxBitmapDataObject_GetBitmap 3417
-#define wxBitmapDataObject_SetBitmap 3418
-#define wxBitmapDataObject_destroy 3419
-#define wxClipboard_new 3421
-#define wxClipboard_destruct 3422
-#define wxClipboard_AddData 3423
-#define wxClipboard_Clear 3424
-#define wxClipboard_Close 3425
-#define wxClipboard_Flush 3426
-#define wxClipboard_GetData 3427
-#define wxClipboard_IsOpened 3428
-#define wxClipboard_Open 3429
-#define wxClipboard_SetData 3430
-#define wxClipboard_UsePrimarySelection 3432
-#define wxClipboard_IsSupported 3433
-#define wxClipboard_Get 3434
-#define wxSpinEvent_GetPosition 3435
-#define wxSpinEvent_SetPosition 3436
-#define wxSplitterWindow_new_0 3437
-#define wxSplitterWindow_new_2 3438
-#define wxSplitterWindow_destruct 3439
-#define wxSplitterWindow_Create 3440
-#define wxSplitterWindow_GetMinimumPaneSize 3441
-#define wxSplitterWindow_GetSashGravity 3442
-#define wxSplitterWindow_GetSashPosition 3443
-#define wxSplitterWindow_GetSplitMode 3444
-#define wxSplitterWindow_GetWindow1 3445
-#define wxSplitterWindow_GetWindow2 3446
-#define wxSplitterWindow_Initialize 3447
-#define wxSplitterWindow_IsSplit 3448
-#define wxSplitterWindow_ReplaceWindow 3449
-#define wxSplitterWindow_SetSashGravity 3450
-#define wxSplitterWindow_SetSashPosition 3451
-#define wxSplitterWindow_SetSashSize 3452
-#define wxSplitterWindow_SetMinimumPaneSize 3453
-#define wxSplitterWindow_SetSplitMode 3454
-#define wxSplitterWindow_SplitHorizontally 3455
-#define wxSplitterWindow_SplitVertically 3456
-#define wxSplitterWindow_Unsplit 3457
-#define wxSplitterWindow_UpdateSize 3458
-#define wxSplitterEvent_GetSashPosition 3459
-#define wxSplitterEvent_GetX 3460
-#define wxSplitterEvent_GetY 3461
-#define wxSplitterEvent_GetWindowBeingRemoved 3462
-#define wxSplitterEvent_SetSashPosition 3463
-#define wxHtmlWindow_new_0 3464
-#define wxHtmlWindow_new_2 3465
-#define wxHtmlWindow_AppendToPage 3466
-#define wxHtmlWindow_GetOpenedAnchor 3467
-#define wxHtmlWindow_GetOpenedPage 3468
-#define wxHtmlWindow_GetOpenedPageTitle 3469
-#define wxHtmlWindow_GetRelatedFrame 3470
-#define wxHtmlWindow_HistoryBack 3471
-#define wxHtmlWindow_HistoryCanBack 3472
-#define wxHtmlWindow_HistoryCanForward 3473
-#define wxHtmlWindow_HistoryClear 3474
-#define wxHtmlWindow_HistoryForward 3475
-#define wxHtmlWindow_LoadFile 3476
-#define wxHtmlWindow_LoadPage 3477
-#define wxHtmlWindow_SelectAll 3478
-#define wxHtmlWindow_SelectionToText 3479
-#define wxHtmlWindow_SelectLine 3480
-#define wxHtmlWindow_SelectWord 3481
-#define wxHtmlWindow_SetBorders 3482
-#define wxHtmlWindow_SetFonts 3483
-#define wxHtmlWindow_SetPage 3484
-#define wxHtmlWindow_SetRelatedFrame 3485
-#define wxHtmlWindow_SetRelatedStatusBar 3486
-#define wxHtmlWindow_ToText 3487
-#define wxHtmlWindow_destroy 3488
-#define wxHtmlLinkEvent_GetLinkInfo 3489
-#define wxSystemSettings_GetColour 3490
-#define wxSystemSettings_GetFont 3491
-#define wxSystemSettings_GetMetric 3492
-#define wxSystemSettings_GetScreenType 3493
-#define wxSystemOptions_GetOption 3494
-#define wxSystemOptions_GetOptionInt 3495
-#define wxSystemOptions_HasOption 3496
-#define wxSystemOptions_IsFalse 3497
-#define wxSystemOptions_SetOption_2_1 3498
-#define wxSystemOptions_SetOption_2_0 3499
-#define wxAuiNotebookEvent_SetSelection 3500
-#define wxAuiNotebookEvent_GetSelection 3501
-#define wxAuiNotebookEvent_SetOldSelection 3502
-#define wxAuiNotebookEvent_GetOldSelection 3503
-#define wxAuiNotebookEvent_SetDragSource 3504
-#define wxAuiNotebookEvent_GetDragSource 3505
-#define wxAuiManagerEvent_SetManager 3506
-#define wxAuiManagerEvent_GetManager 3507
-#define wxAuiManagerEvent_SetPane 3508
-#define wxAuiManagerEvent_GetPane 3509
-#define wxAuiManagerEvent_SetButton 3510
-#define wxAuiManagerEvent_GetButton 3511
-#define wxAuiManagerEvent_SetDC 3512
-#define wxAuiManagerEvent_GetDC 3513
-#define wxAuiManagerEvent_Veto 3514
-#define wxAuiManagerEvent_GetVeto 3515
-#define wxAuiManagerEvent_SetCanVeto 3516
-#define wxAuiManagerEvent_CanVeto 3517
-#define wxLogNull_new 3518
-#define wxLogNull_destroy 3519
-#define wxTaskBarIcon_new 3520
-#define wxTaskBarIcon_destruct 3521
-#define wxTaskBarIcon_PopupMenu 3522
-#define wxTaskBarIcon_RemoveIcon 3523
-#define wxTaskBarIcon_SetIcon 3524
+#define gdicmn_wxDisplaySize 2927
+#define gdicmn_wxSetCursor 2928
+#define wxPrintout_new 2929
+#define wxPrintout_destruct 2930
+#define wxPrintout_GetDC 2931
+#define wxPrintout_GetPageSizeMM 2932
+#define wxPrintout_GetPageSizePixels 2933
+#define wxPrintout_GetPaperRectPixels 2934
+#define wxPrintout_GetPPIPrinter 2935
+#define wxPrintout_GetPPIScreen 2936
+#define wxPrintout_GetTitle 2937
+#define wxPrintout_IsPreview 2938
+#define wxPrintout_FitThisSizeToPaper 2939
+#define wxPrintout_FitThisSizeToPage 2940
+#define wxPrintout_FitThisSizeToPageMargins 2941
+#define wxPrintout_MapScreenSizeToPaper 2942
+#define wxPrintout_MapScreenSizeToPage 2943
+#define wxPrintout_MapScreenSizeToPageMargins 2944
+#define wxPrintout_MapScreenSizeToDevice 2945
+#define wxPrintout_GetLogicalPaperRect 2946
+#define wxPrintout_GetLogicalPageRect 2947
+#define wxPrintout_GetLogicalPageMarginsRect 2948
+#define wxPrintout_SetLogicalOrigin 2949
+#define wxPrintout_OffsetLogicalOrigin 2950
+#define wxStyledTextCtrl_new_2 2951
+#define wxStyledTextCtrl_new_0 2952
+#define wxStyledTextCtrl_destruct 2953
+#define wxStyledTextCtrl_Create 2954
+#define wxStyledTextCtrl_AddText 2955
+#define wxStyledTextCtrl_AddStyledText 2956
+#define wxStyledTextCtrl_InsertText 2957
+#define wxStyledTextCtrl_ClearAll 2958
+#define wxStyledTextCtrl_ClearDocumentStyle 2959
+#define wxStyledTextCtrl_GetLength 2960
+#define wxStyledTextCtrl_GetCharAt 2961
+#define wxStyledTextCtrl_GetCurrentPos 2962
+#define wxStyledTextCtrl_GetAnchor 2963
+#define wxStyledTextCtrl_GetStyleAt 2964
+#define wxStyledTextCtrl_Redo 2965
+#define wxStyledTextCtrl_SetUndoCollection 2966
+#define wxStyledTextCtrl_SelectAll 2967
+#define wxStyledTextCtrl_SetSavePoint 2968
+#define wxStyledTextCtrl_GetStyledText 2969
+#define wxStyledTextCtrl_CanRedo 2970
+#define wxStyledTextCtrl_MarkerLineFromHandle 2971
+#define wxStyledTextCtrl_MarkerDeleteHandle 2972
+#define wxStyledTextCtrl_GetUndoCollection 2973
+#define wxStyledTextCtrl_GetViewWhiteSpace 2974
+#define wxStyledTextCtrl_SetViewWhiteSpace 2975
+#define wxStyledTextCtrl_PositionFromPoint 2976
+#define wxStyledTextCtrl_PositionFromPointClose 2977
+#define wxStyledTextCtrl_GotoLine 2978
+#define wxStyledTextCtrl_GotoPos 2979
+#define wxStyledTextCtrl_SetAnchor 2980
+#define wxStyledTextCtrl_GetCurLine 2981
+#define wxStyledTextCtrl_GetEndStyled 2982
+#define wxStyledTextCtrl_ConvertEOLs 2983
+#define wxStyledTextCtrl_GetEOLMode 2984
+#define wxStyledTextCtrl_SetEOLMode 2985
+#define wxStyledTextCtrl_StartStyling 2986
+#define wxStyledTextCtrl_SetStyling 2987
+#define wxStyledTextCtrl_GetBufferedDraw 2988
+#define wxStyledTextCtrl_SetBufferedDraw 2989
+#define wxStyledTextCtrl_SetTabWidth 2990
+#define wxStyledTextCtrl_GetTabWidth 2991
+#define wxStyledTextCtrl_SetCodePage 2992
+#define wxStyledTextCtrl_MarkerDefine 2993
+#define wxStyledTextCtrl_MarkerSetForeground 2994
+#define wxStyledTextCtrl_MarkerSetBackground 2995
+#define wxStyledTextCtrl_MarkerAdd 2996
+#define wxStyledTextCtrl_MarkerDelete 2997
+#define wxStyledTextCtrl_MarkerDeleteAll 2998
+#define wxStyledTextCtrl_MarkerGet 2999
+#define wxStyledTextCtrl_MarkerNext 3000
+#define wxStyledTextCtrl_MarkerPrevious 3001
+#define wxStyledTextCtrl_MarkerDefineBitmap 3002
+#define wxStyledTextCtrl_MarkerAddSet 3003
+#define wxStyledTextCtrl_MarkerSetAlpha 3004
+#define wxStyledTextCtrl_SetMarginType 3005
+#define wxStyledTextCtrl_GetMarginType 3006
+#define wxStyledTextCtrl_SetMarginWidth 3007
+#define wxStyledTextCtrl_GetMarginWidth 3008
+#define wxStyledTextCtrl_SetMarginMask 3009
+#define wxStyledTextCtrl_GetMarginMask 3010
+#define wxStyledTextCtrl_SetMarginSensitive 3011
+#define wxStyledTextCtrl_GetMarginSensitive 3012
+#define wxStyledTextCtrl_StyleClearAll 3013
+#define wxStyledTextCtrl_StyleSetForeground 3014
+#define wxStyledTextCtrl_StyleSetBackground 3015
+#define wxStyledTextCtrl_StyleSetBold 3016
+#define wxStyledTextCtrl_StyleSetItalic 3017
+#define wxStyledTextCtrl_StyleSetSize 3018
+#define wxStyledTextCtrl_StyleSetFaceName 3019
+#define wxStyledTextCtrl_StyleSetEOLFilled 3020
+#define wxStyledTextCtrl_StyleResetDefault 3021
+#define wxStyledTextCtrl_StyleSetUnderline 3022
+#define wxStyledTextCtrl_StyleSetCase 3023
+#define wxStyledTextCtrl_StyleSetHotSpot 3024
+#define wxStyledTextCtrl_SetSelForeground 3025
+#define wxStyledTextCtrl_SetSelBackground 3026
+#define wxStyledTextCtrl_GetSelAlpha 3027
+#define wxStyledTextCtrl_SetSelAlpha 3028
+#define wxStyledTextCtrl_SetCaretForeground 3029
+#define wxStyledTextCtrl_CmdKeyAssign 3030
+#define wxStyledTextCtrl_CmdKeyClear 3031
+#define wxStyledTextCtrl_CmdKeyClearAll 3032
+#define wxStyledTextCtrl_SetStyleBytes 3033
+#define wxStyledTextCtrl_StyleSetVisible 3034
+#define wxStyledTextCtrl_GetCaretPeriod 3035
+#define wxStyledTextCtrl_SetCaretPeriod 3036
+#define wxStyledTextCtrl_SetWordChars 3037
+#define wxStyledTextCtrl_BeginUndoAction 3038
+#define wxStyledTextCtrl_EndUndoAction 3039
+#define wxStyledTextCtrl_IndicatorSetStyle 3040
+#define wxStyledTextCtrl_IndicatorGetStyle 3041
+#define wxStyledTextCtrl_IndicatorSetForeground 3042
+#define wxStyledTextCtrl_IndicatorGetForeground 3043
+#define wxStyledTextCtrl_SetWhitespaceForeground 3044
+#define wxStyledTextCtrl_SetWhitespaceBackground 3045
+#define wxStyledTextCtrl_GetStyleBits 3046
+#define wxStyledTextCtrl_SetLineState 3047
+#define wxStyledTextCtrl_GetLineState 3048
+#define wxStyledTextCtrl_GetMaxLineState 3049
+#define wxStyledTextCtrl_GetCaretLineVisible 3050
+#define wxStyledTextCtrl_SetCaretLineVisible 3051
+#define wxStyledTextCtrl_GetCaretLineBackground 3052
+#define wxStyledTextCtrl_SetCaretLineBackground 3053
+#define wxStyledTextCtrl_AutoCompShow 3054
+#define wxStyledTextCtrl_AutoCompCancel 3055
+#define wxStyledTextCtrl_AutoCompActive 3056
+#define wxStyledTextCtrl_AutoCompPosStart 3057
+#define wxStyledTextCtrl_AutoCompComplete 3058
+#define wxStyledTextCtrl_AutoCompStops 3059
+#define wxStyledTextCtrl_AutoCompSetSeparator 3060
+#define wxStyledTextCtrl_AutoCompGetSeparator 3061
+#define wxStyledTextCtrl_AutoCompSelect 3062
+#define wxStyledTextCtrl_AutoCompSetCancelAtStart 3063
+#define wxStyledTextCtrl_AutoCompGetCancelAtStart 3064
+#define wxStyledTextCtrl_AutoCompSetFillUps 3065
+#define wxStyledTextCtrl_AutoCompSetChooseSingle 3066
+#define wxStyledTextCtrl_AutoCompGetChooseSingle 3067
+#define wxStyledTextCtrl_AutoCompSetIgnoreCase 3068
+#define wxStyledTextCtrl_AutoCompGetIgnoreCase 3069
+#define wxStyledTextCtrl_UserListShow 3070
+#define wxStyledTextCtrl_AutoCompSetAutoHide 3071
+#define wxStyledTextCtrl_AutoCompGetAutoHide 3072
+#define wxStyledTextCtrl_AutoCompSetDropRestOfWord 3073
+#define wxStyledTextCtrl_AutoCompGetDropRestOfWord 3074
+#define wxStyledTextCtrl_RegisterImage 3075
+#define wxStyledTextCtrl_ClearRegisteredImages 3076
+#define wxStyledTextCtrl_AutoCompGetTypeSeparator 3077
+#define wxStyledTextCtrl_AutoCompSetTypeSeparator 3078
+#define wxStyledTextCtrl_AutoCompSetMaxWidth 3079
+#define wxStyledTextCtrl_AutoCompGetMaxWidth 3080
+#define wxStyledTextCtrl_AutoCompSetMaxHeight 3081
+#define wxStyledTextCtrl_AutoCompGetMaxHeight 3082
+#define wxStyledTextCtrl_SetIndent 3083
+#define wxStyledTextCtrl_GetIndent 3084
+#define wxStyledTextCtrl_SetUseTabs 3085
+#define wxStyledTextCtrl_GetUseTabs 3086
+#define wxStyledTextCtrl_SetLineIndentation 3087
+#define wxStyledTextCtrl_GetLineIndentation 3088
+#define wxStyledTextCtrl_GetLineIndentPosition 3089
+#define wxStyledTextCtrl_GetColumn 3090
+#define wxStyledTextCtrl_SetUseHorizontalScrollBar 3091
+#define wxStyledTextCtrl_GetUseHorizontalScrollBar 3092
+#define wxStyledTextCtrl_SetIndentationGuides 3093
+#define wxStyledTextCtrl_GetIndentationGuides 3094
+#define wxStyledTextCtrl_SetHighlightGuide 3095
+#define wxStyledTextCtrl_GetHighlightGuide 3096
+#define wxStyledTextCtrl_GetLineEndPosition 3097
+#define wxStyledTextCtrl_GetCodePage 3098
+#define wxStyledTextCtrl_GetCaretForeground 3099
+#define wxStyledTextCtrl_GetReadOnly 3100
+#define wxStyledTextCtrl_SetCurrentPos 3101
+#define wxStyledTextCtrl_SetSelectionStart 3102
+#define wxStyledTextCtrl_GetSelectionStart 3103
+#define wxStyledTextCtrl_SetSelectionEnd 3104
+#define wxStyledTextCtrl_GetSelectionEnd 3105
+#define wxStyledTextCtrl_SetPrintMagnification 3106
+#define wxStyledTextCtrl_GetPrintMagnification 3107
+#define wxStyledTextCtrl_SetPrintColourMode 3108
+#define wxStyledTextCtrl_GetPrintColourMode 3109
+#define wxStyledTextCtrl_FindText 3110
+#define wxStyledTextCtrl_FormatRange 3111
+#define wxStyledTextCtrl_GetFirstVisibleLine 3112
+#define wxStyledTextCtrl_GetLine 3113
+#define wxStyledTextCtrl_GetLineCount 3114
+#define wxStyledTextCtrl_SetMarginLeft 3115
+#define wxStyledTextCtrl_GetMarginLeft 3116
+#define wxStyledTextCtrl_SetMarginRight 3117
+#define wxStyledTextCtrl_GetMarginRight 3118
+#define wxStyledTextCtrl_GetModify 3119
+#define wxStyledTextCtrl_SetSelection 3120
+#define wxStyledTextCtrl_GetSelectedText 3121
+#define wxStyledTextCtrl_GetTextRange 3122
+#define wxStyledTextCtrl_HideSelection 3123
+#define wxStyledTextCtrl_LineFromPosition 3124
+#define wxStyledTextCtrl_PositionFromLine 3125
+#define wxStyledTextCtrl_LineScroll 3126
+#define wxStyledTextCtrl_EnsureCaretVisible 3127
+#define wxStyledTextCtrl_ReplaceSelection 3128
+#define wxStyledTextCtrl_SetReadOnly 3129
+#define wxStyledTextCtrl_CanPaste 3130
+#define wxStyledTextCtrl_CanUndo 3131
+#define wxStyledTextCtrl_EmptyUndoBuffer 3132
+#define wxStyledTextCtrl_Undo 3133
+#define wxStyledTextCtrl_Cut 3134
+#define wxStyledTextCtrl_Copy 3135
+#define wxStyledTextCtrl_Paste 3136
+#define wxStyledTextCtrl_Clear 3137
+#define wxStyledTextCtrl_SetText 3138
+#define wxStyledTextCtrl_GetText 3139
+#define wxStyledTextCtrl_GetTextLength 3140
+#define wxStyledTextCtrl_GetOvertype 3141
+#define wxStyledTextCtrl_SetCaretWidth 3142
+#define wxStyledTextCtrl_GetCaretWidth 3143
+#define wxStyledTextCtrl_SetTargetStart 3144
+#define wxStyledTextCtrl_GetTargetStart 3145
+#define wxStyledTextCtrl_SetTargetEnd 3146
+#define wxStyledTextCtrl_GetTargetEnd 3147
+#define wxStyledTextCtrl_ReplaceTarget 3148
+#define wxStyledTextCtrl_SearchInTarget 3149
+#define wxStyledTextCtrl_SetSearchFlags 3150
+#define wxStyledTextCtrl_GetSearchFlags 3151
+#define wxStyledTextCtrl_CallTipShow 3152
+#define wxStyledTextCtrl_CallTipCancel 3153
+#define wxStyledTextCtrl_CallTipActive 3154
+#define wxStyledTextCtrl_CallTipPosAtStart 3155
+#define wxStyledTextCtrl_CallTipSetHighlight 3156
+#define wxStyledTextCtrl_CallTipSetBackground 3157
+#define wxStyledTextCtrl_CallTipSetForeground 3158
+#define wxStyledTextCtrl_CallTipSetForegroundHighlight 3159
+#define wxStyledTextCtrl_CallTipUseStyle 3160
+#define wxStyledTextCtrl_VisibleFromDocLine 3161
+#define wxStyledTextCtrl_DocLineFromVisible 3162
+#define wxStyledTextCtrl_WrapCount 3163
+#define wxStyledTextCtrl_SetFoldLevel 3164
+#define wxStyledTextCtrl_GetFoldLevel 3165
+#define wxStyledTextCtrl_GetLastChild 3166
+#define wxStyledTextCtrl_GetFoldParent 3167
+#define wxStyledTextCtrl_ShowLines 3168
+#define wxStyledTextCtrl_HideLines 3169
+#define wxStyledTextCtrl_GetLineVisible 3170
+#define wxStyledTextCtrl_SetFoldExpanded 3171
+#define wxStyledTextCtrl_GetFoldExpanded 3172
+#define wxStyledTextCtrl_ToggleFold 3173
+#define wxStyledTextCtrl_EnsureVisible 3174
+#define wxStyledTextCtrl_SetFoldFlags 3175
+#define wxStyledTextCtrl_EnsureVisibleEnforcePolicy 3176
+#define wxStyledTextCtrl_SetTabIndents 3177
+#define wxStyledTextCtrl_GetTabIndents 3178
+#define wxStyledTextCtrl_SetBackSpaceUnIndents 3179
+#define wxStyledTextCtrl_GetBackSpaceUnIndents 3180
+#define wxStyledTextCtrl_SetMouseDwellTime 3181
+#define wxStyledTextCtrl_GetMouseDwellTime 3182
+#define wxStyledTextCtrl_WordStartPosition 3183
+#define wxStyledTextCtrl_WordEndPosition 3184
+#define wxStyledTextCtrl_SetWrapMode 3185
+#define wxStyledTextCtrl_GetWrapMode 3186
+#define wxStyledTextCtrl_SetWrapVisualFlags 3187
+#define wxStyledTextCtrl_GetWrapVisualFlags 3188
+#define wxStyledTextCtrl_SetWrapVisualFlagsLocation 3189
+#define wxStyledTextCtrl_GetWrapVisualFlagsLocation 3190
+#define wxStyledTextCtrl_SetWrapStartIndent 3191
+#define wxStyledTextCtrl_GetWrapStartIndent 3192
+#define wxStyledTextCtrl_SetLayoutCache 3193
+#define wxStyledTextCtrl_GetLayoutCache 3194
+#define wxStyledTextCtrl_SetScrollWidth 3195
+#define wxStyledTextCtrl_GetScrollWidth 3196
+#define wxStyledTextCtrl_TextWidth 3197
+#define wxStyledTextCtrl_GetEndAtLastLine 3198
+#define wxStyledTextCtrl_TextHeight 3199
+#define wxStyledTextCtrl_SetUseVerticalScrollBar 3200
+#define wxStyledTextCtrl_GetUseVerticalScrollBar 3201
+#define wxStyledTextCtrl_AppendText 3202
+#define wxStyledTextCtrl_GetTwoPhaseDraw 3203
+#define wxStyledTextCtrl_SetTwoPhaseDraw 3204
+#define wxStyledTextCtrl_TargetFromSelection 3205
+#define wxStyledTextCtrl_LinesJoin 3206
+#define wxStyledTextCtrl_LinesSplit 3207
+#define wxStyledTextCtrl_SetFoldMarginColour 3208
+#define wxStyledTextCtrl_SetFoldMarginHiColour 3209
+#define wxStyledTextCtrl_LineDown 3210
+#define wxStyledTextCtrl_LineDownExtend 3211
+#define wxStyledTextCtrl_LineUp 3212
+#define wxStyledTextCtrl_LineUpExtend 3213
+#define wxStyledTextCtrl_CharLeft 3214
+#define wxStyledTextCtrl_CharLeftExtend 3215
+#define wxStyledTextCtrl_CharRight 3216
+#define wxStyledTextCtrl_CharRightExtend 3217
+#define wxStyledTextCtrl_WordLeft 3218
+#define wxStyledTextCtrl_WordLeftExtend 3219
+#define wxStyledTextCtrl_WordRight 3220
+#define wxStyledTextCtrl_WordRightExtend 3221
+#define wxStyledTextCtrl_Home 3222
+#define wxStyledTextCtrl_HomeExtend 3223
+#define wxStyledTextCtrl_LineEnd 3224
+#define wxStyledTextCtrl_LineEndExtend 3225
+#define wxStyledTextCtrl_DocumentStart 3226
+#define wxStyledTextCtrl_DocumentStartExtend 3227
+#define wxStyledTextCtrl_DocumentEnd 3228
+#define wxStyledTextCtrl_DocumentEndExtend 3229
+#define wxStyledTextCtrl_PageUp 3230
+#define wxStyledTextCtrl_PageUpExtend 3231
+#define wxStyledTextCtrl_PageDown 3232
+#define wxStyledTextCtrl_PageDownExtend 3233
+#define wxStyledTextCtrl_EditToggleOvertype 3234
+#define wxStyledTextCtrl_Cancel 3235
+#define wxStyledTextCtrl_DeleteBack 3236
+#define wxStyledTextCtrl_Tab 3237
+#define wxStyledTextCtrl_BackTab 3238
+#define wxStyledTextCtrl_NewLine 3239
+#define wxStyledTextCtrl_FormFeed 3240
+#define wxStyledTextCtrl_VCHome 3241
+#define wxStyledTextCtrl_VCHomeExtend 3242
+#define wxStyledTextCtrl_ZoomIn 3243
+#define wxStyledTextCtrl_ZoomOut 3244
+#define wxStyledTextCtrl_DelWordLeft 3245
+#define wxStyledTextCtrl_DelWordRight 3246
+#define wxStyledTextCtrl_LineCut 3247
+#define wxStyledTextCtrl_LineDelete 3248
+#define wxStyledTextCtrl_LineTranspose 3249
+#define wxStyledTextCtrl_LineDuplicate 3250
+#define wxStyledTextCtrl_LowerCase 3251
+#define wxStyledTextCtrl_UpperCase 3252
+#define wxStyledTextCtrl_LineScrollDown 3253
+#define wxStyledTextCtrl_LineScrollUp 3254
+#define wxStyledTextCtrl_DeleteBackNotLine 3255
+#define wxStyledTextCtrl_HomeDisplay 3256
+#define wxStyledTextCtrl_HomeDisplayExtend 3257
+#define wxStyledTextCtrl_LineEndDisplay 3258
+#define wxStyledTextCtrl_LineEndDisplayExtend 3259
+#define wxStyledTextCtrl_HomeWrapExtend 3260
+#define wxStyledTextCtrl_LineEndWrap 3261
+#define wxStyledTextCtrl_LineEndWrapExtend 3262
+#define wxStyledTextCtrl_VCHomeWrap 3263
+#define wxStyledTextCtrl_VCHomeWrapExtend 3264
+#define wxStyledTextCtrl_LineCopy 3265
+#define wxStyledTextCtrl_MoveCaretInsideView 3266
+#define wxStyledTextCtrl_LineLength 3267
+#define wxStyledTextCtrl_BraceHighlight 3268
+#define wxStyledTextCtrl_BraceBadLight 3269
+#define wxStyledTextCtrl_BraceMatch 3270
+#define wxStyledTextCtrl_GetViewEOL 3271
+#define wxStyledTextCtrl_SetViewEOL 3272
+#define wxStyledTextCtrl_SetModEventMask 3273
+#define wxStyledTextCtrl_GetEdgeColumn 3274
+#define wxStyledTextCtrl_SetEdgeColumn 3275
+#define wxStyledTextCtrl_SetEdgeMode 3276
+#define wxStyledTextCtrl_GetEdgeMode 3277
+#define wxStyledTextCtrl_GetEdgeColour 3278
+#define wxStyledTextCtrl_SetEdgeColour 3279
+#define wxStyledTextCtrl_SearchAnchor 3280
+#define wxStyledTextCtrl_SearchNext 3281
+#define wxStyledTextCtrl_SearchPrev 3282
+#define wxStyledTextCtrl_LinesOnScreen 3283
+#define wxStyledTextCtrl_UsePopUp 3284
+#define wxStyledTextCtrl_SelectionIsRectangle 3285
+#define wxStyledTextCtrl_SetZoom 3286
+#define wxStyledTextCtrl_GetZoom 3287
+#define wxStyledTextCtrl_GetModEventMask 3288
+#define wxStyledTextCtrl_SetSTCFocus 3289
+#define wxStyledTextCtrl_GetSTCFocus 3290
+#define wxStyledTextCtrl_SetStatus 3291
+#define wxStyledTextCtrl_GetStatus 3292
+#define wxStyledTextCtrl_SetMouseDownCaptures 3293
+#define wxStyledTextCtrl_GetMouseDownCaptures 3294
+#define wxStyledTextCtrl_SetSTCCursor 3295
+#define wxStyledTextCtrl_GetSTCCursor 3296
+#define wxStyledTextCtrl_SetControlCharSymbol 3297
+#define wxStyledTextCtrl_GetControlCharSymbol 3298
+#define wxStyledTextCtrl_WordPartLeft 3299
+#define wxStyledTextCtrl_WordPartLeftExtend 3300
+#define wxStyledTextCtrl_WordPartRight 3301
+#define wxStyledTextCtrl_WordPartRightExtend 3302
+#define wxStyledTextCtrl_SetVisiblePolicy 3303
+#define wxStyledTextCtrl_DelLineLeft 3304
+#define wxStyledTextCtrl_DelLineRight 3305
+#define wxStyledTextCtrl_GetXOffset 3306
+#define wxStyledTextCtrl_ChooseCaretX 3307
+#define wxStyledTextCtrl_SetXCaretPolicy 3308
+#define wxStyledTextCtrl_SetYCaretPolicy 3309
+#define wxStyledTextCtrl_GetPrintWrapMode 3310
+#define wxStyledTextCtrl_SetHotspotActiveForeground 3311
+#define wxStyledTextCtrl_SetHotspotActiveBackground 3312
+#define wxStyledTextCtrl_SetHotspotActiveUnderline 3313
+#define wxStyledTextCtrl_SetHotspotSingleLine 3314
+#define wxStyledTextCtrl_ParaDownExtend 3315
+#define wxStyledTextCtrl_ParaUp 3316
+#define wxStyledTextCtrl_ParaUpExtend 3317
+#define wxStyledTextCtrl_PositionBefore 3318
+#define wxStyledTextCtrl_PositionAfter 3319
+#define wxStyledTextCtrl_CopyRange 3320
+#define wxStyledTextCtrl_CopyText 3321
+#define wxStyledTextCtrl_SetSelectionMode 3322
+#define wxStyledTextCtrl_GetSelectionMode 3323
+#define wxStyledTextCtrl_LineDownRectExtend 3324
+#define wxStyledTextCtrl_LineUpRectExtend 3325
+#define wxStyledTextCtrl_CharLeftRectExtend 3326
+#define wxStyledTextCtrl_CharRightRectExtend 3327
+#define wxStyledTextCtrl_HomeRectExtend 3328
+#define wxStyledTextCtrl_VCHomeRectExtend 3329
+#define wxStyledTextCtrl_LineEndRectExtend 3330
+#define wxStyledTextCtrl_PageUpRectExtend 3331
+#define wxStyledTextCtrl_PageDownRectExtend 3332
+#define wxStyledTextCtrl_StutteredPageUp 3333
+#define wxStyledTextCtrl_StutteredPageUpExtend 3334
+#define wxStyledTextCtrl_StutteredPageDown 3335
+#define wxStyledTextCtrl_StutteredPageDownExtend 3336
+#define wxStyledTextCtrl_WordLeftEnd 3337
+#define wxStyledTextCtrl_WordLeftEndExtend 3338
+#define wxStyledTextCtrl_WordRightEnd 3339
+#define wxStyledTextCtrl_WordRightEndExtend 3340
+#define wxStyledTextCtrl_SetWhitespaceChars 3341
+#define wxStyledTextCtrl_SetCharsDefault 3342
+#define wxStyledTextCtrl_AutoCompGetCurrent 3343
+#define wxStyledTextCtrl_Allocate 3344
+#define wxStyledTextCtrl_FindColumn 3345
+#define wxStyledTextCtrl_GetCaretSticky 3346
+#define wxStyledTextCtrl_SetCaretSticky 3347
+#define wxStyledTextCtrl_ToggleCaretSticky 3348
+#define wxStyledTextCtrl_SetPasteConvertEndings 3349
+#define wxStyledTextCtrl_GetPasteConvertEndings 3350
+#define wxStyledTextCtrl_SelectionDuplicate 3351
+#define wxStyledTextCtrl_SetCaretLineBackAlpha 3352
+#define wxStyledTextCtrl_GetCaretLineBackAlpha 3353
+#define wxStyledTextCtrl_StartRecord 3354
+#define wxStyledTextCtrl_StopRecord 3355
+#define wxStyledTextCtrl_SetLexer 3356
+#define wxStyledTextCtrl_GetLexer 3357
+#define wxStyledTextCtrl_Colourise 3358
+#define wxStyledTextCtrl_SetProperty 3359
+#define wxStyledTextCtrl_SetKeyWords 3360
+#define wxStyledTextCtrl_SetLexerLanguage 3361
+#define wxStyledTextCtrl_GetProperty 3362
+#define wxStyledTextCtrl_GetStyleBitsNeeded 3363
+#define wxStyledTextCtrl_GetCurrentLine 3364
+#define wxStyledTextCtrl_StyleSetSpec 3365
+#define wxStyledTextCtrl_StyleSetFont 3366
+#define wxStyledTextCtrl_StyleSetFontAttr 3367
+#define wxStyledTextCtrl_StyleSetCharacterSet 3368
+#define wxStyledTextCtrl_StyleSetFontEncoding 3369
+#define wxStyledTextCtrl_CmdKeyExecute 3370
+#define wxStyledTextCtrl_SetMargins 3371
+#define wxStyledTextCtrl_GetSelection 3372
+#define wxStyledTextCtrl_PointFromPosition 3373
+#define wxStyledTextCtrl_ScrollToLine 3374
+#define wxStyledTextCtrl_ScrollToColumn 3375
+#define wxStyledTextCtrl_SetVScrollBar 3376
+#define wxStyledTextCtrl_SetHScrollBar 3377
+#define wxStyledTextCtrl_GetLastKeydownProcessed 3378
+#define wxStyledTextCtrl_SetLastKeydownProcessed 3379
+#define wxStyledTextCtrl_SaveFile 3380
+#define wxStyledTextCtrl_LoadFile 3381
+#define wxStyledTextCtrl_DoDragOver 3382
+#define wxStyledTextCtrl_DoDropText 3383
+#define wxStyledTextCtrl_GetUseAntiAliasing 3384
+#define wxStyledTextCtrl_AddTextRaw 3385
+#define wxStyledTextCtrl_InsertTextRaw 3386
+#define wxStyledTextCtrl_GetCurLineRaw 3387
+#define wxStyledTextCtrl_GetLineRaw 3388
+#define wxStyledTextCtrl_GetSelectedTextRaw 3389
+#define wxStyledTextCtrl_GetTextRangeRaw 3390
+#define wxStyledTextCtrl_SetTextRaw 3391
+#define wxStyledTextCtrl_GetTextRaw 3392
+#define wxStyledTextCtrl_AppendTextRaw 3393
+#define wxArtProvider_GetBitmap 3394
+#define wxArtProvider_GetIcon 3395
+#define wxTreeEvent_GetKeyCode 3396
+#define wxTreeEvent_GetItem 3397
+#define wxTreeEvent_GetKeyEvent 3398
+#define wxTreeEvent_GetLabel 3399
+#define wxTreeEvent_GetOldItem 3400
+#define wxTreeEvent_GetPoint 3401
+#define wxTreeEvent_IsEditCancelled 3402
+#define wxTreeEvent_SetToolTip 3403
+#define wxNotebookEvent_GetOldSelection 3404
+#define wxNotebookEvent_GetSelection 3405
+#define wxNotebookEvent_SetOldSelection 3406
+#define wxNotebookEvent_SetSelection 3407
+#define wxFileDataObject_new 3408
+#define wxFileDataObject_AddFile 3409
+#define wxFileDataObject_GetFilenames 3410
+#define wxFileDataObject_destroy 3411
+#define wxTextDataObject_new 3412
+#define wxTextDataObject_GetTextLength 3413
+#define wxTextDataObject_GetText 3414
+#define wxTextDataObject_SetText 3415
+#define wxTextDataObject_destroy 3416
+#define wxBitmapDataObject_new_1_1 3417
+#define wxBitmapDataObject_new_1_0 3418
+#define wxBitmapDataObject_GetBitmap 3419
+#define wxBitmapDataObject_SetBitmap 3420
+#define wxBitmapDataObject_destroy 3421
+#define wxClipboard_new 3423
+#define wxClipboard_destruct 3424
+#define wxClipboard_AddData 3425
+#define wxClipboard_Clear 3426
+#define wxClipboard_Close 3427
+#define wxClipboard_Flush 3428
+#define wxClipboard_GetData 3429
+#define wxClipboard_IsOpened 3430
+#define wxClipboard_Open 3431
+#define wxClipboard_SetData 3432
+#define wxClipboard_UsePrimarySelection 3434
+#define wxClipboard_IsSupported 3435
+#define wxClipboard_Get 3436
+#define wxSpinEvent_GetPosition 3437
+#define wxSpinEvent_SetPosition 3438
+#define wxSplitterWindow_new_0 3439
+#define wxSplitterWindow_new_2 3440
+#define wxSplitterWindow_destruct 3441
+#define wxSplitterWindow_Create 3442
+#define wxSplitterWindow_GetMinimumPaneSize 3443
+#define wxSplitterWindow_GetSashGravity 3444
+#define wxSplitterWindow_GetSashPosition 3445
+#define wxSplitterWindow_GetSplitMode 3446
+#define wxSplitterWindow_GetWindow1 3447
+#define wxSplitterWindow_GetWindow2 3448
+#define wxSplitterWindow_Initialize 3449
+#define wxSplitterWindow_IsSplit 3450
+#define wxSplitterWindow_ReplaceWindow 3451
+#define wxSplitterWindow_SetSashGravity 3452
+#define wxSplitterWindow_SetSashPosition 3453
+#define wxSplitterWindow_SetSashSize 3454
+#define wxSplitterWindow_SetMinimumPaneSize 3455
+#define wxSplitterWindow_SetSplitMode 3456
+#define wxSplitterWindow_SplitHorizontally 3457
+#define wxSplitterWindow_SplitVertically 3458
+#define wxSplitterWindow_Unsplit 3459
+#define wxSplitterWindow_UpdateSize 3460
+#define wxSplitterEvent_GetSashPosition 3461
+#define wxSplitterEvent_GetX 3462
+#define wxSplitterEvent_GetY 3463
+#define wxSplitterEvent_GetWindowBeingRemoved 3464
+#define wxSplitterEvent_SetSashPosition 3465
+#define wxHtmlWindow_new_0 3466
+#define wxHtmlWindow_new_2 3467
+#define wxHtmlWindow_AppendToPage 3468
+#define wxHtmlWindow_GetOpenedAnchor 3469
+#define wxHtmlWindow_GetOpenedPage 3470
+#define wxHtmlWindow_GetOpenedPageTitle 3471
+#define wxHtmlWindow_GetRelatedFrame 3472
+#define wxHtmlWindow_HistoryBack 3473
+#define wxHtmlWindow_HistoryCanBack 3474
+#define wxHtmlWindow_HistoryCanForward 3475
+#define wxHtmlWindow_HistoryClear 3476
+#define wxHtmlWindow_HistoryForward 3477
+#define wxHtmlWindow_LoadFile 3478
+#define wxHtmlWindow_LoadPage 3479
+#define wxHtmlWindow_SelectAll 3480
+#define wxHtmlWindow_SelectionToText 3481
+#define wxHtmlWindow_SelectLine 3482
+#define wxHtmlWindow_SelectWord 3483
+#define wxHtmlWindow_SetBorders 3484
+#define wxHtmlWindow_SetFonts 3485
+#define wxHtmlWindow_SetPage 3486
+#define wxHtmlWindow_SetRelatedFrame 3487
+#define wxHtmlWindow_SetRelatedStatusBar 3488
+#define wxHtmlWindow_ToText 3489
+#define wxHtmlWindow_destroy 3490
+#define wxHtmlLinkEvent_GetLinkInfo 3491
+#define wxSystemSettings_GetColour 3492
+#define wxSystemSettings_GetFont 3493
+#define wxSystemSettings_GetMetric 3494
+#define wxSystemSettings_GetScreenType 3495
+#define wxSystemOptions_GetOption 3496
+#define wxSystemOptions_GetOptionInt 3497
+#define wxSystemOptions_HasOption 3498
+#define wxSystemOptions_IsFalse 3499
+#define wxSystemOptions_SetOption_2_1 3500
+#define wxSystemOptions_SetOption_2_0 3501
+#define wxAuiNotebookEvent_SetSelection 3502
+#define wxAuiNotebookEvent_GetSelection 3503
+#define wxAuiNotebookEvent_SetOldSelection 3504
+#define wxAuiNotebookEvent_GetOldSelection 3505
+#define wxAuiNotebookEvent_SetDragSource 3506
+#define wxAuiNotebookEvent_GetDragSource 3507
+#define wxAuiManagerEvent_SetManager 3508
+#define wxAuiManagerEvent_GetManager 3509
+#define wxAuiManagerEvent_SetPane 3510
+#define wxAuiManagerEvent_GetPane 3511
+#define wxAuiManagerEvent_SetButton 3512
+#define wxAuiManagerEvent_GetButton 3513
+#define wxAuiManagerEvent_SetDC 3514
+#define wxAuiManagerEvent_GetDC 3515
+#define wxAuiManagerEvent_Veto 3516
+#define wxAuiManagerEvent_GetVeto 3517
+#define wxAuiManagerEvent_SetCanVeto 3518
+#define wxAuiManagerEvent_CanVeto 3519
+#define wxLogNull_new 3520
+#define wxLogNull_destroy 3521
+#define wxTaskBarIcon_new 3522
+#define wxTaskBarIcon_destruct 3523
+#define wxTaskBarIcon_PopupMenu 3524
+#define wxTaskBarIcon_RemoveIcon 3525
+#define wxTaskBarIcon_SetIcon 3526
+#define wxLocale_new_0 3527
+#define wxLocale_new_2 3529
+#define wxLocale_destruct 3530
+#define wxLocale_Init 3532
+#define wxLocale_AddCatalog_1 3533
+#define wxLocale_AddCatalog_3 3534
+#define wxLocale_AddCatalogLookupPathPrefix 3535
+#define wxLocale_GetCanonicalName 3536
+#define wxLocale_GetLanguage 3537
+#define wxLocale_GetLanguageName 3538
+#define wxLocale_GetLocale 3539
+#define wxLocale_GetName 3540
+#define wxLocale_GetString_2 3541
+#define wxLocale_GetString_4 3542
+#define wxLocale_GetHeaderValue 3543
+#define wxLocale_GetSysName 3544
+#define wxLocale_GetSystemEncoding 3545
+#define wxLocale_GetSystemEncodingName 3546
+#define wxLocale_GetSystemLanguage 3547
+#define wxLocale_IsLoaded 3548
+#define wxLocale_IsOk 3549
diff --git a/lib/wx/c_src/wxe_callback_impl.cpp b/lib/wx/c_src/wxe_callback_impl.cpp
index e06f68dcbf..3a59004eb0 100644
--- a/lib/wx/c_src/wxe_callback_impl.cpp
+++ b/lib/wx/c_src/wxe_callback_impl.cpp
@@ -284,7 +284,7 @@ EwxListCtrl::~EwxListCtrl() {
* wxListCtrlCompare wrapper
* ****************************************************************************/
-int wxCALLBACK wxEListCtrlCompare(long item1, long item2, long callbackInfoPtr)
+int wxCALLBACK wxEListCtrlCompare(wxeIntPtr item1, wxeIntPtr item2, wxeIntPtr callbackInfoPtr)
{
callbackInfo * cb = (callbackInfo *)callbackInfoPtr;
wxeMemEnv * memenv = ((WxeApp *) wxTheApp)->getMemEnv(cb->port);
diff --git a/lib/wx/c_src/wxe_callback_impl.h b/lib/wx/c_src/wxe_callback_impl.h
index 1c355e4d38..ecfcd3db41 100644
--- a/lib/wx/c_src/wxe_callback_impl.h
+++ b/lib/wx/c_src/wxe_callback_impl.h
@@ -23,6 +23,13 @@
void pre_callback();
void handle_event_callback(ErlDrvPort port, ErlDrvTermData process);
+#if wxCHECK_VERSION(2,9,0)
+ #define wxeIntPtr wxIntPtr
+#else
+ // This is bad but how it was in wx-2.8
+ #define wxeIntPtr long
+#endif
+
/* Fun Callback id */
class wxeEvtListener : public wxEvtHandler
{
@@ -88,6 +95,6 @@ struct callbackInfo {
int callbackID;
};
-int wxCALLBACK wxEListCtrlCompare(long item1, long item2, long callbackInfoPtr);
+int wxCALLBACK wxEListCtrlCompare(wxeIntPtr item1, wxeIntPtr item2, wxeIntPtr callbackInfoPtr);
#endif
diff --git a/lib/wx/c_src/wxe_impl.cpp b/lib/wx/c_src/wxe_impl.cpp
index 5964ccfd00..f617aaf349 100644
--- a/lib/wx/c_src/wxe_impl.cpp
+++ b/lib/wx/c_src/wxe_impl.cpp
@@ -104,7 +104,7 @@ void meta_command(int what, wxe_data *sd) {
}
}
-void send_msg(const char * type, wxString * msg) {
+void send_msg(const char * type, const wxString * msg) {
wxeReturn rt = wxeReturn(WXE_DRV_PORT, init_caller);
rt.addAtom((char *) "wxe_driver");
rt.addAtom((char *) type);
@@ -160,6 +160,13 @@ bool WxeApp::OnInit()
return TRUE;
}
+
+#ifdef _MACOSX
+void WxeApp::MacOpenFile(const wxString &filename) {
+ send_msg("open_file", &filename);
+}
+#endif
+
void WxeApp::shutdown(wxeMetaCommand& Ecmd) {
ExitMainLoop();
}
@@ -411,6 +418,13 @@ void WxeApp::destroyMemEnv(wxeMetaCommand& Ecmd)
wxWindow *parent = NULL;
wxeMemEnv * memenv = refmap[Ecmd.port];
+ if(!memenv) {
+ wxString msg;
+ msg.Printf(wxT("MemEnv already deleted"));
+ send_msg("debug", &msg);
+ return;
+ }
+
if(wxe_debug) {
wxString msg;
msg.Printf(wxT("Destroying all memory "));
@@ -439,7 +453,6 @@ void WxeApp::destroyMemEnv(wxeMetaCommand& Ecmd)
}
if(recurse_level > 0) {
// Delay delete until we are out of dispatch*
- delayed_cleanup->Append(Ecmd.Clone());
} else {
delete win;
}
@@ -448,9 +461,10 @@ void WxeApp::destroyMemEnv(wxeMetaCommand& Ecmd)
}
}
- if(recurse_level > 0)
+ if(recurse_level > 0) {
+ delayed_cleanup->Append(Ecmd.Clone());
return;
-
+ }
// First pass, delete all top parents/windows of all linked objects
// fprintf(stderr, "close port %x\r\n", Ecmd.port);fflush(stderr);
@@ -486,20 +500,20 @@ void WxeApp::destroyMemEnv(wxeMetaCommand& Ecmd)
if(it != ptr2ref.end()) {
wxeRefData *refd = it->second;
if(refd->alloc_in_erl) {
- int type = refd->type;
if((refd->type == 1) && ((wxObject *)ptr)->IsKindOf(CLASSINFO(wxBufferedDC))) {
((wxBufferedDC *)ptr)->m_dc = NULL; // Workaround
}
wxString msg;
- if((refd->type == 0)) { // Maybe also class 1
+ bool cleanup_ref=true;
+ if(refd->type == 0) { // Maybe also class 1
wxClassInfo *cinfo = ((wxObject *)ptr)->GetClassInfo();
msg.Printf(wxT("Memory leak: {wx_ref, %d, %s}"),
refd->ref, cinfo->GetClassName());
send_msg("error", &msg);
} else {
- delete_object(ptr, refd);
+ cleanup_ref = delete_object(ptr, refd);
}
- if(type == 0 || type > 2) {
+ if(cleanup_ref) {
// Delete refs for leaks and non overridden allocs
delete refd;
ptr2ref.erase(it);
@@ -607,7 +621,7 @@ void WxeApp::clearPtr(void * ptr) {
if(((int) refd->pid) != -1) {
// Send terminate pid to owner
- wxeReturn rt = wxeReturn(WXE_DRV_PORT,refd->memenv->owner, false);
+ wxeReturn rt = wxeReturn(WXE_DRV_PORT,refd->pid, false);
rt.addAtom("_wxe_destroy_");
rt.add(ERL_DRV_PID, refd->pid);
rt.addTupleCount(2);
diff --git a/lib/wx/c_src/wxe_impl.h b/lib/wx/c_src/wxe_impl.h
index bb54961edd..5b23e1cbbd 100644
--- a/lib/wx/c_src/wxe_impl.h
+++ b/lib/wx/c_src/wxe_impl.h
@@ -36,17 +36,28 @@ extern "C" {
#include "wxe_callback_impl.h"
#include "wxe_memory.h"
+#if !wxCHECK_VERSION(2,9,0)
+#define wxeLocaleC wxChar *
+#define wxeLocaleC2String(Str) wxString(Str)
+#else
+typedef wxString wxeLocaleC;
+#define wxeLocaleC2String(Str) Str
+#endif
+
#define WXE_NOT_INITIATED 0
#define WXE_INITIATED 1
#define WXE_EXITED 2
#define WXE_ERROR -1
-void send_msg(const char *, wxString *); // For debugging and error msgs
+void send_msg(const char *, const wxString *); // For debugging and error msgs
class WxeApp : public wxApp
{
public:
- virtual bool OnInit();
+ virtual bool OnInit();
+#ifdef _MACOSX
+ virtual void MacOpenFile(const wxString &filename);
+#endif
void shutdown(wxeMetaCommand& event);
int dispatch(wxList *, int, int);
@@ -73,7 +84,7 @@ public:
void init_nonconsts(wxeMemEnv *memenv, ErlDrvTermData caller);
// Code found in gen/wxe_derived_dest.h
- void delete_object(void *ptr, wxeRefData *refd);
+ bool delete_object(void *ptr, wxeRefData *refd);
wxeMemMap refmap;
ptrMap ptr2ref;
diff --git a/lib/wx/configure.in b/lib/wx/configure.in
index 3756786831..a96f1f2632 100755
--- a/lib/wx/configure.in
+++ b/lib/wx/configure.in
@@ -441,12 +441,12 @@ else
else
CWXWIN_PROG=`cygpath -d "$PROGRAMFILES" | cygpath -f - 2>/dev/null`
fi
- CWXWIN3=$CWXWIN_PROG/wxWidgets-2.*.*
- CWXWIN4=$CWXWIN_PROG/wxMSW-2.*.*
- CWX_DOCUMENTED="/opt/local/pgm/wxMSW-2.*.* /opt/local/pgm/wxWidgets-2.*.*"
+ CWXWIN3=$CWXWIN_PROG/wxWidgets-?.*.*
+ CWXWIN4=$CWXWIN_PROG/wxMSW-?.*.*
+ CWX_DOCUMENTED="/opt/local/pgm/wxMSW-?.*.* /opt/local/pgm/wxWidgets-?.*.*"
case $ac_cv_sizeof_void_p in
8)
- CWX_DOCUMENTED="/opt/local64/pgm/wxMSW-2.*.* /opt/local64/pgm/wxWidgets-2.*.* $CWX_DOCUMENTED"
+ CWX_DOCUMENTED="/opt/local64/pgm/wxMSW-?.*.* /opt/local64/pgm/wxWidgets-?.*.* $CWX_DOCUMENTED"
;;
*)
true
@@ -464,12 +464,14 @@ else
WX_CFLAGS="-EHsc -D_UNICODE -DUNICODE -I$WXINCLUDE_MSVC -I$WXINCLUDE_PLAIN -I$WXINCLUDE_CONTRIB -D__WXMSW__"
WX_CXXFLAGS="-TP $WX_CFLAGS"
WX_LIBDIR=$dir/lib/vc_lib
+ WX_LIBDIR64=$dir/lib/vc_x64_lib
WX_RESCOMP="rc.sh -I$WXINCLUDE_PLAIN -D __WIN32__"
RC_FILE_TYPE=res
- for lib in $WX_LIBDIR/wxbase*.lib $WX_LIBDIR2/wxbase*.lib; do
- maybe=`echo $lib | egrep 'wxbase[[0-9]]*u\.lib'`
+ for lib in $WX_LIBDIR $WX_LIBDIR64; do
+ maybe=`ls $lib/wxbase*.lib | egrep 'wxbase[[0-9]]*u\.lib'`
if test '!' -z "$maybe"; then
corelib_number=`echo $maybe | sed 's,.*\([[0-9]].\)u\.lib,\1,'`
+ WX_LIBDIR=$lib
break
fi
done
diff --git a/lib/wx/include/wx.hrl b/lib/wx/include/wx.hrl
index 2dc1791cce..ac852ce054 100644
--- a/lib/wx/include/wx.hrl
+++ b/lib/wx/include/wx.hrl
@@ -1980,10 +1980,255 @@
-define(wxIMAGELIST_DRAW_SELECTED, 4).
-define(wxIMAGELIST_DRAW_TRANSPARENT, 2).
-define(wxIMAGELIST_DRAW_NORMAL, 1).
+% From "intl.h": wxLanguage
+-define(wxLANGUAGE_DEFAULT, 0).
+-define(wxLANGUAGE_UNKNOWN, 1).
+-define(wxLANGUAGE_ABKHAZIAN, 2).
+-define(wxLANGUAGE_AFAR, 3).
+-define(wxLANGUAGE_AFRIKAANS, 4).
+-define(wxLANGUAGE_ALBANIAN, 5).
+-define(wxLANGUAGE_AMHARIC, 6).
+-define(wxLANGUAGE_ARABIC, 7).
+-define(wxLANGUAGE_ARABIC_ALGERIA, 8).
+-define(wxLANGUAGE_ARABIC_BAHRAIN, 9).
+-define(wxLANGUAGE_ARABIC_EGYPT, 10).
+-define(wxLANGUAGE_ARABIC_IRAQ, 11).
+-define(wxLANGUAGE_ARABIC_JORDAN, 12).
+-define(wxLANGUAGE_ARABIC_KUWAIT, 13).
+-define(wxLANGUAGE_ARABIC_LEBANON, 14).
+-define(wxLANGUAGE_ARABIC_LIBYA, 15).
+-define(wxLANGUAGE_ARABIC_MOROCCO, 16).
+-define(wxLANGUAGE_ARABIC_OMAN, 17).
+-define(wxLANGUAGE_ARABIC_QATAR, 18).
+-define(wxLANGUAGE_ARABIC_SAUDI_ARABIA, 19).
+-define(wxLANGUAGE_ARABIC_SUDAN, 20).
+-define(wxLANGUAGE_ARABIC_SYRIA, 21).
+-define(wxLANGUAGE_ARABIC_TUNISIA, 22).
+-define(wxLANGUAGE_ARABIC_UAE, 23).
+-define(wxLANGUAGE_ARABIC_YEMEN, 24).
+-define(wxLANGUAGE_ARMENIAN, 25).
+-define(wxLANGUAGE_ASSAMESE, 26).
+-define(wxLANGUAGE_AYMARA, 27).
+-define(wxLANGUAGE_AZERI, 28).
+-define(wxLANGUAGE_AZERI_CYRILLIC, 29).
+-define(wxLANGUAGE_AZERI_LATIN, 30).
+-define(wxLANGUAGE_BASHKIR, 31).
+-define(wxLANGUAGE_BASQUE, 32).
+-define(wxLANGUAGE_BELARUSIAN, 33).
+-define(wxLANGUAGE_BENGALI, 34).
+-define(wxLANGUAGE_BHUTANI, 35).
+-define(wxLANGUAGE_BIHARI, 36).
+-define(wxLANGUAGE_BISLAMA, 37).
+-define(wxLANGUAGE_BRETON, 38).
+-define(wxLANGUAGE_BULGARIAN, 39).
+-define(wxLANGUAGE_BURMESE, 40).
+-define(wxLANGUAGE_CAMBODIAN, 41).
+-define(wxLANGUAGE_CATALAN, 42).
+-define(wxLANGUAGE_CHINESE, 43).
+-define(wxLANGUAGE_CHINESE_SIMPLIFIED, 44).
+-define(wxLANGUAGE_CHINESE_TRADITIONAL, 45).
+-define(wxLANGUAGE_CHINESE_HONGKONG, 46).
+-define(wxLANGUAGE_CHINESE_MACAU, 47).
+-define(wxLANGUAGE_CHINESE_SINGAPORE, 48).
+-define(wxLANGUAGE_CHINESE_TAIWAN, 49).
+-define(wxLANGUAGE_CORSICAN, 50).
+-define(wxLANGUAGE_CROATIAN, 51).
+-define(wxLANGUAGE_CZECH, 52).
+-define(wxLANGUAGE_DANISH, 53).
+-define(wxLANGUAGE_DUTCH, 54).
+-define(wxLANGUAGE_DUTCH_BELGIAN, 55).
+-define(wxLANGUAGE_ENGLISH, 56).
+-define(wxLANGUAGE_ENGLISH_UK, 57).
+-define(wxLANGUAGE_ENGLISH_US, 58).
+-define(wxLANGUAGE_ENGLISH_AUSTRALIA, 59).
+-define(wxLANGUAGE_ENGLISH_BELIZE, 60).
+-define(wxLANGUAGE_ENGLISH_BOTSWANA, 61).
+-define(wxLANGUAGE_ENGLISH_CANADA, 62).
+-define(wxLANGUAGE_ENGLISH_CARIBBEAN, 63).
+-define(wxLANGUAGE_ENGLISH_DENMARK, 64).
+-define(wxLANGUAGE_ENGLISH_EIRE, 65).
+-define(wxLANGUAGE_ENGLISH_JAMAICA, 66).
+-define(wxLANGUAGE_ENGLISH_NEW_ZEALAND, 67).
+-define(wxLANGUAGE_ENGLISH_PHILIPPINES, 68).
+-define(wxLANGUAGE_ENGLISH_SOUTH_AFRICA, 69).
+-define(wxLANGUAGE_ENGLISH_TRINIDAD, 70).
+-define(wxLANGUAGE_ENGLISH_ZIMBABWE, 71).
+-define(wxLANGUAGE_ESPERANTO, 72).
+-define(wxLANGUAGE_ESTONIAN, 73).
+-define(wxLANGUAGE_FAEROESE, 74).
+-define(wxLANGUAGE_FARSI, 75).
+-define(wxLANGUAGE_FIJI, 76).
+-define(wxLANGUAGE_FINNISH, 77).
+-define(wxLANGUAGE_FRENCH, 78).
+-define(wxLANGUAGE_FRENCH_BELGIAN, 79).
+-define(wxLANGUAGE_FRENCH_CANADIAN, 80).
+-define(wxLANGUAGE_FRENCH_LUXEMBOURG, 81).
+-define(wxLANGUAGE_FRENCH_MONACO, 82).
+-define(wxLANGUAGE_FRENCH_SWISS, 83).
+-define(wxLANGUAGE_FRISIAN, 84).
+-define(wxLANGUAGE_GALICIAN, 85).
+-define(wxLANGUAGE_GEORGIAN, 86).
+-define(wxLANGUAGE_GERMAN, 87).
+-define(wxLANGUAGE_GERMAN_AUSTRIAN, 88).
+-define(wxLANGUAGE_GERMAN_BELGIUM, 89).
+-define(wxLANGUAGE_GERMAN_LIECHTENSTEIN, 90).
+-define(wxLANGUAGE_GERMAN_LUXEMBOURG, 91).
+-define(wxLANGUAGE_GERMAN_SWISS, 92).
+-define(wxLANGUAGE_GREEK, 93).
+-define(wxLANGUAGE_GREENLANDIC, 94).
+-define(wxLANGUAGE_GUARANI, 95).
+-define(wxLANGUAGE_GUJARATI, 96).
+-define(wxLANGUAGE_HAUSA, 97).
+-define(wxLANGUAGE_HEBREW, 98).
+-define(wxLANGUAGE_HINDI, 99).
+-define(wxLANGUAGE_HUNGARIAN, 100).
+-define(wxLANGUAGE_ICELANDIC, 101).
+-define(wxLANGUAGE_INDONESIAN, 102).
+-define(wxLANGUAGE_INTERLINGUA, 103).
+-define(wxLANGUAGE_INTERLINGUE, 104).
+-define(wxLANGUAGE_INUKTITUT, 105).
+-define(wxLANGUAGE_INUPIAK, 106).
+-define(wxLANGUAGE_IRISH, 107).
+-define(wxLANGUAGE_ITALIAN, 108).
+-define(wxLANGUAGE_ITALIAN_SWISS, 109).
+-define(wxLANGUAGE_JAPANESE, 110).
+-define(wxLANGUAGE_JAVANESE, 111).
+-define(wxLANGUAGE_KANNADA, 112).
+-define(wxLANGUAGE_KASHMIRI, 113).
+-define(wxLANGUAGE_KASHMIRI_INDIA, 114).
+-define(wxLANGUAGE_KAZAKH, 115).
+-define(wxLANGUAGE_KERNEWEK, 116).
+-define(wxLANGUAGE_KINYARWANDA, 117).
+-define(wxLANGUAGE_KIRGHIZ, 118).
+-define(wxLANGUAGE_KIRUNDI, 119).
+-define(wxLANGUAGE_KONKANI, 120).
+-define(wxLANGUAGE_KOREAN, 121).
+-define(wxLANGUAGE_KURDISH, 122).
+-define(wxLANGUAGE_LAOTHIAN, 123).
+-define(wxLANGUAGE_LATIN, 124).
+-define(wxLANGUAGE_LATVIAN, 125).
+-define(wxLANGUAGE_LINGALA, 126).
+-define(wxLANGUAGE_LITHUANIAN, 127).
+-define(wxLANGUAGE_MACEDONIAN, 128).
+-define(wxLANGUAGE_MALAGASY, 129).
+-define(wxLANGUAGE_MALAY, 130).
+-define(wxLANGUAGE_MALAYALAM, 131).
+-define(wxLANGUAGE_MALAY_BRUNEI_DARUSSALAM, 132).
+-define(wxLANGUAGE_MALAY_MALAYSIA, 133).
+-define(wxLANGUAGE_MALTESE, 134).
+-define(wxLANGUAGE_MANIPURI, 135).
+-define(wxLANGUAGE_MAORI, 136).
+-define(wxLANGUAGE_MARATHI, 137).
+-define(wxLANGUAGE_MOLDAVIAN, 138).
+-define(wxLANGUAGE_MONGOLIAN, 139).
+-define(wxLANGUAGE_NAURU, 140).
+-define(wxLANGUAGE_NEPALI, 141).
+-define(wxLANGUAGE_NEPALI_INDIA, 142).
+-define(wxLANGUAGE_NORWEGIAN_BOKMAL, 143).
+-define(wxLANGUAGE_NORWEGIAN_NYNORSK, 144).
+-define(wxLANGUAGE_OCCITAN, 145).
+-define(wxLANGUAGE_ORIYA, 146).
+-define(wxLANGUAGE_OROMO, 147).
+-define(wxLANGUAGE_PASHTO, 148).
+-define(wxLANGUAGE_POLISH, 149).
+-define(wxLANGUAGE_PORTUGUESE, 150).
+-define(wxLANGUAGE_PORTUGUESE_BRAZILIAN, 151).
+-define(wxLANGUAGE_PUNJABI, 152).
+-define(wxLANGUAGE_QUECHUA, 153).
+-define(wxLANGUAGE_RHAETO_ROMANCE, 154).
+-define(wxLANGUAGE_ROMANIAN, 155).
+-define(wxLANGUAGE_RUSSIAN, 156).
+-define(wxLANGUAGE_RUSSIAN_UKRAINE, 157).
+-define(wxLANGUAGE_SAMOAN, 158).
+-define(wxLANGUAGE_SANGHO, 159).
+-define(wxLANGUAGE_SANSKRIT, 160).
+-define(wxLANGUAGE_SCOTS_GAELIC, 161).
+-define(wxLANGUAGE_SERBIAN, 162).
+-define(wxLANGUAGE_SERBIAN_CYRILLIC, 163).
+-define(wxLANGUAGE_SERBIAN_LATIN, 164).
+-define(wxLANGUAGE_SERBO_CROATIAN, 165).
+-define(wxLANGUAGE_SESOTHO, 166).
+-define(wxLANGUAGE_SETSWANA, 167).
+-define(wxLANGUAGE_SHONA, 168).
+-define(wxLANGUAGE_SINDHI, 169).
+-define(wxLANGUAGE_SINHALESE, 170).
+-define(wxLANGUAGE_SISWATI, 171).
+-define(wxLANGUAGE_SLOVAK, 172).
+-define(wxLANGUAGE_SLOVENIAN, 173).
+-define(wxLANGUAGE_SOMALI, 174).
+-define(wxLANGUAGE_SPANISH, 175).
+-define(wxLANGUAGE_SPANISH_ARGENTINA, 176).
+-define(wxLANGUAGE_SPANISH_BOLIVIA, 177).
+-define(wxLANGUAGE_SPANISH_CHILE, 178).
+-define(wxLANGUAGE_SPANISH_COLOMBIA, 179).
+-define(wxLANGUAGE_SPANISH_COSTA_RICA, 180).
+-define(wxLANGUAGE_SPANISH_DOMINICAN_REPUBLIC, 181).
+-define(wxLANGUAGE_SPANISH_ECUADOR, 182).
+-define(wxLANGUAGE_SPANISH_EL_SALVADOR, 183).
+-define(wxLANGUAGE_SPANISH_GUATEMALA, 184).
+-define(wxLANGUAGE_SPANISH_HONDURAS, 185).
+-define(wxLANGUAGE_SPANISH_MEXICAN, 186).
+-define(wxLANGUAGE_SPANISH_MODERN, 187).
+-define(wxLANGUAGE_SPANISH_NICARAGUA, 188).
+-define(wxLANGUAGE_SPANISH_PANAMA, 189).
+-define(wxLANGUAGE_SPANISH_PARAGUAY, 190).
+-define(wxLANGUAGE_SPANISH_PERU, 191).
+-define(wxLANGUAGE_SPANISH_PUERTO_RICO, 192).
+-define(wxLANGUAGE_SPANISH_URUGUAY, 193).
+-define(wxLANGUAGE_SPANISH_US, 194).
+-define(wxLANGUAGE_SPANISH_VENEZUELA, 195).
+-define(wxLANGUAGE_SUNDANESE, 196).
+-define(wxLANGUAGE_SWAHILI, 197).
+-define(wxLANGUAGE_SWEDISH, 198).
+-define(wxLANGUAGE_SWEDISH_FINLAND, 199).
+-define(wxLANGUAGE_TAGALOG, 200).
+-define(wxLANGUAGE_TAJIK, 201).
+-define(wxLANGUAGE_TAMIL, 202).
+-define(wxLANGUAGE_TATAR, 203).
+-define(wxLANGUAGE_TELUGU, 204).
+-define(wxLANGUAGE_THAI, 205).
+-define(wxLANGUAGE_TIBETAN, 206).
+-define(wxLANGUAGE_TIGRINYA, 207).
+-define(wxLANGUAGE_TONGA, 208).
+-define(wxLANGUAGE_TSONGA, 209).
+-define(wxLANGUAGE_TURKISH, 210).
+-define(wxLANGUAGE_TURKMEN, 211).
+-define(wxLANGUAGE_TWI, 212).
+-define(wxLANGUAGE_UIGHUR, 213).
+-define(wxLANGUAGE_UKRAINIAN, 214).
+-define(wxLANGUAGE_URDU, 215).
+-define(wxLANGUAGE_URDU_INDIA, 216).
+-define(wxLANGUAGE_URDU_PAKISTAN, 217).
+-define(wxLANGUAGE_UZBEK, 218).
+-define(wxLANGUAGE_UZBEK_CYRILLIC, 219).
+-define(wxLANGUAGE_UZBEK_LATIN, 220).
+-define(wxLANGUAGE_VIETNAMESE, 221).
+-define(wxLANGUAGE_VOLAPUK, 222).
+-define(wxLANGUAGE_WELSH, 223).
+-define(wxLANGUAGE_WOLOF, 224).
+-define(wxLANGUAGE_XHOSA, 225).
+-define(wxLANGUAGE_YIDDISH, 226).
+-define(wxLANGUAGE_YORUBA, 227).
+-define(wxLANGUAGE_ZHUANG, 228).
+-define(wxLANGUAGE_ZULU, 229).
+-define(wxLANGUAGE_USER_DEFINED, 230).
+-define(wxLANGUAGE_VALENCIAN, 536870911).
+-define(wxLANGUAGE_SAMI, 536870912).
% From "intl.h": wxLayoutDirection
-define(wxLayout_Default, 0).
-define(wxLayout_LeftToRight, 1).
-define(wxLayout_RightToLeft, 2).
+% From "intl.h": wxLocaleCategory
+-define(wxLOCALE_CAT_NUMBER, 0).
+-define(wxLOCALE_CAT_DATE, 1).
+-define(wxLOCALE_CAT_MONEY, 2).
+-define(wxLOCALE_CAT_MAX, 3).
+% From "intl.h": wxLocaleInfo
+-define(wxLOCALE_THOUSANDS_SEP, 0).
+-define(wxLOCALE_DECIMAL_POINT, 1).
+% From "intl.h": wxLocaleInitFlags
+-define(wxLOCALE_LOAD_DEFAULT, 1).
+-define(wxLOCALE_CONV_ENCODING, 2).
% From "layout.h"
-define(wxLAYOUT_DEFAULT_MARGIN, 0).
% From "layout.h": wxEdge
diff --git a/lib/wx/src/gen/wxLocale.erl b/lib/wx/src/gen/wxLocale.erl
new file mode 100644
index 0000000000..a1a418bcee
--- /dev/null
+++ b/lib/wx/src/gen/wxLocale.erl
@@ -0,0 +1,278 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2008-2014. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% 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/2.8.12/wx_wxlocale.html">wxLocale</a>.
+%% @type wxLocale(). 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(wxLocale).
+-include("wxe.hrl").
+-export([addCatalog/2,addCatalog/4,addCatalogLookupPathPrefix/1,destroy/1,
+ getCanonicalName/1,getHeaderValue/2,getHeaderValue/3,getLanguage/1,
+ getLanguageName/1,getLocale/1,getName/1,getString/2,getString/3,getString/4,
+ getString/5,getSysName/1,getSystemEncoding/0,getSystemEncodingName/0,
+ getSystemLanguage/0,init/1,init/2,isLoaded/2,isOk/1,new/0,new/1,new/2]).
+
+%% inherited exports
+-export([parent_class/1]).
+
+-export_type([wxLocale/0]).
+%% @hidden
+parent_class(_Class) -> erlang:error({badtype, ?MODULE}).
+
+-type wxLocale() :: wx:wx_object().
+%% @doc See <a href="http://www.wxwidgets.org/manuals/2.8.12/wx_wxlocale.html#wxlocalewxlocale">external documentation</a>.
+-spec new() -> wxLocale().
+new() ->
+ wxe_util:construct(?wxLocale_new_0,
+ <<>>).
+
+%% @equiv new(Language, [])
+-spec new(Language) -> wxLocale() when
+ Language::integer().
+
+new(Language)
+ when is_integer(Language) ->
+ new(Language, []).
+
+%% @doc See <a href="http://www.wxwidgets.org/manuals/2.8.12/wx_wxlocale.html#wxlocalewxlocale">external documentation</a>.
+-spec new(Language, [Option]) -> wxLocale() when
+ Language::integer(),
+ Option :: {flags, integer()}.
+new(Language, Options)
+ when is_integer(Language),is_list(Options) ->
+ MOpts = fun({flags, Flags}, Acc) -> [<<1:32/?UI,Flags:32/?UI>>|Acc];
+ (BadOpt, _) -> erlang:error({badoption, BadOpt}) end,
+ BinOpt = list_to_binary(lists:foldl(MOpts, [<<0:32>>], Options)),
+ wxe_util:construct(?wxLocale_new_2,
+ <<Language:32/?UI, 0:32,BinOpt/binary>>).
+
+%% @equiv init(This, [])
+-spec init(This) -> boolean() when
+ This::wxLocale().
+
+init(This)
+ when is_record(This, wx_ref) ->
+ init(This, []).
+
+%% @doc See <a href="http://www.wxwidgets.org/manuals/2.8.12/wx_wxlocale.html#wxlocaleinit">external documentation</a>.
+-spec init(This, [Option]) -> boolean() when
+ This::wxLocale(),
+ Option :: {language, integer()}
+ | {flags, integer()}.
+init(#wx_ref{type=ThisT,ref=ThisRef}, Options)
+ when is_list(Options) ->
+ ?CLASS(ThisT,wxLocale),
+ MOpts = fun({language, Language}, Acc) -> [<<1:32/?UI,Language:32/?UI>>|Acc];
+ ({flags, Flags}, Acc) -> [<<2:32/?UI,Flags:32/?UI>>|Acc];
+ (BadOpt, _) -> erlang:error({badoption, BadOpt}) end,
+ BinOpt = list_to_binary(lists:foldl(MOpts, [<<0:32>>], Options)),
+ wxe_util:call(?wxLocale_Init,
+ <<ThisRef:32/?UI, 0:32,BinOpt/binary>>).
+
+%% @doc See <a href="http://www.wxwidgets.org/manuals/2.8.12/wx_wxlocale.html#wxlocaleaddcatalog">external documentation</a>.
+-spec addCatalog(This, SzDomain) -> boolean() when
+ This::wxLocale(), SzDomain::unicode:chardata().
+addCatalog(#wx_ref{type=ThisT,ref=ThisRef},SzDomain)
+ when is_list(SzDomain) ->
+ ?CLASS(ThisT,wxLocale),
+ SzDomain_UC = unicode:characters_to_binary([SzDomain,0]),
+ wxe_util:call(?wxLocale_AddCatalog_1,
+ <<ThisRef:32/?UI,(byte_size(SzDomain_UC)):32/?UI,(SzDomain_UC)/binary, 0:(((8- ((0+byte_size(SzDomain_UC)) band 16#7)) band 16#7))/unit:8>>).
+
+%% @doc See <a href="http://www.wxwidgets.org/manuals/2.8.12/wx_wxlocale.html#wxlocaleaddcatalog">external documentation</a>.
+%%<br /> MsgIdLanguage = ?wxLANGUAGE_DEFAULT | ?wxLANGUAGE_UNKNOWN | ?wxLANGUAGE_ABKHAZIAN | ?wxLANGUAGE_AFAR | ?wxLANGUAGE_AFRIKAANS | ?wxLANGUAGE_ALBANIAN | ?wxLANGUAGE_AMHARIC | ?wxLANGUAGE_ARABIC | ?wxLANGUAGE_ARABIC_ALGERIA | ?wxLANGUAGE_ARABIC_BAHRAIN | ?wxLANGUAGE_ARABIC_EGYPT | ?wxLANGUAGE_ARABIC_IRAQ | ?wxLANGUAGE_ARABIC_JORDAN | ?wxLANGUAGE_ARABIC_KUWAIT | ?wxLANGUAGE_ARABIC_LEBANON | ?wxLANGUAGE_ARABIC_LIBYA | ?wxLANGUAGE_ARABIC_MOROCCO | ?wxLANGUAGE_ARABIC_OMAN | ?wxLANGUAGE_ARABIC_QATAR | ?wxLANGUAGE_ARABIC_SAUDI_ARABIA | ?wxLANGUAGE_ARABIC_SUDAN | ?wxLANGUAGE_ARABIC_SYRIA | ?wxLANGUAGE_ARABIC_TUNISIA | ?wxLANGUAGE_ARABIC_UAE | ?wxLANGUAGE_ARABIC_YEMEN | ?wxLANGUAGE_ARMENIAN | ?wxLANGUAGE_ASSAMESE | ?wxLANGUAGE_AYMARA | ?wxLANGUAGE_AZERI | ?wxLANGUAGE_AZERI_CYRILLIC | ?wxLANGUAGE_AZERI_LATIN | ?wxLANGUAGE_BASHKIR | ?wxLANGUAGE_BASQUE | ?wxLANGUAGE_BELARUSIAN | ?wxLANGUAGE_BENGALI | ?wxLANGUAGE_BHUTANI | ?wxLANGUAGE_BIHARI | ?wxLANGUAGE_BISLAMA | ?wxLANGUAGE_BRETON | ?wxLANGUAGE_BULGARIAN | ?wxLANGUAGE_BURMESE | ?wxLANGUAGE_CAMBODIAN | ?wxLANGUAGE_CATALAN | ?wxLANGUAGE_CHINESE | ?wxLANGUAGE_CHINESE_SIMPLIFIED | ?wxLANGUAGE_CHINESE_TRADITIONAL | ?wxLANGUAGE_CHINESE_HONGKONG | ?wxLANGUAGE_CHINESE_MACAU | ?wxLANGUAGE_CHINESE_SINGAPORE | ?wxLANGUAGE_CHINESE_TAIWAN | ?wxLANGUAGE_CORSICAN | ?wxLANGUAGE_CROATIAN | ?wxLANGUAGE_CZECH | ?wxLANGUAGE_DANISH | ?wxLANGUAGE_DUTCH | ?wxLANGUAGE_DUTCH_BELGIAN | ?wxLANGUAGE_ENGLISH | ?wxLANGUAGE_ENGLISH_UK | ?wxLANGUAGE_ENGLISH_US | ?wxLANGUAGE_ENGLISH_AUSTRALIA | ?wxLANGUAGE_ENGLISH_BELIZE | ?wxLANGUAGE_ENGLISH_BOTSWANA | ?wxLANGUAGE_ENGLISH_CANADA | ?wxLANGUAGE_ENGLISH_CARIBBEAN | ?wxLANGUAGE_ENGLISH_DENMARK | ?wxLANGUAGE_ENGLISH_EIRE | ?wxLANGUAGE_ENGLISH_JAMAICA | ?wxLANGUAGE_ENGLISH_NEW_ZEALAND | ?wxLANGUAGE_ENGLISH_PHILIPPINES | ?wxLANGUAGE_ENGLISH_SOUTH_AFRICA | ?wxLANGUAGE_ENGLISH_TRINIDAD | ?wxLANGUAGE_ENGLISH_ZIMBABWE | ?wxLANGUAGE_ESPERANTO | ?wxLANGUAGE_ESTONIAN | ?wxLANGUAGE_FAEROESE | ?wxLANGUAGE_FARSI | ?wxLANGUAGE_FIJI | ?wxLANGUAGE_FINNISH | ?wxLANGUAGE_FRENCH | ?wxLANGUAGE_FRENCH_BELGIAN | ?wxLANGUAGE_FRENCH_CANADIAN | ?wxLANGUAGE_FRENCH_LUXEMBOURG | ?wxLANGUAGE_FRENCH_MONACO | ?wxLANGUAGE_FRENCH_SWISS | ?wxLANGUAGE_FRISIAN | ?wxLANGUAGE_GALICIAN | ?wxLANGUAGE_GEORGIAN | ?wxLANGUAGE_GERMAN | ?wxLANGUAGE_GERMAN_AUSTRIAN | ?wxLANGUAGE_GERMAN_BELGIUM | ?wxLANGUAGE_GERMAN_LIECHTENSTEIN | ?wxLANGUAGE_GERMAN_LUXEMBOURG | ?wxLANGUAGE_GERMAN_SWISS | ?wxLANGUAGE_GREEK | ?wxLANGUAGE_GREENLANDIC | ?wxLANGUAGE_GUARANI | ?wxLANGUAGE_GUJARATI | ?wxLANGUAGE_HAUSA | ?wxLANGUAGE_HEBREW | ?wxLANGUAGE_HINDI | ?wxLANGUAGE_HUNGARIAN | ?wxLANGUAGE_ICELANDIC | ?wxLANGUAGE_INDONESIAN | ?wxLANGUAGE_INTERLINGUA | ?wxLANGUAGE_INTERLINGUE | ?wxLANGUAGE_INUKTITUT | ?wxLANGUAGE_INUPIAK | ?wxLANGUAGE_IRISH | ?wxLANGUAGE_ITALIAN | ?wxLANGUAGE_ITALIAN_SWISS | ?wxLANGUAGE_JAPANESE | ?wxLANGUAGE_JAVANESE | ?wxLANGUAGE_KANNADA | ?wxLANGUAGE_KASHMIRI | ?wxLANGUAGE_KASHMIRI_INDIA | ?wxLANGUAGE_KAZAKH | ?wxLANGUAGE_KERNEWEK | ?wxLANGUAGE_KINYARWANDA | ?wxLANGUAGE_KIRGHIZ | ?wxLANGUAGE_KIRUNDI | ?wxLANGUAGE_KONKANI | ?wxLANGUAGE_KOREAN | ?wxLANGUAGE_KURDISH | ?wxLANGUAGE_LAOTHIAN | ?wxLANGUAGE_LATIN | ?wxLANGUAGE_LATVIAN | ?wxLANGUAGE_LINGALA | ?wxLANGUAGE_LITHUANIAN | ?wxLANGUAGE_MACEDONIAN | ?wxLANGUAGE_MALAGASY | ?wxLANGUAGE_MALAY | ?wxLANGUAGE_MALAYALAM | ?wxLANGUAGE_MALAY_BRUNEI_DARUSSALAM | ?wxLANGUAGE_MALAY_MALAYSIA | ?wxLANGUAGE_MALTESE | ?wxLANGUAGE_MANIPURI | ?wxLANGUAGE_MAORI | ?wxLANGUAGE_MARATHI | ?wxLANGUAGE_MOLDAVIAN | ?wxLANGUAGE_MONGOLIAN | ?wxLANGUAGE_NAURU | ?wxLANGUAGE_NEPALI | ?wxLANGUAGE_NEPALI_INDIA | ?wxLANGUAGE_NORWEGIAN_BOKMAL | ?wxLANGUAGE_NORWEGIAN_NYNORSK | ?wxLANGUAGE_OCCITAN | ?wxLANGUAGE_ORIYA | ?wxLANGUAGE_OROMO | ?wxLANGUAGE_PASHTO | ?wxLANGUAGE_POLISH | ?wxLANGUAGE_PORTUGUESE | ?wxLANGUAGE_PORTUGUESE_BRAZILIAN | ?wxLANGUAGE_PUNJABI | ?wxLANGUAGE_QUECHUA | ?wxLANGUAGE_RHAETO_ROMANCE | ?wxLANGUAGE_ROMANIAN | ?wxLANGUAGE_RUSSIAN | ?wxLANGUAGE_RUSSIAN_UKRAINE | ?wxLANGUAGE_SAMOAN | ?wxLANGUAGE_SANGHO | ?wxLANGUAGE_SANSKRIT | ?wxLANGUAGE_SCOTS_GAELIC | ?wxLANGUAGE_SERBIAN | ?wxLANGUAGE_SERBIAN_CYRILLIC | ?wxLANGUAGE_SERBIAN_LATIN | ?wxLANGUAGE_SERBO_CROATIAN | ?wxLANGUAGE_SESOTHO | ?wxLANGUAGE_SETSWANA | ?wxLANGUAGE_SHONA | ?wxLANGUAGE_SINDHI | ?wxLANGUAGE_SINHALESE | ?wxLANGUAGE_SISWATI | ?wxLANGUAGE_SLOVAK | ?wxLANGUAGE_SLOVENIAN | ?wxLANGUAGE_SOMALI | ?wxLANGUAGE_SPANISH | ?wxLANGUAGE_SPANISH_ARGENTINA | ?wxLANGUAGE_SPANISH_BOLIVIA | ?wxLANGUAGE_SPANISH_CHILE | ?wxLANGUAGE_SPANISH_COLOMBIA | ?wxLANGUAGE_SPANISH_COSTA_RICA | ?wxLANGUAGE_SPANISH_DOMINICAN_REPUBLIC | ?wxLANGUAGE_SPANISH_ECUADOR | ?wxLANGUAGE_SPANISH_EL_SALVADOR | ?wxLANGUAGE_SPANISH_GUATEMALA | ?wxLANGUAGE_SPANISH_HONDURAS | ?wxLANGUAGE_SPANISH_MEXICAN | ?wxLANGUAGE_SPANISH_MODERN | ?wxLANGUAGE_SPANISH_NICARAGUA | ?wxLANGUAGE_SPANISH_PANAMA | ?wxLANGUAGE_SPANISH_PARAGUAY | ?wxLANGUAGE_SPANISH_PERU | ?wxLANGUAGE_SPANISH_PUERTO_RICO | ?wxLANGUAGE_SPANISH_URUGUAY | ?wxLANGUAGE_SPANISH_US | ?wxLANGUAGE_SPANISH_VENEZUELA | ?wxLANGUAGE_SUNDANESE | ?wxLANGUAGE_SWAHILI | ?wxLANGUAGE_SWEDISH | ?wxLANGUAGE_SWEDISH_FINLAND | ?wxLANGUAGE_TAGALOG | ?wxLANGUAGE_TAJIK | ?wxLANGUAGE_TAMIL | ?wxLANGUAGE_TATAR | ?wxLANGUAGE_TELUGU | ?wxLANGUAGE_THAI | ?wxLANGUAGE_TIBETAN | ?wxLANGUAGE_TIGRINYA | ?wxLANGUAGE_TONGA | ?wxLANGUAGE_TSONGA | ?wxLANGUAGE_TURKISH | ?wxLANGUAGE_TURKMEN | ?wxLANGUAGE_TWI | ?wxLANGUAGE_UIGHUR | ?wxLANGUAGE_UKRAINIAN | ?wxLANGUAGE_URDU | ?wxLANGUAGE_URDU_INDIA | ?wxLANGUAGE_URDU_PAKISTAN | ?wxLANGUAGE_UZBEK | ?wxLANGUAGE_UZBEK_CYRILLIC | ?wxLANGUAGE_UZBEK_LATIN | ?wxLANGUAGE_VIETNAMESE | ?wxLANGUAGE_VOLAPUK | ?wxLANGUAGE_WELSH | ?wxLANGUAGE_WOLOF | ?wxLANGUAGE_XHOSA | ?wxLANGUAGE_YIDDISH | ?wxLANGUAGE_YORUBA | ?wxLANGUAGE_ZHUANG | ?wxLANGUAGE_ZULU | ?wxLANGUAGE_USER_DEFINED | ?wxLANGUAGE_VALENCIAN | ?wxLANGUAGE_SAMI
+-spec addCatalog(This, SzDomain, MsgIdLanguage, MsgIdCharset) -> boolean() when
+ This::wxLocale(), SzDomain::unicode:chardata(), MsgIdLanguage::wx:wx_enum(), MsgIdCharset::unicode:chardata().
+addCatalog(#wx_ref{type=ThisT,ref=ThisRef},SzDomain,MsgIdLanguage,MsgIdCharset)
+ when is_list(SzDomain),is_integer(MsgIdLanguage),is_list(MsgIdCharset) ->
+ ?CLASS(ThisT,wxLocale),
+ SzDomain_UC = unicode:characters_to_binary([SzDomain,0]),
+ MsgIdCharset_UC = unicode:characters_to_binary([MsgIdCharset,0]),
+ wxe_util:call(?wxLocale_AddCatalog_3,
+ <<ThisRef:32/?UI,(byte_size(SzDomain_UC)):32/?UI,(SzDomain_UC)/binary, 0:(((8- ((0+byte_size(SzDomain_UC)) band 16#7)) band 16#7))/unit:8,MsgIdLanguage:32/?UI,(byte_size(MsgIdCharset_UC)):32/?UI,(MsgIdCharset_UC)/binary, 0:(((8- ((0+byte_size(MsgIdCharset_UC)) band 16#7)) band 16#7))/unit:8>>).
+
+%% @doc See <a href="http://www.wxwidgets.org/manuals/2.8.12/wx_wxlocale.html#wxlocaleaddcataloglookuppathprefix">external documentation</a>.
+-spec addCatalogLookupPathPrefix(Prefix) -> ok when
+ Prefix::unicode:chardata().
+addCatalogLookupPathPrefix(Prefix)
+ when is_list(Prefix) ->
+ Prefix_UC = unicode:characters_to_binary([Prefix,0]),
+ wxe_util:cast(?wxLocale_AddCatalogLookupPathPrefix,
+ <<(byte_size(Prefix_UC)):32/?UI,(Prefix_UC)/binary, 0:(((8- ((4+byte_size(Prefix_UC)) band 16#7)) band 16#7))/unit:8>>).
+
+%% @doc See <a href="http://www.wxwidgets.org/manuals/2.8.12/wx_wxlocale.html#wxlocalegetcanonicalname">external documentation</a>.
+-spec getCanonicalName(This) -> unicode:charlist() when
+ This::wxLocale().
+getCanonicalName(#wx_ref{type=ThisT,ref=ThisRef}) ->
+ ?CLASS(ThisT,wxLocale),
+ wxe_util:call(?wxLocale_GetCanonicalName,
+ <<ThisRef:32/?UI>>).
+
+%% @doc See <a href="http://www.wxwidgets.org/manuals/2.8.12/wx_wxlocale.html#wxlocalegetlanguage">external documentation</a>.
+-spec getLanguage(This) -> integer() when
+ This::wxLocale().
+getLanguage(#wx_ref{type=ThisT,ref=ThisRef}) ->
+ ?CLASS(ThisT,wxLocale),
+ wxe_util:call(?wxLocale_GetLanguage,
+ <<ThisRef:32/?UI>>).
+
+%% @doc See <a href="http://www.wxwidgets.org/manuals/2.8.12/wx_wxlocale.html#wxlocalegetlanguagename">external documentation</a>.
+-spec getLanguageName(Lang) -> unicode:charlist() when
+ Lang::integer().
+getLanguageName(Lang)
+ when is_integer(Lang) ->
+ wxe_util:call(?wxLocale_GetLanguageName,
+ <<Lang:32/?UI>>).
+
+%% @doc See <a href="http://www.wxwidgets.org/manuals/2.8.12/wx_wxlocale.html#wxlocalegetlocale">external documentation</a>.
+-spec getLocale(This) -> unicode:charlist() when
+ This::wxLocale().
+getLocale(#wx_ref{type=ThisT,ref=ThisRef}) ->
+ ?CLASS(ThisT,wxLocale),
+ wxe_util:call(?wxLocale_GetLocale,
+ <<ThisRef:32/?UI>>).
+
+%% @doc See <a href="http://www.wxwidgets.org/manuals/2.8.12/wx_wxlocale.html#wxlocalegetname">external documentation</a>.
+-spec getName(This) -> unicode:charlist() when
+ This::wxLocale().
+getName(#wx_ref{type=ThisT,ref=ThisRef}) ->
+ ?CLASS(ThisT,wxLocale),
+ wxe_util:call(?wxLocale_GetName,
+ <<ThisRef:32/?UI>>).
+
+%% @equiv getString(This,SzOrigString, [])
+-spec getString(This, SzOrigString) -> unicode:charlist() when
+ This::wxLocale(), SzOrigString::unicode:chardata().
+
+getString(This,SzOrigString)
+ when is_record(This, wx_ref),is_list(SzOrigString) ->
+ getString(This,SzOrigString, []).
+
+%% @doc See <a href="http://www.wxwidgets.org/manuals/2.8.12/wx_wxlocale.html#wxlocalegetstring">external documentation</a>.
+-spec getString(This, SzOrigString, [Option]) -> unicode:charlist() when
+ This::wxLocale(), SzOrigString::unicode:chardata(),
+ Option :: {szDomain, unicode:chardata()}.
+getString(#wx_ref{type=ThisT,ref=ThisRef},SzOrigString, Options)
+ when is_list(SzOrigString),is_list(Options) ->
+ ?CLASS(ThisT,wxLocale),
+ SzOrigString_UC = unicode:characters_to_binary([SzOrigString,0]),
+ MOpts = fun({szDomain, SzDomain}, Acc) -> SzDomain_UC = unicode:characters_to_binary([SzDomain,0]),[<<1:32/?UI,(byte_size(SzDomain_UC)):32/?UI,(SzDomain_UC)/binary, 0:(((8- ((0+byte_size(SzDomain_UC)) band 16#7)) band 16#7))/unit:8>>|Acc];
+ (BadOpt, _) -> erlang:error({badoption, BadOpt}) end,
+ BinOpt = list_to_binary(lists:foldl(MOpts, [<<0:32>>], Options)),
+ wxe_util:call(?wxLocale_GetString_2,
+ <<ThisRef:32/?UI,(byte_size(SzOrigString_UC)):32/?UI,(SzOrigString_UC)/binary, 0:(((8- ((0+byte_size(SzOrigString_UC)) band 16#7)) band 16#7))/unit:8, BinOpt/binary>>).
+
+%% @equiv getString(This,SzOrigString,SzOrigString2,N, [])
+-spec getString(This, SzOrigString, SzOrigString2, N) -> unicode:charlist() when
+ This::wxLocale(), SzOrigString::unicode:chardata(), SzOrigString2::unicode:chardata(), N::integer().
+
+getString(This,SzOrigString,SzOrigString2,N)
+ when is_record(This, wx_ref),is_list(SzOrigString),is_list(SzOrigString2),is_integer(N) ->
+ getString(This,SzOrigString,SzOrigString2,N, []).
+
+%% @doc See <a href="http://www.wxwidgets.org/manuals/2.8.12/wx_wxlocale.html#wxlocalegetstring">external documentation</a>.
+-spec getString(This, SzOrigString, SzOrigString2, N, [Option]) -> unicode:charlist() when
+ This::wxLocale(), SzOrigString::unicode:chardata(), SzOrigString2::unicode:chardata(), N::integer(),
+ Option :: {szDomain, unicode:chardata()}.
+getString(#wx_ref{type=ThisT,ref=ThisRef},SzOrigString,SzOrigString2,N, Options)
+ when is_list(SzOrigString),is_list(SzOrigString2),is_integer(N),is_list(Options) ->
+ ?CLASS(ThisT,wxLocale),
+ SzOrigString_UC = unicode:characters_to_binary([SzOrigString,0]),
+ SzOrigString2_UC = unicode:characters_to_binary([SzOrigString2,0]),
+ MOpts = fun({szDomain, SzDomain}, Acc) -> SzDomain_UC = unicode:characters_to_binary([SzDomain,0]),[<<1:32/?UI,(byte_size(SzDomain_UC)):32/?UI,(SzDomain_UC)/binary, 0:(((8- ((0+byte_size(SzDomain_UC)) band 16#7)) band 16#7))/unit:8>>|Acc];
+ (BadOpt, _) -> erlang:error({badoption, BadOpt}) end,
+ BinOpt = list_to_binary(lists:foldl(MOpts, [<<0:32>>], Options)),
+ wxe_util:call(?wxLocale_GetString_4,
+ <<ThisRef:32/?UI,(byte_size(SzOrigString_UC)):32/?UI,(SzOrigString_UC)/binary, 0:(((8- ((0+byte_size(SzOrigString_UC)) band 16#7)) band 16#7))/unit:8,(byte_size(SzOrigString2_UC)):32/?UI,(SzOrigString2_UC)/binary, 0:(((8- ((4+byte_size(SzOrigString2_UC)) band 16#7)) band 16#7))/unit:8,N:32/?UI, 0:32,BinOpt/binary>>).
+
+%% @equiv getHeaderValue(This,SzHeader, [])
+-spec getHeaderValue(This, SzHeader) -> unicode:charlist() when
+ This::wxLocale(), SzHeader::unicode:chardata().
+
+getHeaderValue(This,SzHeader)
+ when is_record(This, wx_ref),is_list(SzHeader) ->
+ getHeaderValue(This,SzHeader, []).
+
+%% @doc See <a href="http://www.wxwidgets.org/manuals/2.8.12/wx_wxlocale.html#wxlocalegetheadervalue">external documentation</a>.
+-spec getHeaderValue(This, SzHeader, [Option]) -> unicode:charlist() when
+ This::wxLocale(), SzHeader::unicode:chardata(),
+ Option :: {szDomain, unicode:chardata()}.
+getHeaderValue(#wx_ref{type=ThisT,ref=ThisRef},SzHeader, Options)
+ when is_list(SzHeader),is_list(Options) ->
+ ?CLASS(ThisT,wxLocale),
+ SzHeader_UC = unicode:characters_to_binary([SzHeader,0]),
+ MOpts = fun({szDomain, SzDomain}, Acc) -> SzDomain_UC = unicode:characters_to_binary([SzDomain,0]),[<<1:32/?UI,(byte_size(SzDomain_UC)):32/?UI,(SzDomain_UC)/binary, 0:(((8- ((0+byte_size(SzDomain_UC)) band 16#7)) band 16#7))/unit:8>>|Acc];
+ (BadOpt, _) -> erlang:error({badoption, BadOpt}) end,
+ BinOpt = list_to_binary(lists:foldl(MOpts, [<<0:32>>], Options)),
+ wxe_util:call(?wxLocale_GetHeaderValue,
+ <<ThisRef:32/?UI,(byte_size(SzHeader_UC)):32/?UI,(SzHeader_UC)/binary, 0:(((8- ((0+byte_size(SzHeader_UC)) band 16#7)) band 16#7))/unit:8, BinOpt/binary>>).
+
+%% @doc See <a href="http://www.wxwidgets.org/manuals/2.8.12/wx_wxlocale.html#wxlocalegetsysname">external documentation</a>.
+-spec getSysName(This) -> unicode:charlist() when
+ This::wxLocale().
+getSysName(#wx_ref{type=ThisT,ref=ThisRef}) ->
+ ?CLASS(ThisT,wxLocale),
+ wxe_util:call(?wxLocale_GetSysName,
+ <<ThisRef:32/?UI>>).
+
+%% @doc See <a href="http://www.wxwidgets.org/manuals/2.8.12/wx_wxlocale.html#wxlocalegetsystemencoding">external documentation</a>.
+%%<br /> Res = ?wxFONTENCODING_SYSTEM | ?wxFONTENCODING_DEFAULT | ?wxFONTENCODING_ISO8859_1 | ?wxFONTENCODING_ISO8859_2 | ?wxFONTENCODING_ISO8859_3 | ?wxFONTENCODING_ISO8859_4 | ?wxFONTENCODING_ISO8859_5 | ?wxFONTENCODING_ISO8859_6 | ?wxFONTENCODING_ISO8859_7 | ?wxFONTENCODING_ISO8859_8 | ?wxFONTENCODING_ISO8859_9 | ?wxFONTENCODING_ISO8859_10 | ?wxFONTENCODING_ISO8859_11 | ?wxFONTENCODING_ISO8859_12 | ?wxFONTENCODING_ISO8859_13 | ?wxFONTENCODING_ISO8859_14 | ?wxFONTENCODING_ISO8859_15 | ?wxFONTENCODING_ISO8859_MAX | ?wxFONTENCODING_KOI8 | ?wxFONTENCODING_KOI8_U | ?wxFONTENCODING_ALTERNATIVE | ?wxFONTENCODING_BULGARIAN | ?wxFONTENCODING_CP437 | ?wxFONTENCODING_CP850 | ?wxFONTENCODING_CP852 | ?wxFONTENCODING_CP855 | ?wxFONTENCODING_CP866 | ?wxFONTENCODING_CP874 | ?wxFONTENCODING_CP932 | ?wxFONTENCODING_CP936 | ?wxFONTENCODING_CP949 | ?wxFONTENCODING_CP950 | ?wxFONTENCODING_CP1250 | ?wxFONTENCODING_CP1251 | ?wxFONTENCODING_CP1252 | ?wxFONTENCODING_CP1253 | ?wxFONTENCODING_CP1254 | ?wxFONTENCODING_CP1255 | ?wxFONTENCODING_CP1256 | ?wxFONTENCODING_CP1257 | ?wxFONTENCODING_CP12_MAX | ?wxFONTENCODING_UTF7 | ?wxFONTENCODING_UTF8 | ?wxFONTENCODING_EUC_JP | ?wxFONTENCODING_UTF16BE | ?wxFONTENCODING_UTF16LE | ?wxFONTENCODING_UTF32BE | ?wxFONTENCODING_UTF32LE | ?wxFONTENCODING_MACROMAN | ?wxFONTENCODING_MACJAPANESE | ?wxFONTENCODING_MACCHINESETRAD | ?wxFONTENCODING_MACKOREAN | ?wxFONTENCODING_MACARABIC | ?wxFONTENCODING_MACHEBREW | ?wxFONTENCODING_MACGREEK | ?wxFONTENCODING_MACCYRILLIC | ?wxFONTENCODING_MACDEVANAGARI | ?wxFONTENCODING_MACGURMUKHI | ?wxFONTENCODING_MACGUJARATI | ?wxFONTENCODING_MACORIYA | ?wxFONTENCODING_MACBENGALI | ?wxFONTENCODING_MACTAMIL | ?wxFONTENCODING_MACTELUGU | ?wxFONTENCODING_MACKANNADA | ?wxFONTENCODING_MACMALAJALAM | ?wxFONTENCODING_MACSINHALESE | ?wxFONTENCODING_MACBURMESE | ?wxFONTENCODING_MACKHMER | ?wxFONTENCODING_MACTHAI | ?wxFONTENCODING_MACLAOTIAN | ?wxFONTENCODING_MACGEORGIAN | ?wxFONTENCODING_MACARMENIAN | ?wxFONTENCODING_MACCHINESESIMP | ?wxFONTENCODING_MACTIBETAN | ?wxFONTENCODING_MACMONGOLIAN | ?wxFONTENCODING_MACETHIOPIC | ?wxFONTENCODING_MACCENTRALEUR | ?wxFONTENCODING_MACVIATNAMESE | ?wxFONTENCODING_MACARABICEXT | ?wxFONTENCODING_MACSYMBOL | ?wxFONTENCODING_MACDINGBATS | ?wxFONTENCODING_MACTURKISH | ?wxFONTENCODING_MACCROATIAN | ?wxFONTENCODING_MACICELANDIC | ?wxFONTENCODING_MACROMANIAN | ?wxFONTENCODING_MACCELTIC | ?wxFONTENCODING_MACGAELIC | ?wxFONTENCODING_MACKEYBOARD | ?wxFONTENCODING_MAX | ?wxFONTENCODING_MACMIN | ?wxFONTENCODING_MACMAX | ?wxFONTENCODING_UTF16 | ?wxFONTENCODING_UTF32 | ?wxFONTENCODING_UNICODE | ?wxFONTENCODING_GB2312 | ?wxFONTENCODING_BIG5 | ?wxFONTENCODING_SHIFT_JIS
+-spec getSystemEncoding() -> wx:wx_enum().
+getSystemEncoding() ->
+ wxe_util:call(?wxLocale_GetSystemEncoding,
+ <<>>).
+
+%% @doc See <a href="http://www.wxwidgets.org/manuals/2.8.12/wx_wxlocale.html#wxlocalegetsystemencodingname">external documentation</a>.
+-spec getSystemEncodingName() -> unicode:charlist().
+getSystemEncodingName() ->
+ wxe_util:call(?wxLocale_GetSystemEncodingName,
+ <<>>).
+
+%% @doc See <a href="http://www.wxwidgets.org/manuals/2.8.12/wx_wxlocale.html#wxlocalegetsystemlanguage">external documentation</a>.
+-spec getSystemLanguage() -> integer().
+getSystemLanguage() ->
+ wxe_util:call(?wxLocale_GetSystemLanguage,
+ <<>>).
+
+%% @doc See <a href="http://www.wxwidgets.org/manuals/2.8.12/wx_wxlocale.html#wxlocaleisloaded">external documentation</a>.
+-spec isLoaded(This, SzDomain) -> boolean() when
+ This::wxLocale(), SzDomain::unicode:chardata().
+isLoaded(#wx_ref{type=ThisT,ref=ThisRef},SzDomain)
+ when is_list(SzDomain) ->
+ ?CLASS(ThisT,wxLocale),
+ SzDomain_UC = unicode:characters_to_binary([SzDomain,0]),
+ wxe_util:call(?wxLocale_IsLoaded,
+ <<ThisRef:32/?UI,(byte_size(SzDomain_UC)):32/?UI,(SzDomain_UC)/binary, 0:(((8- ((0+byte_size(SzDomain_UC)) band 16#7)) band 16#7))/unit:8>>).
+
+%% @doc See <a href="http://www.wxwidgets.org/manuals/2.8.12/wx_wxlocale.html#wxlocaleisok">external documentation</a>.
+-spec isOk(This) -> boolean() when
+ This::wxLocale().
+isOk(#wx_ref{type=ThisT,ref=ThisRef}) ->
+ ?CLASS(ThisT,wxLocale),
+ wxe_util:call(?wxLocale_IsOk,
+ <<ThisRef:32/?UI>>).
+
+%% @doc Destroys this object, do not use object again
+-spec destroy(This::wxLocale()) -> ok.
+destroy(Obj=#wx_ref{type=Type}) ->
+ ?CLASS(Type,wxLocale),
+ wxe_util:destroy(?wxLocale_destruct,Obj),
+ ok.
diff --git a/lib/wx/src/gen/wx_misc.erl b/lib/wx/src/gen/wx_misc.erl
index 96912ce651..397d48b727 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-2013. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2014. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -30,6 +30,8 @@
launchDefaultBrowser/2,newId/0,registerId/1,setDetectableAutoRepeat/1,
shell/0,shell/1,shutdown/1]).
+-export([displaySize/0,setCursor/1]).
+
%% @doc See <a href="http://www.wxwidgets.org/manuals/2.8.12/wx_miscellany.html#wxgetkeystate">external documentation</a>.
%%<br /> Key = ?WXK_BACK | ?WXK_TAB | ?WXK_RETURN | ?WXK_ESCAPE | ?WXK_SPACE | ?WXK_DELETE | ?WXK_START | ?WXK_LBUTTON | ?WXK_RBUTTON | ?WXK_CANCEL | ?WXK_MBUTTON | ?WXK_CLEAR | ?WXK_SHIFT | ?WXK_ALT | ?WXK_CONTROL | ?WXK_MENU | ?WXK_PAUSE | ?WXK_CAPITAL | ?WXK_END | ?WXK_HOME | ?WXK_LEFT | ?WXK_UP | ?WXK_RIGHT | ?WXK_DOWN | ?WXK_SELECT | ?WXK_PRINT | ?WXK_EXECUTE | ?WXK_SNAPSHOT | ?WXK_INSERT | ?WXK_HELP | ?WXK_NUMPAD0 | ?WXK_NUMPAD1 | ?WXK_NUMPAD2 | ?WXK_NUMPAD3 | ?WXK_NUMPAD4 | ?WXK_NUMPAD5 | ?WXK_NUMPAD6 | ?WXK_NUMPAD7 | ?WXK_NUMPAD8 | ?WXK_NUMPAD9 | ?WXK_MULTIPLY | ?WXK_ADD | ?WXK_SEPARATOR | ?WXK_SUBTRACT | ?WXK_DECIMAL | ?WXK_DIVIDE | ?WXK_F1 | ?WXK_F2 | ?WXK_F3 | ?WXK_F4 | ?WXK_F5 | ?WXK_F6 | ?WXK_F7 | ?WXK_F8 | ?WXK_F9 | ?WXK_F10 | ?WXK_F11 | ?WXK_F12 | ?WXK_F13 | ?WXK_F14 | ?WXK_F15 | ?WXK_F16 | ?WXK_F17 | ?WXK_F18 | ?WXK_F19 | ?WXK_F20 | ?WXK_F21 | ?WXK_F22 | ?WXK_F23 | ?WXK_F24 | ?WXK_NUMLOCK | ?WXK_SCROLL | ?WXK_PAGEUP | ?WXK_PAGEDOWN | ?WXK_NUMPAD_SPACE | ?WXK_NUMPAD_TAB | ?WXK_NUMPAD_ENTER | ?WXK_NUMPAD_F1 | ?WXK_NUMPAD_F2 | ?WXK_NUMPAD_F3 | ?WXK_NUMPAD_F4 | ?WXK_NUMPAD_HOME | ?WXK_NUMPAD_LEFT | ?WXK_NUMPAD_UP | ?WXK_NUMPAD_RIGHT | ?WXK_NUMPAD_DOWN | ?WXK_NUMPAD_PAGEUP | ?WXK_NUMPAD_PAGEDOWN | ?WXK_NUMPAD_END | ?WXK_NUMPAD_BEGIN | ?WXK_NUMPAD_INSERT | ?WXK_NUMPAD_DELETE | ?WXK_NUMPAD_EQUAL | ?WXK_NUMPAD_MULTIPLY | ?WXK_NUMPAD_ADD | ?WXK_NUMPAD_SEPARATOR | ?WXK_NUMPAD_SUBTRACT | ?WXK_NUMPAD_DECIMAL | ?WXK_NUMPAD_DIVIDE | ?WXK_WINDOWS_LEFT | ?WXK_WINDOWS_RIGHT | ?WXK_WINDOWS_MENU | ?WXK_COMMAND | ?WXK_SPECIAL1 | ?WXK_SPECIAL2 | ?WXK_SPECIAL3 | ?WXK_SPECIAL4 | ?WXK_SPECIAL5 | ?WXK_SPECIAL6 | ?WXK_SPECIAL7 | ?WXK_SPECIAL8 | ?WXK_SPECIAL9 | ?WXK_SPECIAL10 | ?WXK_SPECIAL11 | ?WXK_SPECIAL12 | ?WXK_SPECIAL13 | ?WXK_SPECIAL14 | ?WXK_SPECIAL15 | ?WXK_SPECIAL16 | ?WXK_SPECIAL17 | ?WXK_SPECIAL18 | ?WXK_SPECIAL19 | ?WXK_SPECIAL20
-spec getKeyState(Key) -> boolean() when
@@ -224,3 +226,17 @@ isPlatform64Bit() ->
wxe_util:call(?utils_wxIsPlatform64Bit,
<<>>).
+%% @doc See <a href="http://www.wxwidgets.org/manuals/2.8.12/wx_gdicmn.html#gdicmnwxdisplaysize">external documentation</a>.
+-spec displaySize() -> {Width::integer(), Height::integer()}.
+displaySize() ->
+ wxe_util:call(?gdicmn_wxDisplaySize,
+ <<>>).
+
+%% @doc See <a href="http://www.wxwidgets.org/manuals/2.8.12/wx_gdicmn.html#gdicmnwxsetcursor">external documentation</a>.
+-spec setCursor(Cursor) -> ok when
+ Cursor::wxCursor:wxCursor().
+setCursor(#wx_ref{type=CursorT,ref=CursorRef}) ->
+ ?CLASS(CursorT,wxCursor),
+ wxe_util:cast(?gdicmn_wxSetCursor,
+ <<CursorRef:32/?UI>>).
+
diff --git a/lib/wx/src/gen/wxe_debug.hrl b/lib/wx/src/gen/wxe_debug.hrl
index 1f4f22f704..e208b081e8 100644
--- a/lib/wx/src/gen/wxe_debug.hrl
+++ b/lib/wx/src/gen/wxe_debug.hrl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2013. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2014. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -2709,602 +2709,625 @@ wxdebug_table() ->
{2924, {utils, getOsDescription, 0}},
{2925, {utils, isPlatformLittleEndian, 0}},
{2926, {utils, isPlatform64Bit, 0}},
- {2927, {wxPrintout, new, 1}},
- {2928, {wxPrintout, destruct, 0}},
- {2929, {wxPrintout, getDC, 0}},
- {2930, {wxPrintout, getPageSizeMM, 2}},
- {2931, {wxPrintout, getPageSizePixels, 2}},
- {2932, {wxPrintout, getPaperRectPixels, 0}},
- {2933, {wxPrintout, getPPIPrinter, 2}},
- {2934, {wxPrintout, getPPIScreen, 2}},
- {2935, {wxPrintout, getTitle, 0}},
- {2936, {wxPrintout, isPreview, 0}},
- {2937, {wxPrintout, fitThisSizeToPaper, 1}},
- {2938, {wxPrintout, fitThisSizeToPage, 1}},
- {2939, {wxPrintout, fitThisSizeToPageMargins, 2}},
- {2940, {wxPrintout, mapScreenSizeToPaper, 0}},
- {2941, {wxPrintout, mapScreenSizeToPage, 0}},
- {2942, {wxPrintout, mapScreenSizeToPageMargins, 1}},
- {2943, {wxPrintout, mapScreenSizeToDevice, 0}},
- {2944, {wxPrintout, getLogicalPaperRect, 0}},
- {2945, {wxPrintout, getLogicalPageRect, 0}},
- {2946, {wxPrintout, getLogicalPageMarginsRect, 1}},
- {2947, {wxPrintout, setLogicalOrigin, 2}},
- {2948, {wxPrintout, offsetLogicalOrigin, 2}},
- {2949, {wxStyledTextCtrl, new_2, 2}},
- {2950, {wxStyledTextCtrl, new_0, 0}},
- {2951, {wxStyledTextCtrl, destruct, 0}},
- {2952, {wxStyledTextCtrl, create, 2}},
- {2953, {wxStyledTextCtrl, addText, 1}},
- {2954, {wxStyledTextCtrl, addStyledText, 1}},
- {2955, {wxStyledTextCtrl, insertText, 2}},
- {2956, {wxStyledTextCtrl, clearAll, 0}},
- {2957, {wxStyledTextCtrl, clearDocumentStyle, 0}},
- {2958, {wxStyledTextCtrl, getLength, 0}},
- {2959, {wxStyledTextCtrl, getCharAt, 1}},
- {2960, {wxStyledTextCtrl, getCurrentPos, 0}},
- {2961, {wxStyledTextCtrl, getAnchor, 0}},
- {2962, {wxStyledTextCtrl, getStyleAt, 1}},
- {2963, {wxStyledTextCtrl, redo, 0}},
- {2964, {wxStyledTextCtrl, setUndoCollection, 1}},
- {2965, {wxStyledTextCtrl, selectAll, 0}},
- {2966, {wxStyledTextCtrl, setSavePoint, 0}},
- {2967, {wxStyledTextCtrl, getStyledText, 2}},
- {2968, {wxStyledTextCtrl, canRedo, 0}},
- {2969, {wxStyledTextCtrl, markerLineFromHandle, 1}},
- {2970, {wxStyledTextCtrl, markerDeleteHandle, 1}},
- {2971, {wxStyledTextCtrl, getUndoCollection, 0}},
- {2972, {wxStyledTextCtrl, getViewWhiteSpace, 0}},
- {2973, {wxStyledTextCtrl, setViewWhiteSpace, 1}},
- {2974, {wxStyledTextCtrl, positionFromPoint, 1}},
- {2975, {wxStyledTextCtrl, positionFromPointClose, 2}},
- {2976, {wxStyledTextCtrl, gotoLine, 1}},
- {2977, {wxStyledTextCtrl, gotoPos, 1}},
- {2978, {wxStyledTextCtrl, setAnchor, 1}},
- {2979, {wxStyledTextCtrl, getCurLine, 1}},
- {2980, {wxStyledTextCtrl, getEndStyled, 0}},
- {2981, {wxStyledTextCtrl, convertEOLs, 1}},
- {2982, {wxStyledTextCtrl, getEOLMode, 0}},
- {2983, {wxStyledTextCtrl, setEOLMode, 1}},
- {2984, {wxStyledTextCtrl, startStyling, 2}},
- {2985, {wxStyledTextCtrl, setStyling, 2}},
- {2986, {wxStyledTextCtrl, getBufferedDraw, 0}},
- {2987, {wxStyledTextCtrl, setBufferedDraw, 1}},
- {2988, {wxStyledTextCtrl, setTabWidth, 1}},
- {2989, {wxStyledTextCtrl, getTabWidth, 0}},
- {2990, {wxStyledTextCtrl, setCodePage, 1}},
- {2991, {wxStyledTextCtrl, markerDefine, 3}},
- {2992, {wxStyledTextCtrl, markerSetForeground, 2}},
- {2993, {wxStyledTextCtrl, markerSetBackground, 2}},
- {2994, {wxStyledTextCtrl, markerAdd, 2}},
- {2995, {wxStyledTextCtrl, markerDelete, 2}},
- {2996, {wxStyledTextCtrl, markerDeleteAll, 1}},
- {2997, {wxStyledTextCtrl, markerGet, 1}},
- {2998, {wxStyledTextCtrl, markerNext, 2}},
- {2999, {wxStyledTextCtrl, markerPrevious, 2}},
- {3000, {wxStyledTextCtrl, markerDefineBitmap, 2}},
- {3001, {wxStyledTextCtrl, markerAddSet, 2}},
- {3002, {wxStyledTextCtrl, markerSetAlpha, 2}},
- {3003, {wxStyledTextCtrl, setMarginType, 2}},
- {3004, {wxStyledTextCtrl, getMarginType, 1}},
- {3005, {wxStyledTextCtrl, setMarginWidth, 2}},
- {3006, {wxStyledTextCtrl, getMarginWidth, 1}},
- {3007, {wxStyledTextCtrl, setMarginMask, 2}},
- {3008, {wxStyledTextCtrl, getMarginMask, 1}},
- {3009, {wxStyledTextCtrl, setMarginSensitive, 2}},
- {3010, {wxStyledTextCtrl, getMarginSensitive, 1}},
- {3011, {wxStyledTextCtrl, styleClearAll, 0}},
- {3012, {wxStyledTextCtrl, styleSetForeground, 2}},
- {3013, {wxStyledTextCtrl, styleSetBackground, 2}},
- {3014, {wxStyledTextCtrl, styleSetBold, 2}},
- {3015, {wxStyledTextCtrl, styleSetItalic, 2}},
- {3016, {wxStyledTextCtrl, styleSetSize, 2}},
- {3017, {wxStyledTextCtrl, styleSetFaceName, 2}},
- {3018, {wxStyledTextCtrl, styleSetEOLFilled, 2}},
- {3019, {wxStyledTextCtrl, styleResetDefault, 0}},
- {3020, {wxStyledTextCtrl, styleSetUnderline, 2}},
- {3021, {wxStyledTextCtrl, styleSetCase, 2}},
- {3022, {wxStyledTextCtrl, styleSetHotSpot, 2}},
- {3023, {wxStyledTextCtrl, setSelForeground, 2}},
- {3024, {wxStyledTextCtrl, setSelBackground, 2}},
- {3025, {wxStyledTextCtrl, getSelAlpha, 0}},
- {3026, {wxStyledTextCtrl, setSelAlpha, 1}},
- {3027, {wxStyledTextCtrl, setCaretForeground, 1}},
- {3028, {wxStyledTextCtrl, cmdKeyAssign, 3}},
- {3029, {wxStyledTextCtrl, cmdKeyClear, 2}},
- {3030, {wxStyledTextCtrl, cmdKeyClearAll, 0}},
- {3031, {wxStyledTextCtrl, setStyleBytes, 2}},
- {3032, {wxStyledTextCtrl, styleSetVisible, 2}},
- {3033, {wxStyledTextCtrl, getCaretPeriod, 0}},
- {3034, {wxStyledTextCtrl, setCaretPeriod, 1}},
- {3035, {wxStyledTextCtrl, setWordChars, 1}},
- {3036, {wxStyledTextCtrl, beginUndoAction, 0}},
- {3037, {wxStyledTextCtrl, endUndoAction, 0}},
- {3038, {wxStyledTextCtrl, indicatorSetStyle, 2}},
- {3039, {wxStyledTextCtrl, indicatorGetStyle, 1}},
- {3040, {wxStyledTextCtrl, indicatorSetForeground, 2}},
- {3041, {wxStyledTextCtrl, indicatorGetForeground, 1}},
- {3042, {wxStyledTextCtrl, setWhitespaceForeground, 2}},
- {3043, {wxStyledTextCtrl, setWhitespaceBackground, 2}},
- {3044, {wxStyledTextCtrl, getStyleBits, 0}},
- {3045, {wxStyledTextCtrl, setLineState, 2}},
- {3046, {wxStyledTextCtrl, getLineState, 1}},
- {3047, {wxStyledTextCtrl, getMaxLineState, 0}},
- {3048, {wxStyledTextCtrl, getCaretLineVisible, 0}},
- {3049, {wxStyledTextCtrl, setCaretLineVisible, 1}},
- {3050, {wxStyledTextCtrl, getCaretLineBackground, 0}},
- {3051, {wxStyledTextCtrl, setCaretLineBackground, 1}},
- {3052, {wxStyledTextCtrl, autoCompShow, 2}},
- {3053, {wxStyledTextCtrl, autoCompCancel, 0}},
- {3054, {wxStyledTextCtrl, autoCompActive, 0}},
- {3055, {wxStyledTextCtrl, autoCompPosStart, 0}},
- {3056, {wxStyledTextCtrl, autoCompComplete, 0}},
- {3057, {wxStyledTextCtrl, autoCompStops, 1}},
- {3058, {wxStyledTextCtrl, autoCompSetSeparator, 1}},
- {3059, {wxStyledTextCtrl, autoCompGetSeparator, 0}},
- {3060, {wxStyledTextCtrl, autoCompSelect, 1}},
- {3061, {wxStyledTextCtrl, autoCompSetCancelAtStart, 1}},
- {3062, {wxStyledTextCtrl, autoCompGetCancelAtStart, 0}},
- {3063, {wxStyledTextCtrl, autoCompSetFillUps, 1}},
- {3064, {wxStyledTextCtrl, autoCompSetChooseSingle, 1}},
- {3065, {wxStyledTextCtrl, autoCompGetChooseSingle, 0}},
- {3066, {wxStyledTextCtrl, autoCompSetIgnoreCase, 1}},
- {3067, {wxStyledTextCtrl, autoCompGetIgnoreCase, 0}},
- {3068, {wxStyledTextCtrl, userListShow, 2}},
- {3069, {wxStyledTextCtrl, autoCompSetAutoHide, 1}},
- {3070, {wxStyledTextCtrl, autoCompGetAutoHide, 0}},
- {3071, {wxStyledTextCtrl, autoCompSetDropRestOfWord, 1}},
- {3072, {wxStyledTextCtrl, autoCompGetDropRestOfWord, 0}},
- {3073, {wxStyledTextCtrl, registerImage, 2}},
- {3074, {wxStyledTextCtrl, clearRegisteredImages, 0}},
- {3075, {wxStyledTextCtrl, autoCompGetTypeSeparator, 0}},
- {3076, {wxStyledTextCtrl, autoCompSetTypeSeparator, 1}},
- {3077, {wxStyledTextCtrl, autoCompSetMaxWidth, 1}},
- {3078, {wxStyledTextCtrl, autoCompGetMaxWidth, 0}},
- {3079, {wxStyledTextCtrl, autoCompSetMaxHeight, 1}},
- {3080, {wxStyledTextCtrl, autoCompGetMaxHeight, 0}},
- {3081, {wxStyledTextCtrl, setIndent, 1}},
- {3082, {wxStyledTextCtrl, getIndent, 0}},
- {3083, {wxStyledTextCtrl, setUseTabs, 1}},
- {3084, {wxStyledTextCtrl, getUseTabs, 0}},
- {3085, {wxStyledTextCtrl, setLineIndentation, 2}},
- {3086, {wxStyledTextCtrl, getLineIndentation, 1}},
- {3087, {wxStyledTextCtrl, getLineIndentPosition, 1}},
- {3088, {wxStyledTextCtrl, getColumn, 1}},
- {3089, {wxStyledTextCtrl, setUseHorizontalScrollBar, 1}},
- {3090, {wxStyledTextCtrl, getUseHorizontalScrollBar, 0}},
- {3091, {wxStyledTextCtrl, setIndentationGuides, 1}},
- {3092, {wxStyledTextCtrl, getIndentationGuides, 0}},
- {3093, {wxStyledTextCtrl, setHighlightGuide, 1}},
- {3094, {wxStyledTextCtrl, getHighlightGuide, 0}},
- {3095, {wxStyledTextCtrl, getLineEndPosition, 1}},
- {3096, {wxStyledTextCtrl, getCodePage, 0}},
- {3097, {wxStyledTextCtrl, getCaretForeground, 0}},
- {3098, {wxStyledTextCtrl, getReadOnly, 0}},
- {3099, {wxStyledTextCtrl, setCurrentPos, 1}},
- {3100, {wxStyledTextCtrl, setSelectionStart, 1}},
- {3101, {wxStyledTextCtrl, getSelectionStart, 0}},
- {3102, {wxStyledTextCtrl, setSelectionEnd, 1}},
- {3103, {wxStyledTextCtrl, getSelectionEnd, 0}},
- {3104, {wxStyledTextCtrl, setPrintMagnification, 1}},
- {3105, {wxStyledTextCtrl, getPrintMagnification, 0}},
- {3106, {wxStyledTextCtrl, setPrintColourMode, 1}},
- {3107, {wxStyledTextCtrl, getPrintColourMode, 0}},
- {3108, {wxStyledTextCtrl, findText, 4}},
- {3109, {wxStyledTextCtrl, formatRange, 7}},
- {3110, {wxStyledTextCtrl, getFirstVisibleLine, 0}},
- {3111, {wxStyledTextCtrl, getLine, 1}},
- {3112, {wxStyledTextCtrl, getLineCount, 0}},
- {3113, {wxStyledTextCtrl, setMarginLeft, 1}},
- {3114, {wxStyledTextCtrl, getMarginLeft, 0}},
- {3115, {wxStyledTextCtrl, setMarginRight, 1}},
- {3116, {wxStyledTextCtrl, getMarginRight, 0}},
- {3117, {wxStyledTextCtrl, getModify, 0}},
- {3118, {wxStyledTextCtrl, setSelection, 2}},
- {3119, {wxStyledTextCtrl, getSelectedText, 0}},
- {3120, {wxStyledTextCtrl, getTextRange, 2}},
- {3121, {wxStyledTextCtrl, hideSelection, 1}},
- {3122, {wxStyledTextCtrl, lineFromPosition, 1}},
- {3123, {wxStyledTextCtrl, positionFromLine, 1}},
- {3124, {wxStyledTextCtrl, lineScroll, 2}},
- {3125, {wxStyledTextCtrl, ensureCaretVisible, 0}},
- {3126, {wxStyledTextCtrl, replaceSelection, 1}},
- {3127, {wxStyledTextCtrl, setReadOnly, 1}},
- {3128, {wxStyledTextCtrl, canPaste, 0}},
- {3129, {wxStyledTextCtrl, canUndo, 0}},
- {3130, {wxStyledTextCtrl, emptyUndoBuffer, 0}},
- {3131, {wxStyledTextCtrl, undo, 0}},
- {3132, {wxStyledTextCtrl, cut, 0}},
- {3133, {wxStyledTextCtrl, copy, 0}},
- {3134, {wxStyledTextCtrl, paste, 0}},
- {3135, {wxStyledTextCtrl, clear, 0}},
- {3136, {wxStyledTextCtrl, setText, 1}},
- {3137, {wxStyledTextCtrl, getText, 0}},
- {3138, {wxStyledTextCtrl, getTextLength, 0}},
- {3139, {wxStyledTextCtrl, getOvertype, 0}},
- {3140, {wxStyledTextCtrl, setCaretWidth, 1}},
- {3141, {wxStyledTextCtrl, getCaretWidth, 0}},
- {3142, {wxStyledTextCtrl, setTargetStart, 1}},
- {3143, {wxStyledTextCtrl, getTargetStart, 0}},
- {3144, {wxStyledTextCtrl, setTargetEnd, 1}},
- {3145, {wxStyledTextCtrl, getTargetEnd, 0}},
- {3146, {wxStyledTextCtrl, replaceTarget, 1}},
- {3147, {wxStyledTextCtrl, searchInTarget, 1}},
- {3148, {wxStyledTextCtrl, setSearchFlags, 1}},
- {3149, {wxStyledTextCtrl, getSearchFlags, 0}},
- {3150, {wxStyledTextCtrl, callTipShow, 2}},
- {3151, {wxStyledTextCtrl, callTipCancel, 0}},
- {3152, {wxStyledTextCtrl, callTipActive, 0}},
- {3153, {wxStyledTextCtrl, callTipPosAtStart, 0}},
- {3154, {wxStyledTextCtrl, callTipSetHighlight, 2}},
- {3155, {wxStyledTextCtrl, callTipSetBackground, 1}},
- {3156, {wxStyledTextCtrl, callTipSetForeground, 1}},
- {3157, {wxStyledTextCtrl, callTipSetForegroundHighlight, 1}},
- {3158, {wxStyledTextCtrl, callTipUseStyle, 1}},
- {3159, {wxStyledTextCtrl, visibleFromDocLine, 1}},
- {3160, {wxStyledTextCtrl, docLineFromVisible, 1}},
- {3161, {wxStyledTextCtrl, wrapCount, 1}},
- {3162, {wxStyledTextCtrl, setFoldLevel, 2}},
- {3163, {wxStyledTextCtrl, getFoldLevel, 1}},
- {3164, {wxStyledTextCtrl, getLastChild, 2}},
- {3165, {wxStyledTextCtrl, getFoldParent, 1}},
- {3166, {wxStyledTextCtrl, showLines, 2}},
- {3167, {wxStyledTextCtrl, hideLines, 2}},
- {3168, {wxStyledTextCtrl, getLineVisible, 1}},
- {3169, {wxStyledTextCtrl, setFoldExpanded, 2}},
- {3170, {wxStyledTextCtrl, getFoldExpanded, 1}},
- {3171, {wxStyledTextCtrl, toggleFold, 1}},
- {3172, {wxStyledTextCtrl, ensureVisible, 1}},
- {3173, {wxStyledTextCtrl, setFoldFlags, 1}},
- {3174, {wxStyledTextCtrl, ensureVisibleEnforcePolicy, 1}},
- {3175, {wxStyledTextCtrl, setTabIndents, 1}},
- {3176, {wxStyledTextCtrl, getTabIndents, 0}},
- {3177, {wxStyledTextCtrl, setBackSpaceUnIndents, 1}},
- {3178, {wxStyledTextCtrl, getBackSpaceUnIndents, 0}},
- {3179, {wxStyledTextCtrl, setMouseDwellTime, 1}},
- {3180, {wxStyledTextCtrl, getMouseDwellTime, 0}},
- {3181, {wxStyledTextCtrl, wordStartPosition, 2}},
- {3182, {wxStyledTextCtrl, wordEndPosition, 2}},
- {3183, {wxStyledTextCtrl, setWrapMode, 1}},
- {3184, {wxStyledTextCtrl, getWrapMode, 0}},
- {3185, {wxStyledTextCtrl, setWrapVisualFlags, 1}},
- {3186, {wxStyledTextCtrl, getWrapVisualFlags, 0}},
- {3187, {wxStyledTextCtrl, setWrapVisualFlagsLocation, 1}},
- {3188, {wxStyledTextCtrl, getWrapVisualFlagsLocation, 0}},
- {3189, {wxStyledTextCtrl, setWrapStartIndent, 1}},
- {3190, {wxStyledTextCtrl, getWrapStartIndent, 0}},
- {3191, {wxStyledTextCtrl, setLayoutCache, 1}},
- {3192, {wxStyledTextCtrl, getLayoutCache, 0}},
- {3193, {wxStyledTextCtrl, setScrollWidth, 1}},
- {3194, {wxStyledTextCtrl, getScrollWidth, 0}},
- {3195, {wxStyledTextCtrl, textWidth, 2}},
- {3196, {wxStyledTextCtrl, getEndAtLastLine, 0}},
- {3197, {wxStyledTextCtrl, textHeight, 1}},
- {3198, {wxStyledTextCtrl, setUseVerticalScrollBar, 1}},
- {3199, {wxStyledTextCtrl, getUseVerticalScrollBar, 0}},
- {3200, {wxStyledTextCtrl, appendText, 1}},
- {3201, {wxStyledTextCtrl, getTwoPhaseDraw, 0}},
- {3202, {wxStyledTextCtrl, setTwoPhaseDraw, 1}},
- {3203, {wxStyledTextCtrl, targetFromSelection, 0}},
- {3204, {wxStyledTextCtrl, linesJoin, 0}},
- {3205, {wxStyledTextCtrl, linesSplit, 1}},
- {3206, {wxStyledTextCtrl, setFoldMarginColour, 2}},
- {3207, {wxStyledTextCtrl, setFoldMarginHiColour, 2}},
- {3208, {wxStyledTextCtrl, lineDown, 0}},
- {3209, {wxStyledTextCtrl, lineDownExtend, 0}},
- {3210, {wxStyledTextCtrl, lineUp, 0}},
- {3211, {wxStyledTextCtrl, lineUpExtend, 0}},
- {3212, {wxStyledTextCtrl, charLeft, 0}},
- {3213, {wxStyledTextCtrl, charLeftExtend, 0}},
- {3214, {wxStyledTextCtrl, charRight, 0}},
- {3215, {wxStyledTextCtrl, charRightExtend, 0}},
- {3216, {wxStyledTextCtrl, wordLeft, 0}},
- {3217, {wxStyledTextCtrl, wordLeftExtend, 0}},
- {3218, {wxStyledTextCtrl, wordRight, 0}},
- {3219, {wxStyledTextCtrl, wordRightExtend, 0}},
- {3220, {wxStyledTextCtrl, home, 0}},
- {3221, {wxStyledTextCtrl, homeExtend, 0}},
- {3222, {wxStyledTextCtrl, lineEnd, 0}},
- {3223, {wxStyledTextCtrl, lineEndExtend, 0}},
- {3224, {wxStyledTextCtrl, documentStart, 0}},
- {3225, {wxStyledTextCtrl, documentStartExtend, 0}},
- {3226, {wxStyledTextCtrl, documentEnd, 0}},
- {3227, {wxStyledTextCtrl, documentEndExtend, 0}},
- {3228, {wxStyledTextCtrl, pageUp, 0}},
- {3229, {wxStyledTextCtrl, pageUpExtend, 0}},
- {3230, {wxStyledTextCtrl, pageDown, 0}},
- {3231, {wxStyledTextCtrl, pageDownExtend, 0}},
- {3232, {wxStyledTextCtrl, editToggleOvertype, 0}},
- {3233, {wxStyledTextCtrl, cancel, 0}},
- {3234, {wxStyledTextCtrl, deleteBack, 0}},
- {3235, {wxStyledTextCtrl, tab, 0}},
- {3236, {wxStyledTextCtrl, backTab, 0}},
- {3237, {wxStyledTextCtrl, newLine, 0}},
- {3238, {wxStyledTextCtrl, formFeed, 0}},
- {3239, {wxStyledTextCtrl, vCHome, 0}},
- {3240, {wxStyledTextCtrl, vCHomeExtend, 0}},
- {3241, {wxStyledTextCtrl, zoomIn, 0}},
- {3242, {wxStyledTextCtrl, zoomOut, 0}},
- {3243, {wxStyledTextCtrl, delWordLeft, 0}},
- {3244, {wxStyledTextCtrl, delWordRight, 0}},
- {3245, {wxStyledTextCtrl, lineCut, 0}},
- {3246, {wxStyledTextCtrl, lineDelete, 0}},
- {3247, {wxStyledTextCtrl, lineTranspose, 0}},
- {3248, {wxStyledTextCtrl, lineDuplicate, 0}},
- {3249, {wxStyledTextCtrl, lowerCase, 0}},
- {3250, {wxStyledTextCtrl, upperCase, 0}},
- {3251, {wxStyledTextCtrl, lineScrollDown, 0}},
- {3252, {wxStyledTextCtrl, lineScrollUp, 0}},
- {3253, {wxStyledTextCtrl, deleteBackNotLine, 0}},
- {3254, {wxStyledTextCtrl, homeDisplay, 0}},
- {3255, {wxStyledTextCtrl, homeDisplayExtend, 0}},
- {3256, {wxStyledTextCtrl, lineEndDisplay, 0}},
- {3257, {wxStyledTextCtrl, lineEndDisplayExtend, 0}},
- {3258, {wxStyledTextCtrl, homeWrapExtend, 0}},
- {3259, {wxStyledTextCtrl, lineEndWrap, 0}},
- {3260, {wxStyledTextCtrl, lineEndWrapExtend, 0}},
- {3261, {wxStyledTextCtrl, vCHomeWrap, 0}},
- {3262, {wxStyledTextCtrl, vCHomeWrapExtend, 0}},
- {3263, {wxStyledTextCtrl, lineCopy, 0}},
- {3264, {wxStyledTextCtrl, moveCaretInsideView, 0}},
- {3265, {wxStyledTextCtrl, lineLength, 1}},
- {3266, {wxStyledTextCtrl, braceHighlight, 2}},
- {3267, {wxStyledTextCtrl, braceBadLight, 1}},
- {3268, {wxStyledTextCtrl, braceMatch, 1}},
- {3269, {wxStyledTextCtrl, getViewEOL, 0}},
- {3270, {wxStyledTextCtrl, setViewEOL, 1}},
- {3271, {wxStyledTextCtrl, setModEventMask, 1}},
- {3272, {wxStyledTextCtrl, getEdgeColumn, 0}},
- {3273, {wxStyledTextCtrl, setEdgeColumn, 1}},
- {3274, {wxStyledTextCtrl, setEdgeMode, 1}},
- {3275, {wxStyledTextCtrl, getEdgeMode, 0}},
- {3276, {wxStyledTextCtrl, getEdgeColour, 0}},
- {3277, {wxStyledTextCtrl, setEdgeColour, 1}},
- {3278, {wxStyledTextCtrl, searchAnchor, 0}},
- {3279, {wxStyledTextCtrl, searchNext, 2}},
- {3280, {wxStyledTextCtrl, searchPrev, 2}},
- {3281, {wxStyledTextCtrl, linesOnScreen, 0}},
- {3282, {wxStyledTextCtrl, usePopUp, 1}},
- {3283, {wxStyledTextCtrl, selectionIsRectangle, 0}},
- {3284, {wxStyledTextCtrl, setZoom, 1}},
- {3285, {wxStyledTextCtrl, getZoom, 0}},
- {3286, {wxStyledTextCtrl, getModEventMask, 0}},
- {3287, {wxStyledTextCtrl, setSTCFocus, 1}},
- {3288, {wxStyledTextCtrl, getSTCFocus, 0}},
- {3289, {wxStyledTextCtrl, setStatus, 1}},
- {3290, {wxStyledTextCtrl, getStatus, 0}},
- {3291, {wxStyledTextCtrl, setMouseDownCaptures, 1}},
- {3292, {wxStyledTextCtrl, getMouseDownCaptures, 0}},
- {3293, {wxStyledTextCtrl, setSTCCursor, 1}},
- {3294, {wxStyledTextCtrl, getSTCCursor, 0}},
- {3295, {wxStyledTextCtrl, setControlCharSymbol, 1}},
- {3296, {wxStyledTextCtrl, getControlCharSymbol, 0}},
- {3297, {wxStyledTextCtrl, wordPartLeft, 0}},
- {3298, {wxStyledTextCtrl, wordPartLeftExtend, 0}},
- {3299, {wxStyledTextCtrl, wordPartRight, 0}},
- {3300, {wxStyledTextCtrl, wordPartRightExtend, 0}},
- {3301, {wxStyledTextCtrl, setVisiblePolicy, 2}},
- {3302, {wxStyledTextCtrl, delLineLeft, 0}},
- {3303, {wxStyledTextCtrl, delLineRight, 0}},
- {3304, {wxStyledTextCtrl, getXOffset, 0}},
- {3305, {wxStyledTextCtrl, chooseCaretX, 0}},
- {3306, {wxStyledTextCtrl, setXCaretPolicy, 2}},
- {3307, {wxStyledTextCtrl, setYCaretPolicy, 2}},
- {3308, {wxStyledTextCtrl, getPrintWrapMode, 0}},
- {3309, {wxStyledTextCtrl, setHotspotActiveForeground, 2}},
- {3310, {wxStyledTextCtrl, setHotspotActiveBackground, 2}},
- {3311, {wxStyledTextCtrl, setHotspotActiveUnderline, 1}},
- {3312, {wxStyledTextCtrl, setHotspotSingleLine, 1}},
- {3313, {wxStyledTextCtrl, paraDownExtend, 0}},
- {3314, {wxStyledTextCtrl, paraUp, 0}},
- {3315, {wxStyledTextCtrl, paraUpExtend, 0}},
- {3316, {wxStyledTextCtrl, positionBefore, 1}},
- {3317, {wxStyledTextCtrl, positionAfter, 1}},
- {3318, {wxStyledTextCtrl, copyRange, 2}},
- {3319, {wxStyledTextCtrl, copyText, 2}},
- {3320, {wxStyledTextCtrl, setSelectionMode, 1}},
- {3321, {wxStyledTextCtrl, getSelectionMode, 0}},
- {3322, {wxStyledTextCtrl, lineDownRectExtend, 0}},
- {3323, {wxStyledTextCtrl, lineUpRectExtend, 0}},
- {3324, {wxStyledTextCtrl, charLeftRectExtend, 0}},
- {3325, {wxStyledTextCtrl, charRightRectExtend, 0}},
- {3326, {wxStyledTextCtrl, homeRectExtend, 0}},
- {3327, {wxStyledTextCtrl, vCHomeRectExtend, 0}},
- {3328, {wxStyledTextCtrl, lineEndRectExtend, 0}},
- {3329, {wxStyledTextCtrl, pageUpRectExtend, 0}},
- {3330, {wxStyledTextCtrl, pageDownRectExtend, 0}},
- {3331, {wxStyledTextCtrl, stutteredPageUp, 0}},
- {3332, {wxStyledTextCtrl, stutteredPageUpExtend, 0}},
- {3333, {wxStyledTextCtrl, stutteredPageDown, 0}},
- {3334, {wxStyledTextCtrl, stutteredPageDownExtend, 0}},
- {3335, {wxStyledTextCtrl, wordLeftEnd, 0}},
- {3336, {wxStyledTextCtrl, wordLeftEndExtend, 0}},
- {3337, {wxStyledTextCtrl, wordRightEnd, 0}},
- {3338, {wxStyledTextCtrl, wordRightEndExtend, 0}},
- {3339, {wxStyledTextCtrl, setWhitespaceChars, 1}},
- {3340, {wxStyledTextCtrl, setCharsDefault, 0}},
- {3341, {wxStyledTextCtrl, autoCompGetCurrent, 0}},
- {3342, {wxStyledTextCtrl, allocate, 1}},
- {3343, {wxStyledTextCtrl, findColumn, 2}},
- {3344, {wxStyledTextCtrl, getCaretSticky, 0}},
- {3345, {wxStyledTextCtrl, setCaretSticky, 1}},
- {3346, {wxStyledTextCtrl, toggleCaretSticky, 0}},
- {3347, {wxStyledTextCtrl, setPasteConvertEndings, 1}},
- {3348, {wxStyledTextCtrl, getPasteConvertEndings, 0}},
- {3349, {wxStyledTextCtrl, selectionDuplicate, 0}},
- {3350, {wxStyledTextCtrl, setCaretLineBackAlpha, 1}},
- {3351, {wxStyledTextCtrl, getCaretLineBackAlpha, 0}},
- {3352, {wxStyledTextCtrl, startRecord, 0}},
- {3353, {wxStyledTextCtrl, stopRecord, 0}},
- {3354, {wxStyledTextCtrl, setLexer, 1}},
- {3355, {wxStyledTextCtrl, getLexer, 0}},
- {3356, {wxStyledTextCtrl, colourise, 2}},
- {3357, {wxStyledTextCtrl, setProperty, 2}},
- {3358, {wxStyledTextCtrl, setKeyWords, 2}},
- {3359, {wxStyledTextCtrl, setLexerLanguage, 1}},
- {3360, {wxStyledTextCtrl, getProperty, 1}},
- {3361, {wxStyledTextCtrl, getStyleBitsNeeded, 0}},
- {3362, {wxStyledTextCtrl, getCurrentLine, 0}},
- {3363, {wxStyledTextCtrl, styleSetSpec, 2}},
- {3364, {wxStyledTextCtrl, styleSetFont, 2}},
- {3365, {wxStyledTextCtrl, styleSetFontAttr, 7}},
- {3366, {wxStyledTextCtrl, styleSetCharacterSet, 2}},
- {3367, {wxStyledTextCtrl, styleSetFontEncoding, 2}},
- {3368, {wxStyledTextCtrl, cmdKeyExecute, 1}},
- {3369, {wxStyledTextCtrl, setMargins, 2}},
- {3370, {wxStyledTextCtrl, getSelection, 2}},
- {3371, {wxStyledTextCtrl, pointFromPosition, 1}},
- {3372, {wxStyledTextCtrl, scrollToLine, 1}},
- {3373, {wxStyledTextCtrl, scrollToColumn, 1}},
- {3374, {wxStyledTextCtrl, setVScrollBar, 1}},
- {3375, {wxStyledTextCtrl, setHScrollBar, 1}},
- {3376, {wxStyledTextCtrl, getLastKeydownProcessed, 0}},
- {3377, {wxStyledTextCtrl, setLastKeydownProcessed, 1}},
- {3378, {wxStyledTextCtrl, saveFile, 1}},
- {3379, {wxStyledTextCtrl, loadFile, 1}},
- {3380, {wxStyledTextCtrl, doDragOver, 3}},
- {3381, {wxStyledTextCtrl, doDropText, 3}},
- {3382, {wxStyledTextCtrl, getUseAntiAliasing, 0}},
- {3383, {wxStyledTextCtrl, addTextRaw, 1}},
- {3384, {wxStyledTextCtrl, insertTextRaw, 2}},
- {3385, {wxStyledTextCtrl, getCurLineRaw, 1}},
- {3386, {wxStyledTextCtrl, getLineRaw, 1}},
- {3387, {wxStyledTextCtrl, getSelectedTextRaw, 0}},
- {3388, {wxStyledTextCtrl, getTextRangeRaw, 2}},
- {3389, {wxStyledTextCtrl, setTextRaw, 1}},
- {3390, {wxStyledTextCtrl, getTextRaw, 0}},
- {3391, {wxStyledTextCtrl, appendTextRaw, 1}},
- {3392, {wxArtProvider, getBitmap, 2}},
- {3393, {wxArtProvider, getIcon, 2}},
- {3394, {wxTreeEvent, getKeyCode, 0}},
- {3395, {wxTreeEvent, getItem, 0}},
- {3396, {wxTreeEvent, getKeyEvent, 0}},
- {3397, {wxTreeEvent, getLabel, 0}},
- {3398, {wxTreeEvent, getOldItem, 0}},
- {3399, {wxTreeEvent, getPoint, 0}},
- {3400, {wxTreeEvent, isEditCancelled, 0}},
- {3401, {wxTreeEvent, setToolTip, 1}},
- {3402, {wxNotebookEvent, getOldSelection, 0}},
- {3403, {wxNotebookEvent, getSelection, 0}},
- {3404, {wxNotebookEvent, setOldSelection, 1}},
- {3405, {wxNotebookEvent, setSelection, 1}},
- {3406, {wxFileDataObject, new, 0}},
- {3407, {wxFileDataObject, addFile, 1}},
- {3408, {wxFileDataObject, getFilenames, 0}},
- {3409, {wxFileDataObject, 'Destroy', undefined}},
- {3410, {wxTextDataObject, new, 1}},
- {3411, {wxTextDataObject, getTextLength, 0}},
- {3412, {wxTextDataObject, getText, 0}},
- {3413, {wxTextDataObject, setText, 1}},
- {3414, {wxTextDataObject, 'Destroy', undefined}},
- {3415, {wxBitmapDataObject, new_1_1, 1}},
- {3416, {wxBitmapDataObject, new_1_0, 1}},
- {3417, {wxBitmapDataObject, getBitmap, 0}},
- {3418, {wxBitmapDataObject, setBitmap, 1}},
- {3419, {wxBitmapDataObject, 'Destroy', undefined}},
- {3421, {wxClipboard, new, 0}},
- {3422, {wxClipboard, destruct, 0}},
- {3423, {wxClipboard, addData, 1}},
- {3424, {wxClipboard, clear, 0}},
- {3425, {wxClipboard, close, 0}},
- {3426, {wxClipboard, flush, 0}},
- {3427, {wxClipboard, getData, 1}},
- {3428, {wxClipboard, isOpened, 0}},
- {3429, {wxClipboard, open, 0}},
- {3430, {wxClipboard, setData, 1}},
- {3432, {wxClipboard, usePrimarySelection, 1}},
- {3433, {wxClipboard, isSupported, 1}},
- {3434, {wxClipboard, get, 0}},
- {3435, {wxSpinEvent, getPosition, 0}},
- {3436, {wxSpinEvent, setPosition, 1}},
- {3437, {wxSplitterWindow, new_0, 0}},
- {3438, {wxSplitterWindow, new_2, 2}},
- {3439, {wxSplitterWindow, destruct, 0}},
- {3440, {wxSplitterWindow, create, 2}},
- {3441, {wxSplitterWindow, getMinimumPaneSize, 0}},
- {3442, {wxSplitterWindow, getSashGravity, 0}},
- {3443, {wxSplitterWindow, getSashPosition, 0}},
- {3444, {wxSplitterWindow, getSplitMode, 0}},
- {3445, {wxSplitterWindow, getWindow1, 0}},
- {3446, {wxSplitterWindow, getWindow2, 0}},
- {3447, {wxSplitterWindow, initialize, 1}},
- {3448, {wxSplitterWindow, isSplit, 0}},
- {3449, {wxSplitterWindow, replaceWindow, 2}},
- {3450, {wxSplitterWindow, setSashGravity, 1}},
- {3451, {wxSplitterWindow, setSashPosition, 2}},
- {3452, {wxSplitterWindow, setSashSize, 1}},
- {3453, {wxSplitterWindow, setMinimumPaneSize, 1}},
- {3454, {wxSplitterWindow, setSplitMode, 1}},
- {3455, {wxSplitterWindow, splitHorizontally, 3}},
- {3456, {wxSplitterWindow, splitVertically, 3}},
- {3457, {wxSplitterWindow, unsplit, 1}},
- {3458, {wxSplitterWindow, updateSize, 0}},
- {3459, {wxSplitterEvent, getSashPosition, 0}},
- {3460, {wxSplitterEvent, getX, 0}},
- {3461, {wxSplitterEvent, getY, 0}},
- {3462, {wxSplitterEvent, getWindowBeingRemoved, 0}},
- {3463, {wxSplitterEvent, setSashPosition, 1}},
- {3464, {wxHtmlWindow, new_0, 0}},
- {3465, {wxHtmlWindow, new_2, 2}},
- {3466, {wxHtmlWindow, appendToPage, 1}},
- {3467, {wxHtmlWindow, getOpenedAnchor, 0}},
- {3468, {wxHtmlWindow, getOpenedPage, 0}},
- {3469, {wxHtmlWindow, getOpenedPageTitle, 0}},
- {3470, {wxHtmlWindow, getRelatedFrame, 0}},
- {3471, {wxHtmlWindow, historyBack, 0}},
- {3472, {wxHtmlWindow, historyCanBack, 0}},
- {3473, {wxHtmlWindow, historyCanForward, 0}},
- {3474, {wxHtmlWindow, historyClear, 0}},
- {3475, {wxHtmlWindow, historyForward, 0}},
- {3476, {wxHtmlWindow, loadFile, 1}},
- {3477, {wxHtmlWindow, loadPage, 1}},
- {3478, {wxHtmlWindow, selectAll, 0}},
- {3479, {wxHtmlWindow, selectionToText, 0}},
- {3480, {wxHtmlWindow, selectLine, 1}},
- {3481, {wxHtmlWindow, selectWord, 1}},
- {3482, {wxHtmlWindow, setBorders, 1}},
- {3483, {wxHtmlWindow, setFonts, 3}},
- {3484, {wxHtmlWindow, setPage, 1}},
- {3485, {wxHtmlWindow, setRelatedFrame, 2}},
- {3486, {wxHtmlWindow, setRelatedStatusBar, 1}},
- {3487, {wxHtmlWindow, toText, 0}},
- {3488, {wxHtmlWindow, 'Destroy', undefined}},
- {3489, {wxHtmlLinkEvent, getLinkInfo, 0}},
- {3490, {wxSystemSettings, getColour, 1}},
- {3491, {wxSystemSettings, getFont, 1}},
- {3492, {wxSystemSettings, getMetric, 2}},
- {3493, {wxSystemSettings, getScreenType, 0}},
- {3494, {wxSystemOptions, getOption, 1}},
- {3495, {wxSystemOptions, getOptionInt, 1}},
- {3496, {wxSystemOptions, hasOption, 1}},
- {3497, {wxSystemOptions, isFalse, 1}},
- {3498, {wxSystemOptions, setOption_2_1, 2}},
- {3499, {wxSystemOptions, setOption_2_0, 2}},
- {3500, {wxAuiNotebookEvent, setSelection, 1}},
- {3501, {wxAuiNotebookEvent, getSelection, 0}},
- {3502, {wxAuiNotebookEvent, setOldSelection, 1}},
- {3503, {wxAuiNotebookEvent, getOldSelection, 0}},
- {3504, {wxAuiNotebookEvent, setDragSource, 1}},
- {3505, {wxAuiNotebookEvent, getDragSource, 0}},
- {3506, {wxAuiManagerEvent, setManager, 1}},
- {3507, {wxAuiManagerEvent, getManager, 0}},
- {3508, {wxAuiManagerEvent, setPane, 1}},
- {3509, {wxAuiManagerEvent, getPane, 0}},
- {3510, {wxAuiManagerEvent, setButton, 1}},
- {3511, {wxAuiManagerEvent, getButton, 0}},
- {3512, {wxAuiManagerEvent, setDC, 1}},
- {3513, {wxAuiManagerEvent, getDC, 0}},
- {3514, {wxAuiManagerEvent, veto, 1}},
- {3515, {wxAuiManagerEvent, getVeto, 0}},
- {3516, {wxAuiManagerEvent, setCanVeto, 1}},
- {3517, {wxAuiManagerEvent, canVeto, 0}},
- {3518, {wxLogNull, new, 0}},
- {3519, {wxLogNull, 'Destroy', undefined}},
- {3520, {wxTaskBarIcon, new, 0}},
- {3521, {wxTaskBarIcon, destruct, 0}},
- {3522, {wxTaskBarIcon, popupMenu, 1}},
- {3523, {wxTaskBarIcon, removeIcon, 0}},
- {3524, {wxTaskBarIcon, setIcon, 2}},
+ {2927, {gdicmn, displaySize, 2}},
+ {2928, {gdicmn, setCursor, 1}},
+ {2929, {wxPrintout, new, 1}},
+ {2930, {wxPrintout, destruct, 0}},
+ {2931, {wxPrintout, getDC, 0}},
+ {2932, {wxPrintout, getPageSizeMM, 2}},
+ {2933, {wxPrintout, getPageSizePixels, 2}},
+ {2934, {wxPrintout, getPaperRectPixels, 0}},
+ {2935, {wxPrintout, getPPIPrinter, 2}},
+ {2936, {wxPrintout, getPPIScreen, 2}},
+ {2937, {wxPrintout, getTitle, 0}},
+ {2938, {wxPrintout, isPreview, 0}},
+ {2939, {wxPrintout, fitThisSizeToPaper, 1}},
+ {2940, {wxPrintout, fitThisSizeToPage, 1}},
+ {2941, {wxPrintout, fitThisSizeToPageMargins, 2}},
+ {2942, {wxPrintout, mapScreenSizeToPaper, 0}},
+ {2943, {wxPrintout, mapScreenSizeToPage, 0}},
+ {2944, {wxPrintout, mapScreenSizeToPageMargins, 1}},
+ {2945, {wxPrintout, mapScreenSizeToDevice, 0}},
+ {2946, {wxPrintout, getLogicalPaperRect, 0}},
+ {2947, {wxPrintout, getLogicalPageRect, 0}},
+ {2948, {wxPrintout, getLogicalPageMarginsRect, 1}},
+ {2949, {wxPrintout, setLogicalOrigin, 2}},
+ {2950, {wxPrintout, offsetLogicalOrigin, 2}},
+ {2951, {wxStyledTextCtrl, new_2, 2}},
+ {2952, {wxStyledTextCtrl, new_0, 0}},
+ {2953, {wxStyledTextCtrl, destruct, 0}},
+ {2954, {wxStyledTextCtrl, create, 2}},
+ {2955, {wxStyledTextCtrl, addText, 1}},
+ {2956, {wxStyledTextCtrl, addStyledText, 1}},
+ {2957, {wxStyledTextCtrl, insertText, 2}},
+ {2958, {wxStyledTextCtrl, clearAll, 0}},
+ {2959, {wxStyledTextCtrl, clearDocumentStyle, 0}},
+ {2960, {wxStyledTextCtrl, getLength, 0}},
+ {2961, {wxStyledTextCtrl, getCharAt, 1}},
+ {2962, {wxStyledTextCtrl, getCurrentPos, 0}},
+ {2963, {wxStyledTextCtrl, getAnchor, 0}},
+ {2964, {wxStyledTextCtrl, getStyleAt, 1}},
+ {2965, {wxStyledTextCtrl, redo, 0}},
+ {2966, {wxStyledTextCtrl, setUndoCollection, 1}},
+ {2967, {wxStyledTextCtrl, selectAll, 0}},
+ {2968, {wxStyledTextCtrl, setSavePoint, 0}},
+ {2969, {wxStyledTextCtrl, getStyledText, 2}},
+ {2970, {wxStyledTextCtrl, canRedo, 0}},
+ {2971, {wxStyledTextCtrl, markerLineFromHandle, 1}},
+ {2972, {wxStyledTextCtrl, markerDeleteHandle, 1}},
+ {2973, {wxStyledTextCtrl, getUndoCollection, 0}},
+ {2974, {wxStyledTextCtrl, getViewWhiteSpace, 0}},
+ {2975, {wxStyledTextCtrl, setViewWhiteSpace, 1}},
+ {2976, {wxStyledTextCtrl, positionFromPoint, 1}},
+ {2977, {wxStyledTextCtrl, positionFromPointClose, 2}},
+ {2978, {wxStyledTextCtrl, gotoLine, 1}},
+ {2979, {wxStyledTextCtrl, gotoPos, 1}},
+ {2980, {wxStyledTextCtrl, setAnchor, 1}},
+ {2981, {wxStyledTextCtrl, getCurLine, 1}},
+ {2982, {wxStyledTextCtrl, getEndStyled, 0}},
+ {2983, {wxStyledTextCtrl, convertEOLs, 1}},
+ {2984, {wxStyledTextCtrl, getEOLMode, 0}},
+ {2985, {wxStyledTextCtrl, setEOLMode, 1}},
+ {2986, {wxStyledTextCtrl, startStyling, 2}},
+ {2987, {wxStyledTextCtrl, setStyling, 2}},
+ {2988, {wxStyledTextCtrl, getBufferedDraw, 0}},
+ {2989, {wxStyledTextCtrl, setBufferedDraw, 1}},
+ {2990, {wxStyledTextCtrl, setTabWidth, 1}},
+ {2991, {wxStyledTextCtrl, getTabWidth, 0}},
+ {2992, {wxStyledTextCtrl, setCodePage, 1}},
+ {2993, {wxStyledTextCtrl, markerDefine, 3}},
+ {2994, {wxStyledTextCtrl, markerSetForeground, 2}},
+ {2995, {wxStyledTextCtrl, markerSetBackground, 2}},
+ {2996, {wxStyledTextCtrl, markerAdd, 2}},
+ {2997, {wxStyledTextCtrl, markerDelete, 2}},
+ {2998, {wxStyledTextCtrl, markerDeleteAll, 1}},
+ {2999, {wxStyledTextCtrl, markerGet, 1}},
+ {3000, {wxStyledTextCtrl, markerNext, 2}},
+ {3001, {wxStyledTextCtrl, markerPrevious, 2}},
+ {3002, {wxStyledTextCtrl, markerDefineBitmap, 2}},
+ {3003, {wxStyledTextCtrl, markerAddSet, 2}},
+ {3004, {wxStyledTextCtrl, markerSetAlpha, 2}},
+ {3005, {wxStyledTextCtrl, setMarginType, 2}},
+ {3006, {wxStyledTextCtrl, getMarginType, 1}},
+ {3007, {wxStyledTextCtrl, setMarginWidth, 2}},
+ {3008, {wxStyledTextCtrl, getMarginWidth, 1}},
+ {3009, {wxStyledTextCtrl, setMarginMask, 2}},
+ {3010, {wxStyledTextCtrl, getMarginMask, 1}},
+ {3011, {wxStyledTextCtrl, setMarginSensitive, 2}},
+ {3012, {wxStyledTextCtrl, getMarginSensitive, 1}},
+ {3013, {wxStyledTextCtrl, styleClearAll, 0}},
+ {3014, {wxStyledTextCtrl, styleSetForeground, 2}},
+ {3015, {wxStyledTextCtrl, styleSetBackground, 2}},
+ {3016, {wxStyledTextCtrl, styleSetBold, 2}},
+ {3017, {wxStyledTextCtrl, styleSetItalic, 2}},
+ {3018, {wxStyledTextCtrl, styleSetSize, 2}},
+ {3019, {wxStyledTextCtrl, styleSetFaceName, 2}},
+ {3020, {wxStyledTextCtrl, styleSetEOLFilled, 2}},
+ {3021, {wxStyledTextCtrl, styleResetDefault, 0}},
+ {3022, {wxStyledTextCtrl, styleSetUnderline, 2}},
+ {3023, {wxStyledTextCtrl, styleSetCase, 2}},
+ {3024, {wxStyledTextCtrl, styleSetHotSpot, 2}},
+ {3025, {wxStyledTextCtrl, setSelForeground, 2}},
+ {3026, {wxStyledTextCtrl, setSelBackground, 2}},
+ {3027, {wxStyledTextCtrl, getSelAlpha, 0}},
+ {3028, {wxStyledTextCtrl, setSelAlpha, 1}},
+ {3029, {wxStyledTextCtrl, setCaretForeground, 1}},
+ {3030, {wxStyledTextCtrl, cmdKeyAssign, 3}},
+ {3031, {wxStyledTextCtrl, cmdKeyClear, 2}},
+ {3032, {wxStyledTextCtrl, cmdKeyClearAll, 0}},
+ {3033, {wxStyledTextCtrl, setStyleBytes, 2}},
+ {3034, {wxStyledTextCtrl, styleSetVisible, 2}},
+ {3035, {wxStyledTextCtrl, getCaretPeriod, 0}},
+ {3036, {wxStyledTextCtrl, setCaretPeriod, 1}},
+ {3037, {wxStyledTextCtrl, setWordChars, 1}},
+ {3038, {wxStyledTextCtrl, beginUndoAction, 0}},
+ {3039, {wxStyledTextCtrl, endUndoAction, 0}},
+ {3040, {wxStyledTextCtrl, indicatorSetStyle, 2}},
+ {3041, {wxStyledTextCtrl, indicatorGetStyle, 1}},
+ {3042, {wxStyledTextCtrl, indicatorSetForeground, 2}},
+ {3043, {wxStyledTextCtrl, indicatorGetForeground, 1}},
+ {3044, {wxStyledTextCtrl, setWhitespaceForeground, 2}},
+ {3045, {wxStyledTextCtrl, setWhitespaceBackground, 2}},
+ {3046, {wxStyledTextCtrl, getStyleBits, 0}},
+ {3047, {wxStyledTextCtrl, setLineState, 2}},
+ {3048, {wxStyledTextCtrl, getLineState, 1}},
+ {3049, {wxStyledTextCtrl, getMaxLineState, 0}},
+ {3050, {wxStyledTextCtrl, getCaretLineVisible, 0}},
+ {3051, {wxStyledTextCtrl, setCaretLineVisible, 1}},
+ {3052, {wxStyledTextCtrl, getCaretLineBackground, 0}},
+ {3053, {wxStyledTextCtrl, setCaretLineBackground, 1}},
+ {3054, {wxStyledTextCtrl, autoCompShow, 2}},
+ {3055, {wxStyledTextCtrl, autoCompCancel, 0}},
+ {3056, {wxStyledTextCtrl, autoCompActive, 0}},
+ {3057, {wxStyledTextCtrl, autoCompPosStart, 0}},
+ {3058, {wxStyledTextCtrl, autoCompComplete, 0}},
+ {3059, {wxStyledTextCtrl, autoCompStops, 1}},
+ {3060, {wxStyledTextCtrl, autoCompSetSeparator, 1}},
+ {3061, {wxStyledTextCtrl, autoCompGetSeparator, 0}},
+ {3062, {wxStyledTextCtrl, autoCompSelect, 1}},
+ {3063, {wxStyledTextCtrl, autoCompSetCancelAtStart, 1}},
+ {3064, {wxStyledTextCtrl, autoCompGetCancelAtStart, 0}},
+ {3065, {wxStyledTextCtrl, autoCompSetFillUps, 1}},
+ {3066, {wxStyledTextCtrl, autoCompSetChooseSingle, 1}},
+ {3067, {wxStyledTextCtrl, autoCompGetChooseSingle, 0}},
+ {3068, {wxStyledTextCtrl, autoCompSetIgnoreCase, 1}},
+ {3069, {wxStyledTextCtrl, autoCompGetIgnoreCase, 0}},
+ {3070, {wxStyledTextCtrl, userListShow, 2}},
+ {3071, {wxStyledTextCtrl, autoCompSetAutoHide, 1}},
+ {3072, {wxStyledTextCtrl, autoCompGetAutoHide, 0}},
+ {3073, {wxStyledTextCtrl, autoCompSetDropRestOfWord, 1}},
+ {3074, {wxStyledTextCtrl, autoCompGetDropRestOfWord, 0}},
+ {3075, {wxStyledTextCtrl, registerImage, 2}},
+ {3076, {wxStyledTextCtrl, clearRegisteredImages, 0}},
+ {3077, {wxStyledTextCtrl, autoCompGetTypeSeparator, 0}},
+ {3078, {wxStyledTextCtrl, autoCompSetTypeSeparator, 1}},
+ {3079, {wxStyledTextCtrl, autoCompSetMaxWidth, 1}},
+ {3080, {wxStyledTextCtrl, autoCompGetMaxWidth, 0}},
+ {3081, {wxStyledTextCtrl, autoCompSetMaxHeight, 1}},
+ {3082, {wxStyledTextCtrl, autoCompGetMaxHeight, 0}},
+ {3083, {wxStyledTextCtrl, setIndent, 1}},
+ {3084, {wxStyledTextCtrl, getIndent, 0}},
+ {3085, {wxStyledTextCtrl, setUseTabs, 1}},
+ {3086, {wxStyledTextCtrl, getUseTabs, 0}},
+ {3087, {wxStyledTextCtrl, setLineIndentation, 2}},
+ {3088, {wxStyledTextCtrl, getLineIndentation, 1}},
+ {3089, {wxStyledTextCtrl, getLineIndentPosition, 1}},
+ {3090, {wxStyledTextCtrl, getColumn, 1}},
+ {3091, {wxStyledTextCtrl, setUseHorizontalScrollBar, 1}},
+ {3092, {wxStyledTextCtrl, getUseHorizontalScrollBar, 0}},
+ {3093, {wxStyledTextCtrl, setIndentationGuides, 1}},
+ {3094, {wxStyledTextCtrl, getIndentationGuides, 0}},
+ {3095, {wxStyledTextCtrl, setHighlightGuide, 1}},
+ {3096, {wxStyledTextCtrl, getHighlightGuide, 0}},
+ {3097, {wxStyledTextCtrl, getLineEndPosition, 1}},
+ {3098, {wxStyledTextCtrl, getCodePage, 0}},
+ {3099, {wxStyledTextCtrl, getCaretForeground, 0}},
+ {3100, {wxStyledTextCtrl, getReadOnly, 0}},
+ {3101, {wxStyledTextCtrl, setCurrentPos, 1}},
+ {3102, {wxStyledTextCtrl, setSelectionStart, 1}},
+ {3103, {wxStyledTextCtrl, getSelectionStart, 0}},
+ {3104, {wxStyledTextCtrl, setSelectionEnd, 1}},
+ {3105, {wxStyledTextCtrl, getSelectionEnd, 0}},
+ {3106, {wxStyledTextCtrl, setPrintMagnification, 1}},
+ {3107, {wxStyledTextCtrl, getPrintMagnification, 0}},
+ {3108, {wxStyledTextCtrl, setPrintColourMode, 1}},
+ {3109, {wxStyledTextCtrl, getPrintColourMode, 0}},
+ {3110, {wxStyledTextCtrl, findText, 4}},
+ {3111, {wxStyledTextCtrl, formatRange, 7}},
+ {3112, {wxStyledTextCtrl, getFirstVisibleLine, 0}},
+ {3113, {wxStyledTextCtrl, getLine, 1}},
+ {3114, {wxStyledTextCtrl, getLineCount, 0}},
+ {3115, {wxStyledTextCtrl, setMarginLeft, 1}},
+ {3116, {wxStyledTextCtrl, getMarginLeft, 0}},
+ {3117, {wxStyledTextCtrl, setMarginRight, 1}},
+ {3118, {wxStyledTextCtrl, getMarginRight, 0}},
+ {3119, {wxStyledTextCtrl, getModify, 0}},
+ {3120, {wxStyledTextCtrl, setSelection, 2}},
+ {3121, {wxStyledTextCtrl, getSelectedText, 0}},
+ {3122, {wxStyledTextCtrl, getTextRange, 2}},
+ {3123, {wxStyledTextCtrl, hideSelection, 1}},
+ {3124, {wxStyledTextCtrl, lineFromPosition, 1}},
+ {3125, {wxStyledTextCtrl, positionFromLine, 1}},
+ {3126, {wxStyledTextCtrl, lineScroll, 2}},
+ {3127, {wxStyledTextCtrl, ensureCaretVisible, 0}},
+ {3128, {wxStyledTextCtrl, replaceSelection, 1}},
+ {3129, {wxStyledTextCtrl, setReadOnly, 1}},
+ {3130, {wxStyledTextCtrl, canPaste, 0}},
+ {3131, {wxStyledTextCtrl, canUndo, 0}},
+ {3132, {wxStyledTextCtrl, emptyUndoBuffer, 0}},
+ {3133, {wxStyledTextCtrl, undo, 0}},
+ {3134, {wxStyledTextCtrl, cut, 0}},
+ {3135, {wxStyledTextCtrl, copy, 0}},
+ {3136, {wxStyledTextCtrl, paste, 0}},
+ {3137, {wxStyledTextCtrl, clear, 0}},
+ {3138, {wxStyledTextCtrl, setText, 1}},
+ {3139, {wxStyledTextCtrl, getText, 0}},
+ {3140, {wxStyledTextCtrl, getTextLength, 0}},
+ {3141, {wxStyledTextCtrl, getOvertype, 0}},
+ {3142, {wxStyledTextCtrl, setCaretWidth, 1}},
+ {3143, {wxStyledTextCtrl, getCaretWidth, 0}},
+ {3144, {wxStyledTextCtrl, setTargetStart, 1}},
+ {3145, {wxStyledTextCtrl, getTargetStart, 0}},
+ {3146, {wxStyledTextCtrl, setTargetEnd, 1}},
+ {3147, {wxStyledTextCtrl, getTargetEnd, 0}},
+ {3148, {wxStyledTextCtrl, replaceTarget, 1}},
+ {3149, {wxStyledTextCtrl, searchInTarget, 1}},
+ {3150, {wxStyledTextCtrl, setSearchFlags, 1}},
+ {3151, {wxStyledTextCtrl, getSearchFlags, 0}},
+ {3152, {wxStyledTextCtrl, callTipShow, 2}},
+ {3153, {wxStyledTextCtrl, callTipCancel, 0}},
+ {3154, {wxStyledTextCtrl, callTipActive, 0}},
+ {3155, {wxStyledTextCtrl, callTipPosAtStart, 0}},
+ {3156, {wxStyledTextCtrl, callTipSetHighlight, 2}},
+ {3157, {wxStyledTextCtrl, callTipSetBackground, 1}},
+ {3158, {wxStyledTextCtrl, callTipSetForeground, 1}},
+ {3159, {wxStyledTextCtrl, callTipSetForegroundHighlight, 1}},
+ {3160, {wxStyledTextCtrl, callTipUseStyle, 1}},
+ {3161, {wxStyledTextCtrl, visibleFromDocLine, 1}},
+ {3162, {wxStyledTextCtrl, docLineFromVisible, 1}},
+ {3163, {wxStyledTextCtrl, wrapCount, 1}},
+ {3164, {wxStyledTextCtrl, setFoldLevel, 2}},
+ {3165, {wxStyledTextCtrl, getFoldLevel, 1}},
+ {3166, {wxStyledTextCtrl, getLastChild, 2}},
+ {3167, {wxStyledTextCtrl, getFoldParent, 1}},
+ {3168, {wxStyledTextCtrl, showLines, 2}},
+ {3169, {wxStyledTextCtrl, hideLines, 2}},
+ {3170, {wxStyledTextCtrl, getLineVisible, 1}},
+ {3171, {wxStyledTextCtrl, setFoldExpanded, 2}},
+ {3172, {wxStyledTextCtrl, getFoldExpanded, 1}},
+ {3173, {wxStyledTextCtrl, toggleFold, 1}},
+ {3174, {wxStyledTextCtrl, ensureVisible, 1}},
+ {3175, {wxStyledTextCtrl, setFoldFlags, 1}},
+ {3176, {wxStyledTextCtrl, ensureVisibleEnforcePolicy, 1}},
+ {3177, {wxStyledTextCtrl, setTabIndents, 1}},
+ {3178, {wxStyledTextCtrl, getTabIndents, 0}},
+ {3179, {wxStyledTextCtrl, setBackSpaceUnIndents, 1}},
+ {3180, {wxStyledTextCtrl, getBackSpaceUnIndents, 0}},
+ {3181, {wxStyledTextCtrl, setMouseDwellTime, 1}},
+ {3182, {wxStyledTextCtrl, getMouseDwellTime, 0}},
+ {3183, {wxStyledTextCtrl, wordStartPosition, 2}},
+ {3184, {wxStyledTextCtrl, wordEndPosition, 2}},
+ {3185, {wxStyledTextCtrl, setWrapMode, 1}},
+ {3186, {wxStyledTextCtrl, getWrapMode, 0}},
+ {3187, {wxStyledTextCtrl, setWrapVisualFlags, 1}},
+ {3188, {wxStyledTextCtrl, getWrapVisualFlags, 0}},
+ {3189, {wxStyledTextCtrl, setWrapVisualFlagsLocation, 1}},
+ {3190, {wxStyledTextCtrl, getWrapVisualFlagsLocation, 0}},
+ {3191, {wxStyledTextCtrl, setWrapStartIndent, 1}},
+ {3192, {wxStyledTextCtrl, getWrapStartIndent, 0}},
+ {3193, {wxStyledTextCtrl, setLayoutCache, 1}},
+ {3194, {wxStyledTextCtrl, getLayoutCache, 0}},
+ {3195, {wxStyledTextCtrl, setScrollWidth, 1}},
+ {3196, {wxStyledTextCtrl, getScrollWidth, 0}},
+ {3197, {wxStyledTextCtrl, textWidth, 2}},
+ {3198, {wxStyledTextCtrl, getEndAtLastLine, 0}},
+ {3199, {wxStyledTextCtrl, textHeight, 1}},
+ {3200, {wxStyledTextCtrl, setUseVerticalScrollBar, 1}},
+ {3201, {wxStyledTextCtrl, getUseVerticalScrollBar, 0}},
+ {3202, {wxStyledTextCtrl, appendText, 1}},
+ {3203, {wxStyledTextCtrl, getTwoPhaseDraw, 0}},
+ {3204, {wxStyledTextCtrl, setTwoPhaseDraw, 1}},
+ {3205, {wxStyledTextCtrl, targetFromSelection, 0}},
+ {3206, {wxStyledTextCtrl, linesJoin, 0}},
+ {3207, {wxStyledTextCtrl, linesSplit, 1}},
+ {3208, {wxStyledTextCtrl, setFoldMarginColour, 2}},
+ {3209, {wxStyledTextCtrl, setFoldMarginHiColour, 2}},
+ {3210, {wxStyledTextCtrl, lineDown, 0}},
+ {3211, {wxStyledTextCtrl, lineDownExtend, 0}},
+ {3212, {wxStyledTextCtrl, lineUp, 0}},
+ {3213, {wxStyledTextCtrl, lineUpExtend, 0}},
+ {3214, {wxStyledTextCtrl, charLeft, 0}},
+ {3215, {wxStyledTextCtrl, charLeftExtend, 0}},
+ {3216, {wxStyledTextCtrl, charRight, 0}},
+ {3217, {wxStyledTextCtrl, charRightExtend, 0}},
+ {3218, {wxStyledTextCtrl, wordLeft, 0}},
+ {3219, {wxStyledTextCtrl, wordLeftExtend, 0}},
+ {3220, {wxStyledTextCtrl, wordRight, 0}},
+ {3221, {wxStyledTextCtrl, wordRightExtend, 0}},
+ {3222, {wxStyledTextCtrl, home, 0}},
+ {3223, {wxStyledTextCtrl, homeExtend, 0}},
+ {3224, {wxStyledTextCtrl, lineEnd, 0}},
+ {3225, {wxStyledTextCtrl, lineEndExtend, 0}},
+ {3226, {wxStyledTextCtrl, documentStart, 0}},
+ {3227, {wxStyledTextCtrl, documentStartExtend, 0}},
+ {3228, {wxStyledTextCtrl, documentEnd, 0}},
+ {3229, {wxStyledTextCtrl, documentEndExtend, 0}},
+ {3230, {wxStyledTextCtrl, pageUp, 0}},
+ {3231, {wxStyledTextCtrl, pageUpExtend, 0}},
+ {3232, {wxStyledTextCtrl, pageDown, 0}},
+ {3233, {wxStyledTextCtrl, pageDownExtend, 0}},
+ {3234, {wxStyledTextCtrl, editToggleOvertype, 0}},
+ {3235, {wxStyledTextCtrl, cancel, 0}},
+ {3236, {wxStyledTextCtrl, deleteBack, 0}},
+ {3237, {wxStyledTextCtrl, tab, 0}},
+ {3238, {wxStyledTextCtrl, backTab, 0}},
+ {3239, {wxStyledTextCtrl, newLine, 0}},
+ {3240, {wxStyledTextCtrl, formFeed, 0}},
+ {3241, {wxStyledTextCtrl, vCHome, 0}},
+ {3242, {wxStyledTextCtrl, vCHomeExtend, 0}},
+ {3243, {wxStyledTextCtrl, zoomIn, 0}},
+ {3244, {wxStyledTextCtrl, zoomOut, 0}},
+ {3245, {wxStyledTextCtrl, delWordLeft, 0}},
+ {3246, {wxStyledTextCtrl, delWordRight, 0}},
+ {3247, {wxStyledTextCtrl, lineCut, 0}},
+ {3248, {wxStyledTextCtrl, lineDelete, 0}},
+ {3249, {wxStyledTextCtrl, lineTranspose, 0}},
+ {3250, {wxStyledTextCtrl, lineDuplicate, 0}},
+ {3251, {wxStyledTextCtrl, lowerCase, 0}},
+ {3252, {wxStyledTextCtrl, upperCase, 0}},
+ {3253, {wxStyledTextCtrl, lineScrollDown, 0}},
+ {3254, {wxStyledTextCtrl, lineScrollUp, 0}},
+ {3255, {wxStyledTextCtrl, deleteBackNotLine, 0}},
+ {3256, {wxStyledTextCtrl, homeDisplay, 0}},
+ {3257, {wxStyledTextCtrl, homeDisplayExtend, 0}},
+ {3258, {wxStyledTextCtrl, lineEndDisplay, 0}},
+ {3259, {wxStyledTextCtrl, lineEndDisplayExtend, 0}},
+ {3260, {wxStyledTextCtrl, homeWrapExtend, 0}},
+ {3261, {wxStyledTextCtrl, lineEndWrap, 0}},
+ {3262, {wxStyledTextCtrl, lineEndWrapExtend, 0}},
+ {3263, {wxStyledTextCtrl, vCHomeWrap, 0}},
+ {3264, {wxStyledTextCtrl, vCHomeWrapExtend, 0}},
+ {3265, {wxStyledTextCtrl, lineCopy, 0}},
+ {3266, {wxStyledTextCtrl, moveCaretInsideView, 0}},
+ {3267, {wxStyledTextCtrl, lineLength, 1}},
+ {3268, {wxStyledTextCtrl, braceHighlight, 2}},
+ {3269, {wxStyledTextCtrl, braceBadLight, 1}},
+ {3270, {wxStyledTextCtrl, braceMatch, 1}},
+ {3271, {wxStyledTextCtrl, getViewEOL, 0}},
+ {3272, {wxStyledTextCtrl, setViewEOL, 1}},
+ {3273, {wxStyledTextCtrl, setModEventMask, 1}},
+ {3274, {wxStyledTextCtrl, getEdgeColumn, 0}},
+ {3275, {wxStyledTextCtrl, setEdgeColumn, 1}},
+ {3276, {wxStyledTextCtrl, setEdgeMode, 1}},
+ {3277, {wxStyledTextCtrl, getEdgeMode, 0}},
+ {3278, {wxStyledTextCtrl, getEdgeColour, 0}},
+ {3279, {wxStyledTextCtrl, setEdgeColour, 1}},
+ {3280, {wxStyledTextCtrl, searchAnchor, 0}},
+ {3281, {wxStyledTextCtrl, searchNext, 2}},
+ {3282, {wxStyledTextCtrl, searchPrev, 2}},
+ {3283, {wxStyledTextCtrl, linesOnScreen, 0}},
+ {3284, {wxStyledTextCtrl, usePopUp, 1}},
+ {3285, {wxStyledTextCtrl, selectionIsRectangle, 0}},
+ {3286, {wxStyledTextCtrl, setZoom, 1}},
+ {3287, {wxStyledTextCtrl, getZoom, 0}},
+ {3288, {wxStyledTextCtrl, getModEventMask, 0}},
+ {3289, {wxStyledTextCtrl, setSTCFocus, 1}},
+ {3290, {wxStyledTextCtrl, getSTCFocus, 0}},
+ {3291, {wxStyledTextCtrl, setStatus, 1}},
+ {3292, {wxStyledTextCtrl, getStatus, 0}},
+ {3293, {wxStyledTextCtrl, setMouseDownCaptures, 1}},
+ {3294, {wxStyledTextCtrl, getMouseDownCaptures, 0}},
+ {3295, {wxStyledTextCtrl, setSTCCursor, 1}},
+ {3296, {wxStyledTextCtrl, getSTCCursor, 0}},
+ {3297, {wxStyledTextCtrl, setControlCharSymbol, 1}},
+ {3298, {wxStyledTextCtrl, getControlCharSymbol, 0}},
+ {3299, {wxStyledTextCtrl, wordPartLeft, 0}},
+ {3300, {wxStyledTextCtrl, wordPartLeftExtend, 0}},
+ {3301, {wxStyledTextCtrl, wordPartRight, 0}},
+ {3302, {wxStyledTextCtrl, wordPartRightExtend, 0}},
+ {3303, {wxStyledTextCtrl, setVisiblePolicy, 2}},
+ {3304, {wxStyledTextCtrl, delLineLeft, 0}},
+ {3305, {wxStyledTextCtrl, delLineRight, 0}},
+ {3306, {wxStyledTextCtrl, getXOffset, 0}},
+ {3307, {wxStyledTextCtrl, chooseCaretX, 0}},
+ {3308, {wxStyledTextCtrl, setXCaretPolicy, 2}},
+ {3309, {wxStyledTextCtrl, setYCaretPolicy, 2}},
+ {3310, {wxStyledTextCtrl, getPrintWrapMode, 0}},
+ {3311, {wxStyledTextCtrl, setHotspotActiveForeground, 2}},
+ {3312, {wxStyledTextCtrl, setHotspotActiveBackground, 2}},
+ {3313, {wxStyledTextCtrl, setHotspotActiveUnderline, 1}},
+ {3314, {wxStyledTextCtrl, setHotspotSingleLine, 1}},
+ {3315, {wxStyledTextCtrl, paraDownExtend, 0}},
+ {3316, {wxStyledTextCtrl, paraUp, 0}},
+ {3317, {wxStyledTextCtrl, paraUpExtend, 0}},
+ {3318, {wxStyledTextCtrl, positionBefore, 1}},
+ {3319, {wxStyledTextCtrl, positionAfter, 1}},
+ {3320, {wxStyledTextCtrl, copyRange, 2}},
+ {3321, {wxStyledTextCtrl, copyText, 2}},
+ {3322, {wxStyledTextCtrl, setSelectionMode, 1}},
+ {3323, {wxStyledTextCtrl, getSelectionMode, 0}},
+ {3324, {wxStyledTextCtrl, lineDownRectExtend, 0}},
+ {3325, {wxStyledTextCtrl, lineUpRectExtend, 0}},
+ {3326, {wxStyledTextCtrl, charLeftRectExtend, 0}},
+ {3327, {wxStyledTextCtrl, charRightRectExtend, 0}},
+ {3328, {wxStyledTextCtrl, homeRectExtend, 0}},
+ {3329, {wxStyledTextCtrl, vCHomeRectExtend, 0}},
+ {3330, {wxStyledTextCtrl, lineEndRectExtend, 0}},
+ {3331, {wxStyledTextCtrl, pageUpRectExtend, 0}},
+ {3332, {wxStyledTextCtrl, pageDownRectExtend, 0}},
+ {3333, {wxStyledTextCtrl, stutteredPageUp, 0}},
+ {3334, {wxStyledTextCtrl, stutteredPageUpExtend, 0}},
+ {3335, {wxStyledTextCtrl, stutteredPageDown, 0}},
+ {3336, {wxStyledTextCtrl, stutteredPageDownExtend, 0}},
+ {3337, {wxStyledTextCtrl, wordLeftEnd, 0}},
+ {3338, {wxStyledTextCtrl, wordLeftEndExtend, 0}},
+ {3339, {wxStyledTextCtrl, wordRightEnd, 0}},
+ {3340, {wxStyledTextCtrl, wordRightEndExtend, 0}},
+ {3341, {wxStyledTextCtrl, setWhitespaceChars, 1}},
+ {3342, {wxStyledTextCtrl, setCharsDefault, 0}},
+ {3343, {wxStyledTextCtrl, autoCompGetCurrent, 0}},
+ {3344, {wxStyledTextCtrl, allocate, 1}},
+ {3345, {wxStyledTextCtrl, findColumn, 2}},
+ {3346, {wxStyledTextCtrl, getCaretSticky, 0}},
+ {3347, {wxStyledTextCtrl, setCaretSticky, 1}},
+ {3348, {wxStyledTextCtrl, toggleCaretSticky, 0}},
+ {3349, {wxStyledTextCtrl, setPasteConvertEndings, 1}},
+ {3350, {wxStyledTextCtrl, getPasteConvertEndings, 0}},
+ {3351, {wxStyledTextCtrl, selectionDuplicate, 0}},
+ {3352, {wxStyledTextCtrl, setCaretLineBackAlpha, 1}},
+ {3353, {wxStyledTextCtrl, getCaretLineBackAlpha, 0}},
+ {3354, {wxStyledTextCtrl, startRecord, 0}},
+ {3355, {wxStyledTextCtrl, stopRecord, 0}},
+ {3356, {wxStyledTextCtrl, setLexer, 1}},
+ {3357, {wxStyledTextCtrl, getLexer, 0}},
+ {3358, {wxStyledTextCtrl, colourise, 2}},
+ {3359, {wxStyledTextCtrl, setProperty, 2}},
+ {3360, {wxStyledTextCtrl, setKeyWords, 2}},
+ {3361, {wxStyledTextCtrl, setLexerLanguage, 1}},
+ {3362, {wxStyledTextCtrl, getProperty, 1}},
+ {3363, {wxStyledTextCtrl, getStyleBitsNeeded, 0}},
+ {3364, {wxStyledTextCtrl, getCurrentLine, 0}},
+ {3365, {wxStyledTextCtrl, styleSetSpec, 2}},
+ {3366, {wxStyledTextCtrl, styleSetFont, 2}},
+ {3367, {wxStyledTextCtrl, styleSetFontAttr, 7}},
+ {3368, {wxStyledTextCtrl, styleSetCharacterSet, 2}},
+ {3369, {wxStyledTextCtrl, styleSetFontEncoding, 2}},
+ {3370, {wxStyledTextCtrl, cmdKeyExecute, 1}},
+ {3371, {wxStyledTextCtrl, setMargins, 2}},
+ {3372, {wxStyledTextCtrl, getSelection, 2}},
+ {3373, {wxStyledTextCtrl, pointFromPosition, 1}},
+ {3374, {wxStyledTextCtrl, scrollToLine, 1}},
+ {3375, {wxStyledTextCtrl, scrollToColumn, 1}},
+ {3376, {wxStyledTextCtrl, setVScrollBar, 1}},
+ {3377, {wxStyledTextCtrl, setHScrollBar, 1}},
+ {3378, {wxStyledTextCtrl, getLastKeydownProcessed, 0}},
+ {3379, {wxStyledTextCtrl, setLastKeydownProcessed, 1}},
+ {3380, {wxStyledTextCtrl, saveFile, 1}},
+ {3381, {wxStyledTextCtrl, loadFile, 1}},
+ {3382, {wxStyledTextCtrl, doDragOver, 3}},
+ {3383, {wxStyledTextCtrl, doDropText, 3}},
+ {3384, {wxStyledTextCtrl, getUseAntiAliasing, 0}},
+ {3385, {wxStyledTextCtrl, addTextRaw, 1}},
+ {3386, {wxStyledTextCtrl, insertTextRaw, 2}},
+ {3387, {wxStyledTextCtrl, getCurLineRaw, 1}},
+ {3388, {wxStyledTextCtrl, getLineRaw, 1}},
+ {3389, {wxStyledTextCtrl, getSelectedTextRaw, 0}},
+ {3390, {wxStyledTextCtrl, getTextRangeRaw, 2}},
+ {3391, {wxStyledTextCtrl, setTextRaw, 1}},
+ {3392, {wxStyledTextCtrl, getTextRaw, 0}},
+ {3393, {wxStyledTextCtrl, appendTextRaw, 1}},
+ {3394, {wxArtProvider, getBitmap, 2}},
+ {3395, {wxArtProvider, getIcon, 2}},
+ {3396, {wxTreeEvent, getKeyCode, 0}},
+ {3397, {wxTreeEvent, getItem, 0}},
+ {3398, {wxTreeEvent, getKeyEvent, 0}},
+ {3399, {wxTreeEvent, getLabel, 0}},
+ {3400, {wxTreeEvent, getOldItem, 0}},
+ {3401, {wxTreeEvent, getPoint, 0}},
+ {3402, {wxTreeEvent, isEditCancelled, 0}},
+ {3403, {wxTreeEvent, setToolTip, 1}},
+ {3404, {wxNotebookEvent, getOldSelection, 0}},
+ {3405, {wxNotebookEvent, getSelection, 0}},
+ {3406, {wxNotebookEvent, setOldSelection, 1}},
+ {3407, {wxNotebookEvent, setSelection, 1}},
+ {3408, {wxFileDataObject, new, 0}},
+ {3409, {wxFileDataObject, addFile, 1}},
+ {3410, {wxFileDataObject, getFilenames, 0}},
+ {3411, {wxFileDataObject, 'Destroy', undefined}},
+ {3412, {wxTextDataObject, new, 1}},
+ {3413, {wxTextDataObject, getTextLength, 0}},
+ {3414, {wxTextDataObject, getText, 0}},
+ {3415, {wxTextDataObject, setText, 1}},
+ {3416, {wxTextDataObject, 'Destroy', undefined}},
+ {3417, {wxBitmapDataObject, new_1_1, 1}},
+ {3418, {wxBitmapDataObject, new_1_0, 1}},
+ {3419, {wxBitmapDataObject, getBitmap, 0}},
+ {3420, {wxBitmapDataObject, setBitmap, 1}},
+ {3421, {wxBitmapDataObject, 'Destroy', undefined}},
+ {3423, {wxClipboard, new, 0}},
+ {3424, {wxClipboard, destruct, 0}},
+ {3425, {wxClipboard, addData, 1}},
+ {3426, {wxClipboard, clear, 0}},
+ {3427, {wxClipboard, close, 0}},
+ {3428, {wxClipboard, flush, 0}},
+ {3429, {wxClipboard, getData, 1}},
+ {3430, {wxClipboard, isOpened, 0}},
+ {3431, {wxClipboard, open, 0}},
+ {3432, {wxClipboard, setData, 1}},
+ {3434, {wxClipboard, usePrimarySelection, 1}},
+ {3435, {wxClipboard, isSupported, 1}},
+ {3436, {wxClipboard, get, 0}},
+ {3437, {wxSpinEvent, getPosition, 0}},
+ {3438, {wxSpinEvent, setPosition, 1}},
+ {3439, {wxSplitterWindow, new_0, 0}},
+ {3440, {wxSplitterWindow, new_2, 2}},
+ {3441, {wxSplitterWindow, destruct, 0}},
+ {3442, {wxSplitterWindow, create, 2}},
+ {3443, {wxSplitterWindow, getMinimumPaneSize, 0}},
+ {3444, {wxSplitterWindow, getSashGravity, 0}},
+ {3445, {wxSplitterWindow, getSashPosition, 0}},
+ {3446, {wxSplitterWindow, getSplitMode, 0}},
+ {3447, {wxSplitterWindow, getWindow1, 0}},
+ {3448, {wxSplitterWindow, getWindow2, 0}},
+ {3449, {wxSplitterWindow, initialize, 1}},
+ {3450, {wxSplitterWindow, isSplit, 0}},
+ {3451, {wxSplitterWindow, replaceWindow, 2}},
+ {3452, {wxSplitterWindow, setSashGravity, 1}},
+ {3453, {wxSplitterWindow, setSashPosition, 2}},
+ {3454, {wxSplitterWindow, setSashSize, 1}},
+ {3455, {wxSplitterWindow, setMinimumPaneSize, 1}},
+ {3456, {wxSplitterWindow, setSplitMode, 1}},
+ {3457, {wxSplitterWindow, splitHorizontally, 3}},
+ {3458, {wxSplitterWindow, splitVertically, 3}},
+ {3459, {wxSplitterWindow, unsplit, 1}},
+ {3460, {wxSplitterWindow, updateSize, 0}},
+ {3461, {wxSplitterEvent, getSashPosition, 0}},
+ {3462, {wxSplitterEvent, getX, 0}},
+ {3463, {wxSplitterEvent, getY, 0}},
+ {3464, {wxSplitterEvent, getWindowBeingRemoved, 0}},
+ {3465, {wxSplitterEvent, setSashPosition, 1}},
+ {3466, {wxHtmlWindow, new_0, 0}},
+ {3467, {wxHtmlWindow, new_2, 2}},
+ {3468, {wxHtmlWindow, appendToPage, 1}},
+ {3469, {wxHtmlWindow, getOpenedAnchor, 0}},
+ {3470, {wxHtmlWindow, getOpenedPage, 0}},
+ {3471, {wxHtmlWindow, getOpenedPageTitle, 0}},
+ {3472, {wxHtmlWindow, getRelatedFrame, 0}},
+ {3473, {wxHtmlWindow, historyBack, 0}},
+ {3474, {wxHtmlWindow, historyCanBack, 0}},
+ {3475, {wxHtmlWindow, historyCanForward, 0}},
+ {3476, {wxHtmlWindow, historyClear, 0}},
+ {3477, {wxHtmlWindow, historyForward, 0}},
+ {3478, {wxHtmlWindow, loadFile, 1}},
+ {3479, {wxHtmlWindow, loadPage, 1}},
+ {3480, {wxHtmlWindow, selectAll, 0}},
+ {3481, {wxHtmlWindow, selectionToText, 0}},
+ {3482, {wxHtmlWindow, selectLine, 1}},
+ {3483, {wxHtmlWindow, selectWord, 1}},
+ {3484, {wxHtmlWindow, setBorders, 1}},
+ {3485, {wxHtmlWindow, setFonts, 3}},
+ {3486, {wxHtmlWindow, setPage, 1}},
+ {3487, {wxHtmlWindow, setRelatedFrame, 2}},
+ {3488, {wxHtmlWindow, setRelatedStatusBar, 1}},
+ {3489, {wxHtmlWindow, toText, 0}},
+ {3490, {wxHtmlWindow, 'Destroy', undefined}},
+ {3491, {wxHtmlLinkEvent, getLinkInfo, 0}},
+ {3492, {wxSystemSettings, getColour, 1}},
+ {3493, {wxSystemSettings, getFont, 1}},
+ {3494, {wxSystemSettings, getMetric, 2}},
+ {3495, {wxSystemSettings, getScreenType, 0}},
+ {3496, {wxSystemOptions, getOption, 1}},
+ {3497, {wxSystemOptions, getOptionInt, 1}},
+ {3498, {wxSystemOptions, hasOption, 1}},
+ {3499, {wxSystemOptions, isFalse, 1}},
+ {3500, {wxSystemOptions, setOption_2_1, 2}},
+ {3501, {wxSystemOptions, setOption_2_0, 2}},
+ {3502, {wxAuiNotebookEvent, setSelection, 1}},
+ {3503, {wxAuiNotebookEvent, getSelection, 0}},
+ {3504, {wxAuiNotebookEvent, setOldSelection, 1}},
+ {3505, {wxAuiNotebookEvent, getOldSelection, 0}},
+ {3506, {wxAuiNotebookEvent, setDragSource, 1}},
+ {3507, {wxAuiNotebookEvent, getDragSource, 0}},
+ {3508, {wxAuiManagerEvent, setManager, 1}},
+ {3509, {wxAuiManagerEvent, getManager, 0}},
+ {3510, {wxAuiManagerEvent, setPane, 1}},
+ {3511, {wxAuiManagerEvent, getPane, 0}},
+ {3512, {wxAuiManagerEvent, setButton, 1}},
+ {3513, {wxAuiManagerEvent, getButton, 0}},
+ {3514, {wxAuiManagerEvent, setDC, 1}},
+ {3515, {wxAuiManagerEvent, getDC, 0}},
+ {3516, {wxAuiManagerEvent, veto, 1}},
+ {3517, {wxAuiManagerEvent, getVeto, 0}},
+ {3518, {wxAuiManagerEvent, setCanVeto, 1}},
+ {3519, {wxAuiManagerEvent, canVeto, 0}},
+ {3520, {wxLogNull, new, 0}},
+ {3521, {wxLogNull, 'Destroy', undefined}},
+ {3522, {wxTaskBarIcon, new, 0}},
+ {3523, {wxTaskBarIcon, destruct, 0}},
+ {3524, {wxTaskBarIcon, popupMenu, 1}},
+ {3525, {wxTaskBarIcon, removeIcon, 0}},
+ {3526, {wxTaskBarIcon, setIcon, 2}},
+ {3527, {wxLocale, new_0, 0}},
+ {3529, {wxLocale, new_2, 2}},
+ {3530, {wxLocale, destruct, 0}},
+ {3532, {wxLocale, init, 1}},
+ {3533, {wxLocale, addCatalog_1, 1}},
+ {3534, {wxLocale, addCatalog_3, 3}},
+ {3535, {wxLocale, addCatalogLookupPathPrefix, 1}},
+ {3536, {wxLocale, getCanonicalName, 0}},
+ {3537, {wxLocale, getLanguage, 0}},
+ {3538, {wxLocale, getLanguageName, 1}},
+ {3539, {wxLocale, getLocale, 0}},
+ {3540, {wxLocale, getName, 0}},
+ {3541, {wxLocale, getString_2, 2}},
+ {3542, {wxLocale, getString_4, 4}},
+ {3543, {wxLocale, getHeaderValue, 2}},
+ {3544, {wxLocale, getSysName, 0}},
+ {3545, {wxLocale, getSystemEncoding, 0}},
+ {3546, {wxLocale, getSystemEncodingName, 0}},
+ {3547, {wxLocale, getSystemLanguage, 0}},
+ {3548, {wxLocale, isLoaded, 1}},
+ {3549, {wxLocale, isOk, 0}},
{-1, {mod, func, -1}}
].
diff --git a/lib/wx/src/gen/wxe_funcs.hrl b/lib/wx/src/gen/wxe_funcs.hrl
index 109368adb3..97f9bd9695 100644
--- a/lib/wx/src/gen/wxe_funcs.hrl
+++ b/lib/wx/src/gen/wxe_funcs.hrl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2013. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2014. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -2706,599 +2706,622 @@
-define(utils_wxGetOsDescription, 2924).
-define(utils_wxIsPlatformLittleEndian, 2925).
-define(utils_wxIsPlatform64Bit, 2926).
--define(wxPrintout_new, 2927).
--define(wxPrintout_destruct, 2928).
--define(wxPrintout_GetDC, 2929).
--define(wxPrintout_GetPageSizeMM, 2930).
--define(wxPrintout_GetPageSizePixels, 2931).
--define(wxPrintout_GetPaperRectPixels, 2932).
--define(wxPrintout_GetPPIPrinter, 2933).
--define(wxPrintout_GetPPIScreen, 2934).
--define(wxPrintout_GetTitle, 2935).
--define(wxPrintout_IsPreview, 2936).
--define(wxPrintout_FitThisSizeToPaper, 2937).
--define(wxPrintout_FitThisSizeToPage, 2938).
--define(wxPrintout_FitThisSizeToPageMargins, 2939).
--define(wxPrintout_MapScreenSizeToPaper, 2940).
--define(wxPrintout_MapScreenSizeToPage, 2941).
--define(wxPrintout_MapScreenSizeToPageMargins, 2942).
--define(wxPrintout_MapScreenSizeToDevice, 2943).
--define(wxPrintout_GetLogicalPaperRect, 2944).
--define(wxPrintout_GetLogicalPageRect, 2945).
--define(wxPrintout_GetLogicalPageMarginsRect, 2946).
--define(wxPrintout_SetLogicalOrigin, 2947).
--define(wxPrintout_OffsetLogicalOrigin, 2948).
--define(wxStyledTextCtrl_new_2, 2949).
--define(wxStyledTextCtrl_new_0, 2950).
--define(wxStyledTextCtrl_destruct, 2951).
--define(wxStyledTextCtrl_Create, 2952).
--define(wxStyledTextCtrl_AddText, 2953).
--define(wxStyledTextCtrl_AddStyledText, 2954).
--define(wxStyledTextCtrl_InsertText, 2955).
--define(wxStyledTextCtrl_ClearAll, 2956).
--define(wxStyledTextCtrl_ClearDocumentStyle, 2957).
--define(wxStyledTextCtrl_GetLength, 2958).
--define(wxStyledTextCtrl_GetCharAt, 2959).
--define(wxStyledTextCtrl_GetCurrentPos, 2960).
--define(wxStyledTextCtrl_GetAnchor, 2961).
--define(wxStyledTextCtrl_GetStyleAt, 2962).
--define(wxStyledTextCtrl_Redo, 2963).
--define(wxStyledTextCtrl_SetUndoCollection, 2964).
--define(wxStyledTextCtrl_SelectAll, 2965).
--define(wxStyledTextCtrl_SetSavePoint, 2966).
--define(wxStyledTextCtrl_GetStyledText, 2967).
--define(wxStyledTextCtrl_CanRedo, 2968).
--define(wxStyledTextCtrl_MarkerLineFromHandle, 2969).
--define(wxStyledTextCtrl_MarkerDeleteHandle, 2970).
--define(wxStyledTextCtrl_GetUndoCollection, 2971).
--define(wxStyledTextCtrl_GetViewWhiteSpace, 2972).
--define(wxStyledTextCtrl_SetViewWhiteSpace, 2973).
--define(wxStyledTextCtrl_PositionFromPoint, 2974).
--define(wxStyledTextCtrl_PositionFromPointClose, 2975).
--define(wxStyledTextCtrl_GotoLine, 2976).
--define(wxStyledTextCtrl_GotoPos, 2977).
--define(wxStyledTextCtrl_SetAnchor, 2978).
--define(wxStyledTextCtrl_GetCurLine, 2979).
--define(wxStyledTextCtrl_GetEndStyled, 2980).
--define(wxStyledTextCtrl_ConvertEOLs, 2981).
--define(wxStyledTextCtrl_GetEOLMode, 2982).
--define(wxStyledTextCtrl_SetEOLMode, 2983).
--define(wxStyledTextCtrl_StartStyling, 2984).
--define(wxStyledTextCtrl_SetStyling, 2985).
--define(wxStyledTextCtrl_GetBufferedDraw, 2986).
--define(wxStyledTextCtrl_SetBufferedDraw, 2987).
--define(wxStyledTextCtrl_SetTabWidth, 2988).
--define(wxStyledTextCtrl_GetTabWidth, 2989).
--define(wxStyledTextCtrl_SetCodePage, 2990).
--define(wxStyledTextCtrl_MarkerDefine, 2991).
--define(wxStyledTextCtrl_MarkerSetForeground, 2992).
--define(wxStyledTextCtrl_MarkerSetBackground, 2993).
--define(wxStyledTextCtrl_MarkerAdd, 2994).
--define(wxStyledTextCtrl_MarkerDelete, 2995).
--define(wxStyledTextCtrl_MarkerDeleteAll, 2996).
--define(wxStyledTextCtrl_MarkerGet, 2997).
--define(wxStyledTextCtrl_MarkerNext, 2998).
--define(wxStyledTextCtrl_MarkerPrevious, 2999).
--define(wxStyledTextCtrl_MarkerDefineBitmap, 3000).
--define(wxStyledTextCtrl_MarkerAddSet, 3001).
--define(wxStyledTextCtrl_MarkerSetAlpha, 3002).
--define(wxStyledTextCtrl_SetMarginType, 3003).
--define(wxStyledTextCtrl_GetMarginType, 3004).
--define(wxStyledTextCtrl_SetMarginWidth, 3005).
--define(wxStyledTextCtrl_GetMarginWidth, 3006).
--define(wxStyledTextCtrl_SetMarginMask, 3007).
--define(wxStyledTextCtrl_GetMarginMask, 3008).
--define(wxStyledTextCtrl_SetMarginSensitive, 3009).
--define(wxStyledTextCtrl_GetMarginSensitive, 3010).
--define(wxStyledTextCtrl_StyleClearAll, 3011).
--define(wxStyledTextCtrl_StyleSetForeground, 3012).
--define(wxStyledTextCtrl_StyleSetBackground, 3013).
--define(wxStyledTextCtrl_StyleSetBold, 3014).
--define(wxStyledTextCtrl_StyleSetItalic, 3015).
--define(wxStyledTextCtrl_StyleSetSize, 3016).
--define(wxStyledTextCtrl_StyleSetFaceName, 3017).
--define(wxStyledTextCtrl_StyleSetEOLFilled, 3018).
--define(wxStyledTextCtrl_StyleResetDefault, 3019).
--define(wxStyledTextCtrl_StyleSetUnderline, 3020).
--define(wxStyledTextCtrl_StyleSetCase, 3021).
--define(wxStyledTextCtrl_StyleSetHotSpot, 3022).
--define(wxStyledTextCtrl_SetSelForeground, 3023).
--define(wxStyledTextCtrl_SetSelBackground, 3024).
--define(wxStyledTextCtrl_GetSelAlpha, 3025).
--define(wxStyledTextCtrl_SetSelAlpha, 3026).
--define(wxStyledTextCtrl_SetCaretForeground, 3027).
--define(wxStyledTextCtrl_CmdKeyAssign, 3028).
--define(wxStyledTextCtrl_CmdKeyClear, 3029).
--define(wxStyledTextCtrl_CmdKeyClearAll, 3030).
--define(wxStyledTextCtrl_SetStyleBytes, 3031).
--define(wxStyledTextCtrl_StyleSetVisible, 3032).
--define(wxStyledTextCtrl_GetCaretPeriod, 3033).
--define(wxStyledTextCtrl_SetCaretPeriod, 3034).
--define(wxStyledTextCtrl_SetWordChars, 3035).
--define(wxStyledTextCtrl_BeginUndoAction, 3036).
--define(wxStyledTextCtrl_EndUndoAction, 3037).
--define(wxStyledTextCtrl_IndicatorSetStyle, 3038).
--define(wxStyledTextCtrl_IndicatorGetStyle, 3039).
--define(wxStyledTextCtrl_IndicatorSetForeground, 3040).
--define(wxStyledTextCtrl_IndicatorGetForeground, 3041).
--define(wxStyledTextCtrl_SetWhitespaceForeground, 3042).
--define(wxStyledTextCtrl_SetWhitespaceBackground, 3043).
--define(wxStyledTextCtrl_GetStyleBits, 3044).
--define(wxStyledTextCtrl_SetLineState, 3045).
--define(wxStyledTextCtrl_GetLineState, 3046).
--define(wxStyledTextCtrl_GetMaxLineState, 3047).
--define(wxStyledTextCtrl_GetCaretLineVisible, 3048).
--define(wxStyledTextCtrl_SetCaretLineVisible, 3049).
--define(wxStyledTextCtrl_GetCaretLineBackground, 3050).
--define(wxStyledTextCtrl_SetCaretLineBackground, 3051).
--define(wxStyledTextCtrl_AutoCompShow, 3052).
--define(wxStyledTextCtrl_AutoCompCancel, 3053).
--define(wxStyledTextCtrl_AutoCompActive, 3054).
--define(wxStyledTextCtrl_AutoCompPosStart, 3055).
--define(wxStyledTextCtrl_AutoCompComplete, 3056).
--define(wxStyledTextCtrl_AutoCompStops, 3057).
--define(wxStyledTextCtrl_AutoCompSetSeparator, 3058).
--define(wxStyledTextCtrl_AutoCompGetSeparator, 3059).
--define(wxStyledTextCtrl_AutoCompSelect, 3060).
--define(wxStyledTextCtrl_AutoCompSetCancelAtStart, 3061).
--define(wxStyledTextCtrl_AutoCompGetCancelAtStart, 3062).
--define(wxStyledTextCtrl_AutoCompSetFillUps, 3063).
--define(wxStyledTextCtrl_AutoCompSetChooseSingle, 3064).
--define(wxStyledTextCtrl_AutoCompGetChooseSingle, 3065).
--define(wxStyledTextCtrl_AutoCompSetIgnoreCase, 3066).
--define(wxStyledTextCtrl_AutoCompGetIgnoreCase, 3067).
--define(wxStyledTextCtrl_UserListShow, 3068).
--define(wxStyledTextCtrl_AutoCompSetAutoHide, 3069).
--define(wxStyledTextCtrl_AutoCompGetAutoHide, 3070).
--define(wxStyledTextCtrl_AutoCompSetDropRestOfWord, 3071).
--define(wxStyledTextCtrl_AutoCompGetDropRestOfWord, 3072).
--define(wxStyledTextCtrl_RegisterImage, 3073).
--define(wxStyledTextCtrl_ClearRegisteredImages, 3074).
--define(wxStyledTextCtrl_AutoCompGetTypeSeparator, 3075).
--define(wxStyledTextCtrl_AutoCompSetTypeSeparator, 3076).
--define(wxStyledTextCtrl_AutoCompSetMaxWidth, 3077).
--define(wxStyledTextCtrl_AutoCompGetMaxWidth, 3078).
--define(wxStyledTextCtrl_AutoCompSetMaxHeight, 3079).
--define(wxStyledTextCtrl_AutoCompGetMaxHeight, 3080).
--define(wxStyledTextCtrl_SetIndent, 3081).
--define(wxStyledTextCtrl_GetIndent, 3082).
--define(wxStyledTextCtrl_SetUseTabs, 3083).
--define(wxStyledTextCtrl_GetUseTabs, 3084).
--define(wxStyledTextCtrl_SetLineIndentation, 3085).
--define(wxStyledTextCtrl_GetLineIndentation, 3086).
--define(wxStyledTextCtrl_GetLineIndentPosition, 3087).
--define(wxStyledTextCtrl_GetColumn, 3088).
--define(wxStyledTextCtrl_SetUseHorizontalScrollBar, 3089).
--define(wxStyledTextCtrl_GetUseHorizontalScrollBar, 3090).
--define(wxStyledTextCtrl_SetIndentationGuides, 3091).
--define(wxStyledTextCtrl_GetIndentationGuides, 3092).
--define(wxStyledTextCtrl_SetHighlightGuide, 3093).
--define(wxStyledTextCtrl_GetHighlightGuide, 3094).
--define(wxStyledTextCtrl_GetLineEndPosition, 3095).
--define(wxStyledTextCtrl_GetCodePage, 3096).
--define(wxStyledTextCtrl_GetCaretForeground, 3097).
--define(wxStyledTextCtrl_GetReadOnly, 3098).
--define(wxStyledTextCtrl_SetCurrentPos, 3099).
--define(wxStyledTextCtrl_SetSelectionStart, 3100).
--define(wxStyledTextCtrl_GetSelectionStart, 3101).
--define(wxStyledTextCtrl_SetSelectionEnd, 3102).
--define(wxStyledTextCtrl_GetSelectionEnd, 3103).
--define(wxStyledTextCtrl_SetPrintMagnification, 3104).
--define(wxStyledTextCtrl_GetPrintMagnification, 3105).
--define(wxStyledTextCtrl_SetPrintColourMode, 3106).
--define(wxStyledTextCtrl_GetPrintColourMode, 3107).
--define(wxStyledTextCtrl_FindText, 3108).
--define(wxStyledTextCtrl_FormatRange, 3109).
--define(wxStyledTextCtrl_GetFirstVisibleLine, 3110).
--define(wxStyledTextCtrl_GetLine, 3111).
--define(wxStyledTextCtrl_GetLineCount, 3112).
--define(wxStyledTextCtrl_SetMarginLeft, 3113).
--define(wxStyledTextCtrl_GetMarginLeft, 3114).
--define(wxStyledTextCtrl_SetMarginRight, 3115).
--define(wxStyledTextCtrl_GetMarginRight, 3116).
--define(wxStyledTextCtrl_GetModify, 3117).
--define(wxStyledTextCtrl_SetSelection, 3118).
--define(wxStyledTextCtrl_GetSelectedText, 3119).
--define(wxStyledTextCtrl_GetTextRange, 3120).
--define(wxStyledTextCtrl_HideSelection, 3121).
--define(wxStyledTextCtrl_LineFromPosition, 3122).
--define(wxStyledTextCtrl_PositionFromLine, 3123).
--define(wxStyledTextCtrl_LineScroll, 3124).
--define(wxStyledTextCtrl_EnsureCaretVisible, 3125).
--define(wxStyledTextCtrl_ReplaceSelection, 3126).
--define(wxStyledTextCtrl_SetReadOnly, 3127).
--define(wxStyledTextCtrl_CanPaste, 3128).
--define(wxStyledTextCtrl_CanUndo, 3129).
--define(wxStyledTextCtrl_EmptyUndoBuffer, 3130).
--define(wxStyledTextCtrl_Undo, 3131).
--define(wxStyledTextCtrl_Cut, 3132).
--define(wxStyledTextCtrl_Copy, 3133).
--define(wxStyledTextCtrl_Paste, 3134).
--define(wxStyledTextCtrl_Clear, 3135).
--define(wxStyledTextCtrl_SetText, 3136).
--define(wxStyledTextCtrl_GetText, 3137).
--define(wxStyledTextCtrl_GetTextLength, 3138).
--define(wxStyledTextCtrl_GetOvertype, 3139).
--define(wxStyledTextCtrl_SetCaretWidth, 3140).
--define(wxStyledTextCtrl_GetCaretWidth, 3141).
--define(wxStyledTextCtrl_SetTargetStart, 3142).
--define(wxStyledTextCtrl_GetTargetStart, 3143).
--define(wxStyledTextCtrl_SetTargetEnd, 3144).
--define(wxStyledTextCtrl_GetTargetEnd, 3145).
--define(wxStyledTextCtrl_ReplaceTarget, 3146).
--define(wxStyledTextCtrl_SearchInTarget, 3147).
--define(wxStyledTextCtrl_SetSearchFlags, 3148).
--define(wxStyledTextCtrl_GetSearchFlags, 3149).
--define(wxStyledTextCtrl_CallTipShow, 3150).
--define(wxStyledTextCtrl_CallTipCancel, 3151).
--define(wxStyledTextCtrl_CallTipActive, 3152).
--define(wxStyledTextCtrl_CallTipPosAtStart, 3153).
--define(wxStyledTextCtrl_CallTipSetHighlight, 3154).
--define(wxStyledTextCtrl_CallTipSetBackground, 3155).
--define(wxStyledTextCtrl_CallTipSetForeground, 3156).
--define(wxStyledTextCtrl_CallTipSetForegroundHighlight, 3157).
--define(wxStyledTextCtrl_CallTipUseStyle, 3158).
--define(wxStyledTextCtrl_VisibleFromDocLine, 3159).
--define(wxStyledTextCtrl_DocLineFromVisible, 3160).
--define(wxStyledTextCtrl_WrapCount, 3161).
--define(wxStyledTextCtrl_SetFoldLevel, 3162).
--define(wxStyledTextCtrl_GetFoldLevel, 3163).
--define(wxStyledTextCtrl_GetLastChild, 3164).
--define(wxStyledTextCtrl_GetFoldParent, 3165).
--define(wxStyledTextCtrl_ShowLines, 3166).
--define(wxStyledTextCtrl_HideLines, 3167).
--define(wxStyledTextCtrl_GetLineVisible, 3168).
--define(wxStyledTextCtrl_SetFoldExpanded, 3169).
--define(wxStyledTextCtrl_GetFoldExpanded, 3170).
--define(wxStyledTextCtrl_ToggleFold, 3171).
--define(wxStyledTextCtrl_EnsureVisible, 3172).
--define(wxStyledTextCtrl_SetFoldFlags, 3173).
--define(wxStyledTextCtrl_EnsureVisibleEnforcePolicy, 3174).
--define(wxStyledTextCtrl_SetTabIndents, 3175).
--define(wxStyledTextCtrl_GetTabIndents, 3176).
--define(wxStyledTextCtrl_SetBackSpaceUnIndents, 3177).
--define(wxStyledTextCtrl_GetBackSpaceUnIndents, 3178).
--define(wxStyledTextCtrl_SetMouseDwellTime, 3179).
--define(wxStyledTextCtrl_GetMouseDwellTime, 3180).
--define(wxStyledTextCtrl_WordStartPosition, 3181).
--define(wxStyledTextCtrl_WordEndPosition, 3182).
--define(wxStyledTextCtrl_SetWrapMode, 3183).
--define(wxStyledTextCtrl_GetWrapMode, 3184).
--define(wxStyledTextCtrl_SetWrapVisualFlags, 3185).
--define(wxStyledTextCtrl_GetWrapVisualFlags, 3186).
--define(wxStyledTextCtrl_SetWrapVisualFlagsLocation, 3187).
--define(wxStyledTextCtrl_GetWrapVisualFlagsLocation, 3188).
--define(wxStyledTextCtrl_SetWrapStartIndent, 3189).
--define(wxStyledTextCtrl_GetWrapStartIndent, 3190).
--define(wxStyledTextCtrl_SetLayoutCache, 3191).
--define(wxStyledTextCtrl_GetLayoutCache, 3192).
--define(wxStyledTextCtrl_SetScrollWidth, 3193).
--define(wxStyledTextCtrl_GetScrollWidth, 3194).
--define(wxStyledTextCtrl_TextWidth, 3195).
--define(wxStyledTextCtrl_GetEndAtLastLine, 3196).
--define(wxStyledTextCtrl_TextHeight, 3197).
--define(wxStyledTextCtrl_SetUseVerticalScrollBar, 3198).
--define(wxStyledTextCtrl_GetUseVerticalScrollBar, 3199).
--define(wxStyledTextCtrl_AppendText, 3200).
--define(wxStyledTextCtrl_GetTwoPhaseDraw, 3201).
--define(wxStyledTextCtrl_SetTwoPhaseDraw, 3202).
--define(wxStyledTextCtrl_TargetFromSelection, 3203).
--define(wxStyledTextCtrl_LinesJoin, 3204).
--define(wxStyledTextCtrl_LinesSplit, 3205).
--define(wxStyledTextCtrl_SetFoldMarginColour, 3206).
--define(wxStyledTextCtrl_SetFoldMarginHiColour, 3207).
--define(wxStyledTextCtrl_LineDown, 3208).
--define(wxStyledTextCtrl_LineDownExtend, 3209).
--define(wxStyledTextCtrl_LineUp, 3210).
--define(wxStyledTextCtrl_LineUpExtend, 3211).
--define(wxStyledTextCtrl_CharLeft, 3212).
--define(wxStyledTextCtrl_CharLeftExtend, 3213).
--define(wxStyledTextCtrl_CharRight, 3214).
--define(wxStyledTextCtrl_CharRightExtend, 3215).
--define(wxStyledTextCtrl_WordLeft, 3216).
--define(wxStyledTextCtrl_WordLeftExtend, 3217).
--define(wxStyledTextCtrl_WordRight, 3218).
--define(wxStyledTextCtrl_WordRightExtend, 3219).
--define(wxStyledTextCtrl_Home, 3220).
--define(wxStyledTextCtrl_HomeExtend, 3221).
--define(wxStyledTextCtrl_LineEnd, 3222).
--define(wxStyledTextCtrl_LineEndExtend, 3223).
--define(wxStyledTextCtrl_DocumentStart, 3224).
--define(wxStyledTextCtrl_DocumentStartExtend, 3225).
--define(wxStyledTextCtrl_DocumentEnd, 3226).
--define(wxStyledTextCtrl_DocumentEndExtend, 3227).
--define(wxStyledTextCtrl_PageUp, 3228).
--define(wxStyledTextCtrl_PageUpExtend, 3229).
--define(wxStyledTextCtrl_PageDown, 3230).
--define(wxStyledTextCtrl_PageDownExtend, 3231).
--define(wxStyledTextCtrl_EditToggleOvertype, 3232).
--define(wxStyledTextCtrl_Cancel, 3233).
--define(wxStyledTextCtrl_DeleteBack, 3234).
--define(wxStyledTextCtrl_Tab, 3235).
--define(wxStyledTextCtrl_BackTab, 3236).
--define(wxStyledTextCtrl_NewLine, 3237).
--define(wxStyledTextCtrl_FormFeed, 3238).
--define(wxStyledTextCtrl_VCHome, 3239).
--define(wxStyledTextCtrl_VCHomeExtend, 3240).
--define(wxStyledTextCtrl_ZoomIn, 3241).
--define(wxStyledTextCtrl_ZoomOut, 3242).
--define(wxStyledTextCtrl_DelWordLeft, 3243).
--define(wxStyledTextCtrl_DelWordRight, 3244).
--define(wxStyledTextCtrl_LineCut, 3245).
--define(wxStyledTextCtrl_LineDelete, 3246).
--define(wxStyledTextCtrl_LineTranspose, 3247).
--define(wxStyledTextCtrl_LineDuplicate, 3248).
--define(wxStyledTextCtrl_LowerCase, 3249).
--define(wxStyledTextCtrl_UpperCase, 3250).
--define(wxStyledTextCtrl_LineScrollDown, 3251).
--define(wxStyledTextCtrl_LineScrollUp, 3252).
--define(wxStyledTextCtrl_DeleteBackNotLine, 3253).
--define(wxStyledTextCtrl_HomeDisplay, 3254).
--define(wxStyledTextCtrl_HomeDisplayExtend, 3255).
--define(wxStyledTextCtrl_LineEndDisplay, 3256).
--define(wxStyledTextCtrl_LineEndDisplayExtend, 3257).
--define(wxStyledTextCtrl_HomeWrapExtend, 3258).
--define(wxStyledTextCtrl_LineEndWrap, 3259).
--define(wxStyledTextCtrl_LineEndWrapExtend, 3260).
--define(wxStyledTextCtrl_VCHomeWrap, 3261).
--define(wxStyledTextCtrl_VCHomeWrapExtend, 3262).
--define(wxStyledTextCtrl_LineCopy, 3263).
--define(wxStyledTextCtrl_MoveCaretInsideView, 3264).
--define(wxStyledTextCtrl_LineLength, 3265).
--define(wxStyledTextCtrl_BraceHighlight, 3266).
--define(wxStyledTextCtrl_BraceBadLight, 3267).
--define(wxStyledTextCtrl_BraceMatch, 3268).
--define(wxStyledTextCtrl_GetViewEOL, 3269).
--define(wxStyledTextCtrl_SetViewEOL, 3270).
--define(wxStyledTextCtrl_SetModEventMask, 3271).
--define(wxStyledTextCtrl_GetEdgeColumn, 3272).
--define(wxStyledTextCtrl_SetEdgeColumn, 3273).
--define(wxStyledTextCtrl_SetEdgeMode, 3274).
--define(wxStyledTextCtrl_GetEdgeMode, 3275).
--define(wxStyledTextCtrl_GetEdgeColour, 3276).
--define(wxStyledTextCtrl_SetEdgeColour, 3277).
--define(wxStyledTextCtrl_SearchAnchor, 3278).
--define(wxStyledTextCtrl_SearchNext, 3279).
--define(wxStyledTextCtrl_SearchPrev, 3280).
--define(wxStyledTextCtrl_LinesOnScreen, 3281).
--define(wxStyledTextCtrl_UsePopUp, 3282).
--define(wxStyledTextCtrl_SelectionIsRectangle, 3283).
--define(wxStyledTextCtrl_SetZoom, 3284).
--define(wxStyledTextCtrl_GetZoom, 3285).
--define(wxStyledTextCtrl_GetModEventMask, 3286).
--define(wxStyledTextCtrl_SetSTCFocus, 3287).
--define(wxStyledTextCtrl_GetSTCFocus, 3288).
--define(wxStyledTextCtrl_SetStatus, 3289).
--define(wxStyledTextCtrl_GetStatus, 3290).
--define(wxStyledTextCtrl_SetMouseDownCaptures, 3291).
--define(wxStyledTextCtrl_GetMouseDownCaptures, 3292).
--define(wxStyledTextCtrl_SetSTCCursor, 3293).
--define(wxStyledTextCtrl_GetSTCCursor, 3294).
--define(wxStyledTextCtrl_SetControlCharSymbol, 3295).
--define(wxStyledTextCtrl_GetControlCharSymbol, 3296).
--define(wxStyledTextCtrl_WordPartLeft, 3297).
--define(wxStyledTextCtrl_WordPartLeftExtend, 3298).
--define(wxStyledTextCtrl_WordPartRight, 3299).
--define(wxStyledTextCtrl_WordPartRightExtend, 3300).
--define(wxStyledTextCtrl_SetVisiblePolicy, 3301).
--define(wxStyledTextCtrl_DelLineLeft, 3302).
--define(wxStyledTextCtrl_DelLineRight, 3303).
--define(wxStyledTextCtrl_GetXOffset, 3304).
--define(wxStyledTextCtrl_ChooseCaretX, 3305).
--define(wxStyledTextCtrl_SetXCaretPolicy, 3306).
--define(wxStyledTextCtrl_SetYCaretPolicy, 3307).
--define(wxStyledTextCtrl_GetPrintWrapMode, 3308).
--define(wxStyledTextCtrl_SetHotspotActiveForeground, 3309).
--define(wxStyledTextCtrl_SetHotspotActiveBackground, 3310).
--define(wxStyledTextCtrl_SetHotspotActiveUnderline, 3311).
--define(wxStyledTextCtrl_SetHotspotSingleLine, 3312).
--define(wxStyledTextCtrl_ParaDownExtend, 3313).
--define(wxStyledTextCtrl_ParaUp, 3314).
--define(wxStyledTextCtrl_ParaUpExtend, 3315).
--define(wxStyledTextCtrl_PositionBefore, 3316).
--define(wxStyledTextCtrl_PositionAfter, 3317).
--define(wxStyledTextCtrl_CopyRange, 3318).
--define(wxStyledTextCtrl_CopyText, 3319).
--define(wxStyledTextCtrl_SetSelectionMode, 3320).
--define(wxStyledTextCtrl_GetSelectionMode, 3321).
--define(wxStyledTextCtrl_LineDownRectExtend, 3322).
--define(wxStyledTextCtrl_LineUpRectExtend, 3323).
--define(wxStyledTextCtrl_CharLeftRectExtend, 3324).
--define(wxStyledTextCtrl_CharRightRectExtend, 3325).
--define(wxStyledTextCtrl_HomeRectExtend, 3326).
--define(wxStyledTextCtrl_VCHomeRectExtend, 3327).
--define(wxStyledTextCtrl_LineEndRectExtend, 3328).
--define(wxStyledTextCtrl_PageUpRectExtend, 3329).
--define(wxStyledTextCtrl_PageDownRectExtend, 3330).
--define(wxStyledTextCtrl_StutteredPageUp, 3331).
--define(wxStyledTextCtrl_StutteredPageUpExtend, 3332).
--define(wxStyledTextCtrl_StutteredPageDown, 3333).
--define(wxStyledTextCtrl_StutteredPageDownExtend, 3334).
--define(wxStyledTextCtrl_WordLeftEnd, 3335).
--define(wxStyledTextCtrl_WordLeftEndExtend, 3336).
--define(wxStyledTextCtrl_WordRightEnd, 3337).
--define(wxStyledTextCtrl_WordRightEndExtend, 3338).
--define(wxStyledTextCtrl_SetWhitespaceChars, 3339).
--define(wxStyledTextCtrl_SetCharsDefault, 3340).
--define(wxStyledTextCtrl_AutoCompGetCurrent, 3341).
--define(wxStyledTextCtrl_Allocate, 3342).
--define(wxStyledTextCtrl_FindColumn, 3343).
--define(wxStyledTextCtrl_GetCaretSticky, 3344).
--define(wxStyledTextCtrl_SetCaretSticky, 3345).
--define(wxStyledTextCtrl_ToggleCaretSticky, 3346).
--define(wxStyledTextCtrl_SetPasteConvertEndings, 3347).
--define(wxStyledTextCtrl_GetPasteConvertEndings, 3348).
--define(wxStyledTextCtrl_SelectionDuplicate, 3349).
--define(wxStyledTextCtrl_SetCaretLineBackAlpha, 3350).
--define(wxStyledTextCtrl_GetCaretLineBackAlpha, 3351).
--define(wxStyledTextCtrl_StartRecord, 3352).
--define(wxStyledTextCtrl_StopRecord, 3353).
--define(wxStyledTextCtrl_SetLexer, 3354).
--define(wxStyledTextCtrl_GetLexer, 3355).
--define(wxStyledTextCtrl_Colourise, 3356).
--define(wxStyledTextCtrl_SetProperty, 3357).
--define(wxStyledTextCtrl_SetKeyWords, 3358).
--define(wxStyledTextCtrl_SetLexerLanguage, 3359).
--define(wxStyledTextCtrl_GetProperty, 3360).
--define(wxStyledTextCtrl_GetStyleBitsNeeded, 3361).
--define(wxStyledTextCtrl_GetCurrentLine, 3362).
--define(wxStyledTextCtrl_StyleSetSpec, 3363).
--define(wxStyledTextCtrl_StyleSetFont, 3364).
--define(wxStyledTextCtrl_StyleSetFontAttr, 3365).
--define(wxStyledTextCtrl_StyleSetCharacterSet, 3366).
--define(wxStyledTextCtrl_StyleSetFontEncoding, 3367).
--define(wxStyledTextCtrl_CmdKeyExecute, 3368).
--define(wxStyledTextCtrl_SetMargins, 3369).
--define(wxStyledTextCtrl_GetSelection, 3370).
--define(wxStyledTextCtrl_PointFromPosition, 3371).
--define(wxStyledTextCtrl_ScrollToLine, 3372).
--define(wxStyledTextCtrl_ScrollToColumn, 3373).
--define(wxStyledTextCtrl_SetVScrollBar, 3374).
--define(wxStyledTextCtrl_SetHScrollBar, 3375).
--define(wxStyledTextCtrl_GetLastKeydownProcessed, 3376).
--define(wxStyledTextCtrl_SetLastKeydownProcessed, 3377).
--define(wxStyledTextCtrl_SaveFile, 3378).
--define(wxStyledTextCtrl_LoadFile, 3379).
--define(wxStyledTextCtrl_DoDragOver, 3380).
--define(wxStyledTextCtrl_DoDropText, 3381).
--define(wxStyledTextCtrl_GetUseAntiAliasing, 3382).
--define(wxStyledTextCtrl_AddTextRaw, 3383).
--define(wxStyledTextCtrl_InsertTextRaw, 3384).
--define(wxStyledTextCtrl_GetCurLineRaw, 3385).
--define(wxStyledTextCtrl_GetLineRaw, 3386).
--define(wxStyledTextCtrl_GetSelectedTextRaw, 3387).
--define(wxStyledTextCtrl_GetTextRangeRaw, 3388).
--define(wxStyledTextCtrl_SetTextRaw, 3389).
--define(wxStyledTextCtrl_GetTextRaw, 3390).
--define(wxStyledTextCtrl_AppendTextRaw, 3391).
--define(wxArtProvider_GetBitmap, 3392).
--define(wxArtProvider_GetIcon, 3393).
--define(wxTreeEvent_GetKeyCode, 3394).
--define(wxTreeEvent_GetItem, 3395).
--define(wxTreeEvent_GetKeyEvent, 3396).
--define(wxTreeEvent_GetLabel, 3397).
--define(wxTreeEvent_GetOldItem, 3398).
--define(wxTreeEvent_GetPoint, 3399).
--define(wxTreeEvent_IsEditCancelled, 3400).
--define(wxTreeEvent_SetToolTip, 3401).
--define(wxNotebookEvent_GetOldSelection, 3402).
--define(wxNotebookEvent_GetSelection, 3403).
--define(wxNotebookEvent_SetOldSelection, 3404).
--define(wxNotebookEvent_SetSelection, 3405).
--define(wxFileDataObject_new, 3406).
--define(wxFileDataObject_AddFile, 3407).
--define(wxFileDataObject_GetFilenames, 3408).
--define(wxFileDataObject_destroy, 3409).
--define(wxTextDataObject_new, 3410).
--define(wxTextDataObject_GetTextLength, 3411).
--define(wxTextDataObject_GetText, 3412).
--define(wxTextDataObject_SetText, 3413).
--define(wxTextDataObject_destroy, 3414).
--define(wxBitmapDataObject_new_1_1, 3415).
--define(wxBitmapDataObject_new_1_0, 3416).
--define(wxBitmapDataObject_GetBitmap, 3417).
--define(wxBitmapDataObject_SetBitmap, 3418).
--define(wxBitmapDataObject_destroy, 3419).
--define(wxClipboard_new, 3421).
--define(wxClipboard_destruct, 3422).
--define(wxClipboard_AddData, 3423).
--define(wxClipboard_Clear, 3424).
--define(wxClipboard_Close, 3425).
--define(wxClipboard_Flush, 3426).
--define(wxClipboard_GetData, 3427).
--define(wxClipboard_IsOpened, 3428).
--define(wxClipboard_Open, 3429).
--define(wxClipboard_SetData, 3430).
--define(wxClipboard_UsePrimarySelection, 3432).
--define(wxClipboard_IsSupported, 3433).
--define(wxClipboard_Get, 3434).
--define(wxSpinEvent_GetPosition, 3435).
--define(wxSpinEvent_SetPosition, 3436).
--define(wxSplitterWindow_new_0, 3437).
--define(wxSplitterWindow_new_2, 3438).
--define(wxSplitterWindow_destruct, 3439).
--define(wxSplitterWindow_Create, 3440).
--define(wxSplitterWindow_GetMinimumPaneSize, 3441).
--define(wxSplitterWindow_GetSashGravity, 3442).
--define(wxSplitterWindow_GetSashPosition, 3443).
--define(wxSplitterWindow_GetSplitMode, 3444).
--define(wxSplitterWindow_GetWindow1, 3445).
--define(wxSplitterWindow_GetWindow2, 3446).
--define(wxSplitterWindow_Initialize, 3447).
--define(wxSplitterWindow_IsSplit, 3448).
--define(wxSplitterWindow_ReplaceWindow, 3449).
--define(wxSplitterWindow_SetSashGravity, 3450).
--define(wxSplitterWindow_SetSashPosition, 3451).
--define(wxSplitterWindow_SetSashSize, 3452).
--define(wxSplitterWindow_SetMinimumPaneSize, 3453).
--define(wxSplitterWindow_SetSplitMode, 3454).
--define(wxSplitterWindow_SplitHorizontally, 3455).
--define(wxSplitterWindow_SplitVertically, 3456).
--define(wxSplitterWindow_Unsplit, 3457).
--define(wxSplitterWindow_UpdateSize, 3458).
--define(wxSplitterEvent_GetSashPosition, 3459).
--define(wxSplitterEvent_GetX, 3460).
--define(wxSplitterEvent_GetY, 3461).
--define(wxSplitterEvent_GetWindowBeingRemoved, 3462).
--define(wxSplitterEvent_SetSashPosition, 3463).
--define(wxHtmlWindow_new_0, 3464).
--define(wxHtmlWindow_new_2, 3465).
--define(wxHtmlWindow_AppendToPage, 3466).
--define(wxHtmlWindow_GetOpenedAnchor, 3467).
--define(wxHtmlWindow_GetOpenedPage, 3468).
--define(wxHtmlWindow_GetOpenedPageTitle, 3469).
--define(wxHtmlWindow_GetRelatedFrame, 3470).
--define(wxHtmlWindow_HistoryBack, 3471).
--define(wxHtmlWindow_HistoryCanBack, 3472).
--define(wxHtmlWindow_HistoryCanForward, 3473).
--define(wxHtmlWindow_HistoryClear, 3474).
--define(wxHtmlWindow_HistoryForward, 3475).
--define(wxHtmlWindow_LoadFile, 3476).
--define(wxHtmlWindow_LoadPage, 3477).
--define(wxHtmlWindow_SelectAll, 3478).
--define(wxHtmlWindow_SelectionToText, 3479).
--define(wxHtmlWindow_SelectLine, 3480).
--define(wxHtmlWindow_SelectWord, 3481).
--define(wxHtmlWindow_SetBorders, 3482).
--define(wxHtmlWindow_SetFonts, 3483).
--define(wxHtmlWindow_SetPage, 3484).
--define(wxHtmlWindow_SetRelatedFrame, 3485).
--define(wxHtmlWindow_SetRelatedStatusBar, 3486).
--define(wxHtmlWindow_ToText, 3487).
--define(wxHtmlWindow_destroy, 3488).
--define(wxHtmlLinkEvent_GetLinkInfo, 3489).
--define(wxSystemSettings_GetColour, 3490).
--define(wxSystemSettings_GetFont, 3491).
--define(wxSystemSettings_GetMetric, 3492).
--define(wxSystemSettings_GetScreenType, 3493).
--define(wxSystemOptions_GetOption, 3494).
--define(wxSystemOptions_GetOptionInt, 3495).
--define(wxSystemOptions_HasOption, 3496).
--define(wxSystemOptions_IsFalse, 3497).
--define(wxSystemOptions_SetOption_2_1, 3498).
--define(wxSystemOptions_SetOption_2_0, 3499).
--define(wxAuiNotebookEvent_SetSelection, 3500).
--define(wxAuiNotebookEvent_GetSelection, 3501).
--define(wxAuiNotebookEvent_SetOldSelection, 3502).
--define(wxAuiNotebookEvent_GetOldSelection, 3503).
--define(wxAuiNotebookEvent_SetDragSource, 3504).
--define(wxAuiNotebookEvent_GetDragSource, 3505).
--define(wxAuiManagerEvent_SetManager, 3506).
--define(wxAuiManagerEvent_GetManager, 3507).
--define(wxAuiManagerEvent_SetPane, 3508).
--define(wxAuiManagerEvent_GetPane, 3509).
--define(wxAuiManagerEvent_SetButton, 3510).
--define(wxAuiManagerEvent_GetButton, 3511).
--define(wxAuiManagerEvent_SetDC, 3512).
--define(wxAuiManagerEvent_GetDC, 3513).
--define(wxAuiManagerEvent_Veto, 3514).
--define(wxAuiManagerEvent_GetVeto, 3515).
--define(wxAuiManagerEvent_SetCanVeto, 3516).
--define(wxAuiManagerEvent_CanVeto, 3517).
--define(wxLogNull_new, 3518).
--define(wxLogNull_destroy, 3519).
--define(wxTaskBarIcon_new, 3520).
--define(wxTaskBarIcon_destruct, 3521).
--define(wxTaskBarIcon_PopupMenu, 3522).
--define(wxTaskBarIcon_RemoveIcon, 3523).
--define(wxTaskBarIcon_SetIcon, 3524).
+-define(gdicmn_wxDisplaySize, 2927).
+-define(gdicmn_wxSetCursor, 2928).
+-define(wxPrintout_new, 2929).
+-define(wxPrintout_destruct, 2930).
+-define(wxPrintout_GetDC, 2931).
+-define(wxPrintout_GetPageSizeMM, 2932).
+-define(wxPrintout_GetPageSizePixels, 2933).
+-define(wxPrintout_GetPaperRectPixels, 2934).
+-define(wxPrintout_GetPPIPrinter, 2935).
+-define(wxPrintout_GetPPIScreen, 2936).
+-define(wxPrintout_GetTitle, 2937).
+-define(wxPrintout_IsPreview, 2938).
+-define(wxPrintout_FitThisSizeToPaper, 2939).
+-define(wxPrintout_FitThisSizeToPage, 2940).
+-define(wxPrintout_FitThisSizeToPageMargins, 2941).
+-define(wxPrintout_MapScreenSizeToPaper, 2942).
+-define(wxPrintout_MapScreenSizeToPage, 2943).
+-define(wxPrintout_MapScreenSizeToPageMargins, 2944).
+-define(wxPrintout_MapScreenSizeToDevice, 2945).
+-define(wxPrintout_GetLogicalPaperRect, 2946).
+-define(wxPrintout_GetLogicalPageRect, 2947).
+-define(wxPrintout_GetLogicalPageMarginsRect, 2948).
+-define(wxPrintout_SetLogicalOrigin, 2949).
+-define(wxPrintout_OffsetLogicalOrigin, 2950).
+-define(wxStyledTextCtrl_new_2, 2951).
+-define(wxStyledTextCtrl_new_0, 2952).
+-define(wxStyledTextCtrl_destruct, 2953).
+-define(wxStyledTextCtrl_Create, 2954).
+-define(wxStyledTextCtrl_AddText, 2955).
+-define(wxStyledTextCtrl_AddStyledText, 2956).
+-define(wxStyledTextCtrl_InsertText, 2957).
+-define(wxStyledTextCtrl_ClearAll, 2958).
+-define(wxStyledTextCtrl_ClearDocumentStyle, 2959).
+-define(wxStyledTextCtrl_GetLength, 2960).
+-define(wxStyledTextCtrl_GetCharAt, 2961).
+-define(wxStyledTextCtrl_GetCurrentPos, 2962).
+-define(wxStyledTextCtrl_GetAnchor, 2963).
+-define(wxStyledTextCtrl_GetStyleAt, 2964).
+-define(wxStyledTextCtrl_Redo, 2965).
+-define(wxStyledTextCtrl_SetUndoCollection, 2966).
+-define(wxStyledTextCtrl_SelectAll, 2967).
+-define(wxStyledTextCtrl_SetSavePoint, 2968).
+-define(wxStyledTextCtrl_GetStyledText, 2969).
+-define(wxStyledTextCtrl_CanRedo, 2970).
+-define(wxStyledTextCtrl_MarkerLineFromHandle, 2971).
+-define(wxStyledTextCtrl_MarkerDeleteHandle, 2972).
+-define(wxStyledTextCtrl_GetUndoCollection, 2973).
+-define(wxStyledTextCtrl_GetViewWhiteSpace, 2974).
+-define(wxStyledTextCtrl_SetViewWhiteSpace, 2975).
+-define(wxStyledTextCtrl_PositionFromPoint, 2976).
+-define(wxStyledTextCtrl_PositionFromPointClose, 2977).
+-define(wxStyledTextCtrl_GotoLine, 2978).
+-define(wxStyledTextCtrl_GotoPos, 2979).
+-define(wxStyledTextCtrl_SetAnchor, 2980).
+-define(wxStyledTextCtrl_GetCurLine, 2981).
+-define(wxStyledTextCtrl_GetEndStyled, 2982).
+-define(wxStyledTextCtrl_ConvertEOLs, 2983).
+-define(wxStyledTextCtrl_GetEOLMode, 2984).
+-define(wxStyledTextCtrl_SetEOLMode, 2985).
+-define(wxStyledTextCtrl_StartStyling, 2986).
+-define(wxStyledTextCtrl_SetStyling, 2987).
+-define(wxStyledTextCtrl_GetBufferedDraw, 2988).
+-define(wxStyledTextCtrl_SetBufferedDraw, 2989).
+-define(wxStyledTextCtrl_SetTabWidth, 2990).
+-define(wxStyledTextCtrl_GetTabWidth, 2991).
+-define(wxStyledTextCtrl_SetCodePage, 2992).
+-define(wxStyledTextCtrl_MarkerDefine, 2993).
+-define(wxStyledTextCtrl_MarkerSetForeground, 2994).
+-define(wxStyledTextCtrl_MarkerSetBackground, 2995).
+-define(wxStyledTextCtrl_MarkerAdd, 2996).
+-define(wxStyledTextCtrl_MarkerDelete, 2997).
+-define(wxStyledTextCtrl_MarkerDeleteAll, 2998).
+-define(wxStyledTextCtrl_MarkerGet, 2999).
+-define(wxStyledTextCtrl_MarkerNext, 3000).
+-define(wxStyledTextCtrl_MarkerPrevious, 3001).
+-define(wxStyledTextCtrl_MarkerDefineBitmap, 3002).
+-define(wxStyledTextCtrl_MarkerAddSet, 3003).
+-define(wxStyledTextCtrl_MarkerSetAlpha, 3004).
+-define(wxStyledTextCtrl_SetMarginType, 3005).
+-define(wxStyledTextCtrl_GetMarginType, 3006).
+-define(wxStyledTextCtrl_SetMarginWidth, 3007).
+-define(wxStyledTextCtrl_GetMarginWidth, 3008).
+-define(wxStyledTextCtrl_SetMarginMask, 3009).
+-define(wxStyledTextCtrl_GetMarginMask, 3010).
+-define(wxStyledTextCtrl_SetMarginSensitive, 3011).
+-define(wxStyledTextCtrl_GetMarginSensitive, 3012).
+-define(wxStyledTextCtrl_StyleClearAll, 3013).
+-define(wxStyledTextCtrl_StyleSetForeground, 3014).
+-define(wxStyledTextCtrl_StyleSetBackground, 3015).
+-define(wxStyledTextCtrl_StyleSetBold, 3016).
+-define(wxStyledTextCtrl_StyleSetItalic, 3017).
+-define(wxStyledTextCtrl_StyleSetSize, 3018).
+-define(wxStyledTextCtrl_StyleSetFaceName, 3019).
+-define(wxStyledTextCtrl_StyleSetEOLFilled, 3020).
+-define(wxStyledTextCtrl_StyleResetDefault, 3021).
+-define(wxStyledTextCtrl_StyleSetUnderline, 3022).
+-define(wxStyledTextCtrl_StyleSetCase, 3023).
+-define(wxStyledTextCtrl_StyleSetHotSpot, 3024).
+-define(wxStyledTextCtrl_SetSelForeground, 3025).
+-define(wxStyledTextCtrl_SetSelBackground, 3026).
+-define(wxStyledTextCtrl_GetSelAlpha, 3027).
+-define(wxStyledTextCtrl_SetSelAlpha, 3028).
+-define(wxStyledTextCtrl_SetCaretForeground, 3029).
+-define(wxStyledTextCtrl_CmdKeyAssign, 3030).
+-define(wxStyledTextCtrl_CmdKeyClear, 3031).
+-define(wxStyledTextCtrl_CmdKeyClearAll, 3032).
+-define(wxStyledTextCtrl_SetStyleBytes, 3033).
+-define(wxStyledTextCtrl_StyleSetVisible, 3034).
+-define(wxStyledTextCtrl_GetCaretPeriod, 3035).
+-define(wxStyledTextCtrl_SetCaretPeriod, 3036).
+-define(wxStyledTextCtrl_SetWordChars, 3037).
+-define(wxStyledTextCtrl_BeginUndoAction, 3038).
+-define(wxStyledTextCtrl_EndUndoAction, 3039).
+-define(wxStyledTextCtrl_IndicatorSetStyle, 3040).
+-define(wxStyledTextCtrl_IndicatorGetStyle, 3041).
+-define(wxStyledTextCtrl_IndicatorSetForeground, 3042).
+-define(wxStyledTextCtrl_IndicatorGetForeground, 3043).
+-define(wxStyledTextCtrl_SetWhitespaceForeground, 3044).
+-define(wxStyledTextCtrl_SetWhitespaceBackground, 3045).
+-define(wxStyledTextCtrl_GetStyleBits, 3046).
+-define(wxStyledTextCtrl_SetLineState, 3047).
+-define(wxStyledTextCtrl_GetLineState, 3048).
+-define(wxStyledTextCtrl_GetMaxLineState, 3049).
+-define(wxStyledTextCtrl_GetCaretLineVisible, 3050).
+-define(wxStyledTextCtrl_SetCaretLineVisible, 3051).
+-define(wxStyledTextCtrl_GetCaretLineBackground, 3052).
+-define(wxStyledTextCtrl_SetCaretLineBackground, 3053).
+-define(wxStyledTextCtrl_AutoCompShow, 3054).
+-define(wxStyledTextCtrl_AutoCompCancel, 3055).
+-define(wxStyledTextCtrl_AutoCompActive, 3056).
+-define(wxStyledTextCtrl_AutoCompPosStart, 3057).
+-define(wxStyledTextCtrl_AutoCompComplete, 3058).
+-define(wxStyledTextCtrl_AutoCompStops, 3059).
+-define(wxStyledTextCtrl_AutoCompSetSeparator, 3060).
+-define(wxStyledTextCtrl_AutoCompGetSeparator, 3061).
+-define(wxStyledTextCtrl_AutoCompSelect, 3062).
+-define(wxStyledTextCtrl_AutoCompSetCancelAtStart, 3063).
+-define(wxStyledTextCtrl_AutoCompGetCancelAtStart, 3064).
+-define(wxStyledTextCtrl_AutoCompSetFillUps, 3065).
+-define(wxStyledTextCtrl_AutoCompSetChooseSingle, 3066).
+-define(wxStyledTextCtrl_AutoCompGetChooseSingle, 3067).
+-define(wxStyledTextCtrl_AutoCompSetIgnoreCase, 3068).
+-define(wxStyledTextCtrl_AutoCompGetIgnoreCase, 3069).
+-define(wxStyledTextCtrl_UserListShow, 3070).
+-define(wxStyledTextCtrl_AutoCompSetAutoHide, 3071).
+-define(wxStyledTextCtrl_AutoCompGetAutoHide, 3072).
+-define(wxStyledTextCtrl_AutoCompSetDropRestOfWord, 3073).
+-define(wxStyledTextCtrl_AutoCompGetDropRestOfWord, 3074).
+-define(wxStyledTextCtrl_RegisterImage, 3075).
+-define(wxStyledTextCtrl_ClearRegisteredImages, 3076).
+-define(wxStyledTextCtrl_AutoCompGetTypeSeparator, 3077).
+-define(wxStyledTextCtrl_AutoCompSetTypeSeparator, 3078).
+-define(wxStyledTextCtrl_AutoCompSetMaxWidth, 3079).
+-define(wxStyledTextCtrl_AutoCompGetMaxWidth, 3080).
+-define(wxStyledTextCtrl_AutoCompSetMaxHeight, 3081).
+-define(wxStyledTextCtrl_AutoCompGetMaxHeight, 3082).
+-define(wxStyledTextCtrl_SetIndent, 3083).
+-define(wxStyledTextCtrl_GetIndent, 3084).
+-define(wxStyledTextCtrl_SetUseTabs, 3085).
+-define(wxStyledTextCtrl_GetUseTabs, 3086).
+-define(wxStyledTextCtrl_SetLineIndentation, 3087).
+-define(wxStyledTextCtrl_GetLineIndentation, 3088).
+-define(wxStyledTextCtrl_GetLineIndentPosition, 3089).
+-define(wxStyledTextCtrl_GetColumn, 3090).
+-define(wxStyledTextCtrl_SetUseHorizontalScrollBar, 3091).
+-define(wxStyledTextCtrl_GetUseHorizontalScrollBar, 3092).
+-define(wxStyledTextCtrl_SetIndentationGuides, 3093).
+-define(wxStyledTextCtrl_GetIndentationGuides, 3094).
+-define(wxStyledTextCtrl_SetHighlightGuide, 3095).
+-define(wxStyledTextCtrl_GetHighlightGuide, 3096).
+-define(wxStyledTextCtrl_GetLineEndPosition, 3097).
+-define(wxStyledTextCtrl_GetCodePage, 3098).
+-define(wxStyledTextCtrl_GetCaretForeground, 3099).
+-define(wxStyledTextCtrl_GetReadOnly, 3100).
+-define(wxStyledTextCtrl_SetCurrentPos, 3101).
+-define(wxStyledTextCtrl_SetSelectionStart, 3102).
+-define(wxStyledTextCtrl_GetSelectionStart, 3103).
+-define(wxStyledTextCtrl_SetSelectionEnd, 3104).
+-define(wxStyledTextCtrl_GetSelectionEnd, 3105).
+-define(wxStyledTextCtrl_SetPrintMagnification, 3106).
+-define(wxStyledTextCtrl_GetPrintMagnification, 3107).
+-define(wxStyledTextCtrl_SetPrintColourMode, 3108).
+-define(wxStyledTextCtrl_GetPrintColourMode, 3109).
+-define(wxStyledTextCtrl_FindText, 3110).
+-define(wxStyledTextCtrl_FormatRange, 3111).
+-define(wxStyledTextCtrl_GetFirstVisibleLine, 3112).
+-define(wxStyledTextCtrl_GetLine, 3113).
+-define(wxStyledTextCtrl_GetLineCount, 3114).
+-define(wxStyledTextCtrl_SetMarginLeft, 3115).
+-define(wxStyledTextCtrl_GetMarginLeft, 3116).
+-define(wxStyledTextCtrl_SetMarginRight, 3117).
+-define(wxStyledTextCtrl_GetMarginRight, 3118).
+-define(wxStyledTextCtrl_GetModify, 3119).
+-define(wxStyledTextCtrl_SetSelection, 3120).
+-define(wxStyledTextCtrl_GetSelectedText, 3121).
+-define(wxStyledTextCtrl_GetTextRange, 3122).
+-define(wxStyledTextCtrl_HideSelection, 3123).
+-define(wxStyledTextCtrl_LineFromPosition, 3124).
+-define(wxStyledTextCtrl_PositionFromLine, 3125).
+-define(wxStyledTextCtrl_LineScroll, 3126).
+-define(wxStyledTextCtrl_EnsureCaretVisible, 3127).
+-define(wxStyledTextCtrl_ReplaceSelection, 3128).
+-define(wxStyledTextCtrl_SetReadOnly, 3129).
+-define(wxStyledTextCtrl_CanPaste, 3130).
+-define(wxStyledTextCtrl_CanUndo, 3131).
+-define(wxStyledTextCtrl_EmptyUndoBuffer, 3132).
+-define(wxStyledTextCtrl_Undo, 3133).
+-define(wxStyledTextCtrl_Cut, 3134).
+-define(wxStyledTextCtrl_Copy, 3135).
+-define(wxStyledTextCtrl_Paste, 3136).
+-define(wxStyledTextCtrl_Clear, 3137).
+-define(wxStyledTextCtrl_SetText, 3138).
+-define(wxStyledTextCtrl_GetText, 3139).
+-define(wxStyledTextCtrl_GetTextLength, 3140).
+-define(wxStyledTextCtrl_GetOvertype, 3141).
+-define(wxStyledTextCtrl_SetCaretWidth, 3142).
+-define(wxStyledTextCtrl_GetCaretWidth, 3143).
+-define(wxStyledTextCtrl_SetTargetStart, 3144).
+-define(wxStyledTextCtrl_GetTargetStart, 3145).
+-define(wxStyledTextCtrl_SetTargetEnd, 3146).
+-define(wxStyledTextCtrl_GetTargetEnd, 3147).
+-define(wxStyledTextCtrl_ReplaceTarget, 3148).
+-define(wxStyledTextCtrl_SearchInTarget, 3149).
+-define(wxStyledTextCtrl_SetSearchFlags, 3150).
+-define(wxStyledTextCtrl_GetSearchFlags, 3151).
+-define(wxStyledTextCtrl_CallTipShow, 3152).
+-define(wxStyledTextCtrl_CallTipCancel, 3153).
+-define(wxStyledTextCtrl_CallTipActive, 3154).
+-define(wxStyledTextCtrl_CallTipPosAtStart, 3155).
+-define(wxStyledTextCtrl_CallTipSetHighlight, 3156).
+-define(wxStyledTextCtrl_CallTipSetBackground, 3157).
+-define(wxStyledTextCtrl_CallTipSetForeground, 3158).
+-define(wxStyledTextCtrl_CallTipSetForegroundHighlight, 3159).
+-define(wxStyledTextCtrl_CallTipUseStyle, 3160).
+-define(wxStyledTextCtrl_VisibleFromDocLine, 3161).
+-define(wxStyledTextCtrl_DocLineFromVisible, 3162).
+-define(wxStyledTextCtrl_WrapCount, 3163).
+-define(wxStyledTextCtrl_SetFoldLevel, 3164).
+-define(wxStyledTextCtrl_GetFoldLevel, 3165).
+-define(wxStyledTextCtrl_GetLastChild, 3166).
+-define(wxStyledTextCtrl_GetFoldParent, 3167).
+-define(wxStyledTextCtrl_ShowLines, 3168).
+-define(wxStyledTextCtrl_HideLines, 3169).
+-define(wxStyledTextCtrl_GetLineVisible, 3170).
+-define(wxStyledTextCtrl_SetFoldExpanded, 3171).
+-define(wxStyledTextCtrl_GetFoldExpanded, 3172).
+-define(wxStyledTextCtrl_ToggleFold, 3173).
+-define(wxStyledTextCtrl_EnsureVisible, 3174).
+-define(wxStyledTextCtrl_SetFoldFlags, 3175).
+-define(wxStyledTextCtrl_EnsureVisibleEnforcePolicy, 3176).
+-define(wxStyledTextCtrl_SetTabIndents, 3177).
+-define(wxStyledTextCtrl_GetTabIndents, 3178).
+-define(wxStyledTextCtrl_SetBackSpaceUnIndents, 3179).
+-define(wxStyledTextCtrl_GetBackSpaceUnIndents, 3180).
+-define(wxStyledTextCtrl_SetMouseDwellTime, 3181).
+-define(wxStyledTextCtrl_GetMouseDwellTime, 3182).
+-define(wxStyledTextCtrl_WordStartPosition, 3183).
+-define(wxStyledTextCtrl_WordEndPosition, 3184).
+-define(wxStyledTextCtrl_SetWrapMode, 3185).
+-define(wxStyledTextCtrl_GetWrapMode, 3186).
+-define(wxStyledTextCtrl_SetWrapVisualFlags, 3187).
+-define(wxStyledTextCtrl_GetWrapVisualFlags, 3188).
+-define(wxStyledTextCtrl_SetWrapVisualFlagsLocation, 3189).
+-define(wxStyledTextCtrl_GetWrapVisualFlagsLocation, 3190).
+-define(wxStyledTextCtrl_SetWrapStartIndent, 3191).
+-define(wxStyledTextCtrl_GetWrapStartIndent, 3192).
+-define(wxStyledTextCtrl_SetLayoutCache, 3193).
+-define(wxStyledTextCtrl_GetLayoutCache, 3194).
+-define(wxStyledTextCtrl_SetScrollWidth, 3195).
+-define(wxStyledTextCtrl_GetScrollWidth, 3196).
+-define(wxStyledTextCtrl_TextWidth, 3197).
+-define(wxStyledTextCtrl_GetEndAtLastLine, 3198).
+-define(wxStyledTextCtrl_TextHeight, 3199).
+-define(wxStyledTextCtrl_SetUseVerticalScrollBar, 3200).
+-define(wxStyledTextCtrl_GetUseVerticalScrollBar, 3201).
+-define(wxStyledTextCtrl_AppendText, 3202).
+-define(wxStyledTextCtrl_GetTwoPhaseDraw, 3203).
+-define(wxStyledTextCtrl_SetTwoPhaseDraw, 3204).
+-define(wxStyledTextCtrl_TargetFromSelection, 3205).
+-define(wxStyledTextCtrl_LinesJoin, 3206).
+-define(wxStyledTextCtrl_LinesSplit, 3207).
+-define(wxStyledTextCtrl_SetFoldMarginColour, 3208).
+-define(wxStyledTextCtrl_SetFoldMarginHiColour, 3209).
+-define(wxStyledTextCtrl_LineDown, 3210).
+-define(wxStyledTextCtrl_LineDownExtend, 3211).
+-define(wxStyledTextCtrl_LineUp, 3212).
+-define(wxStyledTextCtrl_LineUpExtend, 3213).
+-define(wxStyledTextCtrl_CharLeft, 3214).
+-define(wxStyledTextCtrl_CharLeftExtend, 3215).
+-define(wxStyledTextCtrl_CharRight, 3216).
+-define(wxStyledTextCtrl_CharRightExtend, 3217).
+-define(wxStyledTextCtrl_WordLeft, 3218).
+-define(wxStyledTextCtrl_WordLeftExtend, 3219).
+-define(wxStyledTextCtrl_WordRight, 3220).
+-define(wxStyledTextCtrl_WordRightExtend, 3221).
+-define(wxStyledTextCtrl_Home, 3222).
+-define(wxStyledTextCtrl_HomeExtend, 3223).
+-define(wxStyledTextCtrl_LineEnd, 3224).
+-define(wxStyledTextCtrl_LineEndExtend, 3225).
+-define(wxStyledTextCtrl_DocumentStart, 3226).
+-define(wxStyledTextCtrl_DocumentStartExtend, 3227).
+-define(wxStyledTextCtrl_DocumentEnd, 3228).
+-define(wxStyledTextCtrl_DocumentEndExtend, 3229).
+-define(wxStyledTextCtrl_PageUp, 3230).
+-define(wxStyledTextCtrl_PageUpExtend, 3231).
+-define(wxStyledTextCtrl_PageDown, 3232).
+-define(wxStyledTextCtrl_PageDownExtend, 3233).
+-define(wxStyledTextCtrl_EditToggleOvertype, 3234).
+-define(wxStyledTextCtrl_Cancel, 3235).
+-define(wxStyledTextCtrl_DeleteBack, 3236).
+-define(wxStyledTextCtrl_Tab, 3237).
+-define(wxStyledTextCtrl_BackTab, 3238).
+-define(wxStyledTextCtrl_NewLine, 3239).
+-define(wxStyledTextCtrl_FormFeed, 3240).
+-define(wxStyledTextCtrl_VCHome, 3241).
+-define(wxStyledTextCtrl_VCHomeExtend, 3242).
+-define(wxStyledTextCtrl_ZoomIn, 3243).
+-define(wxStyledTextCtrl_ZoomOut, 3244).
+-define(wxStyledTextCtrl_DelWordLeft, 3245).
+-define(wxStyledTextCtrl_DelWordRight, 3246).
+-define(wxStyledTextCtrl_LineCut, 3247).
+-define(wxStyledTextCtrl_LineDelete, 3248).
+-define(wxStyledTextCtrl_LineTranspose, 3249).
+-define(wxStyledTextCtrl_LineDuplicate, 3250).
+-define(wxStyledTextCtrl_LowerCase, 3251).
+-define(wxStyledTextCtrl_UpperCase, 3252).
+-define(wxStyledTextCtrl_LineScrollDown, 3253).
+-define(wxStyledTextCtrl_LineScrollUp, 3254).
+-define(wxStyledTextCtrl_DeleteBackNotLine, 3255).
+-define(wxStyledTextCtrl_HomeDisplay, 3256).
+-define(wxStyledTextCtrl_HomeDisplayExtend, 3257).
+-define(wxStyledTextCtrl_LineEndDisplay, 3258).
+-define(wxStyledTextCtrl_LineEndDisplayExtend, 3259).
+-define(wxStyledTextCtrl_HomeWrapExtend, 3260).
+-define(wxStyledTextCtrl_LineEndWrap, 3261).
+-define(wxStyledTextCtrl_LineEndWrapExtend, 3262).
+-define(wxStyledTextCtrl_VCHomeWrap, 3263).
+-define(wxStyledTextCtrl_VCHomeWrapExtend, 3264).
+-define(wxStyledTextCtrl_LineCopy, 3265).
+-define(wxStyledTextCtrl_MoveCaretInsideView, 3266).
+-define(wxStyledTextCtrl_LineLength, 3267).
+-define(wxStyledTextCtrl_BraceHighlight, 3268).
+-define(wxStyledTextCtrl_BraceBadLight, 3269).
+-define(wxStyledTextCtrl_BraceMatch, 3270).
+-define(wxStyledTextCtrl_GetViewEOL, 3271).
+-define(wxStyledTextCtrl_SetViewEOL, 3272).
+-define(wxStyledTextCtrl_SetModEventMask, 3273).
+-define(wxStyledTextCtrl_GetEdgeColumn, 3274).
+-define(wxStyledTextCtrl_SetEdgeColumn, 3275).
+-define(wxStyledTextCtrl_SetEdgeMode, 3276).
+-define(wxStyledTextCtrl_GetEdgeMode, 3277).
+-define(wxStyledTextCtrl_GetEdgeColour, 3278).
+-define(wxStyledTextCtrl_SetEdgeColour, 3279).
+-define(wxStyledTextCtrl_SearchAnchor, 3280).
+-define(wxStyledTextCtrl_SearchNext, 3281).
+-define(wxStyledTextCtrl_SearchPrev, 3282).
+-define(wxStyledTextCtrl_LinesOnScreen, 3283).
+-define(wxStyledTextCtrl_UsePopUp, 3284).
+-define(wxStyledTextCtrl_SelectionIsRectangle, 3285).
+-define(wxStyledTextCtrl_SetZoom, 3286).
+-define(wxStyledTextCtrl_GetZoom, 3287).
+-define(wxStyledTextCtrl_GetModEventMask, 3288).
+-define(wxStyledTextCtrl_SetSTCFocus, 3289).
+-define(wxStyledTextCtrl_GetSTCFocus, 3290).
+-define(wxStyledTextCtrl_SetStatus, 3291).
+-define(wxStyledTextCtrl_GetStatus, 3292).
+-define(wxStyledTextCtrl_SetMouseDownCaptures, 3293).
+-define(wxStyledTextCtrl_GetMouseDownCaptures, 3294).
+-define(wxStyledTextCtrl_SetSTCCursor, 3295).
+-define(wxStyledTextCtrl_GetSTCCursor, 3296).
+-define(wxStyledTextCtrl_SetControlCharSymbol, 3297).
+-define(wxStyledTextCtrl_GetControlCharSymbol, 3298).
+-define(wxStyledTextCtrl_WordPartLeft, 3299).
+-define(wxStyledTextCtrl_WordPartLeftExtend, 3300).
+-define(wxStyledTextCtrl_WordPartRight, 3301).
+-define(wxStyledTextCtrl_WordPartRightExtend, 3302).
+-define(wxStyledTextCtrl_SetVisiblePolicy, 3303).
+-define(wxStyledTextCtrl_DelLineLeft, 3304).
+-define(wxStyledTextCtrl_DelLineRight, 3305).
+-define(wxStyledTextCtrl_GetXOffset, 3306).
+-define(wxStyledTextCtrl_ChooseCaretX, 3307).
+-define(wxStyledTextCtrl_SetXCaretPolicy, 3308).
+-define(wxStyledTextCtrl_SetYCaretPolicy, 3309).
+-define(wxStyledTextCtrl_GetPrintWrapMode, 3310).
+-define(wxStyledTextCtrl_SetHotspotActiveForeground, 3311).
+-define(wxStyledTextCtrl_SetHotspotActiveBackground, 3312).
+-define(wxStyledTextCtrl_SetHotspotActiveUnderline, 3313).
+-define(wxStyledTextCtrl_SetHotspotSingleLine, 3314).
+-define(wxStyledTextCtrl_ParaDownExtend, 3315).
+-define(wxStyledTextCtrl_ParaUp, 3316).
+-define(wxStyledTextCtrl_ParaUpExtend, 3317).
+-define(wxStyledTextCtrl_PositionBefore, 3318).
+-define(wxStyledTextCtrl_PositionAfter, 3319).
+-define(wxStyledTextCtrl_CopyRange, 3320).
+-define(wxStyledTextCtrl_CopyText, 3321).
+-define(wxStyledTextCtrl_SetSelectionMode, 3322).
+-define(wxStyledTextCtrl_GetSelectionMode, 3323).
+-define(wxStyledTextCtrl_LineDownRectExtend, 3324).
+-define(wxStyledTextCtrl_LineUpRectExtend, 3325).
+-define(wxStyledTextCtrl_CharLeftRectExtend, 3326).
+-define(wxStyledTextCtrl_CharRightRectExtend, 3327).
+-define(wxStyledTextCtrl_HomeRectExtend, 3328).
+-define(wxStyledTextCtrl_VCHomeRectExtend, 3329).
+-define(wxStyledTextCtrl_LineEndRectExtend, 3330).
+-define(wxStyledTextCtrl_PageUpRectExtend, 3331).
+-define(wxStyledTextCtrl_PageDownRectExtend, 3332).
+-define(wxStyledTextCtrl_StutteredPageUp, 3333).
+-define(wxStyledTextCtrl_StutteredPageUpExtend, 3334).
+-define(wxStyledTextCtrl_StutteredPageDown, 3335).
+-define(wxStyledTextCtrl_StutteredPageDownExtend, 3336).
+-define(wxStyledTextCtrl_WordLeftEnd, 3337).
+-define(wxStyledTextCtrl_WordLeftEndExtend, 3338).
+-define(wxStyledTextCtrl_WordRightEnd, 3339).
+-define(wxStyledTextCtrl_WordRightEndExtend, 3340).
+-define(wxStyledTextCtrl_SetWhitespaceChars, 3341).
+-define(wxStyledTextCtrl_SetCharsDefault, 3342).
+-define(wxStyledTextCtrl_AutoCompGetCurrent, 3343).
+-define(wxStyledTextCtrl_Allocate, 3344).
+-define(wxStyledTextCtrl_FindColumn, 3345).
+-define(wxStyledTextCtrl_GetCaretSticky, 3346).
+-define(wxStyledTextCtrl_SetCaretSticky, 3347).
+-define(wxStyledTextCtrl_ToggleCaretSticky, 3348).
+-define(wxStyledTextCtrl_SetPasteConvertEndings, 3349).
+-define(wxStyledTextCtrl_GetPasteConvertEndings, 3350).
+-define(wxStyledTextCtrl_SelectionDuplicate, 3351).
+-define(wxStyledTextCtrl_SetCaretLineBackAlpha, 3352).
+-define(wxStyledTextCtrl_GetCaretLineBackAlpha, 3353).
+-define(wxStyledTextCtrl_StartRecord, 3354).
+-define(wxStyledTextCtrl_StopRecord, 3355).
+-define(wxStyledTextCtrl_SetLexer, 3356).
+-define(wxStyledTextCtrl_GetLexer, 3357).
+-define(wxStyledTextCtrl_Colourise, 3358).
+-define(wxStyledTextCtrl_SetProperty, 3359).
+-define(wxStyledTextCtrl_SetKeyWords, 3360).
+-define(wxStyledTextCtrl_SetLexerLanguage, 3361).
+-define(wxStyledTextCtrl_GetProperty, 3362).
+-define(wxStyledTextCtrl_GetStyleBitsNeeded, 3363).
+-define(wxStyledTextCtrl_GetCurrentLine, 3364).
+-define(wxStyledTextCtrl_StyleSetSpec, 3365).
+-define(wxStyledTextCtrl_StyleSetFont, 3366).
+-define(wxStyledTextCtrl_StyleSetFontAttr, 3367).
+-define(wxStyledTextCtrl_StyleSetCharacterSet, 3368).
+-define(wxStyledTextCtrl_StyleSetFontEncoding, 3369).
+-define(wxStyledTextCtrl_CmdKeyExecute, 3370).
+-define(wxStyledTextCtrl_SetMargins, 3371).
+-define(wxStyledTextCtrl_GetSelection, 3372).
+-define(wxStyledTextCtrl_PointFromPosition, 3373).
+-define(wxStyledTextCtrl_ScrollToLine, 3374).
+-define(wxStyledTextCtrl_ScrollToColumn, 3375).
+-define(wxStyledTextCtrl_SetVScrollBar, 3376).
+-define(wxStyledTextCtrl_SetHScrollBar, 3377).
+-define(wxStyledTextCtrl_GetLastKeydownProcessed, 3378).
+-define(wxStyledTextCtrl_SetLastKeydownProcessed, 3379).
+-define(wxStyledTextCtrl_SaveFile, 3380).
+-define(wxStyledTextCtrl_LoadFile, 3381).
+-define(wxStyledTextCtrl_DoDragOver, 3382).
+-define(wxStyledTextCtrl_DoDropText, 3383).
+-define(wxStyledTextCtrl_GetUseAntiAliasing, 3384).
+-define(wxStyledTextCtrl_AddTextRaw, 3385).
+-define(wxStyledTextCtrl_InsertTextRaw, 3386).
+-define(wxStyledTextCtrl_GetCurLineRaw, 3387).
+-define(wxStyledTextCtrl_GetLineRaw, 3388).
+-define(wxStyledTextCtrl_GetSelectedTextRaw, 3389).
+-define(wxStyledTextCtrl_GetTextRangeRaw, 3390).
+-define(wxStyledTextCtrl_SetTextRaw, 3391).
+-define(wxStyledTextCtrl_GetTextRaw, 3392).
+-define(wxStyledTextCtrl_AppendTextRaw, 3393).
+-define(wxArtProvider_GetBitmap, 3394).
+-define(wxArtProvider_GetIcon, 3395).
+-define(wxTreeEvent_GetKeyCode, 3396).
+-define(wxTreeEvent_GetItem, 3397).
+-define(wxTreeEvent_GetKeyEvent, 3398).
+-define(wxTreeEvent_GetLabel, 3399).
+-define(wxTreeEvent_GetOldItem, 3400).
+-define(wxTreeEvent_GetPoint, 3401).
+-define(wxTreeEvent_IsEditCancelled, 3402).
+-define(wxTreeEvent_SetToolTip, 3403).
+-define(wxNotebookEvent_GetOldSelection, 3404).
+-define(wxNotebookEvent_GetSelection, 3405).
+-define(wxNotebookEvent_SetOldSelection, 3406).
+-define(wxNotebookEvent_SetSelection, 3407).
+-define(wxFileDataObject_new, 3408).
+-define(wxFileDataObject_AddFile, 3409).
+-define(wxFileDataObject_GetFilenames, 3410).
+-define(wxFileDataObject_destroy, 3411).
+-define(wxTextDataObject_new, 3412).
+-define(wxTextDataObject_GetTextLength, 3413).
+-define(wxTextDataObject_GetText, 3414).
+-define(wxTextDataObject_SetText, 3415).
+-define(wxTextDataObject_destroy, 3416).
+-define(wxBitmapDataObject_new_1_1, 3417).
+-define(wxBitmapDataObject_new_1_0, 3418).
+-define(wxBitmapDataObject_GetBitmap, 3419).
+-define(wxBitmapDataObject_SetBitmap, 3420).
+-define(wxBitmapDataObject_destroy, 3421).
+-define(wxClipboard_new, 3423).
+-define(wxClipboard_destruct, 3424).
+-define(wxClipboard_AddData, 3425).
+-define(wxClipboard_Clear, 3426).
+-define(wxClipboard_Close, 3427).
+-define(wxClipboard_Flush, 3428).
+-define(wxClipboard_GetData, 3429).
+-define(wxClipboard_IsOpened, 3430).
+-define(wxClipboard_Open, 3431).
+-define(wxClipboard_SetData, 3432).
+-define(wxClipboard_UsePrimarySelection, 3434).
+-define(wxClipboard_IsSupported, 3435).
+-define(wxClipboard_Get, 3436).
+-define(wxSpinEvent_GetPosition, 3437).
+-define(wxSpinEvent_SetPosition, 3438).
+-define(wxSplitterWindow_new_0, 3439).
+-define(wxSplitterWindow_new_2, 3440).
+-define(wxSplitterWindow_destruct, 3441).
+-define(wxSplitterWindow_Create, 3442).
+-define(wxSplitterWindow_GetMinimumPaneSize, 3443).
+-define(wxSplitterWindow_GetSashGravity, 3444).
+-define(wxSplitterWindow_GetSashPosition, 3445).
+-define(wxSplitterWindow_GetSplitMode, 3446).
+-define(wxSplitterWindow_GetWindow1, 3447).
+-define(wxSplitterWindow_GetWindow2, 3448).
+-define(wxSplitterWindow_Initialize, 3449).
+-define(wxSplitterWindow_IsSplit, 3450).
+-define(wxSplitterWindow_ReplaceWindow, 3451).
+-define(wxSplitterWindow_SetSashGravity, 3452).
+-define(wxSplitterWindow_SetSashPosition, 3453).
+-define(wxSplitterWindow_SetSashSize, 3454).
+-define(wxSplitterWindow_SetMinimumPaneSize, 3455).
+-define(wxSplitterWindow_SetSplitMode, 3456).
+-define(wxSplitterWindow_SplitHorizontally, 3457).
+-define(wxSplitterWindow_SplitVertically, 3458).
+-define(wxSplitterWindow_Unsplit, 3459).
+-define(wxSplitterWindow_UpdateSize, 3460).
+-define(wxSplitterEvent_GetSashPosition, 3461).
+-define(wxSplitterEvent_GetX, 3462).
+-define(wxSplitterEvent_GetY, 3463).
+-define(wxSplitterEvent_GetWindowBeingRemoved, 3464).
+-define(wxSplitterEvent_SetSashPosition, 3465).
+-define(wxHtmlWindow_new_0, 3466).
+-define(wxHtmlWindow_new_2, 3467).
+-define(wxHtmlWindow_AppendToPage, 3468).
+-define(wxHtmlWindow_GetOpenedAnchor, 3469).
+-define(wxHtmlWindow_GetOpenedPage, 3470).
+-define(wxHtmlWindow_GetOpenedPageTitle, 3471).
+-define(wxHtmlWindow_GetRelatedFrame, 3472).
+-define(wxHtmlWindow_HistoryBack, 3473).
+-define(wxHtmlWindow_HistoryCanBack, 3474).
+-define(wxHtmlWindow_HistoryCanForward, 3475).
+-define(wxHtmlWindow_HistoryClear, 3476).
+-define(wxHtmlWindow_HistoryForward, 3477).
+-define(wxHtmlWindow_LoadFile, 3478).
+-define(wxHtmlWindow_LoadPage, 3479).
+-define(wxHtmlWindow_SelectAll, 3480).
+-define(wxHtmlWindow_SelectionToText, 3481).
+-define(wxHtmlWindow_SelectLine, 3482).
+-define(wxHtmlWindow_SelectWord, 3483).
+-define(wxHtmlWindow_SetBorders, 3484).
+-define(wxHtmlWindow_SetFonts, 3485).
+-define(wxHtmlWindow_SetPage, 3486).
+-define(wxHtmlWindow_SetRelatedFrame, 3487).
+-define(wxHtmlWindow_SetRelatedStatusBar, 3488).
+-define(wxHtmlWindow_ToText, 3489).
+-define(wxHtmlWindow_destroy, 3490).
+-define(wxHtmlLinkEvent_GetLinkInfo, 3491).
+-define(wxSystemSettings_GetColour, 3492).
+-define(wxSystemSettings_GetFont, 3493).
+-define(wxSystemSettings_GetMetric, 3494).
+-define(wxSystemSettings_GetScreenType, 3495).
+-define(wxSystemOptions_GetOption, 3496).
+-define(wxSystemOptions_GetOptionInt, 3497).
+-define(wxSystemOptions_HasOption, 3498).
+-define(wxSystemOptions_IsFalse, 3499).
+-define(wxSystemOptions_SetOption_2_1, 3500).
+-define(wxSystemOptions_SetOption_2_0, 3501).
+-define(wxAuiNotebookEvent_SetSelection, 3502).
+-define(wxAuiNotebookEvent_GetSelection, 3503).
+-define(wxAuiNotebookEvent_SetOldSelection, 3504).
+-define(wxAuiNotebookEvent_GetOldSelection, 3505).
+-define(wxAuiNotebookEvent_SetDragSource, 3506).
+-define(wxAuiNotebookEvent_GetDragSource, 3507).
+-define(wxAuiManagerEvent_SetManager, 3508).
+-define(wxAuiManagerEvent_GetManager, 3509).
+-define(wxAuiManagerEvent_SetPane, 3510).
+-define(wxAuiManagerEvent_GetPane, 3511).
+-define(wxAuiManagerEvent_SetButton, 3512).
+-define(wxAuiManagerEvent_GetButton, 3513).
+-define(wxAuiManagerEvent_SetDC, 3514).
+-define(wxAuiManagerEvent_GetDC, 3515).
+-define(wxAuiManagerEvent_Veto, 3516).
+-define(wxAuiManagerEvent_GetVeto, 3517).
+-define(wxAuiManagerEvent_SetCanVeto, 3518).
+-define(wxAuiManagerEvent_CanVeto, 3519).
+-define(wxLogNull_new, 3520).
+-define(wxLogNull_destroy, 3521).
+-define(wxTaskBarIcon_new, 3522).
+-define(wxTaskBarIcon_destruct, 3523).
+-define(wxTaskBarIcon_PopupMenu, 3524).
+-define(wxTaskBarIcon_RemoveIcon, 3525).
+-define(wxTaskBarIcon_SetIcon, 3526).
+-define(wxLocale_new_0, 3527).
+-define(wxLocale_new_2, 3529).
+-define(wxLocale_destruct, 3530).
+-define(wxLocale_Init, 3532).
+-define(wxLocale_AddCatalog_1, 3533).
+-define(wxLocale_AddCatalog_3, 3534).
+-define(wxLocale_AddCatalogLookupPathPrefix, 3535).
+-define(wxLocale_GetCanonicalName, 3536).
+-define(wxLocale_GetLanguage, 3537).
+-define(wxLocale_GetLanguageName, 3538).
+-define(wxLocale_GetLocale, 3539).
+-define(wxLocale_GetName, 3540).
+-define(wxLocale_GetString_2, 3541).
+-define(wxLocale_GetString_4, 3542).
+-define(wxLocale_GetHeaderValue, 3543).
+-define(wxLocale_GetSysName, 3544).
+-define(wxLocale_GetSystemEncoding, 3545).
+-define(wxLocale_GetSystemEncodingName, 3546).
+-define(wxLocale_GetSystemLanguage, 3547).
+-define(wxLocale_IsLoaded, 3548).
+-define(wxLocale_IsOk, 3549).
diff --git a/lib/wx/src/wx.app.src b/lib/wx/src/wx.app.src
index e13982b0c1..d5ac478f20 100644
--- a/lib/wx/src/wx.app.src
+++ b/lib/wx/src/wx.app.src
@@ -33,5 +33,6 @@
]},
{registered, []},
{applications, [stdlib, kernel]},
- {env, []}
+ {env, []},
+ {runtime_dependencies, ["stdlib-2.0","kernel-3.0","erts-6.0"]}
]}.
diff --git a/lib/wx/src/wxe_master.erl b/lib/wx/src/wxe_master.erl
index b98a7c793e..4b8a8f5720 100644
--- a/lib/wx/src/wxe_master.erl
+++ b/lib/wx/src/wxe_master.erl
@@ -28,7 +28,7 @@
-behaviour(gen_server).
%% API
--export([start/1, init_port/1, init_opengl/0]).
+-export([start/1, init_port/1, init_opengl/0, fetch_msgs/0]).
%% gen_server callbacks
-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
@@ -36,7 +36,9 @@
-record(state, {cb_port, %% Callback port and to erlang messages goes via it.
users, %% List of wx servers, needed ??
- driver}). %% Driver name so wx_server can create it's own port
+ driver, %% Driver name so wx_server can create it's own port
+ msgs=[] %% Early messages (such as openfiles on OSX)
+ }).
-include("wxe.hrl").
-include("gen/wxe_debug.hrl").
@@ -76,12 +78,18 @@ init_port(SilentStart) ->
%%--------------------------------------------------------------------
-%% Initlizes the opengl library
+%% Initalizes the opengl library
%%--------------------------------------------------------------------
init_opengl() ->
GLLib = wxe_util:wxgl_dl(),
wxe_util:call(?WXE_INIT_OPENGL, <<(list_to_binary(GLLib))/binary, 0:8>>).
+%%--------------------------------------------------------------------
+%% Fetch early messages, hack to get start up args on mac
+%%--------------------------------------------------------------------
+fetch_msgs() ->
+ gen_server:call(?MODULE, fetch_msgs, infinity).
+
%%====================================================================
%% gen_server callbacks
%%====================================================================
@@ -152,6 +160,8 @@ init([SilentStart]) ->
%%--------------------------------------------------------------------
handle_call(init_port, From, State=#state{driver=Driver,cb_port=CBPort, users=Users}) ->
{reply, {Driver,CBPort}, State#state{users=gb_sets:add(From,Users)}};
+handle_call(fetch_msgs, _From, State=#state{msgs=Msgs}) ->
+ {reply, lists:reverse(Msgs), State#state{msgs=[]}};
handle_call(_Request, _From, State) ->
%%io:format("Unknown request ~p sent to ~p from ~p ~n",[_Request, ?MODULE, _From]),
Reply = ok,
@@ -182,6 +192,8 @@ handle_info({wxe_driver, internal_error, Msg}, State) ->
handle_info({wxe_driver, debug, Msg}, State) ->
io:format("WX DBG: ~s~n", [Msg]),
{noreply, State};
+handle_info({wxe_driver, open_file, File}, State=#state{msgs=Msgs}) ->
+ {noreply, State#state{msgs=[File|Msgs]}};
handle_info(_Info, State) ->
io:format("Unknown message ~p sent to ~p~n",[_Info, ?MODULE]),
{noreply, State}.
diff --git a/lib/wx/src/wxe_server.erl b/lib/wx/src/wxe_server.erl
index aed9dca7ce..465b9da2e0 100644
--- a/lib/wx/src/wxe_server.erl
+++ b/lib/wx/src/wxe_server.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2013. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2014. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -192,17 +192,6 @@ handle_info({'DOWN',_,process,Pid,_}, State=#state{users=Users0,cleaners=Cs}) ->
{noreply, State}
end;
-handle_info(Msg = {'_wxe_destroy_', Pid}, State)
- when is_pid(Pid) ->
- case erlang:is_process_alive(Pid) of
- true ->
- Pid ! Msg,
- ok;
- false ->
- ok
- end,
- {noreply, State};
-
handle_info(_Info, State) ->
?log("Unknown message ~p sent to ~p~n",[_Info, ?MODULE]),
{noreply, State}.
diff --git a/lib/wx/test/wx_basic_SUITE.erl b/lib/wx/test/wx_basic_SUITE.erl
index 7bdbd4594c..e3bbb21a23 100644
--- a/lib/wx/test/wx_basic_SUITE.erl
+++ b/lib/wx/test/wx_basic_SUITE.erl
@@ -341,23 +341,22 @@ wx_object(Config) ->
Me = self(),
?m({call, foobar, {Me, _}}, wx_object:call(Frame, foobar)),
?m(ok, wx_object:cast(Frame, foobar2)),
- ?m([{cast, foobar2}], flush()),
+ ?m([{cast, foobar2}|_], flush()),
FramePid = wx_object:get_pid(Frame),
io:format("wx_object pid ~p~n",[FramePid]),
FramePid ! foo3,
- ?m([{info, foo3}], flush()),
+ ?m([{info, foo3}|_], flush()),
?m(ok, wx_object:cast(Frame, fun(_) -> hehe end)),
- ?m([{cast, hehe}], flush()),
+ ?m([{cast, hehe}|_], flush()),
wxWindow:refresh(Frame),
- ?m([{sync_event, #wx{event=#wxPaint{}}, _}], flush()),
+ ?m([{sync_event, #wx{event=#wxPaint{}}, _}|_], flush()),
?m(ok, wx_object:cast(Frame, fun(_) -> timer:sleep(200), slept end)),
%% The sleep above should not hinder the Paint event below
%% Which it did in my buggy handling of the sync_callback
wxWindow:refresh(Frame),
- ?m([{sync_event, #wx{event=#wxPaint{}}, _}], flush()),
timer:sleep(500),
- ?m([{cast, slept}], flush()),
+ ?m([{sync_event, #wx{event=#wxPaint{}}, _}, {cast, slept}|_], flush()),
Monitor = erlang:monitor(process, FramePid),
case proplists:get_value(user, Config, false) of
@@ -397,7 +396,7 @@ check_events([], Async, Sync) ->
end.
flush() ->
- flush([], 500).
+ flush([], 1500).
flush(Acc, Wait) ->
receive
diff --git a/lib/wx/test/wx_class_SUITE.erl b/lib/wx/test/wx_class_SUITE.erl
index 0e151ccc9b..b375c9d515 100644
--- a/lib/wx/test/wx_class_SUITE.erl
+++ b/lib/wx/test/wx_class_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2008-2013. All Rights Reserved.
+%% Copyright Ericsson AB 2008-2014. All Rights Reserved.
%%
%% The contents of this file are subject to the Erlang Public License,
%% Version 1.1, (the "License"); you may not use this file except in
@@ -344,21 +344,21 @@ listCtrlSort(Config) ->
Wx = wx:new(),
Frame = wxFrame:new(Wx, ?wxID_ANY, "Frame"),
- LC = wxListCtrl:new(Frame, [{style, ?wxLC_REPORT bor ?wxLC_SORT_ASCENDING}]),
+ LC = wxListCtrl:new(Frame, [{style, ?wxLC_REPORT}]),
%% must be done crashes in wxwidgets otherwise.
wxListCtrl:insertColumn(LC, 0, "Column"),
Add = fun(Int) ->
- wxListCtrl:insertItem(LC, Int, integer_to_list(Int)),
+ wxListCtrl:insertItem(LC, Int, "ABC " ++ integer_to_list(Int)),
%% ItemData Can only be integers currently
- wxListCtrl:setItemData(LC, Int, abs(2500-Int))
+ wxListCtrl:setItemData(LC, Int, abs(50-Int))
end,
- wx:foreach(Add, lists:seq(0,5000)),
+ wx:foreach(Add, lists:seq(0,50)),
wxWindow:show(Frame),
- timer:sleep(200),
+ timer:sleep(2000),
Sort = fun() ->
wxListCtrl:sortItems(LC, fun(A, B) ->
@@ -374,11 +374,12 @@ listCtrlSort(Config) ->
io:format("Sorted ~p ~n",[Time]),
Item = wxListItem:new(),
+ wxListItem:setMask(Item, ?wxLIST_MASK_TEXT),
_List = wx:map(fun(Int) ->
wxListItem:setId(Item, Int),
?m(true, wxListCtrl:getItem(LC, Item)),
- io:format("~s~n",[wxListItem:getText(Item)])
- end, lists:seq(0,100)),
+ io:format("~p: ~s~n",[Int, wxListItem:getText(Item)])
+ end, lists:seq(0,10)),
wxListItem:destroy(Item),
wx_test_lib:wx_destroy(Frame,Config).
diff --git a/lib/wx/vsn.mk b/lib/wx/vsn.mk
index c018b4fb86..5523c20440 100644
--- a/lib/wx/vsn.mk
+++ b/lib/wx/vsn.mk
@@ -1 +1 @@
-WX_VSN = 1.1.2
+WX_VSN = 1.2
diff --git a/lib/xmerl/src/xmerl.app.src b/lib/xmerl/src/xmerl.app.src
index b471447bbd..45cfe9d250 100644
--- a/lib/xmerl/src/xmerl.app.src
+++ b/lib/xmerl/src/xmerl.app.src
@@ -39,5 +39,6 @@
{registered, []},
{env, []},
- {applications, [kernel, stdlib]}
+ {applications, [kernel, stdlib]},
+ {runtime_dependencies, ["stdlib-2.0","kernel-3.0","erts-6.0"]}
]}.
diff --git a/lib/xmerl/vsn.mk b/lib/xmerl/vsn.mk
index 333466c11e..aab2a37d6c 100644
--- a/lib/xmerl/vsn.mk
+++ b/lib/xmerl/vsn.mk
@@ -1 +1 @@
-XMERL_VSN = 1.3.6
+XMERL_VSN = 1.3.7